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 }