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 }