commit 59b30ab1404c3c97b232afb51dea024f499fd4ea
parent 130276062d937dc40b5c9b757b526d099d4da412
Author: rminnich@gmail.com <none@none>
Date: Wed, 19 May 2010 14:33:20 -0700
hg mv did not add this file!
Diffstat:
1 file changed, 173 insertions(+), 0 deletions(-)
diff --git a/src/9vx/ratrace/ratrace.c b/src/9vx/ratrace/ratrace.c
@@ -0,0 +1,173 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+
+Channel *out;
+Channel *quit;
+Channel *forkc;
+int nread = 0;
+
+typedef struct Str Str;
+struct Str {
+ char *buf;
+ int len;
+};
+
+void
+die(char *s)
+{
+ fprint(2, "%s\n", s);
+ exits(s);
+}
+void
+cwrite(int fd, char *path, char *cmd, int len)
+{
+ if (write(fd, cmd, len) < len) {
+ fprint(2, "cwrite: %s: failed %d bytes: %r\n", path, len);
+ sendp(quit, nil);
+ threadexits(nil);
+ }
+}
+void
+reader(void *v)
+{
+ char *ctl, *truss;
+ int pid, newpid;
+ int cfd, tfd;
+ Str *s;
+ int forking = 0;
+
+ pid = (int)v;
+ ctl = smprint("/proc/%d/ctl", pid);
+ if ((cfd = open(ctl, OWRITE)) < 0)
+ die(smprint("%s: %r", ctl));
+ truss = smprint("/proc/%d/syscall", pid);
+ if ((tfd = open(truss, OREAD)) < 0)
+ die(smprint("%s: %r", truss));
+
+ cwrite(cfd, ctl, "stop", 4);
+ cwrite(cfd, truss, "startsyscall", 12);
+
+ s = mallocz(sizeof(Str) + 8192, 1);
+ s->buf = (char *)&s[1];
+ /* 8191 is not a typo. It ensures a null-terminated string. The device currently limits to 4096 anyway */
+ while((s->len = pread(tfd, s->buf, 8191, 0ULL)) > 0){
+ if (forking && (s->buf[1] == '=') && (s->buf[3] != '-')) {
+ forking = 0;
+ newpid = strtol(&s->buf[3], 0, 0);
+ sendp(forkc, (void*)newpid);
+ procrfork(reader, (void*)newpid, 8192, 0);
+ }
+
+ /* There are three tests here and they (I hope) guarantee no false positives */
+ if (strstr(s->buf, " Rfork") != nil) {
+ char *a[8];
+ char *rf;
+ rf = strdup(s->buf);
+ if (tokenize(rf, a, 8) == 5) {
+ unsigned long flags;
+ flags = strtoul(a[4], 0, 16);
+ if (flags & RFPROC)
+ forking = 1;
+ }
+ free(rf);
+ }
+ sendp(out, s);
+ cwrite(cfd, truss, "startsyscall", 12);
+ s = mallocz(sizeof(Str) + 8192, 1);
+ s->buf = (char *)&s[1];
+
+ }
+ sendp(quit, nil);
+ threadexitsall(nil);
+}
+
+
+void
+writer(void *)
+{
+ Alt a[4];
+ Str *s;
+ int newpid;
+
+ a[0].op = CHANRCV;
+ a[0].c = quit;
+ a[0].v = nil;
+ a[1].op = CHANRCV;
+ a[1].c = out;
+ a[1].v = &s;
+ a[2].op = CHANRCV;
+ a[2].c = forkc;
+ a[2].v = &newpid;
+ a[3].op = CHANEND;
+
+ for(;;) {
+ switch(alt(a)){
+ case 0:
+ nread--;
+ if(nread <= 0)
+ goto done;
+ break;
+ case 1:
+ /* it's a nice null terminated thing */
+ fprint(2, "%s", s->buf);
+ free(s);
+ break;
+ case 2:
+// procrfork(reader, (void*)newpid, 8192, 0);
+ nread++;
+ break;
+ }
+ }
+done:
+ exits(nil);
+}
+
+void
+usage(void){
+ fprint(2, "Usage: syscalltrace [-c cmd] [pid] (one of these is required)\n");
+ exits("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ int pid;
+ char *cmd = nil;
+ char **args = nil;
+
+ ARGBEGIN{
+ case 'c':
+ cmd = strdup(EARGF(usage()));
+ args = argv;
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ /* run a command? */
+ if(cmd) {
+ pid = fork();
+ if (pid < 0) {
+ fprint(2, "No fork: %r\n");
+ exits("fork failed");
+ }
+ if(pid == 0) {
+ exec(cmd, args);
+ fprint(2, "Bad exec: %s: %r\n", cmd);
+ exits("Bad exec");
+ }
+ } else {
+ if(argc != 1)
+ sysfatal("usage");
+ pid = atoi(argv[0]);
+ }
+
+ out = chancreate(sizeof(char*), 0);
+ quit = chancreate(sizeof(char*), 0);
+ forkc = chancreate(sizeof(ulong *), 0);
+ nread++;
+ procrfork(writer, nil, 8192, 0);
+ reader((void*)pid);
+}