rminnichmerge57758a716 years agoHistory
887 lines · 17.5 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"netif.h" #pragma profile 0 typedef struct Trace Trace;/* This is a trace--a segment of memory to watch for entries and exits */struct Trace {	struct Trace *next;	void *func;	void *start;	void *end;	int enabled;	char name[16];}; enum {	Qdir,	Qctl,	Qdata,}; enum {	TraceEntry = 1, 	TraceExit,}; /* fix me make this programmable */enum {	defaultlogsize = 8192,}; /* This represents a trace "hit" or event */typedef struct Tracelog Tracelog;struct Tracelog {	uvlong ticks;	int info;	uintptr pc;	/* these are different depending on type */	uintptr dat[5];	int machno;};  static Rendez tracesleep;static QLock traceslock;/* this will contain as many entries as there are valid pc values */static Trace **tracemap;static Trace *traces; /* This stores all the traces */static Lock loglk;static Tracelog *tracelog = nil;int traceactive = 0;/* trace indices. These are just unsigned longs. You mask them  * to get an index. This makes fifo empty/full etc. trivial.  */static uint pw = 0, pr = 0;static int tracesactive = 0;static int all = 0;static int watching = 0;static int slothits = 0;static unsigned int traceinhits = 0;static unsigned int newplfail = 0;static unsigned long logsize = defaultlogsize, logmask = defaultlogsize - 1; static int printsize = 0;	//The length of a line being printed /* These are for observing a single process */static int *pidwatch = nil;static int numpids = 0;static const PIDWATCHSIZE = 32; /* The number of PIDS that can be watched. Pretty arbitrary. */ int codesize = 0; static uvlong lastestamp; /* last entry timestamp */static uvlong lastxstamp; /* last exit timestamp */ /* Trace events can be either Entries or Exits */static char eventname[] = {	[TraceEntry] = 'E',	[TraceExit] = 'X',};	static Dirtab tracedir[]={	".",		{Qdir, 0, QTDIR},	0,		DMDIR|0555,	"tracectl",	{Qctl},		0,		0664,	"trace",	{Qdata},	0,		0440,}; char hex[] = {	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',	'8',	'9',	'a',	'b',	'c',	'd',	'e',	'f',}; /* big-endian ... */voidhex8(u32int l, char *c){	int i;	for(i = 2; i; i--){		c[i-1] = hex[l&0xf];		l >>= 4;	}} voidhex16(u32int l, char *c){	int i;	for(i = 4; i; i--){		c[i-1] = hex[l&0xf];		l >>= 4;	}} voidhex32(u32int l, char *c){	int i;	for(i = 8; i; i--){		c[i-1] = hex[l&0xf];		l >>= 4;	}} voidhex64(u64int l, char *c){	hex32(l>>32, c);	hex32(l, &c[8]);} static intlognonempty(void *){	return pw - pr;} static intlogfull(void){	return (pw - pr) >= logsize;} static u64int idx(u64int f){	return f & logmask;} /* * Check if the given trace overlaps any others * Returns 1 if there is overlap, 0 if clear. */intoverlapping(Trace *p) {	Trace *curr; 	curr = traces; 	if (!curr)		return 0; 	do {		if ((curr->start < p->start && p->start < curr->end) ||				(curr->start < p->end && p->end < curr->end))			return 1;		curr = curr->next;	} while (curr != nil); 	return 0;} /* Make sure a PC is valid and traced; if so, return its Trace *//* if dopanic == 1, the kernel will panic on an invalid PC */struct Trace **traceslot(void *pc, int dopanic){	int index;	struct Trace **p; 	if (pc > etext) {		if (dopanic)			panic("Bad PC %p", pc); 		print("Invalid PC %p\n", pc);		return nil;	}	index = (int)((uintptr)pc - KTZERO);	if (index > codesize){		if (dopanic) {			panic("Bad PC %p", pc);			while(1);		}		print("Invalid PC %p\n", pc);		return nil;	}	p = &tracemap[index];	if (tracemap[index])		ainc(&slothits);	return p;} /* Check if the given PC is traced and return a Trace if so */struct Trace *traced(void *pc, int dopanic){	struct Trace **p; 	p = traceslot(pc, dopanic);		if (p == nil)		return nil; 	return *p;} /* * Return 1 if pid is being watched or no pids are being watched. * Return 0 if pids are being watched and the argument is not * among them. */intwatchingpid(int pid) {	int i;		if (pidwatch[0] == 0)		return 1;		for (i = 0; i < numpids; i++) {		if (pidwatch[i] == pid)			return 1;	}	return 0;} /* * Remove a trace. */voidremovetrace(Trace *p) {	unsigned char *cp;	struct Trace *prev;	struct Trace *curr;	struct Trace **slot; 	slot = traceslot(p->start, 0);	for(cp = p->start; cp <= p->end; slot++, cp++)		*slot = nil; 	curr = traces;		if (curr == p) {		if (curr->next) {			traces = curr->next;		} else {			traces = nil;	//this seems to work fine		}		free(curr);		return;	} 	prev = curr;	curr = curr->next;	do {		if (curr == p) {			prev->next = curr->next;			return;		}		prev = curr;		curr = curr->next;	} while (curr != nil); } /* it is recommended that you call these with something sane. *//* these next two functions assume you locked tracelock */ /* Turn on a trace */voidtraceon(struct Trace *p){	unsigned char *cp;	struct Trace **slot;	slot = traceslot(p->start, 0);	for(cp = p->start; cp <= p->end; slot++, cp++)		*slot = p;	p->enabled = 1;	tracesactive++;} /* Turn off a trace */voidtraceoff(struct Trace  *p){	unsigned char *cp;	struct Trace **slot;	slot = traceslot(p->start, 0);	for(cp = p->start; cp <= p->end; slot++, cp++)		*slot = nil;	p->enabled = 0;	tracesactive--;} /* Make a new tracelog (an event) *//* can return NULL, meaning, no record for you */static struct Tracelog *newpl(void){	uint index;		index = ainc((int *)&pw); 	return &tracelog[idx(index)]; } /* Called every time a (traced) function starts *//* this is not really smp safe. FIX */voidtracein(void* pc, uintptr a1, uintptr a2, uintptr a3, uintptr a4){		struct Tracelog *pl; 	/* if we are here, tracing is active. Turn it off. */	traceactive = 0;	if (! traced(pc, 1)){		traceactive = 1;		return; 	}			ainc((int *)&traceinhits);	/* Continue if we are watching this pid or we're not watching any */	if (!all)		if (!up || !watchingpid(up->pid)){			traceactive = 1;			return;	} 	pl = newpl(); 	if (! pl) {		ainc((int *)&newplfail);		traceactive = 1;		return;	} 	cycles(&pl->ticks); 	pl->pc = (uintptr)pc;	if (up)		pl->dat[0] = up->pid;	else		pl->dat[0] = (unsigned long)-1; 	pl->dat[1] = a1;	pl->dat[2] = a2;	pl->dat[3] = a3;	pl->dat[4] = a4; 	pl->info = TraceEntry;	pl->machno = m->machno;	traceactive = 1;} /* Called every time a traced function exits */voidtraceout(void* pc, uintptr retval){	struct Tracelog *pl;	/* if we are here, tracing is active. Turn it off. */	traceactive = 0;	if (! traced(pc, 1)){		traceactive = 1;		return; 	}			if (!all)		if (!up || !watchingpid(up->pid)){			traceactive = 1;			return;		} 	pl = newpl();	if (! pl){		traceactive = 1;		return;	} 	cycles(&pl->ticks); 	pl->pc = (uintptr)pc;	if (up)		pl->dat[0] = up->pid;	else		pl->dat[0] = (unsigned long)-1; 	pl->dat[1] = retval;	pl->dat[2] = 0;	pl->dat[3] = 0; 	pl->info = TraceExit;	pl->machno = m->machno;	traceactive = 1;} /* Create a new trace with the given range */static Trace *mktrace(void *func, void *start, void *end){	Trace *p;	p = mallocz(sizeof p[0], 1);	p->func = func;	p->start = start;	p->end = end;	return p;} /* Get rid of an old trace */static voidfreetrace(Trace *p){	free(p);}  static Chan*traceattach(char *spec){	return devattach('T', spec);} static Walkqid*tracewalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, tracedir, nelem(tracedir), devgen);} static longtracestat(Chan *c, uchar *db, long n){	return devstat(c, db, n, tracedir, nelem(tracedir), devgen);} static Chan*traceopen(Chan *c, int omode){ 	/* if there is no tracelog, allocate one. Open always fails	 * if the basic alloc fails. You can resize it later. 	 */ 	codesize = (uintptr)etext - (uintptr)KTZERO;	if (! tracemap)		//tracemap = mallocz(sizeof(struct tracemap *)*codesize, 1);		tracemap = mallocz(sizeof(struct Trace *)*codesize, 1);	if (! tracemap)		error("tracemap malloc failed");	if (! tracelog)		tracelog = mallocz(sizeof(*tracelog)*logsize, 1);	/* I guess malloc doesn't toss an error */	if (! tracelog)		error("tracelog malloc failed");	if (! pidwatch)		pidwatch = mallocz(sizeof(int)*PIDWATCHSIZE, 1);	if (! pidwatch)		error("pidwatch malloc failed"); 	c = devopen(c, omode, tracedir, nelem(tracedir), devgen);	return c;} static voidtraceclose(Chan *){} /* * Reading from the device, either the data or control files. * The data reading involves deep rminnich magic so we don't have * to call print(), which is traced. */static long

Lines 1–500 of 887.