// FIXME: i think the logic here is wrong when the target // prctl handles a cloning proc...should we clone the ctls // in the traps list? in any case, prctl 81ac0668e4 // breaks this test. i think it is because of the // introduced call to ctlclrtrap on ctl death. @include l1 = "../l1"; prctl = "../../prctl/prctl"; //l1 = "../l1.x"; l1names = l1+".names"; prnames = prctl+".names"; traps = [:]; @define dumptraps() { foreach(@lambda(k,v) { printf("%a: %a\n", k, v); }, traps); } @define add1(ctl, br) { @local addr; addr = br->bp->addr; if(traps[(void*)addr] == nil) traps[(void*)addr] = [ ctl->id ]; else append(traps[(void*)addr], ctl->id); dumptraps(); } @define xdel(l, x) { @local i, m; m = length(l); for(i = 0; i < m; i++) if(l[i] == x) break; if(i == m) error("could not find %d in a list\n", x); listdel(l, i); } @define sub1(ctl, br) { @local addr; addr = br->bp->addr; if(traps[(void*)addr] == nil) error("invalid trap clear addr=%x state=%a\n", addr, traps[(void*)addr]); else xdel(traps[(void*)addr], ctl->id); dumptraps(); } @define clr(ctl, bp) { @local addr; addr = bp->addr; if(traps[(void*)addr] == nil || length(traps[(void*)addr]) > 0) printf("invalid bp removal addr=%x state=%a!\n", addr, traps[(void*)addr]); else traps[(void*)addr] = nil; } @define walkstack(pc, fp) { @local sp; printf("\t%y\n", pc); while(fp){ pc = fp[1]; printf("\t%y\n", pc); fp = (`u64*)*fp; } } @define htforeach(f, ht) { @local hp, i, sz; sz = ht->sz; for(i = 0; i < sz; i++){ hp = ht->ht[i]; while(hp){ f(hp->key, hp->val); hp = hp->next; } } } @define enumctls(dom) { @local fn, l; l = []; @define fn(k, v) { append(l, (`Ctl*)v); } htforeach(fn, dom`ctltab); return l; } @define checkctls(dom) { @local notebp, ctls, as, bps; ctls = enumctls(dom); as = [:]; bps = [:]; @define notebp(bp) { if(bps[bp] == nil) bps[bp] = 1; else bps[bp]++; } foreach(@lambda(ctl){ printf("ctl %d %p\n", ctl->id, ctl); as[ctl->as] = ctl->as; printf("braddr:\n"); htforeach(@lambda(k,v) { @local addr, br; addr = (`u64)k; br = (`Brkref*)v; printf("\t%x -> %d %p %x %d\n", addr, br->id, br->bp, br->bp->addr, br->bp->cnt); notebp(br->bp); }, ctl->braddr); printf("brid:\n"); htforeach(@lambda(k,v) { @local id, br; id = (`u64)k; br = (`Brkref*)v; printf("\t%d -> %d %p %x %d\n", id, br->id, br->bp, br->bp->addr, br->bp->cnt); notebp(br->bp); }, ctl->brid); }, ctls); foreach(@lambda(a,v) { printf("as %p\n", a); printf("bpaddr:\n"); htforeach(@lambda(k,v) { @local addr, bp; addr = (`u64)k; bp = (`Brk*)v; printf("\t%x -> %p %x %d\n", addr, bp, bp->addr, bp->cnt); if(2*bp->cnt != bps[bp]) error("ref count! 2*%d != %d\n", bp->cnt, bps[bp]); }, a->bpaddr); }, as); } @define doit(args) { @local mux, l1ns, prns, as, dom, e, nexec, prctlpid, tracepr; @define tracepr(ctl) { @local dom; dom = mkdom(prns, ctl.mem()); // dom.xtrap(&dom`writemsg, // @lambda(ctl){ // @local pd, xmsg, regs; // regs = ctl.reg(); // pd = mkdom(prns, ctl.mem()); // xmsg = (`Msg*){pd}regs->rsi; // printf("writemsg %e:\n", // (enum Mkind)xmsg->op); // checkctls(pd); // }); dom.xtrap(&dom`note_settrap0, @lambda(ctl){ @local sp, i, regs, xctl, xaddr, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); xctl = (`Ctl*){pd}regs->rdi; xaddr = (`u64){pd}regs->rsi; printf("%y (ctl = %d (%p), addr = %p)\n", (void*){pd}regs->rip, xctl->id, xctl, xaddr); }); dom.xtrap(&dom`note_settrap1, @lambda(ctl){ @local sp, i, regs, xctl, xbr, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); xctl = (`Ctl*){pd}regs->rdi; xbr = (`Brkref*){pd}regs->rsi; printf("%y (ctl = %d (%p), br = %p)\n", (void*){pd}regs->rip, xctl->id, xctl, xbr); add1(xctl, xbr); }); dom.xtrap(&dom`note_clrtrap0, @lambda(ctl){ @local sp, i, regs, xctl, xbr, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); xctl = (`Ctl*){pd}regs->rdi; xbr = (`Brkref*){pd}regs->rsi; printf("%y (ctl = %d (%p), br = %p, addr = %p)\n", (void*){pd}regs->rip, xctl->id, xctl, xbr, xbr->bp->addr); sub1(xctl, xbr); }); dom.xtrap(&dom`note_clrbrk0, @lambda(ctl){ @local sp, i, regs, xctl, xbp, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); xctl = (`Ctl*){pd}regs->rdi; xbp = (`Brk*){pd}regs->rsi; printf("%y (ctl = %d (%p), bp = %p)\n", (void*){pd}regs->rip, xctl->id, xctl, xbp); clr(xctl, xbp); }); dom.xtrap(&dom`editbrk, @lambda(ctl){ @local sp, i, regs, xctl, xbp, xset, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); xctl = (`Ctl*){pd}regs->rdi; xbp = (`Brk*){pd}regs->rsi; xset = (int){pd}regs->rdx; printf("%y (ctl = %d (%p), bp = %p, set = %d", (void*){pd}regs->rip, xctl->id, xctl, xbp, xset); if(xset == 0) printf(" text = %x)\n", xbp->text); else printf(" text = %x)\n", 0xcc); }); dom.xtrap(&dom`xfatal, @lambda(ctl){ @local sp, regs, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); walkstack((`u64*)sp[0], (`u64*){pd}regs->rbp); }); dom.xtrap(&dom`xfatalno, @lambda(ctl){ @local sp, regs, pd; regs = ctl.reg(); sp = (void**){dom}regs->rsp; pd = mkdom(prns, ctl.mem()); walkstack((`u64*)sp[0], (`u64*){pd}regs->rbp); }); } prctlpid = nil; nexec = 0; npop = 0; e = sprintfa("@names clp64le { @include \"%s\" };", l1names); l1ns = eval(e); e = sprintfa("@names clp64le { @include \"%s\" };", prnames); prns = eval(e); mux = mkctlmux_local(); push(args, l1); ctl = mux.launch(args, 0); as = ctl.mem(); dom = mkdom(l1ns, as); dom.trace(ctlmux`Efork, @lambda(ctl, newctl){ printf("fork %d -> %d\n", ctl.id, newctl.id); if(ctl.id == prctlpid){ printf("releasing %d\n", newctl.id); newctl.detach(); } }); dom.trace(ctlmux`Eexec, @lambda(ctl){ nexec++; printf("exec -> %d\n", ctl.id); if(nexec == 1){ prctlpid = ctl.id; printf("prctl is %d\n", ctl.id); tracepr(ctl); } if(nexec > 1) ctl.detach(); }); dom.xtrap(&dom`finivm, @lambda(ctl){ printf("vm is exiting\n"); dumptraps(); return nil; }); dom.xcont(); mux.run(); } doit([ "tracemclones.cqct" ]);