vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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 }