ref: 5f7a6b7ea3c4ae1b51beffe3309e9b6b0491e71f
dir: /sys/src/libdtracy/prog.c/
#include <u.h> #include <libc.h> #include <dtracy.h> int dteverify(DTExpr *p) { int i, nregs; u32int ins; u8int a, b, c; nregs = 16; for(i = 0; i < p->n; i++){ ins = p->b[i]; a = ins >> 16; b = ins >> 8; c = ins; switch(ins>>24){ case DTE_ADD: if(ins == 0) continue; /* wet floor */ case DTE_SUB: case DTE_MUL: case DTE_UDIV: case DTE_UMOD: case DTE_SDIV: case DTE_SMOD: case DTE_AND: case DTE_OR: case DTE_XOR: case DTE_XNOR: case DTE_LSL: case DTE_LSR: case DTE_ASR: case DTE_SEQ: case DTE_SNE: case DTE_SLT: case DTE_SLE: if(a >= nregs || b >= nregs || c >= nregs || c == 0) goto invalid; break; case DTE_LDI: case DTE_XORI: if(c >= nregs || c == 0) goto invalid; break; case DTE_BEQ: case DTE_BNE: case DTE_BLT: case DTE_BLE: if(a >= nregs || b >= nregs || i + 1 + c >= p->n) goto invalid; break; case DTE_RET: if(a >= nregs || b != 0 || c != 0) goto invalid; break; case DTE_LDV: if(a >= DTNVARS || b >= nregs) goto invalid; break; case DTE_ZXT: case DTE_SXT: if(a >= nregs || b == 0 || b > 64 || c >= nregs) goto invalid; break; default: goto invalid; } } if(p->n == 0 || p->b[p->n - 1] >> 24 != DTE_RET){ werrstr("must end with RET"); return -1; } return 0; invalid: werrstr("invalid instruction %#.8ux @ %#.4ux", ins, i); return -1; } int dtgverify(DTChan *, DTActGr *g) { int i; if(g->pred != nil && dteverify(g->pred) < 0) return -1; for(i = 0; i < g->nact; i++) switch(g->acts[i].type){ case ACTTRACE: if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0 || (uint)g->acts[i].size > 8) return -1; break; case ACTTRACESTR: if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0 || (uint)g->acts[i].size > DTRECMAX) return -1; break; case ACTAGGKEY: if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0 || (uint)g->acts[i].size > 8) return -1; if(i == g->nact - 1 || g->acts[i+1].type != ACTAGGVAL || g->acts[i+1].agg.id != g->acts[i].agg.id) return -1; break; case ACTAGGVAL: if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0 || (uint)g->acts[i].size > 8) return -1; if(i == 0 || g->acts[i-1].type != ACTAGGKEY) return -1; if(dtaunpackid(&g->acts[i].agg) < 0) return -1; break; case ACTCANCEL: if(g->acts[i].p == nil || dteverify(g->acts[i].p) < 0) return -1; if(i != g->nact - 1) return -1; break; default: return -1; } return 0; } int dteexec(DTExpr *p, DTTrigInfo *info, s64int *retv) { s64int R[16]; u32int ins; u8int a, b, c; int i; R[0] = 0; for(i = 0;; i++){ ins = p->b[i]; a = ins >> 16; b = ins >> 8; c = ins; switch(ins >> 24){ case DTE_ADD: R[c] = R[a] + R[b]; break; case DTE_SUB: R[c] = R[a] - R[b]; break; case DTE_MUL: R[c] = R[a] * R[b]; break; case DTE_SDIV: if(R[b] == 0) goto div0; R[c] = R[a] / R[b]; break; case DTE_SMOD: if(R[b] == 0) goto div0; R[c] = R[a] % R[b]; break; case DTE_UDIV: if(R[b] == 0) goto div0; R[c] = (uvlong)R[a] / (uvlong)R[b]; break; case DTE_UMOD: if(R[b] == 0) goto div0; R[c] = (uvlong)R[a] % (uvlong)R[b]; break; case DTE_AND: R[c] = R[a] & R[b]; break; case DTE_OR: R[c] = R[a] | R[b]; break; case DTE_XOR: R[c] = R[a] ^ R[b]; break; case DTE_XNOR: R[c] = ~(R[a] ^ R[b]); break; case DTE_LDI: R[c] = (s64int)ins << 40 >> 54 << (ins >> 8 & 63); break; case DTE_XORI: R[c] ^= (s64int)ins << 40 >> 54 << (ins >> 8 & 63); break; case DTE_LSL: if((u64int)R[b] >= 64) R[c] = 0; else R[c] = R[a] << R[b]; break; case DTE_LSR: if((u64int)R[b] >= 64) R[c] = 0; else R[c] = (u64int)R[a] >> R[b]; break; case DTE_ASR: if((u64int)R[b] >= 64) R[c] = R[a] >> 63; else R[c] = R[a] >> R[b]; break; case DTE_SEQ: R[c] = R[a] == R[b]; break; case DTE_SNE: R[c] = R[a] != R[b]; break; case DTE_SLT: R[c] = R[a] < R[b]; break; case DTE_SLE: R[c] = R[a] <= R[b]; break; case DTE_BEQ: if(R[a] == R[b]) i += c; break; case DTE_BNE: if(R[a] != R[b]) i += c; break; case DTE_BLT: if(R[a] < R[b]) i += c; break; case DTE_BLE: if(R[a] <= R[b]) i += c; break; case DTE_LDV: switch(a){ case DTV_ARG0: case DTV_ARG1: case DTV_ARG2: case DTV_ARG3: case DTV_ARG4: case DTV_ARG5: case DTV_ARG6: case DTV_ARG7: case DTV_ARG8: case DTV_ARG9: R[b] = info->arg[a - DTV_ARG0]; break; case DTV_TIME: R[b] = info->ts; break; case DTV_MACHNO: R[b] = info->machno; break; default: R[b] = dtgetvar(a); break; } case DTE_ZXT: R[c] = (uvlong)R[a] << 64 - b >> 64 - b; break; case DTE_SXT: R[c] = (vlong)R[a] << 64 - b >> 64 - b; break; case DTE_RET: *retv = R[a]; return 0; } } div0: snprint(info->ch->errstr, sizeof(info->ch->errstr), "division by zero"); return -1; } int dtpeekstr(uvlong addr, u8int *v, int len) { int i; for(i = 0; i < len; i++){ if(addr + i < addr || dtpeek(addr + i, &v[i], 1) < 0){ memset(v, 0, len); return -1; } if(v[i] == 0) break; } if(i < len) memset(&v[i], 0, len - i); return 0; } #define PUT1(c) *bp++ = c; #define PUT2(c) *bp++ = c; *bp++ = c >> 8; #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) { DTBuf *b; u8int *bp; s64int v; uchar aggkey[8]; int i, j; b = g->chan->wrbufs[info->machno]; if(b->wr + g->reclen > DTBUFSZ) return 0; if(g->pred != nil){ if(dteexec(g->pred, info, &v) < 0) return -1; if(v == 0) return 0; } bp = &b->data[b->wr]; PUT4(info->epid); PUT8(info->ts); for(i = 0; i < g->nact; i++){ if(g->acts[i].type == ACTCANCEL) return 0; if(dteexec(g->acts[i].p, info, &v) < 0) return -1; switch(g->acts[i].type){ case ACTTRACE: for(j = 0; j < g->acts[i].size; j++){ *bp++ = v; v >>= 8; } break; case ACTTRACESTR: if(dtpeekstr(v, bp, g->acts[i].size) < 0){ dtcfault(info, DTFILL, "ip", dtgetvar(DTV_PID), v); return 0; } bp += g->acts[i].size; break; case ACTAGGKEY: for(j = 0; j < g->acts[i].size; j++){ aggkey[j] = v; v >>= 8; } break; case ACTAGGVAL: dtarecord(g->chan, info->machno, &g->acts[i].agg, aggkey, g->acts[i-1].size, v); break; } } assert(bp - b->data - b->wr == g->reclen); b->wr = bp - b->data; return 0; } void dtptrigger(DTProbe *p, DTTrigInfo *info) { DTEnab *e; info->ts = dttime(); info->machno = dtmachlock(-1); for(e = p->enablist.probnext; e != &p->enablist; e = e->probnext) if(e->gr->chan->state == DTCGO){ info->ch = e->gr->chan; info->epid = e->epid; if(dtgexec(e->gr, info) < 0) e->gr->chan->state = DTCFAULT; } dtmachunlock(info->machno); }