ratrace.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       ratrace.c (3387B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <thread.h>
            5 
            6 Channel *out;
            7 Channel *quit;
            8 Channel *forkc;
            9 int nread = 0;
           10 
           11 typedef struct Str Str;
           12 struct Str {
           13         char *buf;
           14         int len;
           15 };
           16 
           17 void
           18 die(char *s)
           19 {
           20         fprint(2, "%s\n", s);
           21         exits(s);
           22 }
           23 void
           24 cwrite(int fd, char *path, char *cmd, int len)
           25 {
           26         if (write(fd, cmd, len)  < len) {
           27                 fprint(2, "cwrite: %s: failed %d bytes: %r\n", path, len);
           28                 sendp(quit, nil);
           29                 threadexits(nil);
           30         }
           31 }
           32 
           33 void
           34 hang(int pid)
           35 {
           36         char *ctl;
           37         int cfd;
           38         ctl = smprint("/proc/%d/ctl", pid);
           39         if ((cfd = open(ctl, OWRITE)) < 0)
           40                 die(smprint("%s: %r", ctl));
           41         if (write(cfd, "hang", 4) < 4) {
           42                 print("%s: %r\n", ctl);
           43                 exits("can't hang child");
           44         }
           45 
           46 }
           47 
           48 void
           49 reader(void *v)
           50 {
           51         char *ctl, *truss;
           52         int pid, newpid;
           53         int cfd, tfd;
           54         Str *s;
           55         int forking = 0;
           56 
           57         pid = (int)v;
           58         ctl = smprint("/proc/%d/ctl", pid);
           59         if ((cfd = open(ctl, OWRITE)) < 0)
           60                 die(smprint("%s: %r", ctl));
           61         truss = smprint("/proc/%d/syscall", pid);
           62         if ((tfd = open(truss, OREAD)) < 0)
           63                 die(smprint("%s: %r", truss));
           64 
           65         cwrite(cfd, ctl, "stop", 4);
           66         cwrite(cfd, truss, "startsyscall", 12);
           67 
           68         s = mallocz(sizeof(Str) + 8192, 1);
           69         s->buf = (char *)&s[1];
           70         /* 8191 is not a typo. It ensures a null-terminated string. The device currently limits to 4096 anyway */
           71         while((s->len = pread(tfd, s->buf, 8191, 0ULL)) > 0){
           72                 if (forking && (s->buf[1] == '=') && (s->buf[3] != '-')) {
           73                         forking = 0;
           74                         newpid = strtol(&s->buf[3], 0, 0);
           75                         sendp(forkc, (void*)newpid);
           76                         procrfork(reader, (void*)newpid, 8192, 0);
           77                 }
           78 
           79                 /* There are three tests here and they (I hope) guarantee no false positives */
           80                 if (strstr(s->buf, " Rfork") != nil) {
           81                         char *a[8];
           82                         char *rf;
           83                         rf = strdup(s->buf);
           84                          if (tokenize(rf, a, 8) == 5) {
           85                                 unsigned long flags;
           86                                 flags = strtoul(a[4], 0, 16);
           87                                 if (flags & RFPROC)
           88                                         forking = 1;
           89                         }
           90                         free(rf);                        
           91                 }
           92                 sendp(out, s);                        
           93                 cwrite(cfd, truss, "startsyscall", 12);
           94                 s = mallocz(sizeof(Str) + 8192, 1);
           95                 s->buf = (char *)&s[1];
           96 
           97         }
           98         sendp(quit, nil);
           99         threadexitsall(nil);
          100 }
          101 
          102 
          103 void
          104 writer(void *)
          105 {
          106         Alt a[4];
          107         Str *s;
          108         int newpid;
          109 
          110         a[0].op = CHANRCV;
          111         a[0].c = quit;
          112         a[0].v = nil;
          113         a[1].op = CHANRCV;
          114         a[1].c = out;
          115         a[1].v = &s;
          116         a[2].op = CHANRCV;
          117         a[2].c = forkc;
          118         a[2].v = &newpid;
          119         a[3].op = CHANEND;
          120 
          121         for(;;) { 
          122         switch(alt(a)){
          123         case 0:
          124                 nread--;
          125                 if(nread <= 0)
          126                         goto done;
          127                 break;
          128         case 1:
          129                 /* it's a nice null terminated thing */
          130                 fprint(2, "%s", s->buf);
          131                 free(s);
          132                 break;
          133         case 2:
          134 //                procrfork(reader, (void*)newpid, 8192, 0);
          135                 nread++;
          136                 break;
          137         }
          138         }
          139 done:
          140         exits(nil);
          141 }
          142 
          143 void
          144 usage(void){
          145         fprint(2, "Usage: syscalltrace [-c cmd] [pid] (one of these is required)\n");
          146         exits("usage");
          147 }
          148 
          149 void
          150 threadmain(int argc, char **argv)
          151 {
          152         int pid;
          153         char *cmd = nil;
          154         char **args = nil;
          155 
          156         ARGBEGIN{
          157         case 'c':
          158                 cmd = strdup(EARGF(usage()));
          159                 args = argv;
          160                 break;
          161         default:
          162                 usage();
          163         }ARGEND;
          164 
          165         /* run a command? */
          166         if(cmd) {
          167                 pid = fork();
          168                 if (pid < 0) {
          169                         fprint(2, "No fork: %r\n");
          170                         exits("fork failed");
          171                 }
          172                 if(pid == 0) {
          173                         hang(getpid());
          174                         exec(cmd, args);
          175                         fprint(2, "Bad exec: %s: %r\n", cmd);
          176                         exits("Bad exec");
          177                 }
          178         } else {
          179                 if(argc != 1)
          180                         sysfatal("usage");
          181                 pid = atoi(argv[0]);
          182         }
          183 
          184         out = chancreate(sizeof(char*), 0);
          185         quit = chancreate(sizeof(char*), 0);
          186         forkc = chancreate(sizeof(ulong *), 0);
          187         nread++;
          188         procrfork(writer, nil, 8192, 0);
          189         reader((void*)pid);
          190 }