URI: 
       ttruss - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       ttruss (5244B)
       ---
            1 // poor emulation of SVR5 truss command - traces system calls
            2 
            3 include("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                 "seek",
           88                 "fversion",
           89                 "errstr",
           90                 "stat",
           91                 "fstat",
           92                 "wstat",
           93                 "fwstat",
           94                 "mount",
           95                 "await",
           96                 "pread",
           97                 "pwrite",
           98         };
           99 
          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         };
          150 
          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)]);
          156 }
          157 
          158 defn setuptruss() {
          159         local lst, offset, name, addr;
          160 
          161         trussbpt = {};
          162         offset = trapoffset();
          163         lst = trusscalls;
          164         while lst do
          165         {
          166                 name = head lst;
          167                 lst = tail lst;
          168                 addr = addressof(name);
          169                 if addr then
          170                 {
          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);
          182                 }
          183         }
          184 }
          185 
          186 defn trussflush() {
          187         stop(pid);                // already stopped, but flushes output
          188 }
          189 
          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");
          198 }
          199 
          200 defn truss() {
          201         local pc, lst, offset, prevpc, pcspret, ret;
          202 
          203         offset = trapoffset();
          204 
          205         stop(pid);
          206         _stoprunning = 0;
          207         setuptruss();
          208         pcspret = UPCSPRET();
          209 
          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 }
          261 
          262 defn cleantruss() {
          263         local lst, offset, addr;
          264 
          265         stop(pid);
          266         offset = trapoffset();
          267         lst = trussbpt;
          268         while lst do
          269         {
          270                 addr = head lst;
          271                 lst = tail lst;
          272                 bpdel(addr);
          273         }
          274         trussbpt = {};
          275         **PC = @*PC;        // repair current instruction
          276 }
          277 
          278 defn untruss() {
          279         cleantruss();
          280         start(pid);
          281 }
          282 
          283 print(acidfile);