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