// portable acid for all architectures defn pfl(addr) { print(pcfile(addr), ":", pcline(addr), "\n"); } defn notestk(addr) { local pc, sp; complex Ureg addr; pc = addr.pc\X; sp = addr.sp\X; print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); pfl(pc); _stk({"PC", pc, "SP", sp, linkreg(addr)}, 1); } defn notelstk(addr) { local pc, sp; complex Ureg addr; pc = addr.pc\X; sp = addr.sp\X; print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); pfl(pc); _stk({"PC", pc, "SP", sp, linkreg(addr)}, 1); } defn params(param) { while param do { sym = head param; print(sym[0], "=", itoa(sym[1], "%#ux")); param = tail param; if param then print (","); } } stkprefix = ""; stkignore = {}; stkend = 0; defn locals(l) { local sym; while l do { sym = head l; print(stkprefix, "\t", sym[0], "=", itoa(sym[1], "%#ux"), "\n"); l = tail l; } } defn _stkign(frame) { local file; file = pcfile(frame[0]); s = stkignore; while s do { if regexp(head s, file) then return 1; s = tail s; } return 0; } // print a stack trace // // in a run of leading frames in files matched by regexps in stkignore, // only print the last one. defn _stk(regs, dolocals) { local stk, frame, pc, fn, done, callerpc, paramlist, locallist; stk = strace(regs); if stkignore then { while stk && tail stk && _stkign(head tail stk) do stk = tail stk; } callerpc = 0; done = 0; while stk && !done do { frame = head stk; stk = tail stk; fn = frame[0]; pc = frame[1]; callerpc = frame[2]; paramlist = frame[3]; locallist = frame[4]; print(stkprefix, fmt(fn, 'a'), "("); params(paramlist); print(")"); if pc != fn then print("+", itoa(pc-fn, "%#ux")); print(" "); pfl(pc); if dolocals then locals(locallist); if fn == var("threadmain") || fn == var("p9main") then done=1; if fn == var("threadstart") || fn == var("scheduler") then done=1; if callerpc == 0 then done=1; } if callerpc && !done then { print(stkprefix, fmt(callerpc, 'a'), " "); pfl(callerpc); } } defn findsrc(file) { local lst, src; if file[0] == '/' then { src = file(file); if src != {} then { srcfiles = append srcfiles, file; srctext = append srctext, src; return src; } return {}; } lst = srcpath; while head lst do { src = file(head lst+file); if src != {} then { srcfiles = append srcfiles, file; srctext = append srctext, src; return src; } lst = tail lst; } } defn line(addr) { local src, file; file = pcfile(addr); src = match(file, srcfiles); if src >= 0 then src = srctext[src]; else src = findsrc(file); if src == {} then { print("no source for ", file, "\n"); return {}; } line = pcline(addr)-1; print(file, ":", src[line], "\n"); } defn addsrcdir(dir) { dir = dir+"/"; if match(dir, srcpath) >= 0 then { print("already in srcpath\n"); return {}; } srcpath = {dir}+srcpath; } defn source() { local l; l = srcpath; while l do { print(head l, "\n"); l = tail l; } l = srcfiles; while l do { print("\t", head l, "\n"); l = tail l; } } defn Bsrc(addr) { local lst; lst = srcpath; file = pcfile(addr); if file[0] == '/' && access(file) then { rc("B "+file+":"+itoa(pcline(addr))); return {}; } while head lst do { name = head lst+file; if access(name) then { rc("B "+name+":"+itoa(pcline(addr))); return {}; } lst = tail lst; } print("no source for ", file, "\n"); } defn srcline(addr) { local text, cline, line, file, src; file = pcfile(addr); src = match(file,srcfiles); if (src>=0) then src = srctext[src]; else src = findsrc(file); if (src=={}) then { return "(no source)"; } return src[pcline(addr)-1]; } defn src(addr) { local src, file, line, cline, text; file = pcfile(addr); src = match(file, srcfiles); if src >= 0 then src = srctext[src]; else src = findsrc(file); if src == {} then { print("no source for ", file, "\n"); return {}; } cline = pcline(addr)-1; print(file, ":", cline+1, "\n"); line = cline-5; loop 0,10 do { if line >= 0 then { if line == cline then print(">"); else print(" "); text = src[line]; if text == {} then return {}; print(line+1, "\t", text, "\n"); } line = line+1; } } defn step() // single step the process { local lst, lpl, addr, bput; bput = 0; if match(*PC, bplist) >= 0 then { // Sitting on a breakpoint bput = fmt(*PC, bpfmt); *bput = @bput; } lst = follow(*PC); lpl = lst; while lpl do { // place break points *(head lpl) = bpinst; lpl = tail lpl; } startstop(pid); // do the step while lst do { // remove the breakpoints addr = fmt(head lst, bpfmt); *addr = @addr; lst = tail lst; } if bput != 0 then *bput = bpinst; } defn bpset(addr) // set a breakpoint { if status(pid) != "Stopped" then { print("Waiting...\n"); stop(pid); } if match(addr, bplist) >= 0 then print("breakpoint already set at ", fmt(addr, 'a'), "\n"); else { *fmt(addr, bpfmt) = bpinst; bplist = append bplist, addr; } } defn bptab() // print a table of breakpoints { local lst, addr; lst = bplist; while lst do { addr = head lst; print("\t", fmt(addr, 'X'), " ", fmt(addr, 'a'), " ", fmt(addr, 'i'), "\n"); lst = tail lst; } } defn bpdel(addr) // delete a breakpoint { local n, pc, nbplist; if addr == 0 then { while bplist do { pc = head bplist; pc = fmt(pc, bpfmt); *pc = @pc; bplist = tail bplist; } return {}; } n = match(addr, bplist); if n < 0 then { print("no breakpoint at ", fmt(addr, 'a'), "\n"); return {}; } addr = fmt(addr, bpfmt); *addr = @addr; nbplist = {}; // delete from list while bplist do { pc = head bplist; if pc != addr then nbplist = append nbplist, pc; bplist = tail bplist; } bplist = nbplist; // delete from memory } defn cont() // continue execution { local addr; addr = fmt(*PC, bpfmt); if match(addr, bplist) >= 0 then { // Sitting on a breakpoint *addr = @addr; step(); // Step over *addr = bpinst; } startstop(pid); // Run } defn stopped(pid) // called from acid when a process changes state { pfixstop(pid); pstop(pid); // stub so this is easy to replace } defn procs() // print status of processes { local c, lst, cpid; cpid = pid; lst = proclist; while lst do { np = head lst; setproc(np); if np == cpid then c = '>'; else c = ' '; print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n"); lst = tail lst; } pid = cpid; if pid != 0 then setproc(pid); } _asmlines = 30; defn asm(addr) { local bound; bound = fnbound(addr); addr = fmt(addr, 'i'); loop 1,_asmlines do { print(fmt(addr, 'a'), " ", fmt(addr, 'X')); print("\t", @addr++, "\n"); if bound != {} && addr > bound[1] then { lasmaddr = addr; return {}; } } lasmaddr = addr; } defn casm() { asm(lasmaddr); } defn xasm(addr) { local bound; bound = fnbound(addr); addr = fmt(addr, 'i'); loop 1,_asmlines do { print(fmt(addr, 'a'), " ", fmt(addr, 'X')); print("\t", *addr++, "\n"); if bound != {} && addr > bound[1] then { lasmaddr = addr; return {}; } } lasmaddr = addr; } defn xcasm() { xasm(lasmaddr); } defn win() { local npid, estr; bplist = {}; notes = {}; estr = "/sys/lib/acid/window '0 0 600 400' "+textfile; if progargs != "" then estr = estr+" "+progargs; npid = rc(estr); npid = atoi(npid); if npid == 0 then error("win failed to create process"); setproc(npid); stopped(npid); } defn win2() { local npid, estr; bplist = {}; notes = {}; estr = "/sys/lib/acid/transcript '0 0 600 400' '100 100 700 500' "+textfile; if progargs != "" then estr = estr+" "+progargs; npid = rc(estr); npid = atoi(npid); if npid == 0 then error("win failed to create process"); setproc(npid); stopped(npid); } printstopped = 1; defn new() { local a; bplist = {}; newproc(progargs); a = var("p9main"); if a == {} then a = var("main"); if a == {} then return {}; bpset(a); while *PC != a do cont(); bpdel(a); } defn stmnt() // step one statement { local line; line = pcline(*PC); while 1 do { step(); if line != pcline(*PC) then { src(*PC); return {}; } } } defn func() // step until we leave the current function { local bound, end, start, pc; bound = fnbound(*PC); if bound == {} then { print("cannot locate text symbol\n"); return {}; } pc = *PC; start = bound[0]; end = bound[1]; while pc >= start && pc < end do { step(); pc = *PC; } } defn next() { local sp, bound, pc; sp = *SP; bound = fnbound(*PC); if bound == {} then { print("cannot locate text symbol\n"); return {}; } stmnt(); pc = *PC; if pc >= bound[0] && pc < bound[1] then return {}; while (pc < bound[0] || pc > bound[1]) && sp >= *SP do { step(); pc = *PC; } src(*PC); } defn maps() { local m, mm; m = map(); while m != {} do { mm = head m; m = tail m; print(mm[2]\X, " ", mm[3]\X, " ", mm[4]\X, " ", mm[0], " ", mm[1], "\n"); } } defn dump(addr, n, fmt) { loop 0, n do { print(fmt(addr, 'X'), ": "); addr = mem(addr, fmt); } } defn mem(addr, fmt) { local i, c, n; i = 0; while fmt[i] != 0 do { c = fmt[i]; n = 0; while '0' <= fmt[i] && fmt[i] <= '9' do { n = 10*n + fmt[i]-'0'; i = i+1; } if n <= 0 then n = 1; addr = fmt(addr, fmt[i]); while n > 0 do { print(*addr++, " "); n = n-1; } i = i+1; } print("\n"); return addr; } defn symbols(pattern) { local l, s, name; l = symbols; while l do { s = head l; if regexp(pattern, s[0]) then { name = s[4]; if name == {} then name = ""; print(s[0], "\t", s[1], "\t", s[2], "\t", s[3], "\t", name, "\n"); } l = tail l; } } defn havesymbol(name) { local l, s; l = symbols; while l do { s = head l; l = tail l; if s[0] == name then return 1; } return 0; } defn spsrch(len) { local addr, a, s, e; addr = *SP; s = origin & 0x7fffffff; e = etext & 0x7fffffff; loop 1, len do { a = *addr++; c = a & 0x7fffffff; if c > s && c < e then { print("src(", a, ")\n"); pfl(a); } } } defn acidtypes() { local syms; local l; l = textfile(); if l != {} then { syms = "acidtypes"; while l != {} do { syms = syms + " " + ((head l)[0]); l = tail l; } includepipe(syms); } } defn getregs() { local regs, l; regs = {}; l = registers; while l != {} do { regs = append regs, var(l[0]); l = tail l; } return regs; } defn setregs(regs) { local l; l = registers; while l != {} do { var(l[0]) = regs[0]; l = tail l; regs = tail regs; } return regs; } defn resetregs() { local l; l = registers; while l != {} do { var(l[0]) = register(l[0]); l = tail l; } } defn clearregs() { local l; l = registers; while l != {} do { var(l[0]) = refconst(~0); l = tail l; } } progargs=""; print(acidfile);