ref: fc1d4d1b24669d870a45310f8122e6b10ff953d0
dir: /sys/lib/acid/port/
// 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\A; sp = addr.sp\A; print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); pfl(pc); _stk(pc, sp, linkreg(addr), 1); } defn notelstk(addr) { local pc, sp; complex Ureg addr; pc = addr.pc\A; sp = addr.sp\A; print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " "); pfl(pc); _stk(pc, 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(file) { 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(pc, sp, link, dolocals) { local stk, ign, last, lastpc; stk = strace(pc, sp, link); if stkignore then ign = 1; else ign = 0; last = stk; lastpc = pc; while stk do { if ign then { if !_stkign(pcfile(pc)) then { ign = 0; stk = last; pc = lastpc; } } frame = head stk; if !ign then { print(stkprefix, fmt(frame[0], 'a'), "("); params(frame[2]); print(")+", itoa(pc-frame[0], "%ux"), " "); pfl(pc); if dolocals then locals(frame[3]); } last = stk; lastpc = pc; stk = tail stk; pc = frame[1]; } print(stkprefix, fmt(pc, 'a'), " "); pfl(pc); } 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, ":", line+1, ":", 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 { text = src[line]; if text == {} then return {}; if line == cline then print(">"); else print(" "); 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; } wpupdate(0); 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, 'A'), " ", fmt(addr, 'a'), " ", fmt(addr, 'i'), "\n"); lst = tail lst; } } defn bpdel(addr) // delete a breakpoint { local n, pc, nbplist; 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 wpflush() // copy wplist to /proc/$pid/watchpt { local s, lst, el; lst = wplist; s = ""; while lst do { el = head lst; s = s + (el[0] + " " + itoa(el[1]) + " " + itoa(el[2]) + "\n"); lst = tail lst; } lst = proclist; while lst do { if access("/proc/"+itoa(head lst)+"/watchpt") then printto("/proc/"+itoa(head lst)+"/watchpt", s); lst = tail lst; } } defn wpset(type, addr, len) // set a watchpoint { local lst; if status(pid) != "Stopped" then { print("Waiting...\n"); stop(pid); } if !regexp("^[rwx\\-]+$", type) then { print("invalid type\n"); return {}; } lst = proclist; while lst do { if rc("echo '"+type+" "+itoa(addr)+" "+itoa(len)+"' >> /proc/"+itoa(head lst)+"/watchpt") != "" then return {}; lst = tail lst; } wplist = append wplist, {type, addr, len, {}}; } defn wptab() // print a table of watchpoints { local lst, el; lst = wplist; while lst do { el = head lst; print("\t", el[0], " ", fmt(el[1], 'A'), " ", fmt(el[1], 'a'), " ", fmt(el[2], 'd'), "\n"); lst = tail lst; } } defn wpdel(addr) { local lst, el, found, nwplist; lst = wplist; found = 0; nwplist = {}; while lst do { el = head lst; if el[1] == addr then found = 1; else nwplist = append nwplist, el; lst = tail lst; } if found == 0 then { print("no watchpoint at ", fmt(addr, 'a'), "\n"); return {}; } wplist = nwplist; wpflush(); } defn bytes(b) { local s; s = ""; while b do { s = s + itoa(head b, "%#.2x "); b = tail b; } return s; } defn wpupdate(ch) // update remembered values { local el, nwplist, mem, lst, i; lst = wplist; nwplist = {}; while lst do { el = head lst; i = 0; mem = {}; while i < el[2] do { mem = append mem, *((el[1] + i)\b); i = i + 1; } if ch && el[3] != {} && el[3] != mem then { print("\t", fmt(el[1], 'a'), "\twas ", bytes(el[3]), "\n"); print("\t", fmt(el[1], 'a'), "\tis ", bytes(mem), "\n"); } nwplist = append nwplist, {el[0], el[1], el[2], mem}; lst = tail lst; } wplist = nwplist; } defn wpprocess() // trapped at watchpoint { local pts; local el; pts = getfields(getfields(notes[0], " ", 1)[2], ",", 1); while pts do { el = head pts; el = wplist[atoi(el)]; if el != {} then { print("\ttriggered ", el[0], " watchpoint at ", fmt(el[1], 'a'), " (", fmt(el[1], 'A'), ")\n"); } pts = tail pts; } wpupdate(1); } 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; } wpupdate(0); startstop(pid); // Run } defn stopped(pid) // called from acid when a process changes state { 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, 'A')); print("\t", @addr++, "\n"); if bound != {} && addr > bound[1] then { lasmaddr = addr; return {}; } } lasmaddr = addr; } defn casm() { asm(lasmaddr); } defn win() { local npid, estr; bplist = {}; wplist = {}; 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 = {}; wplist = {}; 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); } defn new() { bplist = {}; wplist = {}; newproc(progargs); // Dont miss the delay slot calls bpset(follow(main)[0]); cont(); bpdel(*PC); } 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; sp = *SP; bound = fnbound(*PC); 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 dump(addr, n, fmt) { // see definition of dump in acid manual: it does n+1 iterations loop 0, n do { print(fmt(addr, 'A'), ": "); 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; l = symbols; while l do { s = head l; if regexp(pattern, s[0]) then print(s[0], "\t", s[1], "\t", s[2], "\n"); l = tail l; } } 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 procattach() { wpflush(); } defn dying() { wplist = {}; wpflush(); } progargs=""; print("/sys/lib/acid/port");