1 /* -*- D -*-
2  *
3  * Execution flow trace with arguments
4  *
5  * Activate tracing between
6  *    ::nsf::configure dtrace on
7  * and
8  *    ::nsf::configure dtrace off
9  *
10  * Since this D script accesses the C data structures it is sensitive
11  * to the representation sizes of the data structures (e.g. pointers).
12  * Make sure to call the script with the appropriate architecture flag
13  * on Mac OS X; on SunOS, there is apparently a -32 or -64 flag.
14  *
15  * Example:
16  *
17  *   sudo dtrace -arch x86_64 -x bufsize=20m -F -s dtrace/execution-flow-args.d \
18  *	-c "./nxsh dtrace/sample.tcl"
19  *
20  * -gustaf neumann
21  */
22 
23 enum {maxstrlen = 50};
24 
25 /*
26  * Needed data structures to access the content of Tcl_Objs.
27  */
28 typedef struct Tcl_Obj Tcl_Obj;
29 
30 typedef struct Tcl_ObjType {
31     char *name;
32     void *freeIntRepProc;
33     void *dupIntRepProc;
34     void *updateStringProc;
35     void *setFromAnyProc;
36 } Tcl_ObjType;
37 
38 struct Tcl_Obj {
39     int refCount;
40     char *bytes;
41     int length;
42     Tcl_ObjType *typePtr;
43     union {
44 	long longValue;
45 	double doubleValue;
46 	void *otherValuePtr;
47 	int64_t wideValue;
48 	struct {
49 	    void *ptr1;
50 	    void *ptr2;
51 	} twoPtrValue;
52 	struct {
53 	    void *ptr;
54 	    unsigned long value;
55 	} ptrAndLongRep;
56     } internalRep;
57 };
58 
59 /*
60  * Handling "nsf::configure dtrace on|off".
61  */
62 nsf*:::configure-probe /!self->tracing && copyinstr(arg0) == "dtrace" / {
63   self->tracing = (arg1 && copyinstr(arg1) == "on") ? 1 : 0;
64 }
65 
66 nsf*:::configure-probe /self->tracing && copyinstr(arg0) == "dtrace" / {
67   self->tracing = (arg1 && copyinstr(arg1) == "off") ? 0 : 1;
68 }
69 
70 /*
71  * Output object, class, method, number of arguments and first two
72  * arguments upon method invocation.
73  */
74 nsf*:::method-entry /self->tracing/ {
75 
76   this->objv = arg3 ? ((Tcl_Obj**)copyin((user_addr_t)((Tcl_Obj**)arg4),
77 					 sizeof(Tcl_Obj*) * arg3)) : NULL;
78 
79   this->i = 0;
80   this->o = arg3 > this->i && *(this->objv + this->i) ?
81     (Tcl_Obj*)copyin((user_addr_t)*(this->objv + this->i), sizeof(Tcl_Obj)) : NULL;
82   this->s0 = this->o ? (this->o->bytes ? copyinstr((user_addr_t)this->o->bytes, maxstrlen) :
83 			lltostr(this->o->internalRep.longValue)) : "";
84 
85   this->i = 1;
86   this->o = arg3 > this->i && *(this->objv + this->i) ?
87     (Tcl_Obj*)copyin((user_addr_t)*(this->objv + this->i), sizeof(Tcl_Obj)) : NULL;
88   this->s1 = this->o ? (this->o->bytes ? copyinstr((user_addr_t)this->o->bytes, maxstrlen) :
89 			lltostr(this->o->internalRep.longValue)) : "";
90 
91   printf("%s %s.%s (%d) %s %s",
92 	 copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3,
93 	 this->s0, this->s1);
94 }
95 
96 /*
97  * Output object, class, method and return code upon method return.
98  */
99 nsf*:::method-return /self->tracing/ {
100   printf("%s %s.%s -> %d", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
101 }
102