rminnichmerge57758a716 years agoHistory
196 lines · 3.4 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <bio.h>#include <thread.h>/*8c truss2.c &&8l -o truss2 truss2.8 &&win & truss2 $apidcat /proc/205/statusecho 'lstk()' | acid 205*/ Channel *out;Channel *quit;Channel *forkc;int nread = 0; typedef struct Str Str;struct Str {	char *buf;	int len;}; voiddie(char *s){	fprint(2, "%s\n", s);	exits(s);}voidcwrite(int fd, char *path, char *cmd, int len){	if (write(fd, cmd, len)  < len) {		print("cwrite: %s: failed %d bytes: %r\n", path, len);		sendp(quit, nil);		threadexits(nil);	}} voidhang(void){	char *ctl;	int cfd;	ctl = smprint("/proc/%d/ctl", getpid());	if ((cfd = open(ctl, OWRITE)) < 0)		die(smprint("%s: %r", ctl));	if (write(cfd, "hang", 4) < 4) {		print("%s: %r\n", ctl);		exits("can't hang child");	} }voidreader(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);}  voidwriter(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 */		print("%s", s->buf);		free(s);		break;	case 2://		procrfork(reader, (void*)newpid, 8192, 0);		nread++;		break;	}	}done:	exits(nil);} voidusage(void){	fprint(2, "Usage: syscalltrace [-c cmd] [pid] (one of these is required)\n");	exits("usage");} voidthreadmain(int argc, char **argv){	int pid;	char *cmd = nil;	char **args = nil; 	ARGBEGIN{	case 'c':		cmd = EARGF(usage());		args = argv++;		break;	default:		usage();	}ARGEND; 	/* run a command? */	if(cmd) {		pid = fork();		if (pid < 0) {			print("No fork: %r\n");			exits("fork failed");		}		if(pid == 0) {			hang();			exec(cmd, args);			print("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);}