--- /sys/src/9k/k10/syscall.c +++ /sys/src/9k/k10/syscall.c @@ -9,6 +9,7 @@ #include "/sys/src/libc/9syscall/sys.h" #include +#include #include "amd64.h" #include "ureg.h" @@ -206,6 +207,7 @@ syscall(int scallnr, Ureg* ureg) int i, s; Ar0 ar0; static Ar0 zar0; + void (*pt)(Proc*, int, vlong, vlong); if(!userureg(ureg)) panic("syscall: cs %#llux\n", ureg->cs); @@ -217,6 +219,9 @@ syscall(int scallnr, Ureg* ureg) up->pc = ureg->ip; up->dbgreg = ureg; + if(up->trace && (pt = proctrace) != nil) + pt(up, STrap, todget(nil), STrapSC|scallnr); + if(up->procctl == Proc_tracesyscall){ up->procctl = Proc_stopme; procctl(up); --- /sys/src/9k/k10/trap.c +++ /sys/src/9k/k10/trap.c @@ -6,6 +6,7 @@ #include "../port/error.h" #include +#include #include "ureg.h" #include "amd64.h" @@ -281,6 +282,7 @@ trap(Ureg* ureg) int clockintr, vno, user; char buf[ERRMAX]; Vctl *ctl, *v; + void (*pt)(Proc*, int, vlong, vlong); m->perf.intrts = perfticks(); user = userureg(ureg); @@ -300,7 +302,9 @@ trap(Ureg* ureg) m->intr++; if(vno >= IdtPIC && vno != IdtSYSCALL) m->lastintr = ctl->irq; - } + }else if(user && up->trace && (pt = proctrace) != nil) + if(vno != IdtPF) + pt(up, STrap, 0, vno); if(ctl->isr) ctl->isr(vno); @@ -519,9 +523,10 @@ unexpected(Ureg* ureg, void*) static void faultamd64(Ureg* ureg, void*) { - u64int addr; + u64int addr, arg; int read, user, insyscall; char buf[ERRMAX]; + void (*pt)(Proc*, int, vlong, vlong); addr = cr2get(); user = userureg(ureg); @@ -539,6 +544,14 @@ faultamd64(Ureg* ureg, void*) } read = !(ureg->error & 2); + if(up->trace && (pt = proctrace) != nil){ + if(read) + arg = STrapRPF | (addr&STrapMask); + else + arg = STrapWPF | (addr&STrapMask); + pt(up, STrap, 0, arg); + } + insyscall = up->insyscall; up->insyscall = 1; if(fault(addr, read) < 0){ --- /sys/src/9k/port/devproc.c +++ /sys/src/9k/port/devproc.c @@ -157,7 +157,6 @@ static Traceevent *tevents; static Lock tlock; static int topens; static int tproduced, tconsumed; -void (*proctrace)(Proc*, int, vlong); static void profclock(Ureg *ur, Timer *) @@ -269,7 +268,7 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) } static void -_proctrace(Proc* p, Tevent etype, vlong ts) +_proctrace(Proc* p, Tevent etype, vlong ts, vlong) { Traceevent *te; @@ -1373,7 +1372,7 @@ procctlreq(Proc *p, char *va, int n) Cmdtab *ct; vlong time; char *e; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); if(p->kp) /* no ctl requests to kprocs */ error(Eperm); @@ -1536,7 +1535,7 @@ procctlreq(Proc *p, char *va, int n) case CMevent: pt = proctrace; if(up->trace && pt) - pt(up, SUser, 0); + pt(up, SUser, 0, 0); break; } --- /dev/null +++ /sys/src/9k/port/devptrace.c @@ -0,0 +1,302 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "netif.h" + +#include + + +enum { + Qdir, + Qctl, + Qdata, +}; + +enum { + CMsize, + CMtrace, +}; + +static Dirtab tracedir[]= +{ + ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, + "ptracectl", {Qctl}, 0, 0664, + "ptrace", {Qdata}, 0, 0440, +}; + +static Lock tlk; +static int topens; +static int tproduced, tconsumed, ntevents, ntmask; +static uchar *tevents; + +static Chan* +traceattach(char *spec) +{ + return devattach(L'σ', 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 void +_ptrace(Proc *p, int etype, vlong ts, vlong arg) +{ + int i; + uchar *te; + + if (p->trace == 0 || topens == 0) + return; + + lock(&tlk); + if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= ntevents){ + unlock(&tlk); + return; + } + if(ts == 0) + ts = todget(nil); + i = (tproduced&ntmask) * PTsize; + te = &tevents[i]; + PBIT32(te, (int)p->pid); + te += BIT32SZ; + PBIT32(te, etype); + te += BIT32SZ; + PBIT32(te, m->machno); + te += BIT32SZ; + PBIT64(te, ts); + te += BIT64SZ; + PBIT64(te, arg); + tproduced++; + if(etype == SDead) + p->trace = 0; + unlock(&tlk); +} + + +static Chan* +traceopen(Chan *c, int omode) +{ + int q; + + q = c->qid.path; + switch(q){ + case Qdata: + lock(&tlk); + if (waserror()){ + unlock(&tlk); + nexterror(); + } + if(topens > 0) + error(Einuse); + if(ntevents == 0) + error("must set trace size first"); + if(up->trace != 0) + error("a traced process can't open the trace device"); + tproduced = tconsumed = 0; + proctrace = _ptrace; + topens++; + poperror(); + unlock(&tlk); + break; + } + c = devopen(c, omode, tracedir, nelem(tracedir), devgen); + return c; +} + +static void +traceclose(Chan *c) +{ + int q; + + q = c->qid.path; + switch(q){ + case Qdata: + if(c->flag & COPEN){ + lock(&tlk); + topens--; + tproduced = tconsumed = 0; + proctrace = nil; + unlock(&tlk); + } + } +} + +static long +traceread(Chan *c, void *a, long n, vlong offset) +{ + int q, xopens, xevents, xprod, xcons, navail, ne, i; + char *s, *e; + + q = c->qid.path; + switch(q){ + case Qdir: + return devdirread(c, a, n, tracedir, nelem(tracedir), devgen); + break; + case Qctl: + e = up->genbuf + sizeof up->genbuf; + lock(&tlk); + xopens = topens; + xevents = ntevents; + xprod = tproduced; + xcons = tconsumed; + unlock(&tlk); + s = seprint(up->genbuf, e, "opens %d\n", xopens); + s = seprint(s, e, "size %d\n", xevents); + s = seprint(s, e, "produced %d\n", xprod); + seprint(s, e, "consumed %d\n", xcons); + return readstr(offset, a, n, up->genbuf); + break; + case Qdata: + /* no locks! */ + navail = tproduced - tconsumed; + if(navail <= 0) + return 0; + if(navail > n / PTsize) + navail = n / PTsize; + s = a; + e = a; + while(navail > 0) { + if((tconsumed & ntmask) + navail > ntevents) + ne = ntevents - (tconsumed & ntmask); + else + ne = navail; + i = ne * PTsize; + memmove(e, &tevents[(tconsumed & ntmask)*PTsize], i); + + tconsumed += ne; + e += i; + navail -= ne; + } + return e - s; + break; + default: + error(Egreg); + } + error("not yet implemented"); + return -1; +} + +static Cmdtab proccmd[] = +{ + CMsize, "size", 2, + CMtrace, "trace", 0, +}; + +static long +tracewrite(Chan *c, void *a, long n, vlong) +{ + int i, q, sz, msk, pid; + Cmdbuf *cb; + Cmdtab *ct; + uchar *nt; + Proc *p; + + q = c->qid.path; + switch(q){ + case Qctl: + break; + default: + error(Egreg); + } + cb = parsecmd(a, n); + if(waserror()){ + free(cb); + nexterror(); + } + ct = lookupcmd(cb, proccmd, nelem(proccmd)); + + switch(ct->index){ + case CMsize: + sz = atoi(cb->f[1]); + if(sz == 0){ + lock(&tlk); + ntevents = 0; + ntmask = 0; + unlock(&tlk); + } + msk = sz-1; + if((sz&msk) != 0) + error("wrong size. use a power of two."); + if(sz > 512*1024) + error("size is too large"); + lock(&tlk); + if(waserror()){ + unlock(&tlk); + nexterror(); + } + if(sz > ntevents){ + nt = realloc(tevents, PTsize * sz); + if(nt == nil) + error("not enough memory"); + tevents = nt; + ntevents = sz; + ntmask = msk; + } + tproduced = 0; + tconsumed = 0; + poperror(); + unlock(&tlk); + break; + case CMtrace: + if(cb->nf != 2 && cb->nf != 3) + error(Ebadctl); + pid = atoi(cb->f[1]); + i = psindex(pid); + if(i < 0) + error(Eprocdied); + p = psincref(i); + if(p == nil) + error(Eprocdied); + qlock(&p->debug); + if(waserror()){ + qunlock(&p->debug); + psdecref(p); + nexterror(); + } + if(p->pid != pid) + error(Eprocdied); + if(cb->nf == 2) + p->trace ^= p->trace; + else + p->trace = (atoi(cb->f[2]) != 0); + poperror(); + qunlock(&p->debug); + psdecref(p); + break; + } + + poperror(); + free(cb); + return n; +} + +Dev ptracedevtab = { + L'σ', + "ptrace", + devreset, + devinit, + devshutdown, + traceattach, + tracewalk, + tracestat, + traceopen, + devcreate, + traceclose, + traceread, + devbread, + tracewrite, + devbwrite, + devremove, + devwstat, +}; --- /sys/src/9k/port/devtrace.c +++ /sys/src/9k/port/devtrace.c @@ -6,6 +6,13 @@ #include "../port/error.h" #include "netif.h" +/* + * NB: To be used with 6l -e so tracein/out are called upon + * function entry and exit. + * There's no trace(3) man page, look at write source to see the + * commands. + */ + #pragma profile 0 typedef struct Trace Trace; --- /sys/src/9k/port/edf.c +++ /sys/src/9k/port/edf.c @@ -7,7 +7,7 @@ #include "../port/error.h" #include "../port/edf.h" -#include +#include /* debugging */ enum { @@ -138,7 +138,7 @@ deadlineintr(Ureg*, Timer *t) /* Proc reached deadline */ extern int panicking; Proc *p; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); if(panicking || active.exiting) return; @@ -155,7 +155,7 @@ deadlineintr(Ureg*, Timer *t) */ if(p == up){ if(up->trace && (pt = proctrace)) - pt(up, SInts, 0); + pt(up, SInts, 0, 0); up->delaysched++; delayedscheds++; } @@ -166,7 +166,7 @@ release(Proc *p) { /* Called with edflock held */ Edf *e; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); long n; vlong nowns; @@ -199,8 +199,8 @@ release(Proc *p) now, p->pid, statename[p->state], e->r, e->d, e->t, e->S); if(pt = proctrace){ nowns = todget(nil); - pt(p, SRelease, nowns); - pt(p, SDeadline, nowns + 1000LL*e->D); + pt(p, SRelease, nowns, 0); + pt(p, SDeadline, nowns + 1000LL*e->D, 0); } }else{ DPRINT("%lud release %d[%s], too late t=%lud, called from %#p\n", @@ -273,7 +273,7 @@ edfrecord(Proc *p) { long used; Edf *e; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); if((e = edflock(p)) == nil) return; @@ -285,7 +285,7 @@ edfrecord(Proc *p) if(e->S > 0){ if(e->S <= used){ if(pt = proctrace) - pt(p, SSlice, 0); + pt(p, SSlice, 0, 0); DPRINT("%lud edfrecord slice used up\n", now); e->d = now; e->S = 0; @@ -300,7 +300,7 @@ void edfrun(Proc *p, int edfpri) { Edf *e; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); long tns; e = p->edf; @@ -327,7 +327,7 @@ edfrun(Proc *p, int edfpri) DPRINT("v"); } if(p->trace && (pt = proctrace)) - pt(p, SInte, todget(nil) + e->tns); + pt(p, SInte, todget(nil) + e->tns, 0); e->tmode = Trelative; e->tf = deadlineintr; e->ta = p; @@ -345,7 +345,7 @@ edfadmit(Proc *p) Edf *e; int i; Proc *r; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); long tns; e = p->edf; @@ -374,7 +374,7 @@ edfadmit(Proc *p) edflock(p); if(p->trace && (pt = proctrace)) - pt(p, SAdmit, 0); + pt(p, SAdmit, 0, 0); /* Look for another proc with the same period to synchronize to */ for(i=0; (r = psincref(i)) != nil; i++) { @@ -440,12 +440,12 @@ void edfstop(Proc *p) { Edf *e; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); if(e = edflock(p)){ DPRINT("%lud edfstop %d[%s]\n", now, p->pid, statename[p->state]); if(p->trace && (pt = proctrace)) - pt(p, SExpel, 0); + pt(p, SExpel, 0, 0); e->flags &= ~Admitted; if(e->tt) timerdel(e); @@ -465,13 +465,13 @@ edfyield(void) { /* sleep until next release */ Edf *e; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); long n; if((e = edflock(up)) == nil) return; if(up->trace && (pt = proctrace)) - pt(up, SYield, 0); + pt(up, SYield, 0, 0); if((n = now - e->t) > 0){ if(n < e->T) e->t += e->T; @@ -503,7 +503,7 @@ edfready(Proc *p) Edf *e; Schedq *rq; Proc *l, *pp; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); long n; if((e = edflock(p)) == nil) @@ -588,7 +588,7 @@ edfready(Proc *p) p->state = Ready; unlock(runq); if(p->trace && (pt = proctrace)) - pt(p, SReady, 0); + pt(p, SReady, 0, 0); return 1; } --- /sys/src/9k/port/portfns.h +++ /sys/src/9k/port/portfns.h @@ -231,7 +231,7 @@ void procrestore(Proc*); void procsave(Proc*); Proc* psincref(int); void psdecref(Proc*); -void (*proctrace)(Proc*, int, vlong); +void (*proctrace)(Proc*, int, vlong, vlong); void procwired(Proc*, int); Pte* ptealloc(void); Pte* ptecpy(Pte*); --- /sys/src/9k/port/proc.c +++ /sys/src/9k/port/proc.c @@ -7,7 +7,7 @@ #include "../port/edf.h" #include "errstr.h" -#include +#include int nrdy; Ref noteidalloc; @@ -404,7 +404,7 @@ ready(Proc *p) Mreg s; int pri; Schedq *rq; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); s = splhi(); if(edfready(p)){ @@ -423,7 +423,7 @@ ready(Proc *p) queueproc(rq, p); pt = proctrace; if(pt) - pt(p, SReady, 0); + pt(p, SReady, 0, 0); splx(s); } @@ -491,7 +491,7 @@ runproc(void) Proc *p; ulong start, now; int i; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); start = perfticks(); @@ -551,7 +551,7 @@ found: } pt = proctrace; if(pt) - pt(p, SRun, 0); + pt(p, SRun, 0, 0); return p; } @@ -701,7 +701,7 @@ void sleep(Rendez *r, int (*f)(void*), void *arg) { Mreg s; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); s = splhi(); @@ -739,7 +739,7 @@ sleep(Rendez *r, int (*f)(void*), void *arg) */ pt = proctrace; if(pt) - pt(up, SSleep, 0); + pt(up, SSleep, 0, 0); up->state = Wakeme; up->r = r; @@ -1008,7 +1008,7 @@ pexit(char *exitstr, int freemem) Rgrp *rgrp; Pgrp *pgrp; Chan *dot; - void (*pt)(Proc*, int, vlong); + void (*pt)(Proc*, int, vlong, vlong); if(up->syscalltrace != nil) free(up->syscalltrace); @@ -1018,7 +1018,7 @@ pexit(char *exitstr, int freemem) timerdel(up); pt = proctrace; if(pt) - pt(up, SDead, 0); + pt(up, SDead, 0, 0); /* nil out all the resources under lock (free later) */ qlock(&up->debug); --- /sys/src/9k/port/qlock.c +++ /sys/src/9k/port/qlock.c @@ -4,6 +4,8 @@ #include "dat.h" #include "fns.h" +#include + struct { ulong rlock; ulong rlockq; @@ -17,6 +19,7 @@ void qlock(QLock *q) { Proc *p; + void (*pt)(Proc*, int, vlong, vlong); if(m->ilockdepth != 0) print("qlock: %#p: ilockdepth %d", getcallerpc(&q), m->ilockdepth); @@ -43,6 +46,8 @@ qlock(QLock *q) up->qnext = 0; up->state = Queueing; up->qpc = getcallerpc(&q); + if(up->trace && (pt = proctrace) != nil) + pt(up, SSleep, 0, Queueing | (up->qpc<<8)); unlock(&q->use); sched(); q->qpc = getcallerpc(&q); @@ -91,6 +96,8 @@ void rlock(RWlock *q) { Proc *p; + void (*pt)(Proc*, int, vlong, vlong); + uintptr pc; lock(&q->use); rwstats.rlock++; @@ -112,6 +119,10 @@ rlock(RWlock *q) q->tail = up; up->qnext = 0; up->state = QueueingR; + if(up->trace && (pt = proctrace) != nil){ + pc = getcallerpc(&q); + pt(up, SSleep, 0, QueueingR | (pc<<8)); + } unlock(&q->use); sched(); } @@ -143,6 +154,8 @@ void wlock(RWlock *q) { Proc *p; + uintptr pc; + void (*pt)(Proc*, int, vlong, vlong); lock(&q->use); rwstats.wlock++; @@ -167,6 +180,10 @@ wlock(RWlock *q) q->tail = up; up->qnext = 0; up->state = QueueingW; + if(up->trace && (pt = proctrace) != nil){ + pc = getcallerpc(&q); + pt(up, SSleep, 0, QueueingW|(pc<<8)); + } unlock(&q->use); sched(); } --- /sys/src/9k/port/sysproc.c +++ /sys/src/9k/port/sysproc.c @@ -8,6 +8,7 @@ #include "../port/edf.h" #include +#include void sysr1(Ar0* ar0, va_list list) @@ -27,6 +28,8 @@ sysrfork(Ar0* ar0, va_list list) Rgrp *org; Egrp *oeg; Mach *wm; + void (*pt)(Proc*, int, vlong, vlong); + u64int ptarg; /* * int rfork(int); @@ -199,6 +202,10 @@ sysrfork(Ar0* ar0, va_list list) wm = up->wired; if(wm) procwired(p, wm->machno); + if(p->trace && (pt = proctrace) != nil){ + strncpy((char*)&ptarg, p->text, sizeof ptarg); + pt(p, SName, 0, ptarg); + } ready(p); sched(); @@ -243,6 +250,8 @@ sysexec(Ar0* ar0, va_list list) char line[sizeof(Exec)], *progarg[sizeof(Exec)/2+1]; long hdrsz, magic, textsz, datasz, bsssz; uintptr textlim, textmin, datalim, bsslim, entry, stack; + void (*pt)(Proc*, int, vlong, vlong); + u64int ptarg; /* * void* exec(char* name, char* argv[]); @@ -524,6 +533,11 @@ sysexec(Ar0* ar0, va_list list) } } + if(up->trace && (pt = proctrace) != nil){ + strncpy((char*)&ptarg, elem, sizeof ptarg); + pt(up, SName, 0, ptarg); + } + /* Text. Shared. Attaches to cache image if possible */ /* attachimage returns a locked cache image */ @@ -830,7 +844,8 @@ void sysrendezvous(Ar0* ar0, va_list list) { Proc *p, **l; - uintptr tag, val; + uintptr tag, val, pc; + void (*pt)(Proc*, int, vlong, vlong); /* * void* rendezvous(void*, void*); @@ -864,6 +879,10 @@ sysrendezvous(Ar0* ar0, va_list list) up->rendhash = *l; *l = up; up->state = Rendezvous; + if(up->trace && (pt = proctrace) != nil){ + pc = (uintptr)sysrendezvous; + pt(up, SSleep, 0, Rendezvous|(pc<<8)); + } unlock(up->rgrp); sched();