#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 longLines 1–500 of 887. Load more
#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 ... */ void hex8(u32int l, char *c) { int i; for(i = 2; i; i--){ c[i-1] = hex[l&0xf]; l >>= 4; } } void hex16(u32int l, char *c) { int i; for(i = 4; i; i--){ c[i-1] = hex[l&0xf]; l >>= 4; } } void hex32(u32int l, char *c) { int i; for(i = 8; i; i--){ c[i-1] = hex[l&0xf]; l >>= 4; } } void hex64(u64int l, char *c) { hex32(l>>32, c); hex32(l, &c[8]); } static int lognonempty(void *) { return pw - pr; } static int logfull(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. */ int overlapping(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. */ int watchingpid(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. */ void removetrace(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 */ void traceon(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 */ void traceoff(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 */ void tracein(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 */ void traceout(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 void freetrace(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 long tracestat(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 void traceclose(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