xref: /plan9-contrib/sys/src/9k/port/devtrace.c (revision d46407a37b53d968b453d19c0e464c526df5e227)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier #include	"netif.h"
89ef1f84bSDavid du Colombier 
9*d46407a3SDavid du Colombier /*
10*d46407a3SDavid du Colombier  * NB: To be used with 6l -e so tracein/out are called upon
11*d46407a3SDavid du Colombier  * function entry and exit.
12*d46407a3SDavid du Colombier  * There's no trace(3) man page, look at write source to see the
13*d46407a3SDavid du Colombier  * commands.
14*d46407a3SDavid du Colombier  */
15*d46407a3SDavid du Colombier 
169ef1f84bSDavid du Colombier #pragma profile 0
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier typedef struct Trace Trace;
199ef1f84bSDavid du Colombier /* This is a trace--a segment of memory to watch for entries and exits */
209ef1f84bSDavid du Colombier struct Trace {
219ef1f84bSDavid du Colombier 	struct Trace *next;
229ef1f84bSDavid du Colombier 	void *func;
239ef1f84bSDavid du Colombier 	void *start;
249ef1f84bSDavid du Colombier 	void *end;
259ef1f84bSDavid du Colombier 	int enabled;
269ef1f84bSDavid du Colombier 	char name[16];
279ef1f84bSDavid du Colombier };
289ef1f84bSDavid du Colombier 
299ef1f84bSDavid du Colombier enum {
309ef1f84bSDavid du Colombier 	Qdir,
319ef1f84bSDavid du Colombier 	Qctl,
329ef1f84bSDavid du Colombier 	Qdata,
339ef1f84bSDavid du Colombier };
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier enum {
369ef1f84bSDavid du Colombier 	TraceEntry = 1,
379ef1f84bSDavid du Colombier 	TraceExit,
389ef1f84bSDavid du Colombier };
399ef1f84bSDavid du Colombier 
409ef1f84bSDavid du Colombier /* fix me make this programmable */
419ef1f84bSDavid du Colombier enum {
429ef1f84bSDavid du Colombier 	defaultlogsize = 8192,
439ef1f84bSDavid du Colombier };
449ef1f84bSDavid du Colombier 
459ef1f84bSDavid du Colombier /* This represents a trace "hit" or event */
469ef1f84bSDavid du Colombier typedef struct Tracelog Tracelog;
479ef1f84bSDavid du Colombier struct Tracelog {
489ef1f84bSDavid du Colombier 	uvlong ticks;
499ef1f84bSDavid du Colombier 	int info;
509ef1f84bSDavid du Colombier 	uintptr pc;
519ef1f84bSDavid du Colombier 	/* these are different depending on type */
529ef1f84bSDavid du Colombier 	uintptr dat[5];
539ef1f84bSDavid du Colombier 	int machno;
549ef1f84bSDavid du Colombier };
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier static Rendez tracesleep;
589ef1f84bSDavid du Colombier static QLock traceslock;
599ef1f84bSDavid du Colombier /* this will contain as many entries as there are valid pc values */
609ef1f84bSDavid du Colombier static Trace **tracemap;
619ef1f84bSDavid du Colombier static Trace *traces; /* This stores all the traces */
629ef1f84bSDavid du Colombier static Lock loglk;
639ef1f84bSDavid du Colombier static Tracelog *tracelog = nil;
649ef1f84bSDavid du Colombier int traceactive = 0;
659ef1f84bSDavid du Colombier /* trace indices. These are just unsigned longs. You mask them
669ef1f84bSDavid du Colombier  * to get an index. This makes fifo empty/full etc. trivial.
679ef1f84bSDavid du Colombier  */
689ef1f84bSDavid du Colombier static uint pw = 0, pr = 0;
699ef1f84bSDavid du Colombier static int tracesactive = 0;
709ef1f84bSDavid du Colombier static int all = 0;
719ef1f84bSDavid du Colombier static int watching = 0;
729ef1f84bSDavid du Colombier static int slothits = 0;
739ef1f84bSDavid du Colombier static unsigned int traceinhits = 0;
749ef1f84bSDavid du Colombier static unsigned int newplfail = 0;
759ef1f84bSDavid du Colombier static unsigned long logsize = defaultlogsize, logmask = defaultlogsize - 1;
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier static int printsize = 0;	//The length of a line being printed
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier /* These are for observing a single process */
809ef1f84bSDavid du Colombier static int *pidwatch = nil;
819ef1f84bSDavid du Colombier static int numpids = 0;
829ef1f84bSDavid du Colombier static const PIDWATCHSIZE = 32; /* The number of PIDS that can be watched. Pretty arbitrary. */
839ef1f84bSDavid du Colombier 
849ef1f84bSDavid du Colombier int codesize = 0;
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier static uvlong lastestamp; /* last entry timestamp */
879ef1f84bSDavid du Colombier static uvlong lastxstamp; /* last exit timestamp */
889ef1f84bSDavid du Colombier 
899ef1f84bSDavid du Colombier /* Trace events can be either Entries or Exits */
909ef1f84bSDavid du Colombier static char eventname[] = {
919ef1f84bSDavid du Colombier 	[TraceEntry] = 'E',
929ef1f84bSDavid du Colombier 	[TraceExit] = 'X',
939ef1f84bSDavid du Colombier };
949ef1f84bSDavid du Colombier 
959ef1f84bSDavid du Colombier static Dirtab tracedir[]={
969ef1f84bSDavid du Colombier 	".",		{Qdir, 0, QTDIR},	0,		DMDIR|0555,
979ef1f84bSDavid du Colombier 	"tracectl",	{Qctl},		0,		0664,
989ef1f84bSDavid du Colombier 	"trace",	{Qdata},	0,		0440,
999ef1f84bSDavid du Colombier };
1009ef1f84bSDavid du Colombier 
1019ef1f84bSDavid du Colombier char hex[] = {
1029ef1f84bSDavid du Colombier 	'0',
1039ef1f84bSDavid du Colombier 	'1',
1049ef1f84bSDavid du Colombier 	'2',
1059ef1f84bSDavid du Colombier 	'3',
1069ef1f84bSDavid du Colombier 	'4',
1079ef1f84bSDavid du Colombier 	'5',
1089ef1f84bSDavid du Colombier 	'6',
1099ef1f84bSDavid du Colombier 	'7',
1109ef1f84bSDavid du Colombier 	'8',
1119ef1f84bSDavid du Colombier 	'9',
1129ef1f84bSDavid du Colombier 	'a',
1139ef1f84bSDavid du Colombier 	'b',
1149ef1f84bSDavid du Colombier 	'c',
1159ef1f84bSDavid du Colombier 	'd',
1169ef1f84bSDavid du Colombier 	'e',
1179ef1f84bSDavid du Colombier 	'f',
1189ef1f84bSDavid du Colombier };
1199ef1f84bSDavid du Colombier 
1209ef1f84bSDavid du Colombier /* big-endian ... */
1219ef1f84bSDavid du Colombier void
hex8(u32int l,char * c)1229ef1f84bSDavid du Colombier hex8(u32int l, char *c)
1239ef1f84bSDavid du Colombier {
1249ef1f84bSDavid du Colombier 	int i;
1259ef1f84bSDavid du Colombier 	for(i = 2; i; i--){
1269ef1f84bSDavid du Colombier 		c[i-1] = hex[l&0xf];
1279ef1f84bSDavid du Colombier 		l >>= 4;
1289ef1f84bSDavid du Colombier 	}
1299ef1f84bSDavid du Colombier }
1309ef1f84bSDavid du Colombier 
1319ef1f84bSDavid du Colombier void
hex16(u32int l,char * c)1329ef1f84bSDavid du Colombier hex16(u32int l, char *c)
1339ef1f84bSDavid du Colombier {
1349ef1f84bSDavid du Colombier 	int i;
1359ef1f84bSDavid du Colombier 	for(i = 4; i; i--){
1369ef1f84bSDavid du Colombier 		c[i-1] = hex[l&0xf];
1379ef1f84bSDavid du Colombier 		l >>= 4;
1389ef1f84bSDavid du Colombier 	}
1399ef1f84bSDavid du Colombier }
1409ef1f84bSDavid du Colombier 
1419ef1f84bSDavid du Colombier void
hex32(u32int l,char * c)1429ef1f84bSDavid du Colombier hex32(u32int l, char *c)
1439ef1f84bSDavid du Colombier {
1449ef1f84bSDavid du Colombier 	int i;
1459ef1f84bSDavid du Colombier 	for(i = 8; i; i--){
1469ef1f84bSDavid du Colombier 		c[i-1] = hex[l&0xf];
1479ef1f84bSDavid du Colombier 		l >>= 4;
1489ef1f84bSDavid du Colombier 	}
1499ef1f84bSDavid du Colombier }
1509ef1f84bSDavid du Colombier 
1519ef1f84bSDavid du Colombier void
hex64(u64int l,char * c)1529ef1f84bSDavid du Colombier hex64(u64int l, char *c)
1539ef1f84bSDavid du Colombier {
1549ef1f84bSDavid du Colombier 	hex32(l>>32, c);
1559ef1f84bSDavid du Colombier 	hex32(l, &c[8]);
1569ef1f84bSDavid du Colombier }
1579ef1f84bSDavid du Colombier 
1589ef1f84bSDavid du Colombier static int
lognonempty(void *)1599ef1f84bSDavid du Colombier lognonempty(void *)
1609ef1f84bSDavid du Colombier {
1619ef1f84bSDavid du Colombier 	return pw - pr;
1629ef1f84bSDavid du Colombier }
1639ef1f84bSDavid du Colombier 
1649ef1f84bSDavid du Colombier static int
logfull(void)1659ef1f84bSDavid du Colombier logfull(void)
1669ef1f84bSDavid du Colombier {
1679ef1f84bSDavid du Colombier 	return (pw - pr) >= logsize;
1689ef1f84bSDavid du Colombier }
1699ef1f84bSDavid du Colombier 
1709ef1f84bSDavid du Colombier static u64int
idx(u64int f)1719ef1f84bSDavid du Colombier idx(u64int f)
1729ef1f84bSDavid du Colombier {
1739ef1f84bSDavid du Colombier 	return f & logmask;
1749ef1f84bSDavid du Colombier }
1759ef1f84bSDavid du Colombier 
1769ef1f84bSDavid du Colombier /*
1779ef1f84bSDavid du Colombier  * Check if the given trace overlaps any others
1789ef1f84bSDavid du Colombier  * Returns 1 if there is overlap, 0 if clear.
1799ef1f84bSDavid du Colombier  */
1809ef1f84bSDavid du Colombier int
overlapping(Trace * p)1819ef1f84bSDavid du Colombier overlapping(Trace *p) {
1829ef1f84bSDavid du Colombier 	Trace *curr;
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier 	curr = traces;
1859ef1f84bSDavid du Colombier 
1869ef1f84bSDavid du Colombier 	if (!curr)
1879ef1f84bSDavid du Colombier 		return 0;
1889ef1f84bSDavid du Colombier 
1899ef1f84bSDavid du Colombier 	do {
1909ef1f84bSDavid du Colombier 		if ((curr->start < p->start && p->start < curr->end) ||
1919ef1f84bSDavid du Colombier 				(curr->start < p->end && p->end < curr->end))
1929ef1f84bSDavid du Colombier 			return 1;
1939ef1f84bSDavid du Colombier 		curr = curr->next;
1949ef1f84bSDavid du Colombier 	} while (curr != nil);
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier 	return 0;
1979ef1f84bSDavid du Colombier }
1989ef1f84bSDavid du Colombier 
1999ef1f84bSDavid du Colombier /* Make sure a PC is valid and traced; if so, return its Trace */
2009ef1f84bSDavid du Colombier /* if dopanic == 1, the kernel will panic on an invalid PC */
2019ef1f84bSDavid du Colombier struct Trace **
traceslot(void * pc,int dopanic)2029ef1f84bSDavid du Colombier traceslot(void *pc, int dopanic)
2039ef1f84bSDavid du Colombier {
2049ef1f84bSDavid du Colombier 	int index;
2059ef1f84bSDavid du Colombier 	struct Trace **p;
2069ef1f84bSDavid du Colombier 
2079ef1f84bSDavid du Colombier 	if (pc > etext) {
2089ef1f84bSDavid du Colombier 		if (dopanic)
2099ef1f84bSDavid du Colombier 			panic("Bad PC %p", pc);
2109ef1f84bSDavid du Colombier 
2119ef1f84bSDavid du Colombier 		print("Invalid PC %p\n", pc);
2129ef1f84bSDavid du Colombier 		return nil;
2139ef1f84bSDavid du Colombier 	}
2149ef1f84bSDavid du Colombier 	index = (int)((uintptr)pc - KTZERO);
2159ef1f84bSDavid du Colombier 	if (index > codesize){
2169ef1f84bSDavid du Colombier 		if (dopanic) {
2179ef1f84bSDavid du Colombier 			panic("Bad PC %p", pc);
2189ef1f84bSDavid du Colombier 			while(1);
2199ef1f84bSDavid du Colombier 		}
2209ef1f84bSDavid du Colombier 		print("Invalid PC %p\n", pc);
2219ef1f84bSDavid du Colombier 		return nil;
2229ef1f84bSDavid du Colombier 	}
2239ef1f84bSDavid du Colombier 	p = &tracemap[index];
2249ef1f84bSDavid du Colombier 	if (tracemap[index])
2259ef1f84bSDavid du Colombier 		ainc(&slothits);
2269ef1f84bSDavid du Colombier 	return p;
2279ef1f84bSDavid du Colombier }
2289ef1f84bSDavid du Colombier 
2299ef1f84bSDavid du Colombier /* Check if the given PC is traced and return a Trace if so */
2309ef1f84bSDavid du Colombier struct Trace *
traced(void * pc,int dopanic)2319ef1f84bSDavid du Colombier traced(void *pc, int dopanic)
2329ef1f84bSDavid du Colombier {
2339ef1f84bSDavid du Colombier 	struct Trace **p;
2349ef1f84bSDavid du Colombier 
2359ef1f84bSDavid du Colombier 	p = traceslot(pc, dopanic);
2369ef1f84bSDavid du Colombier 
2379ef1f84bSDavid du Colombier 	if (p == nil)
2389ef1f84bSDavid du Colombier 		return nil;
2399ef1f84bSDavid du Colombier 
2409ef1f84bSDavid du Colombier 	return *p;
2419ef1f84bSDavid du Colombier }
2429ef1f84bSDavid du Colombier 
2439ef1f84bSDavid du Colombier /*
2449ef1f84bSDavid du Colombier  * Return 1 if pid is being watched or no pids are being watched.
2459ef1f84bSDavid du Colombier  * Return 0 if pids are being watched and the argument is not
2469ef1f84bSDavid du Colombier  * among them.
2479ef1f84bSDavid du Colombier  */
2489ef1f84bSDavid du Colombier int
watchingpid(int pid)2499ef1f84bSDavid du Colombier watchingpid(int pid) {
2509ef1f84bSDavid du Colombier 	int i;
2519ef1f84bSDavid du Colombier 
2529ef1f84bSDavid du Colombier 	if (pidwatch[0] == 0)
2539ef1f84bSDavid du Colombier 		return 1;
2549ef1f84bSDavid du Colombier 
2559ef1f84bSDavid du Colombier 	for (i = 0; i < numpids; i++) {
2569ef1f84bSDavid du Colombier 		if (pidwatch[i] == pid)
2579ef1f84bSDavid du Colombier 			return 1;
2589ef1f84bSDavid du Colombier 	}
2599ef1f84bSDavid du Colombier 	return 0;
2609ef1f84bSDavid du Colombier }
2619ef1f84bSDavid du Colombier 
2629ef1f84bSDavid du Colombier /*
2639ef1f84bSDavid du Colombier  * Remove a trace.
2649ef1f84bSDavid du Colombier  */
2659ef1f84bSDavid du Colombier void
removetrace(Trace * p)2669ef1f84bSDavid du Colombier removetrace(Trace *p) {
2679ef1f84bSDavid du Colombier 	unsigned char *cp;
2689ef1f84bSDavid du Colombier 	struct Trace *prev;
2699ef1f84bSDavid du Colombier 	struct Trace *curr;
2709ef1f84bSDavid du Colombier 	struct Trace **slot;
2719ef1f84bSDavid du Colombier 
2729ef1f84bSDavid du Colombier 	slot = traceslot(p->start, 0);
2739ef1f84bSDavid du Colombier 	for(cp = p->start; cp <= p->end; slot++, cp++)
2749ef1f84bSDavid du Colombier 		*slot = nil;
2759ef1f84bSDavid du Colombier 
2769ef1f84bSDavid du Colombier 	curr = traces;
2779ef1f84bSDavid du Colombier 
2789ef1f84bSDavid du Colombier 	if (curr == p) {
2799ef1f84bSDavid du Colombier 		if (curr->next) {
2809ef1f84bSDavid du Colombier 			traces = curr->next;
2819ef1f84bSDavid du Colombier 		} else {
2829ef1f84bSDavid du Colombier 			traces = nil;	//this seems to work fine
2839ef1f84bSDavid du Colombier 		}
2849ef1f84bSDavid du Colombier 		free(curr);
2859ef1f84bSDavid du Colombier 		return;
2869ef1f84bSDavid du Colombier 	}
2879ef1f84bSDavid du Colombier 
2889ef1f84bSDavid du Colombier 	prev = curr;
2899ef1f84bSDavid du Colombier 	curr = curr->next;
2909ef1f84bSDavid du Colombier 	do {
2919ef1f84bSDavid du Colombier 		if (curr == p) {
2929ef1f84bSDavid du Colombier 			prev->next = curr->next;
2939ef1f84bSDavid du Colombier 			return;
2949ef1f84bSDavid du Colombier 		}
2959ef1f84bSDavid du Colombier 		prev = curr;
2969ef1f84bSDavid du Colombier 		curr = curr->next;
2979ef1f84bSDavid du Colombier 	} while (curr != nil);
2989ef1f84bSDavid du Colombier 
2999ef1f84bSDavid du Colombier }
3009ef1f84bSDavid du Colombier 
3019ef1f84bSDavid du Colombier /* it is recommended that you call these with something sane. */
3029ef1f84bSDavid du Colombier /* these next two functions assume you locked tracelock */
3039ef1f84bSDavid du Colombier 
3049ef1f84bSDavid du Colombier /* Turn on a trace */
3059ef1f84bSDavid du Colombier void
traceon(struct Trace * p)3069ef1f84bSDavid du Colombier traceon(struct Trace *p)
3079ef1f84bSDavid du Colombier {
3089ef1f84bSDavid du Colombier 	unsigned char *cp;
3099ef1f84bSDavid du Colombier 	struct Trace **slot;
3109ef1f84bSDavid du Colombier 	slot = traceslot(p->start, 0);
3119ef1f84bSDavid du Colombier 	for(cp = p->start; cp <= p->end; slot++, cp++)
3129ef1f84bSDavid du Colombier 		*slot = p;
3139ef1f84bSDavid du Colombier 	p->enabled = 1;
3149ef1f84bSDavid du Colombier 	tracesactive++;
3159ef1f84bSDavid du Colombier }
3169ef1f84bSDavid du Colombier 
3179ef1f84bSDavid du Colombier /* Turn off a trace */
3189ef1f84bSDavid du Colombier void
traceoff(struct Trace * p)3199ef1f84bSDavid du Colombier traceoff(struct Trace  *p)
3209ef1f84bSDavid du Colombier {
3219ef1f84bSDavid du Colombier 	unsigned char *cp;
3229ef1f84bSDavid du Colombier 	struct Trace **slot;
3239ef1f84bSDavid du Colombier 	slot = traceslot(p->start, 0);
3249ef1f84bSDavid du Colombier 	for(cp = p->start; cp <= p->end; slot++, cp++)
3259ef1f84bSDavid du Colombier 		*slot = nil;
3269ef1f84bSDavid du Colombier 	p->enabled = 0;
3279ef1f84bSDavid du Colombier 	tracesactive--;
3289ef1f84bSDavid du Colombier }
3299ef1f84bSDavid du Colombier 
3309ef1f84bSDavid du Colombier /* Make a new tracelog (an event) */
3319ef1f84bSDavid du Colombier /* can return NULL, meaning, no record for you */
3329ef1f84bSDavid du Colombier static struct Tracelog *
newpl(void)3339ef1f84bSDavid du Colombier newpl(void)
3349ef1f84bSDavid du Colombier {
3359ef1f84bSDavid du Colombier 	uint index;
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier 	index = ainc((int *)&pw);
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier 	return &tracelog[idx(index)];
3409ef1f84bSDavid du Colombier 
3419ef1f84bSDavid du Colombier }
3429ef1f84bSDavid du Colombier 
3439ef1f84bSDavid du Colombier /* Called every time a (traced) function starts */
3449ef1f84bSDavid du Colombier /* this is not really smp safe. FIX */
3459ef1f84bSDavid du Colombier void
tracein(void * pc,uintptr a1,uintptr a2,uintptr a3,uintptr a4)3469ef1f84bSDavid du Colombier tracein(void* pc, uintptr a1, uintptr a2, uintptr a3, uintptr a4)
3479ef1f84bSDavid du Colombier {
3489ef1f84bSDavid du Colombier 	struct Tracelog *pl;
3499ef1f84bSDavid du Colombier 
3509ef1f84bSDavid du Colombier 	/* if we are here, tracing is active. Turn it off. */
3519ef1f84bSDavid du Colombier 	traceactive = 0;
3529ef1f84bSDavid du Colombier 	if (! traced(pc, 1)){
3539ef1f84bSDavid du Colombier 		traceactive = 1;
3549ef1f84bSDavid du Colombier 		return;
3559ef1f84bSDavid du Colombier 	}
3569ef1f84bSDavid du Colombier 
3579ef1f84bSDavid du Colombier 	ainc((int *)&traceinhits);
3589ef1f84bSDavid du Colombier 	/* Continue if we are watching this pid or we're not watching any */
3599ef1f84bSDavid du Colombier 	if (!all)
3609ef1f84bSDavid du Colombier 		if (!up || !watchingpid(up->pid)){
3619ef1f84bSDavid du Colombier 			traceactive = 1;
3629ef1f84bSDavid du Colombier 			return;
3639ef1f84bSDavid du Colombier 	}
3649ef1f84bSDavid du Colombier 
3659ef1f84bSDavid du Colombier 	pl = newpl();
3669ef1f84bSDavid du Colombier 
3679ef1f84bSDavid du Colombier 	if (! pl) {
3689ef1f84bSDavid du Colombier 		ainc((int *)&newplfail);
3699ef1f84bSDavid du Colombier 		traceactive = 1;
3709ef1f84bSDavid du Colombier 		return;
3719ef1f84bSDavid du Colombier 	}
3729ef1f84bSDavid du Colombier 
3739ef1f84bSDavid du Colombier 	cycles(&pl->ticks);
3749ef1f84bSDavid du Colombier 
3759ef1f84bSDavid du Colombier 	pl->pc = (uintptr)pc;
3769ef1f84bSDavid du Colombier 	if (up)
3779ef1f84bSDavid du Colombier 		pl->dat[0] = up->pid;
3789ef1f84bSDavid du Colombier 	else
3799ef1f84bSDavid du Colombier 		pl->dat[0] = (unsigned long)-1;
3809ef1f84bSDavid du Colombier 
3819ef1f84bSDavid du Colombier 	pl->dat[1] = a1;
3829ef1f84bSDavid du Colombier 	pl->dat[2] = a2;
3839ef1f84bSDavid du Colombier 	pl->dat[3] = a3;
3849ef1f84bSDavid du Colombier 	pl->dat[4] = a4;
3859ef1f84bSDavid du Colombier 
3869ef1f84bSDavid du Colombier 	pl->info = TraceEntry;
3879ef1f84bSDavid du Colombier 	pl->machno = m->machno;
3889ef1f84bSDavid du Colombier 	traceactive = 1;
3899ef1f84bSDavid du Colombier }
3909ef1f84bSDavid du Colombier 
3919ef1f84bSDavid du Colombier /* Called every time a traced function exits */
3929ef1f84bSDavid du Colombier void
traceout(void * pc,uintptr retval)3939ef1f84bSDavid du Colombier traceout(void* pc, uintptr retval)
3949ef1f84bSDavid du Colombier {
3959ef1f84bSDavid du Colombier 	struct Tracelog *pl;
3969ef1f84bSDavid du Colombier 	/* if we are here, tracing is active. Turn it off. */
3979ef1f84bSDavid du Colombier 	traceactive = 0;
3989ef1f84bSDavid du Colombier 	if (! traced(pc, 1)){
3999ef1f84bSDavid du Colombier 		traceactive = 1;
4009ef1f84bSDavid du Colombier 		return;
4019ef1f84bSDavid du Colombier 	}
4029ef1f84bSDavid du Colombier 
4039ef1f84bSDavid du Colombier 	if (!all)
4049ef1f84bSDavid du Colombier 		if (!up || !watchingpid(up->pid)){
4059ef1f84bSDavid du Colombier 			traceactive = 1;
4069ef1f84bSDavid du Colombier 			return;
4079ef1f84bSDavid du Colombier 		}
4089ef1f84bSDavid du Colombier 
4099ef1f84bSDavid du Colombier 	pl = newpl();
4109ef1f84bSDavid du Colombier 	if (! pl){
4119ef1f84bSDavid du Colombier 		traceactive = 1;
4129ef1f84bSDavid du Colombier 		return;
4139ef1f84bSDavid du Colombier 	}
4149ef1f84bSDavid du Colombier 
4159ef1f84bSDavid du Colombier 	cycles(&pl->ticks);
4169ef1f84bSDavid du Colombier 
4179ef1f84bSDavid du Colombier 	pl->pc = (uintptr)pc;
4189ef1f84bSDavid du Colombier 	if (up)
4199ef1f84bSDavid du Colombier 		pl->dat[0] = up->pid;
4209ef1f84bSDavid du Colombier 	else
4219ef1f84bSDavid du Colombier 		pl->dat[0] = (unsigned long)-1;
4229ef1f84bSDavid du Colombier 
4239ef1f84bSDavid du Colombier 	pl->dat[1] = retval;
4249ef1f84bSDavid du Colombier 	pl->dat[2] = 0;
4259ef1f84bSDavid du Colombier 	pl->dat[3] = 0;
4269ef1f84bSDavid du Colombier 
4279ef1f84bSDavid du Colombier 	pl->info = TraceExit;
4289ef1f84bSDavid du Colombier 	pl->machno = m->machno;
4299ef1f84bSDavid du Colombier 	traceactive = 1;
4309ef1f84bSDavid du Colombier }
4319ef1f84bSDavid du Colombier 
4329ef1f84bSDavid du Colombier /* Create a new trace with the given range */
4339ef1f84bSDavid du Colombier static Trace *
mktrace(void * func,void * start,void * end)4349ef1f84bSDavid du Colombier mktrace(void *func, void *start, void *end)
4359ef1f84bSDavid du Colombier {
4369ef1f84bSDavid du Colombier 	Trace *p;
4379ef1f84bSDavid du Colombier 	p = mallocz(sizeof p[0], 1);
4389ef1f84bSDavid du Colombier 	p->func = func;
4399ef1f84bSDavid du Colombier 	p->start = start;
4409ef1f84bSDavid du Colombier 	p->end = end;
4419ef1f84bSDavid du Colombier 	return p;
4429ef1f84bSDavid du Colombier }
4439ef1f84bSDavid du Colombier 
4449ef1f84bSDavid du Colombier /* Get rid of an old trace */
4459ef1f84bSDavid du Colombier static void
freetrace(Trace * p)4469ef1f84bSDavid du Colombier freetrace(Trace *p)
4479ef1f84bSDavid du Colombier {
4489ef1f84bSDavid du Colombier 	free(p);
4499ef1f84bSDavid du Colombier }
4509ef1f84bSDavid du Colombier 
4519ef1f84bSDavid du Colombier 
4529ef1f84bSDavid du Colombier static Chan*
traceattach(char * spec)4539ef1f84bSDavid du Colombier traceattach(char *spec)
4549ef1f84bSDavid du Colombier {
4559ef1f84bSDavid du Colombier 	return devattach('T', spec);
4569ef1f84bSDavid du Colombier }
4579ef1f84bSDavid du Colombier 
4589ef1f84bSDavid du Colombier static Walkqid*
tracewalk(Chan * c,Chan * nc,char ** name,int nname)4599ef1f84bSDavid du Colombier tracewalk(Chan *c, Chan *nc, char **name, int nname)
4609ef1f84bSDavid du Colombier {
4619ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, tracedir, nelem(tracedir), devgen);
4629ef1f84bSDavid du Colombier }
4639ef1f84bSDavid du Colombier 
4649ef1f84bSDavid du Colombier static long
tracestat(Chan * c,uchar * db,long n)4659ef1f84bSDavid du Colombier tracestat(Chan *c, uchar *db, long n)
4669ef1f84bSDavid du Colombier {
4679ef1f84bSDavid du Colombier 	return devstat(c, db, n, tracedir, nelem(tracedir), devgen);
4689ef1f84bSDavid du Colombier }
4699ef1f84bSDavid du Colombier 
4709ef1f84bSDavid du Colombier static Chan*
traceopen(Chan * c,int omode)4719ef1f84bSDavid du Colombier traceopen(Chan *c, int omode)
4729ef1f84bSDavid du Colombier {
4739ef1f84bSDavid du Colombier 
4749ef1f84bSDavid du Colombier 	/* if there is no tracelog, allocate one. Open always fails
4759ef1f84bSDavid du Colombier 	 * if the basic alloc fails. You can resize it later.
4769ef1f84bSDavid du Colombier 	 */
4779ef1f84bSDavid du Colombier 
4789ef1f84bSDavid du Colombier 	codesize = (uintptr)etext - (uintptr)KTZERO;
4799ef1f84bSDavid du Colombier 	if (! tracemap)
4809ef1f84bSDavid du Colombier 		//tracemap = mallocz(sizeof(struct tracemap *)*codesize, 1);
4819ef1f84bSDavid du Colombier 		tracemap = mallocz(sizeof(struct Trace *)*codesize, 1);
4829ef1f84bSDavid du Colombier 	if (! tracemap)
4839ef1f84bSDavid du Colombier 		error("tracemap malloc failed");
4849ef1f84bSDavid du Colombier 	if (! tracelog)
4859ef1f84bSDavid du Colombier 		tracelog = mallocz(sizeof(*tracelog)*logsize, 1);
4869ef1f84bSDavid du Colombier 	/* I guess malloc doesn't toss an error */
4879ef1f84bSDavid du Colombier 	if (! tracelog)
4889ef1f84bSDavid du Colombier 		error("tracelog malloc failed");
4899ef1f84bSDavid du Colombier 	if (! pidwatch)
4909ef1f84bSDavid du Colombier 		pidwatch = mallocz(sizeof(int)*PIDWATCHSIZE, 1);
4919ef1f84bSDavid du Colombier 	if (! pidwatch)
4929ef1f84bSDavid du Colombier 		error("pidwatch malloc failed");
4939ef1f84bSDavid du Colombier 	c = devopen(c, omode, tracedir, nelem(tracedir), devgen);
4949ef1f84bSDavid du Colombier 	return c;
4959ef1f84bSDavid du Colombier }
4969ef1f84bSDavid du Colombier 
4979ef1f84bSDavid du Colombier static void
traceclose(Chan *)4989ef1f84bSDavid du Colombier traceclose(Chan *)
4999ef1f84bSDavid du Colombier {
5009ef1f84bSDavid du Colombier }
5019ef1f84bSDavid du Colombier 
5029ef1f84bSDavid du Colombier /*
5039ef1f84bSDavid du Colombier  * Reading from the device, either the data or control files.
5049ef1f84bSDavid du Colombier  * The data reading involves deep rminnich magic so we don't have
5059ef1f84bSDavid du Colombier  * to call print(), which is traced.
5069ef1f84bSDavid du Colombier  */
5079ef1f84bSDavid du Colombier static long
traceread(Chan * c,void * a,long n,vlong offset)5089ef1f84bSDavid du Colombier traceread(Chan *c, void *a, long n, vlong offset)
5099ef1f84bSDavid du Colombier {
5109ef1f84bSDavid du Colombier 	char *buf;
5119ef1f84bSDavid du Colombier 	char *cp = a;
5129ef1f84bSDavid du Colombier 	struct Tracelog *pl;
5139ef1f84bSDavid du Colombier 	Trace *p;
5149ef1f84bSDavid du Colombier 	int i, j;
5159ef1f84bSDavid du Colombier 	int saveactive = traceactive;
5169ef1f84bSDavid du Colombier 	traceactive = 0;
5179ef1f84bSDavid du Colombier 	static QLock gate;
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 	if (waserror()) {
5209ef1f84bSDavid du Colombier 		traceactive = saveactive;
5219ef1f84bSDavid du Colombier 		nexterror();
5229ef1f84bSDavid du Colombier 	}
5239ef1f84bSDavid du Colombier 
5249ef1f84bSDavid du Colombier 	if(c->qid.type == QTDIR) {
5259ef1f84bSDavid du Colombier 		long l = devdirread(c, a, n, tracedir, nelem(tracedir), devgen);
5269ef1f84bSDavid du Colombier 		poperror();
5279ef1f84bSDavid du Colombier 		traceactive = saveactive;
5289ef1f84bSDavid du Colombier 		return l;
5299ef1f84bSDavid du Colombier 	}
5309ef1f84bSDavid du Colombier 
5319ef1f84bSDavid du Colombier 	switch((int) c->qid.path){
5329ef1f84bSDavid du Colombier 	default:
5339ef1f84bSDavid du Colombier 		error("traceread: bad qid");
5349ef1f84bSDavid du Colombier 	case Qctl:
5359ef1f84bSDavid du Colombier 		i = 0;
5369ef1f84bSDavid du Colombier 		qlock(&traceslock);
5379ef1f84bSDavid du Colombier 		buf = malloc(READSTR);
5389ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "logsize %lud\n", logsize);
5399ef1f84bSDavid du Colombier 		for(p = traces; p != nil; p = p->next)
5409ef1f84bSDavid du Colombier 			i += snprint(buf + i, READSTR - i, "trace %p %p new %s\n",
5419ef1f84bSDavid du Colombier 				p->start, p->end, p->name);
5429ef1f84bSDavid du Colombier 
5439ef1f84bSDavid du Colombier 		for(p = traces; p != nil; p = p->next)
5449ef1f84bSDavid du Colombier 			i += snprint(buf + i, READSTR - i, "#trace %p traced? %p\n",
5459ef1f84bSDavid du Colombier 				p->func, traced(p->func, 0));
5469ef1f84bSDavid du Colombier 
5479ef1f84bSDavid du Colombier 		for(p = traces; p != nil; p = p->next)
5489ef1f84bSDavid du Colombier 			if (p->enabled)
5499ef1f84bSDavid du Colombier 				i += snprint(buf + i, READSTR - i, "trace %s on\n",
5509ef1f84bSDavid du Colombier 				p->name);
5519ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "#tracehits %d, in queue %d\n",
5529ef1f84bSDavid du Colombier 				pw, pw-pr);
5539ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "#tracelog %p\n", tracelog);
5549ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "#traceactive %d\n", saveactive);
5559ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "#slothits %d\n", slothits);
5569ef1f84bSDavid du Colombier 		i += snprint(buf + i, READSTR - i, "#traceinhits %d\n", traceinhits);
5579ef1f84bSDavid du Colombier 		for (j = 0; j < numpids - 1; j++)
5589ef1f84bSDavid du Colombier 			i += snprint(buf + i, READSTR - i, "watch %d\n", pidwatch[j]);
5599ef1f84bSDavid du Colombier 		snprint(buf + i, READSTR - i, "watch %d\n", pidwatch[numpids - 1]);
5609ef1f84bSDavid du Colombier 		n = readstr(offset, a, n, buf);
5619ef1f84bSDavid du Colombier 		free(buf);
5629ef1f84bSDavid du Colombier 		qunlock(&traceslock);
5639ef1f84bSDavid du Colombier 		break;
5649ef1f84bSDavid du Colombier 	case Qdata:
5659ef1f84bSDavid du Colombier 
5669ef1f84bSDavid du Colombier 		// Set the printsize
5679ef1f84bSDavid du Colombier 		/* 32-bit E PCPCPCPC TIMETIMETIMETIME PID# CR XXARG1XX XXARG2XX XXARG3XX XXARG4XX\n */
5689ef1f84bSDavid du Colombier 		if (sizeof(uintptr) == 4) {
5699ef1f84bSDavid du Colombier 			printsize = 73;		// 32-bit format
5709ef1f84bSDavid du Colombier 		} else {
5719ef1f84bSDavid du Colombier 			printsize = 121;	// must be 64-bit
5729ef1f84bSDavid du Colombier 		}
5739ef1f84bSDavid du Colombier 
5749ef1f84bSDavid du Colombier 		i = 0;
5759ef1f84bSDavid du Colombier 		while(lognonempty((void *)0)){
5769ef1f84bSDavid du Colombier 			int j;
5779ef1f84bSDavid du Colombier 
5789ef1f84bSDavid du Colombier 			if ((pw - pr) > logsize)
5799ef1f84bSDavid du Colombier 				pr = pw - logsize;
5809ef1f84bSDavid du Colombier 
5819ef1f84bSDavid du Colombier 			pl = tracelog + idx(pr);
5829ef1f84bSDavid du Colombier 
5839ef1f84bSDavid du Colombier 			if ((i + printsize) > n)
5849ef1f84bSDavid du Colombier 				break;
5859ef1f84bSDavid du Colombier 			/* simple format */
5869ef1f84bSDavid du Colombier 			if (sizeof(uintptr) == 4) {
5879ef1f84bSDavid du Colombier 				cp[0] = eventname[pl->info];
5889ef1f84bSDavid du Colombier 				cp ++;
5899ef1f84bSDavid du Colombier 				*cp++ = ' ';
5909ef1f84bSDavid du Colombier 				hex32((uint)pl->pc, cp);
5919ef1f84bSDavid du Colombier 				cp[8] = ' ';
5929ef1f84bSDavid du Colombier 				cp += 9;
5939ef1f84bSDavid du Colombier 				hex64(pl->ticks, cp);
5949ef1f84bSDavid du Colombier 				cp[16] = ' ';
5959ef1f84bSDavid du Colombier 				cp += 17;
5969ef1f84bSDavid du Colombier 				hex16(pl->dat[0], cp);
5979ef1f84bSDavid du Colombier 				cp += 4;
5989ef1f84bSDavid du Colombier 				cp[0] = ' ';
5999ef1f84bSDavid du Colombier 				cp++;
6009ef1f84bSDavid du Colombier 				hex8(pl->machno, cp);
6019ef1f84bSDavid du Colombier 				cp += 2;
6029ef1f84bSDavid du Colombier 				cp[0] = ' ';
6039ef1f84bSDavid du Colombier 				cp++;
6049ef1f84bSDavid du Colombier 				for(j = 1; j < 4; j++){
6059ef1f84bSDavid du Colombier 					hex32(pl->dat[j], cp);
6069ef1f84bSDavid du Colombier 					cp[8] = ' ';
6079ef1f84bSDavid du Colombier 					cp += 9;
6089ef1f84bSDavid du Colombier 				}
6099ef1f84bSDavid du Colombier 				/* adjust for extra skip above */
6109ef1f84bSDavid du Colombier 				cp--;
6119ef1f84bSDavid du Colombier 				*cp++ = '\n';
6129ef1f84bSDavid du Colombier 				pr++;
6139ef1f84bSDavid du Colombier 				i += printsize;
6149ef1f84bSDavid du Colombier 			} else  {
6159ef1f84bSDavid du Colombier 				cp[0] = eventname[pl->info];
6169ef1f84bSDavid du Colombier 				cp ++;
6179ef1f84bSDavid du Colombier 				*cp++ = ' ';
6189ef1f84bSDavid du Colombier 				hex64((u64int)pl->pc, cp);
6199ef1f84bSDavid du Colombier 				cp[16] = ' ';
6209ef1f84bSDavid du Colombier 				cp += 17;
6219ef1f84bSDavid du Colombier 				hex64(pl->ticks, cp);
6229ef1f84bSDavid du Colombier 				cp[16] = ' ';
6239ef1f84bSDavid du Colombier 				cp += 17;
6249ef1f84bSDavid du Colombier 				hex32(pl->dat[0], cp);
6259ef1f84bSDavid du Colombier 				cp += 8;
6269ef1f84bSDavid du Colombier 				cp[0] = ' ';
6279ef1f84bSDavid du Colombier 				cp++;
6289ef1f84bSDavid du Colombier 				cp[0] = ' ';
6299ef1f84bSDavid du Colombier 				cp++;
6309ef1f84bSDavid du Colombier 				cp[0] = ' ';
6319ef1f84bSDavid du Colombier 				cp++;
6329ef1f84bSDavid du Colombier 				cp[0] = ' ';
6339ef1f84bSDavid du Colombier 				cp++;
6349ef1f84bSDavid du Colombier 				hex8(pl->machno, cp);
6359ef1f84bSDavid du Colombier 				cp += 4;
6369ef1f84bSDavid du Colombier 				for (j = 1; j < 5; j++) {
6379ef1f84bSDavid du Colombier 					hex64(pl->dat[j], cp);
6389ef1f84bSDavid du Colombier 					cp[16] = ' ';
6399ef1f84bSDavid du Colombier 					cp += 17;
6409ef1f84bSDavid du Colombier 				}
6419ef1f84bSDavid du Colombier 				cp--;
6429ef1f84bSDavid du Colombier 				*cp++ = '\n';
6439ef1f84bSDavid du Colombier 				pr++;
6449ef1f84bSDavid du Colombier 				i += printsize;
6459ef1f84bSDavid du Colombier 			}
6469ef1f84bSDavid du Colombier 		}
6479ef1f84bSDavid du Colombier 		n = i;
6489ef1f84bSDavid du Colombier 		break;
6499ef1f84bSDavid du Colombier 	}
6509ef1f84bSDavid du Colombier 	poperror();
6519ef1f84bSDavid du Colombier 	traceactive = saveactive;
6529ef1f84bSDavid du Colombier 	return n;
6539ef1f84bSDavid du Colombier }
6549ef1f84bSDavid du Colombier 
6559ef1f84bSDavid du Colombier /*
6569ef1f84bSDavid du Colombier  * Process commands sent to the ctl file.
6579ef1f84bSDavid du Colombier  */
6589ef1f84bSDavid du Colombier static long
tracewrite(Chan * c,void * a,long n,vlong)6599ef1f84bSDavid du Colombier tracewrite(Chan *c, void *a, long n, vlong)
6609ef1f84bSDavid du Colombier {
6619ef1f84bSDavid du Colombier 	char *tok[6]; //changed this so "tracein" works with the new 4th arg
6629ef1f84bSDavid du Colombier 	char *ep, *s = nil;
6639ef1f84bSDavid du Colombier 	Trace *p, **pp, *foo;
6649ef1f84bSDavid du Colombier 	int ntok;
6659ef1f84bSDavid du Colombier 	int saveactive = traceactive;
6669ef1f84bSDavid du Colombier 	traceactive = 0;
6679ef1f84bSDavid du Colombier 
6689ef1f84bSDavid du Colombier 	qlock(&traceslock);
6699ef1f84bSDavid du Colombier 	if(waserror()){
6709ef1f84bSDavid du Colombier 		qunlock(&traceslock);
6719ef1f84bSDavid du Colombier 		if(s != nil) free(s);
6729ef1f84bSDavid du Colombier 		traceactive = saveactive;
6739ef1f84bSDavid du Colombier 		nexterror();
6749ef1f84bSDavid du Colombier 	}
6759ef1f84bSDavid du Colombier 	switch((uintptr)c->qid.path){
6769ef1f84bSDavid du Colombier 	default:
6779ef1f84bSDavid du Colombier 		error("tracewrite: bad qid");
6789ef1f84bSDavid du Colombier 	case Qctl:
6799ef1f84bSDavid du Colombier 		s = malloc(n + 1);
6809ef1f84bSDavid du Colombier 		memmove(s, a, n);
6819ef1f84bSDavid du Colombier 		s[n] = 0;
6829ef1f84bSDavid du Colombier 		ntok = tokenize(s, tok, nelem(tok));
6839ef1f84bSDavid du Colombier 		if(!strcmp(tok[0], "trace")){	/* 'trace' ktextaddr 'on'|'off'|'mk'|'del' [name] */
6849ef1f84bSDavid du Colombier 			if(ntok < 3) {
6859ef1f84bSDavid du Colombier 				error("devtrace: usage: 'trace' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name]");
6869ef1f84bSDavid du Colombier 			}
6879ef1f84bSDavid du Colombier 			for(pp = &traces; *pp != nil; pp = &(*pp)->next){
6889ef1f84bSDavid du Colombier 				if(!strcmp(tok[1], (*pp)->name))
6899ef1f84bSDavid du Colombier 					break;
6909ef1f84bSDavid du Colombier }
6919ef1f84bSDavid du Colombier 			p = *pp;
6929ef1f84bSDavid du Colombier 			if((ntok > 3) && (!strcmp(tok[3], "new"))){
6939ef1f84bSDavid du Colombier 				uintptr addr;
6949ef1f84bSDavid du Colombier 				void *start, *end, *func;
6959ef1f84bSDavid du Colombier 				if (ntok != 5) {
6969ef1f84bSDavid du Colombier 					error("devtrace: usage: trace <ktextstart> <ktextend> new <name>");
6979ef1f84bSDavid du Colombier 				}
6989ef1f84bSDavid du Colombier 				addr = (uintptr)strtoul(tok[1], &ep, 16);
6999ef1f84bSDavid du Colombier 				if (addr < KTZERO)
7009ef1f84bSDavid du Colombier 					addr |= KTZERO;
7019ef1f84bSDavid du Colombier 				func = start = (void *)addr;
7029ef1f84bSDavid du Colombier 				if(*ep) {
7039ef1f84bSDavid du Colombier 					error("devtrace: start address not in recognized format");
7049ef1f84bSDavid du Colombier 				}
7059ef1f84bSDavid du Colombier 				addr = (uintptr)strtoul(tok[2], &ep, 16);
7069ef1f84bSDavid du Colombier 				if (addr < KTZERO)
7079ef1f84bSDavid du Colombier 					addr |= KTZERO;
7089ef1f84bSDavid du Colombier 				end = (void *)addr;
7099ef1f84bSDavid du Colombier 				if(*ep) {
7109ef1f84bSDavid du Colombier 					error("devtrace: end address not in recognized format");
7119ef1f84bSDavid du Colombier 				}
7129ef1f84bSDavid du Colombier 
7139ef1f84bSDavid du Colombier 				if (start > end || start > etext || end > etext)
7149ef1f84bSDavid du Colombier 					error("devtrace: invalid address range");
7159ef1f84bSDavid du Colombier 
7169ef1f84bSDavid du Colombier 				/* What do we do here? start and end are weird *
7179ef1f84bSDavid du Colombier 				if((addr < (uintptr)start) || (addr > (uintptr)end)
7189ef1f84bSDavid du Colombier 					error("devtrace: address out of bounds");
7199ef1f84bSDavid du Colombier 				 */
7209ef1f84bSDavid du Colombier 				if(p) {
7219ef1f84bSDavid du Colombier 					error("devtrace: trace already exists");
7229ef1f84bSDavid du Colombier 				}
7239ef1f84bSDavid du Colombier 				p = mktrace(func, start, end);
7249ef1f84bSDavid du Colombier 				for (foo = traces; foo != nil; foo = foo->next) {
7259ef1f84bSDavid du Colombier 					if (!strcmp(tok[4], foo->name))
7269ef1f84bSDavid du Colombier 						error("devtrace: trace with that name already exists");
7279ef1f84bSDavid du Colombier 				}
7289ef1f84bSDavid du Colombier 
7299ef1f84bSDavid du Colombier 				if (!overlapping(p)) {
7309ef1f84bSDavid du Colombier 					p->next = traces;
7319ef1f84bSDavid du Colombier 					if(ntok < 5)
7329ef1f84bSDavid du Colombier 						snprint(p->name, sizeof p->name, "%p", func);
7339ef1f84bSDavid du Colombier 					else
7349ef1f84bSDavid du Colombier 						strncpy(p->name, tok[4], sizeof p->name);
7359ef1f84bSDavid du Colombier 					traces = p;
7369ef1f84bSDavid du Colombier 				} else {
7379ef1f84bSDavid du Colombier 					error("devtrace: given range overlaps with existing trace");
7389ef1f84bSDavid du Colombier 				}
7399ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "remove")){
7409ef1f84bSDavid du Colombier 				if (ntok != 3)
7419ef1f84bSDavid du Colombier 					error("devtrace: usage: trace <name> remove");
7429ef1f84bSDavid du Colombier 				if (p == nil) {
7439ef1f84bSDavid du Colombier 					error("devtrace: trace not found");
7449ef1f84bSDavid du Colombier 				}
7459ef1f84bSDavid du Colombier 				removetrace(p);
7469ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "on")){
7479ef1f84bSDavid du Colombier 				if (ntok != 3)
7489ef1f84bSDavid du Colombier 					error("devtrace: usage: trace <name> on");
7499ef1f84bSDavid du Colombier 
7509ef1f84bSDavid du Colombier 				if(p == nil) {
7519ef1f84bSDavid du Colombier 					error("devtrace: trace not found");
7529ef1f84bSDavid du Colombier 				}
7539ef1f84bSDavid du Colombier 				if (! traced(p->func, 0)){
7549ef1f84bSDavid du Colombier 					traceon(p);
7559ef1f84bSDavid du Colombier 				}
7569ef1f84bSDavid du Colombier 			} else if(!strcmp(tok[2], "off")){
7579ef1f84bSDavid du Colombier 				if (ntok != 3)
7589ef1f84bSDavid du Colombier 					error("devtrace: usage: trace <name> off");
7599ef1f84bSDavid du Colombier 				if(p == nil) {
7609ef1f84bSDavid du Colombier 					error("devtrace: trace not found");
7619ef1f84bSDavid du Colombier 				}
7629ef1f84bSDavid du Colombier 				if(traced(p->func, 0)){
7639ef1f84bSDavid du Colombier 					traceoff(p);
7649ef1f84bSDavid du Colombier 				}
7659ef1f84bSDavid du Colombier 			}
7669ef1f84bSDavid du Colombier 		} else if(!strcmp(tok[0], "query")){
7679ef1f84bSDavid du Colombier 			/* See if addr is being traced */
7689ef1f84bSDavid du Colombier 			Trace* p;
7699ef1f84bSDavid du Colombier 			uintptr addr;
7709ef1f84bSDavid du Colombier 			if (ntok != 2) {
7719ef1f84bSDavid du Colombier 				error("devtrace: usage: query <addr>");
7729ef1f84bSDavid du Colombier 			}
7739ef1f84bSDavid du Colombier 			addr = (uintptr)strtoul(tok[1], &ep, 16);
7749ef1f84bSDavid du Colombier 			if (addr < KTZERO)
7759ef1f84bSDavid du Colombier 				addr |= KTZERO;
7769ef1f84bSDavid du Colombier 			p = traced((void *)addr, 0);
7779ef1f84bSDavid du Colombier 			if (p) {
7789ef1f84bSDavid du Colombier 				print("Probing is enabled\n");
7799ef1f84bSDavid du Colombier 			} else {
7809ef1f84bSDavid du Colombier 				print("Probing is disabled\n");
7819ef1f84bSDavid du Colombier 			}
7829ef1f84bSDavid du Colombier 		} else if(!strcmp(tok[0], "size")){
7839ef1f84bSDavid du Colombier 			int l, size;
7849ef1f84bSDavid du Colombier 			struct Tracelog *newtracelog;
7859ef1f84bSDavid du Colombier 
7869ef1f84bSDavid du Colombier 			if (ntok != 2)
7879ef1f84bSDavid du Colombier 				error("devtrace: usage: size <exponent>");
7889ef1f84bSDavid du Colombier 
7899ef1f84bSDavid du Colombier 			l = strtoul(tok[1], &ep, 0);
7909ef1f84bSDavid du Colombier 			if(*ep) {
7919ef1f84bSDavid du Colombier 				error("devtrace: size not in recognized format");
7929ef1f84bSDavid du Colombier 			}
7939ef1f84bSDavid du Colombier 			size = 1 << l;
7949ef1f84bSDavid du Colombier 			/* sort of foolish. Alloc new trace first, then free old. */
7959ef1f84bSDavid du Colombier 			/* and too bad if there are unread traces */
7969ef1f84bSDavid du Colombier 			newtracelog = mallocz(sizeof(*newtracelog)*size, 1);
7979ef1f84bSDavid du Colombier 			/* does malloc throw waserror? I don't know */
7989ef1f84bSDavid du Colombier 			if (newtracelog){
7999ef1f84bSDavid du Colombier 				free(tracelog);
8009ef1f84bSDavid du Colombier 				tracelog = newtracelog;
8019ef1f84bSDavid du Colombier 				logsize = size;
8029ef1f84bSDavid du Colombier 				logmask = size - 1;
8039ef1f84bSDavid du Colombier 				pr = pw = 0;
8049ef1f84bSDavid du Colombier 			} else  {
8059ef1f84bSDavid du Colombier 				error("devtrace:  can't allocate that much");
8069ef1f84bSDavid du Colombier 			}
8079ef1f84bSDavid du Colombier 		} else if (!strcmp(tok[0], "testtracein")) {
8089ef1f84bSDavid du Colombier 			/* Manually jump to a certain bit of traced code */
8099ef1f84bSDavid du Colombier 			uintptr pc, a1, a2, a3, a4;
8109ef1f84bSDavid du Colombier 			int x;
8119ef1f84bSDavid du Colombier 
8129ef1f84bSDavid du Colombier 			if (ntok != 6)
8139ef1f84bSDavid du Colombier 				error("devtrace: usage: testtracein <pc> <arg1> <arg2> <arg3> <arg4>");
8149ef1f84bSDavid du Colombier 
8159ef1f84bSDavid du Colombier 			pc = (uintptr)strtoul(tok[1], &ep, 16);
8169ef1f84bSDavid du Colombier 			if (pc < KTZERO)
8179ef1f84bSDavid du Colombier 				pc |= KTZERO;
8189ef1f84bSDavid du Colombier 			a1 = (uintptr)strtoul(tok[2], &ep, 16);
8199ef1f84bSDavid du Colombier 			a2 = (uintptr)strtoul(tok[3], &ep, 16);
8209ef1f84bSDavid du Colombier 			a3 = (uintptr)strtoul(tok[4], &ep, 16);
8219ef1f84bSDavid du Colombier 			a4 = (uintptr)strtoul(tok[5], &ep, 16);
8229ef1f84bSDavid du Colombier 
8239ef1f84bSDavid du Colombier 			if (traced((void *)pc, 0)) {
8249ef1f84bSDavid du Colombier 				x = splhi();
8259ef1f84bSDavid du Colombier 				watching = 1;
8269ef1f84bSDavid du Colombier 				tracein((void *)pc, a1, a2, a3, a4);
8279ef1f84bSDavid du Colombier 				watching = 0;
8289ef1f84bSDavid du Colombier 				splx(x);
8299ef1f84bSDavid du Colombier 			}
8309ef1f84bSDavid du Colombier 		} else if (!strcmp(tok[0], "watch")) {
8319ef1f84bSDavid du Colombier 			/* Watch a certain PID */
8329ef1f84bSDavid du Colombier 			int pid;
8339ef1f84bSDavid du Colombier 
8349ef1f84bSDavid du Colombier 			if (ntok != 2) {
8359ef1f84bSDavid du Colombier 				error("devtrace: usage: watch [0|<PID>]");
8369ef1f84bSDavid du Colombier 			}
8379ef1f84bSDavid du Colombier 
8389ef1f84bSDavid du Colombier 			pid = atoi(tok[1]);
8399ef1f84bSDavid du Colombier 			if (pid == 0) {
8409ef1f84bSDavid du Colombier 				pidwatch = mallocz(sizeof(int)*PIDWATCHSIZE, 1);
8419ef1f84bSDavid du Colombier 				numpids = 0;
8429ef1f84bSDavid du Colombier 			} else if (pid < 0) {
8439ef1f84bSDavid du Colombier 				error("PID must be greater than zero.");
8449ef1f84bSDavid du Colombier 			} else if (numpids < PIDWATCHSIZE) {
8459ef1f84bSDavid du Colombier 				pidwatch[numpids] = pid;
8469ef1f84bSDavid du Colombier 				ainc(&numpids);
8479ef1f84bSDavid du Colombier 			} else {
8489ef1f84bSDavid du Colombier 				error("pidwatch array full!");
8499ef1f84bSDavid du Colombier 			}
8509ef1f84bSDavid du Colombier 		} else if (!strcmp(tok[0], "start")) {
8519ef1f84bSDavid du Colombier 			if (ntok != 1)
8529ef1f84bSDavid du Colombier 				error("devtrace: usage: start");
8539ef1f84bSDavid du Colombier 			saveactive = 1;
8549ef1f84bSDavid du Colombier 		} else if (!strcmp(tok[0], "stop")) {
8559ef1f84bSDavid du Colombier 			if (ntok != 1)
8569ef1f84bSDavid du Colombier 				error("devtrace: usage: stop");
8579ef1f84bSDavid du Colombier 			saveactive = 0;
8589ef1f84bSDavid du Colombier 			all = 0;
8599ef1f84bSDavid du Colombier 		} else if (!strcmp(tok[0], "all")) {
8609ef1f84bSDavid du Colombier 			if (ntok != 1)
8619ef1f84bSDavid du Colombier 				error("devtrace: usage: all");
8629ef1f84bSDavid du Colombier 			saveactive = 1;
8639ef1f84bSDavid du Colombier 			all = 1;
8649ef1f84bSDavid du Colombier 		} else {
8659ef1f84bSDavid du Colombier 			error("devtrace:  usage: 'trace' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name] or:  'size' buffersize (power of 2)");
8669ef1f84bSDavid du Colombier 		}
8679ef1f84bSDavid du Colombier 		free(s);
8689ef1f84bSDavid du Colombier 		break;
8699ef1f84bSDavid du Colombier 	}
8709ef1f84bSDavid du Colombier 	poperror();
8719ef1f84bSDavid du Colombier 	qunlock(&traceslock);
8729ef1f84bSDavid du Colombier 	traceactive = saveactive;
8739ef1f84bSDavid du Colombier 	return n;
8749ef1f84bSDavid du Colombier }
8759ef1f84bSDavid du Colombier 
8769ef1f84bSDavid du Colombier Dev tracedevtab = {
8779ef1f84bSDavid du Colombier 	'T',
8789ef1f84bSDavid du Colombier 	"trace",
8799ef1f84bSDavid du Colombier 	devreset,
8809ef1f84bSDavid du Colombier 	devinit,
8819ef1f84bSDavid du Colombier 	devshutdown,
8829ef1f84bSDavid du Colombier 	traceattach,
8839ef1f84bSDavid du Colombier 	tracewalk,
8849ef1f84bSDavid du Colombier 	tracestat,
8859ef1f84bSDavid du Colombier 	traceopen,
8869ef1f84bSDavid du Colombier 	devcreate,
8879ef1f84bSDavid du Colombier 	traceclose,
8889ef1f84bSDavid du Colombier 	traceread,
8899ef1f84bSDavid du Colombier 	devbread,
8909ef1f84bSDavid du Colombier 	tracewrite,
8919ef1f84bSDavid du Colombier 	devbwrite,
8929ef1f84bSDavid du Colombier 	devremove,
8939ef1f84bSDavid du Colombier 	devwstat,
8949ef1f84bSDavid du Colombier };
895