diff --git a/sys/include/dtracy.h b/sys/include/dtracy.h index 3e2ff81f1..cd8d577b3 100644 --- a/sys/include/dtracy.h +++ b/sys/include/dtracy.h @@ -41,6 +41,8 @@ struct DTName { /* we assign all pairs (probe,action-group) (called an enabling or DTEnab) a unique ID called EPID. we could also use probe IDs and action group IDs but using a single 32-bit ID for both is more flexible/efficient. + + epid == -1 indicates a fault record (see below) */ struct DTEnab { u32int epid; @@ -235,6 +237,10 @@ struct DTTrigInfo { DTChan *ch; }; +/* fault records are used to note when a probe had to be aborted (e.g. because of a page fault) */ +enum { + DTFILL = 1, /* illegal address */ +}; void dtinit(int); void dtsync(void); @@ -269,6 +275,7 @@ int dtcread(DTChan *, void *, int); int dtcaggread(DTChan *, void *, int); void dtcreset(DTChan *); void dtcrun(DTChan *, int); +int dtcfault(DTTrigInfo *, int, char *, ...); /* aggbuf functions */ int dtaunpackid(DTAgg *); diff --git a/sys/src/cmd/dtracy/act.c b/sys/src/cmd/dtracy/act.c index 063be6cb9..3412382c3 100644 --- a/sys/src/cmd/dtracy/act.c +++ b/sys/src/cmd/dtracy/act.c @@ -462,6 +462,34 @@ parseclause(Clause *cl, uchar *p, uchar *e, Enab *en, Biobuf *bp) return 0; } +uchar * +parsefault(uchar *p0, uchar *e) +{ + uchar *p; + u32int epid; + u8int type, dummy; + u16int n; + Enab *en; + + p = unpack(p0, e, "csci", &type, &n, &dummy, &epid); + if(p == nil) return nil; + en = epidlookup(epid); + switch(type){ + case DTFILL: { + u32int pid; + u64int addr; + + p = unpack(p, e, "iv", &pid, &addr); + if(p == nil) return nil; + fprint(2, "dtracy: illegal access: probe=%s, pid=%d, addr=%#llx\n", en != nil ? en->probe : nil, pid, addr); + break; + } + default: + fprint(2, "dtracy: unknown fault type %#.2ux\n", type); + } + return p0 + n - 12; +} + int parsebuf(uchar *p, int n, Biobuf *bp) { @@ -474,6 +502,11 @@ parsebuf(uchar *p, int n, Biobuf *bp) while(p < e){ p = unpack(p, e, "iv", &epid, &ts); if(p == nil) goto err; + if(epid == (u32int)-1){ + p = parsefault(p, e); + if(p == nil) goto err; + continue; + } en = epidlookup(epid); if(en == nil) goto err; if(parseclause(en->cl, p - 12, p + en->reclen - 12, en, bp) < 0) return -1; diff --git a/sys/src/libdtracy/prog.c b/sys/src/libdtracy/prog.c index f0637acad..402638f13 100644 --- a/sys/src/libdtracy/prog.c +++ b/sys/src/libdtracy/prog.c @@ -230,6 +230,55 @@ dtpeekstr(uvlong addr, u8int *v, int len) #define PUT4(c) *bp++ = c; *bp++ = c >> 8; *bp++ = c >> 16; *bp++ = c >> 24; #define PUT8(c) PUT4(c); PUT4(c>>32); +int +dtcfault(DTTrigInfo *info, int type, char *fmt, ...) +{ + DTBuf *b; + va_list va; + int n; + char *s; + u8int *bp; + u32int l; + uvlong q; + + b = info->ch->wrbufs[info->machno]; + n = 20; + va_start(va, fmt); + for(s = fmt; *s != 0; s++) + switch(*s){ + case 'i': n += 4; break; + case 'p': n += 8; break; + default: + assert(0); + } + va_end(va); + if(b->wr + n > DTBUFSZ) + return -1; + bp = &b->data[b->wr]; + PUT4(-1); + PUT8(info->ts); + PUT1(type); + PUT2(n); + PUT1(0); + PUT4(info->epid); + va_start(va, fmt); + for(s = fmt; *s != 0; s++) + switch(*s){ + case 'i': + l = va_arg(va, int); + PUT4(l); + break; + case 'p': + q = (uintptr) va_arg(va, void *); + PUT8(q); + break; + } + va_end(va); + assert(bp - b->data - b->wr == n); + b->wr = bp - b->data; + return 0; +} + static int dtgexec(DTActGr *g, DTTrigInfo *info) { @@ -265,8 +314,8 @@ dtgexec(DTActGr *g, DTTrigInfo *info) break; case ACTTRACESTR: if(dtpeekstr(v, bp, g->acts[i].size) < 0){ - snprint(info->ch->errstr, sizeof(info->ch->errstr), "fault @ %#llux", v); - return -1; + dtcfault(info, DTFILL, "ip", dtgetvar(DTV_PID), v); + return 0; } bp += g->acts[i].size; break;