Blob


1 // poor emulation of SVR5 truss command - traces system calls
3 include("syscall");
5 _stoprunning = 0;
7 defn stopped(pid) {
8 local l;
9 local pc;
10 pc = *PC;
11 if notes then {
12 if (notes[0]!="sys: breakpoint") then
13 {
14 print(pid,": ",trapreason(),"\t");
15 print(fmt(pc,97),"\t",fmt(pc,105),"\n");
16 print("Notes pending:\n");
17 l = notes;
18 while l do
19 {
20 print("\t",head l,"\n");
21 l = tail l;
22 }
23 _stoprunning = 1;
24 }
25 }
26 }
28 defn _addressof(pattern) {
29 local s, l;
30 l = symbols;
31 pattern = "^\\$*"+pattern+"$";
32 while l do
33 {
34 s = head l;
35 if regexp(pattern, s[0]) && ((s[1] == 'T') || (s[1] == 'L')) then
36 return s[2];
37 l = tail l;
38 }
39 return 0;
40 }
42 stopPC = {};
43 readPC = {};
44 fd2pathPC = {};
45 errstrPC = {};
46 awaitPC = {};
47 _waitPC = {};
48 _errstrPC = {};
49 trusscalls = {
50 "sysr1",
51 "_errstr",
52 "bind",
53 "chdir",
54 "close",
55 "dup",
56 "alarm",
57 "exec",
58 "_exits",
59 "_fsession",
60 "fauth",
61 "_fstat",
62 "segbrk",
63 "_mount",
64 "open",
65 "_read",
66 "oseek",
67 "sleep",
68 "_stat",
69 "rfork",
70 "_write",
71 "pipe",
72 "create",
73 "fd2path",
74 "brk_",
75 "remove",
76 "_wstat",
77 "_fwstat",
78 "notify",
79 "noted",
80 "segattach",
81 "segdetach",
82 "segfree",
83 "segflush",
84 "rendezvous",
85 "unmount",
86 "_wait",
87 "seek",
88 "fversion",
89 "errstr",
90 "stat",
91 "fstat",
92 "wstat",
93 "fwstat",
94 "mount",
95 "await",
96 "pread",
97 "pwrite",
98 };
100 trussapecalls = {
101 "_SYSR1",
102 "__ERRSTR",
103 "_BIND",
104 "_CHDIR",
105 "_CLOSE",
106 "_DUP",
107 "_ALARM",
108 "_EXEC",
109 "_EXITS",
110 "__FSESSION",
111 "_FAUTH",
112 "__FSTAT",
113 "_SEGBRK",
114 "__MOUNT",
115 "_OPEN",
116 "__READ",
117 "_OSEEK",
118 "_SLEEP",
119 "__STAT",
120 "_RFORK",
121 "__WRITE",
122 "_PIPE",
123 "_CREATE",
124 "_FD2PATH",
125 "_BRK_",
126 "_REMOVE",
127 "__WSTAT",
128 "__FWSTAT",
129 "_NOTIFY",
130 "_NOTED",
131 "_SEGATTACH",
132 "_SEGDETACH",
133 "_SEGFREE",
134 "_SEGFLUSH",
135 "_RENDEZVOUS",
136 "_UNMOUNT",
137 "__WAIT",
138 "_SEEK",
139 "__NFVERSION",
140 "__NERRSTR",
141 "_STAT",
142 "__NFSTAT",
143 "__NWSTAT",
144 "__NFWSTAT",
145 "__NMOUNT",
146 "__NAWAIT",
147 "_PREAD",
148 "_PWRITE",
149 };
151 defn addressof(pattern) {
152 // translate to ape system calls if we have an ape binary
153 if _addressof("_EXITS") == 0 then
154 return _addressof(pattern);
155 return _addressof(trussapecalls[match(pattern, trusscalls)]);
158 defn setuptruss() {
159 local lst, offset, name, addr;
161 trussbpt = {};
162 offset = trapoffset();
163 lst = trusscalls;
164 while lst do
166 name = head lst;
167 lst = tail lst;
168 addr = addressof(name);
169 if addr then
171 bpset(addr+offset);
172 trussbpt = append trussbpt, (addr+offset);
173 // sometimes _exits is renamed $_exits
174 if(regexp("exits|exec", name)) then stopPC = append stopPC, (addr+offset);
175 if(regexp("read", name)) then readPC = append readPC, (addr+offset);
176 if(regexp("fd2path", name)) then fd2pathPC = append fd2pathPC, (addr+offset);
177 if(regexp("^\\$*await", name)) then awaitPC = append awaitPC, (addr+offset);
178 if(regexp("^\\$*errstr", name)) then errstrPC = append errstrPC, (addr+offset);
179 // compatibility hacks for old kernel
180 if(regexp("_wait", name)) then _waitPC = append _waitPC, (addr+offset);
181 if(regexp("_errstr", name)) then _errstrPC = append _errstrPC, (addr+offset);
186 defn trussflush() {
187 stop(pid); // already stopped, but flushes output
190 defn new() {
191 bplist = {};
192 newproc(progargs);
193 bpset(follow(main)[0]);
194 cont();
195 bpdel(*PC);
196 // clear the hang bit, which is left set by newproc, so programs we fork/exec don't hang
197 printto("/proc/"+itoa(pid)+"/ctl", "nohang");
200 defn truss() {
201 local pc, lst, offset, prevpc, pcspret, ret;
203 offset = trapoffset();
205 stop(pid);
206 _stoprunning = 0;
207 setuptruss();
208 pcspret = UPCSPRET();
210 while !_stoprunning do {
211 cont();
212 if notes[0]!="sys: breakpoint" then {
213 cleantruss();
214 return {};
216 pc = *PC;
217 if match(*PC, stopPC)>=0 then {
218 print(pid,": ",trapreason(),"\t");
219 print(fmt(pc,'a'),"\t",fmt(pc,'i'),"\n");
220 cleantruss();
221 return {};
223 if match(*PC, trussbpt)>=0 then {
224 usyscall();
225 trussflush();
226 prevpc = *PC;
227 step();
228 ret = eval pcspret[2];
229 print("\treturn value: ", ret\D, "\n");
230 if (ret>=0) && (match(prevpc, readPC)>=0) then {
231 print("\tdata: ");
232 printtextordata(*((eval pcspret[1])+4), ret);
233 print("\n");
235 if (ret>=0) && (match(prevpc, fd2pathPC)>=0) then {
236 print("\tdata: \"", *(*((eval pcspret[1])+4)\s), "\"\n");
238 if (ret>=0) && (match(prevpc, errstrPC)>=0) then {
239 print("\tdata: \"", *(*(eval pcspret[1])\s), "\"\n");
241 if (ret>=0) && (match(prevpc, awaitPC)>=0) then {
242 print("\tdata: ");
243 printtextordata(*(eval pcspret[1]), ret);
244 print("\n");
246 // compatibility hacks for old kernel:
247 if (ret>=0) && (match(prevpc, _waitPC)>=0) then {
248 print("\tdata: ");
249 printtextordata(*(eval pcspret[1]), 12+3*12+64);
250 print("\n");
252 if (ret>=0) && (match(prevpc, _errstrPC)>=0) then {
253 print("\tdata: ");
254 printtextordata(*(eval pcspret[1]), 64);
255 print("\n");
258 trussflush();
262 defn cleantruss() {
263 local lst, offset, addr;
265 stop(pid);
266 offset = trapoffset();
267 lst = trussbpt;
268 while lst do
270 addr = head lst;
271 lst = tail lst;
272 bpdel(addr);
274 trussbpt = {};
275 **PC = @*PC; // repair current instruction
278 defn untruss() {
279 cleantruss();
280 start(pid);
283 print(acidfile);