Blob
1 // poor emulation of SVR5 truss command - traces system calls3 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") then13 {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 do19 {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 do33 {34 s = head l;35 if regexp(pattern, s[0]) && ((s[1] == 'T') || (s[1] == 'L')) then36 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 binary153 if _addressof("_EXITS") == 0 then154 return _addressof(pattern);155 return _addressof(trussapecalls[match(pattern, trusscalls)]);156 }158 defn setuptruss() {159 local lst, offset, name, addr;161 trussbpt = {};162 offset = trapoffset();163 lst = trusscalls;164 while lst do165 {166 name = head lst;167 lst = tail lst;168 addr = addressof(name);169 if addr then170 {171 bpset(addr+offset);172 trussbpt = append trussbpt, (addr+offset);173 // sometimes _exits is renamed $_exits174 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 kernel180 if(regexp("_wait", name)) then _waitPC = append _waitPC, (addr+offset);181 if(regexp("_errstr", name)) then _errstrPC = append _errstrPC, (addr+offset);182 }183 }184 }186 defn trussflush() {187 stop(pid); // already stopped, but flushes output188 }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 hang197 printto("/proc/"+itoa(pid)+"/ctl", "nohang");198 }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 {};215 }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 {};222 }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");234 }235 if (ret>=0) && (match(prevpc, fd2pathPC)>=0) then {236 print("\tdata: \"", *(*((eval pcspret[1])+4)\s), "\"\n");237 }238 if (ret>=0) && (match(prevpc, errstrPC)>=0) then {239 print("\tdata: \"", *(*(eval pcspret[1])\s), "\"\n");240 }241 if (ret>=0) && (match(prevpc, awaitPC)>=0) then {242 print("\tdata: ");243 printtextordata(*(eval pcspret[1]), ret);244 print("\n");245 }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");251 }252 if (ret>=0) && (match(prevpc, _errstrPC)>=0) then {253 print("\tdata: ");254 printtextordata(*(eval pcspret[1]), 64);255 print("\n");256 }257 }258 trussflush();259 }260 }262 defn cleantruss() {263 local lst, offset, addr;265 stop(pid);266 offset = trapoffset();267 lst = trussbpt;268 while lst do269 {270 addr = head lst;271 lst = tail lst;272 bpdel(addr);273 }274 trussbpt = {};275 **PC = @*PC; // repair current instruction276 }278 defn untruss() {279 cleantruss();280 start(pid);281 }283 print(acidfile);