]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/acid/truss
ip/tftpd: add a syslog message about what error we return to the client on a NAK
[plan9front.git] / sys / lib / acid / truss
1 // poor emulation of SVR5 truss command - traces system calls
2
3 include("/sys/lib/acid/syscall");
4
5 _stoprunning = 0;
6
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 }
27
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 }
41
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                 "semacquire",
88                 "semrelease",
89                 "seek",
90                 "fversion",
91                 "errstr",
92                 "stat",
93                 "fstat",
94                 "wstat",
95                 "fwstat",
96                 "mount",
97                 "await",
98                 "pread",
99                 "pwrite",
100                 "tsemacquire",
101                 "_nsec",
102         };
103
104 trussapecalls = {
105                 "_SYSR1",
106                 "__ERRSTR",
107                 "_BIND",
108                 "_CHDIR",
109                 "_CLOSE",
110                 "_DUP",
111                 "_ALARM",
112                 "_EXEC",
113                 "_EXITS",
114                 "__FSESSION",
115                 "_FAUTH",
116                 "__FSTAT",
117                 "_SEGBRK",
118                 "__MOUNT",
119                 "_OPEN",
120                 "__READ",
121                 "_OSEEK",
122                 "_SLEEP",
123                 "__STAT",
124                 "_RFORK",
125                 "__WRITE",
126                 "_PIPE",
127                 "_CREATE",
128                 "_FD2PATH",
129                 "_BRK_",
130                 "_REMOVE",
131                 "__WSTAT",
132                 "__FWSTAT",
133                 "_NOTIFY",
134                 "_NOTED",
135                 "_SEGATTACH",
136                 "_SEGDETACH",
137                 "_SEGFREE",
138                 "_SEGFLUSH",
139                 "_RENDEZVOUS",
140                 "_UNMOUNT",
141                 "__WAIT",
142                 "_SEMACQUIRE",
143                 "_SEMRELEASE",
144                 "_SEEK",
145                 "__NFVERSION",
146                 "__NERRSTR",
147                 "_STAT",
148                 "__NFSTAT",
149                 "__NWSTAT",
150                 "__NFWSTAT",
151                 "__NMOUNT",
152                 "__NAWAIT",
153                 "_PREAD",
154                 "_PWRITE",
155                 "_TSEMACQUIRE",
156                 "__NSEC",
157         };
158
159 defn addressof(pattern) {
160         // translate to ape system calls if we have an ape binary
161         if _addressof("_EXITS") != 0 then
162                 pattern = trussapecalls[match(pattern, trusscalls)];
163         if regexp("(seek|_SEEK)", pattern) && (objtype=="amd64" || objtype == "power64") then
164                 pattern = "_" + pattern;
165         return _addressof(pattern);
166 }
167
168 defn setuptruss() {
169         local lst, offset, name, addr;
170
171         trussbpt = {};
172         offset = trapoffset();
173         lst = trusscalls;
174         while lst do
175         {
176                 name = head lst;
177                 lst = tail lst;
178                 addr = addressof(name);
179                 if addr then
180                 {
181                         bpset(addr+offset);
182                         trussbpt = append trussbpt, (addr+offset);
183                         // sometimes _exits is renamed $_exits
184                         if(regexp("exits|exec", name)) then stopPC = append stopPC, (addr+offset);
185                         if(regexp("read", name)) then readPC = append readPC, (addr+offset);
186                         if(regexp("fd2path", name)) then fd2pathPC = append fd2pathPC, (addr+offset);
187                         if(regexp("^\\$*await", name)) then awaitPC = append awaitPC, (addr+offset);
188                         if(regexp("^\\$*errstr", name)) then errstrPC = append errstrPC, (addr+offset);
189                         // compatibility hacks for old kernel
190                         if(regexp("_wait", name)) then _waitPC = append _waitPC, (addr+offset);
191                         if(regexp("_errstr", name)) then _errstrPC = append _errstrPC, (addr+offset);
192                 }
193         }
194 }
195
196 defn trussflush() {
197         stop(pid);              // already stopped, but flushes output
198 }
199
200 defn new() {
201         bplist = {};
202         newproc(progargs);
203         bpset(follow(main)[0]);
204         cont();
205         bpdel(*PC);
206         // clear the hang bit, which is left set by newproc, so programs we fork/exec don't hang
207         printto("/proc/"+itoa(pid)+"/ctl", "nohang");
208 }
209
210 defn truss() {
211         local pc, lst, offset, prevpc, pcspret, arg, ret;
212
213         offset = trapoffset();
214
215         stop(pid);
216         _stoprunning = 0;
217         setuptruss();
218         pcspret = UPCSPRET();
219
220         while !_stoprunning do {
221                 cont();
222                 if notes[0]!="sys: breakpoint" then {
223                         cleantruss();
224                         return {};
225                 }
226                 pc = *PC;
227                 if match(*PC, stopPC)>=0 then {
228                         print(pid,": ",trapreason(),"\t");
229                         print(fmt(pc,'a'),"\t",fmt(pc,'i'),"\n");
230                         cleantruss();
231                         return {};
232                 }
233                 if match(*PC, trussbpt)>=0 then {
234                         usyscall();
235                         trussflush();
236                         prevpc = *PC;
237                         step();
238                         arg = eval pcspret[1];
239                         ret = eval pcspret[2];
240                         print("\treturn value: ", ret\D, "\n");
241                         if (ret>=0) && (match(prevpc, readPC)>=0) then {
242                                 print("\tdata: ");
243                                 printtextordata(arg[1], ret);
244                                 print("\n");
245                         }
246                         if (ret>=0) && (match(prevpc, fd2pathPC)>=0) then {
247                                 print("\tdata: \"", *(arg[1]\s), "\"\n");
248                         }
249                         if (ret>=0) && (match(prevpc, errstrPC)>=0) then {
250                                 print("\tdata: \"", *(arg[0]\s), "\"\n");
251                         }
252                         if (ret>=0) && (match(prevpc, awaitPC)>=0) then {
253                                 print("\tdata: ");
254                                 printtextordata(arg[0], ret);
255                                 print("\n");
256                         }
257                         // compatibility hacks for old kernel:
258                         if (ret>=0) && (match(prevpc, _waitPC)>=0) then {
259                                 print("\tdata: ");
260                                 printtextordata(arg[0], 12+3*12+64);
261                                 print("\n");
262                         }
263                         if (ret>=0) && (match(prevpc, _errstrPC)>=0) then {
264                                 print("\tdata: ");
265                                 printtextordata(arg[0], 64);
266                                 print("\n");
267                         }
268                 }
269                 trussflush();
270         }
271 }
272
273 defn cleantruss() {
274         local lst, offset, addr;
275
276         stop(pid);
277         offset = trapoffset();
278         lst = trussbpt;
279         while lst do
280         {
281                 addr = head lst;
282                 lst = tail lst;
283                 bpdel(addr);
284         }
285         trussbpt = {};
286         **PC = @*PC;    // repair current instruction
287 }
288
289 defn untruss() {
290         cleantruss();
291         start(pid);
292 }
293
294 print("/sys/lib/acid/truss");