truss 5.1 KB

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