From 0a61c07d591273b76da21fb8386b669989da3707 Mon Sep 17 00:00:00 2001 From: rsc Date: Mon, 19 Apr 2004 18:18:37 +0000 Subject: [PATCH] acid files --- acid/386 | 210 +++++++++++++++++ acid/68020 | 137 +++++++++++ acid/acme | 133 +++++++++++ acid/alef | 147 ++++++++++++ acid/alpha | 205 +++++++++++++++++ acid/arm | 104 +++++++++ acid/core | Bin 0 -> 122880 bytes acid/coverage | 128 +++++++++++ acid/elflink | 54 +++++ acid/kernel | 295 ++++++++++++++++++++++++ acid/leak | 138 +++++++++++ acid/mips | 217 ++++++++++++++++++ acid/network | 169 ++++++++++++++ acid/pool | 306 +++++++++++++++++++++++++ acid/port | 599 ++++++++++++++++++++++++++++++++++++++++++++++++ acid/power | 120 ++++++++++ acid/sparc | 218 ++++++++++++++++++ acid/syscall | 196 ++++++++++++++++ acid/thread | 365 +++++++++++++++++++++++++++++ acid/transcript | 33 +++ acid/trump | 171 ++++++++++++++ acid/truss | 283 +++++++++++++++++++++++ acid/window | 23 ++ 23 files changed, 4251 insertions(+) create mode 100644 acid/386 create mode 100644 acid/68020 create mode 100644 acid/acme create mode 100644 acid/alef create mode 100644 acid/alpha create mode 100644 acid/arm create mode 100644 acid/core create mode 100644 acid/coverage create mode 100644 acid/elflink create mode 100644 acid/kernel create mode 100644 acid/leak create mode 100644 acid/mips create mode 100644 acid/network create mode 100644 acid/pool create mode 100644 acid/port create mode 100644 acid/power create mode 100644 acid/sparc create mode 100644 acid/syscall create mode 100644 acid/thread create mode 100755 acid/transcript create mode 100644 acid/trump create mode 100644 acid/truss create mode 100755 acid/window diff --git a/acid/386 b/acid/386 new file mode 100644 index 00000000..252ece8e --- /dev/null +++ b/acid/386 @@ -0,0 +1,210 @@ +// 386 support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'b'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/386/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn linkreg(addr) +{ + return {}; +} + +defn stk() // trace +{ + _stk({"PC", *PC, "SP", *SP}, 0); +} + +defn lstk() // trace with locals +{ + _stk({"PC", *PC, "SP", *SP}, 1); +} + +defn gpr() // print general(hah hah!) purpose registers +{ + print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n"); + print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n"); +} + +defn spr() // print special processor registers +{ + local pc; + local cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n"); + print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n"); + print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n"); + + cause = *TRAP; + print("TRAP\t", cause, " ", reason(cause), "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn mmregs() +{ + print("MM0\t", *MM0, " MM1\t", *MM1, "\n"); + print("MM2\t", *MM2, " MM3\t", *MM3, "\n"); + print("MM4\t", *MM4, " MM5\t", *MM5, "\n"); + print("MM6\t", *MM6, " MM7\t", *MM7, "\n"); +} + +defn pstop(pid) +{ + local l; + local pc; + + pc = *PC; + + print(pid,": ", reason(*TRAP), "\t"); + print(fmt(pc, 'a'), "\t", *fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +aggr Ureg +{ + 'U' 0 di; + 'U' 4 si; + 'U' 8 bp; + 'U' 12 nsp; + 'U' 16 bx; + 'U' 20 dx; + 'U' 24 cx; + 'U' 28 ax; + 'U' 32 gs; + 'U' 36 fs; + 'U' 40 es; + 'U' 44 ds; + 'U' 48 trap; + 'U' 52 ecode; + 'U' 56 pc; + 'U' 60 cs; + 'U' 64 flags; + { + 'U' 68 usp; + 'U' 68 sp; + }; + 'U' 72 ss; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" di ", addr.di, "\n"); + print(" si ", addr.si, "\n"); + print(" bp ", addr.bp, "\n"); + print(" nsp ", addr.nsp, "\n"); + print(" bx ", addr.bx, "\n"); + print(" dx ", addr.dx, "\n"); + print(" cx ", addr.cx, "\n"); + print(" ax ", addr.ax, "\n"); + print(" gs ", addr.gs, "\n"); + print(" fs ", addr.fs, "\n"); + print(" es ", addr.es, "\n"); + print(" ds ", addr.ds, "\n"); + print(" trap ", addr.trap, "\n"); + print(" ecode ", addr.ecode, "\n"); + print(" pc ", addr.pc, "\n"); + print(" cs ", addr.cs, "\n"); + print(" flags ", addr.flags, "\n"); + print(" sp ", addr.sp, "\n"); + print(" ss ", addr.ss, "\n"); +}; +sizeofUreg = 76; + +aggr Linkdebug +{ + 'X' 0 version; + 'X' 4 map; +}; + +aggr Linkmap +{ + 'X' 0 addr; + 'X' 4 name; + 'X' 8 dynsect; + 'X' 12 next; + 'X' 16 prev; +}; + +defn +linkdebug() +{ + local a; + + if !havesymbol("_DYNAMIC") then + return 0; + + a = _DYNAMIC; + while *a != 0 do { + if *a == 21 then // 21 == DT_DEBUG + return *(a+4); + a = a+8; + } + return 0; +} + +defn +acidmap() +{ + if systype == "linux" then { + local r, m, n; + + r = linkdebug(); + if r then { + complex Linkdebug r; + m = r.map; + n = 0; + while m != 0 && n < 100 do { + complex Linkmap m; + if m.name && *(m.name\b) then + textfile({*(m.name\s), m.addr\X}); + m = m.next; + n = n+1; + } + } + } + + local syms; + local l; + + l = textfile(); + if l != {} then { + syms = "acidtypes"; + while l != {} do { + syms = syms + " " + ((head l)[0]); + l = tail l; + } + includepipe(syms); + } +} + +print(acidfile); diff --git a/acid/68020 b/acid/68020 new file mode 100644 index 00000000..f57da9f9 --- /dev/null +++ b/acid/68020 @@ -0,0 +1,137 @@ +// 68020 support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'x'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/68020/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn linkreg(addr) +{ + return 0; +} + +defn stk() // trace +{ + _stk(*PC, *A7, 0, 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *A7, 0, 1); +} + +defn gpr() // print general purpose registers +{ + print("R0\t", *R0, "R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n"); + print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "R7\t", *R7, "\n"); + print("A0\t", *A0, "A1\t", *A1, "A2\t", *A2, "A3\t", *A3, "\n"); + print("A4\t", *A4, "A5\t", *A5, "A6\t", *A6, "A7\t", *A7, "\n"); +} + +defn spr() // print special processor registers +{ + local pc; + local cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + print("SP\t", *A7, " MAGIC\t", *MAGIC, "\n"); + + cause = *VO; + print("SR\t", *SR, "VO ", cause, " ", reason(cause), "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l; + local pc; + + pc = *PC; + + print(pid,": ", reason(*VO), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +aggr Ureg +{ + 'U' 0 r0; + 'U' 4 r1; + 'U' 8 r2; + 'U' 12 r3; + 'U' 16 r4; + 'U' 20 r5; + 'U' 24 r6; + 'U' 28 r7; + 'U' 32 a0; + 'U' 36 a1; + 'U' 40 a2; + 'U' 44 a3; + 'U' 48 a4; + 'U' 52 a5; + 'U' 56 a6; + 'U' 60 sp; + 'U' 64 usp; + 'U' 68 magic; + 'u' 72 sr; + 'U' 74 pc; + 'u' 78 vo; + 'a' 80 microstate; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" r0 ", addr.r0, "\n"); + print(" r1 ", addr.r1, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" a0 ", addr.a0, "\n"); + print(" a1 ", addr.a1, "\n"); + print(" a2 ", addr.a2, "\n"); + print(" a3 ", addr.a3, "\n"); + print(" a4 ", addr.a4, "\n"); + print(" a5 ", addr.a5, "\n"); + print(" a6 ", addr.a6, "\n"); + print(" sp ", addr.sp, "\n"); + print(" usp ", addr.usp, "\n"); + print(" magic ", addr.magic, "\n"); + print(" sr ", addr.sr, "\n"); + print(" pc ", addr.pc, "\n"); + print(" vo ", addr.vo, "\n"); + print(" microstate ", addr.microstate, "\n"); +}; + +print(acidfile); diff --git a/acid/acme b/acid/acme new file mode 100644 index 00000000..1cce6eb8 --- /dev/null +++ b/acid/acme @@ -0,0 +1,133 @@ +// support for acme; acid must be run with /acme/acid/$cputype/Acid + + +defn w(*code) +{ + local dir; + + printto("/tmp/acme.acid", eval code); + rc("cat /tmp/acme.acid | wnew -d "+"Acid/-stk'("+itoa(pid)+")'"); +} + +defn procstk(pid, name) +{ + local dir; + + printto("/tmp/acme.acid", stk()); + rc("cat /tmp/acme.acid | wnew -d "+"Acid/-'"+name+"("+itoa(pid)+")'"); +} + +defn taskstk(tid, name) +{ + local dir; + + printto("/tmp/acme.acid", threadstk(tid)); + rc("cat /tmp/acme.acid | wnew -d "+"Acid/-"+name+"'("+itoa(pid)+")'"); +} + +defn _stk(pc, sp, link, dolocals) +{ + local stk; + + print("At pc:", pc, ":", fmt(pc, 'a'), " "); + pfl(pc); + + stk = strace(pc, sp, link); + + while stk do { + frame = head stk; + print(fmt(frame[0], 'a'), "("); + params(frame[2], frame[0]); + print(") "); + print("\n\tcalled from ", fmt(frame[1], 'a'), " "); + pfl(frame[1]); + stk = tail stk; + if dolocals then + locals(frame[3], frame[0]); + } +} + +//defn _stk(pc, sp, dolocals) +//{ +// w(__stk(pc, sp, dolocals)); +//} + + +defn params(param, name) +{ + while param do { + sym = head param; + print("*", fmt(name, 'a'), ":", sym[0], "=", sym[1]); + param = tail param; + if param then + print (","); + } +} + +defn locals(l, name) +{ + local sym; + + while l do { + sym = head l; + print("\t*", fmt(name, 'a'), ":", sym[0], "=", sym[1], "\n"); + l = tail l; + } +} + +defn bptab() // print a table of breakpoints +{ + local lst, addr; + + lst = bplist; + while lst do { + addr = head lst; + print("\tbpdel(", fmt(addr, 'a'), ")\n"); + lst = tail lst; + } +} + +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 + print(">"); + print("\t", "setproc(", np, ")\t", status(np), " at ", fmt(*PC, 'a'), "\n"); + lst = tail lst; + } + pid = cpid; + if pid != 0 then + setproc(pid); +} + +defn allstacks() // print stacks of processes and threads +{ + complex Proc P; + local T, Tq; + local c, lst, cpid; + + cpid = pid; + P = (Proc)pq.$head; + while P != 0 do{ + Tq = (Tqueue)P.threads; + T = (Thread)Tq.$head; + setproc(P.pid); + while T != 0 do{ + if(T.cmdname == 0) then taskstk(T, "unknown"); + else taskstk(T, *(T.cmdname\s)); + T = T.nextt; + } + P = P.next; + } + pid = cpid; + if pid != 0 then + setproc(pid); +} + +print(acidfile); diff --git a/acid/alef b/acid/alef new file mode 100644 index 00000000..323a0ffa --- /dev/null +++ b/acid/alef @@ -0,0 +1,147 @@ +// runtime library definitions +if objtype=="mips2" then objtype="mips"; + +include("/sys/src/alef/lib/"+objtype+"/acid"); + +defn +pchan(addr) +{ + local l, n; + + complex Chan addr; + + if addr.sva then + print("Sender waiting: buffer ", addr.sva, "\n"); + else + print("No sender\n"); + + if addr.rva then + print("Receiver waiting: buffer ", addr.rva, "\n"); + else + print("No receiver\n"); + + if addr.async then { + n = 0; + l = addr.qh; + while l do { + n = n+1; + l = l.next; + } + print("Async channel\n\t", n\D, " messsages queued\n\t"); + l = addr.free; + while l do { + n = n+1; + l = l.next; + } + print(n\D, " free buffers\n"); + } + + if addr.selt then { + l = "send"; + if addr.selt then + l = "receive"; + print("In select ", l, ": task ", addr.selt\X, "\n"); + labstk(addr.selt); + } +} + +defn +tdb() +{ + local ta, tq; + + // Private proc tdb pointer + ta = *{ 0x7fffe000, + 0x0ffdf000, + 0xbfff5000 }[match(objtype, {"mips", "sparc", "386"})]; + + complex Tdb ta; + + print("tdb ", ta.ntask, " tasks:"); + if *ta then + print("locked\n"); + else + print("unlocked\n"); + + if ta.ctask then { + print("current task ", ta.ctask, "\n"); + Task(ta.ctask); + } + else + print("proc is idle\n"); + + tq = (Task)ta.runhd; + if tq == 0 then + return {}; + + print("Tasks ready to run:\n"); + while tq != 0 do { + print("Task(", tq, ")\n"); + tq = tq.link; + } +} + +defn +lselect(addr) +{ + local c; + + complex Task addr; + complex Chan c; + + c = addr.slist; + if c == 0 then { + print("No select pending\n"); + return {}; + } + while c do { + print("pchan(", c\X, ")\n"); + c = c.sellink; + } +} + +defn +pqlock(addr) +{ + local t; + + complex QLock addr; + + if *addr then + print("QLock is under modification\n"); + if addr.used == 0 then + return {}; + + print("QLock is held\n"); + t = addr.queue; + complex Task t; + if t == 0 then { + print("No tasks waiting\n"); + return {}; + } + print("Tasks waiting:\n"); + while t do { + print("Task(", t, ")\n"); + tq = tq.qlink; + } +} + +srcpath = { + "./", + "/sys/src/alef/lib/port/", + "/sys/src/alef/lib/p9/", + "/sys/src/alef/lib/"+objtype+"/" +}; + +defn labstk(l) +{ + if objtype == "386" then + _stk(ALEF_switch, *l, linkreg(0), 0); + else + _stk(*(l+4), *l, linkreg(0), 0); +} + +print(acidfile); + +include("/sys/src/alef/lib/port/acid."+objtype); +include("/sys/src/alef/lib/p9/acid."+objtype); diff --git a/acid/alpha b/acid/alpha new file mode 100644 index 00000000..5912271d --- /dev/null +++ b/acid/alpha @@ -0,0 +1,205 @@ +// Alpha support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'X'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/alpha/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn stk() // trace +{ + _stk(*PC, *SP, linkreg(0), 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *SP, linkreg(0), 1); +} + +defn gpr() // print general purpose registers +{ + print("R0\t", *R0, "\n"); + print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n"); + print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n"); + print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n"); + print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n"); + print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n"); + print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n"); + print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n"); + print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n"); + print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n"); + print("R28\t", *R28, " R29\t", *R29, " R30\t", *SP\Y, "\n"); +} + +defn fpr() +{ + print("F0\t", *fmt(F0, 'G'), "\tF1\t", *fmt(F1, 'G'), "\n"); + print("F2\t", *fmt(F2, 'G'), "\tF3\t", *fmt(F3, 'G'), "\n"); + print("F4\t", *fmt(F4, 'G'), "\tF5\t", *fmt(F5, 'G'), "\n"); + print("F6\t", *fmt(F6, 'G'), "\tF7\t", *fmt(F7, 'G'), "\n"); + print("F8\t", *fmt(F8, 'G'), "\tF9\t", *fmt(F9, 'G'), "\n"); + print("F10\t", *fmt(F10, 'G'), "\tF11\t", *fmt(F11, 'G'), "\n"); + print("F12\t", *fmt(F12, 'G'), "\tF13\t", *fmt(F13, 'G'), "\n"); + print("F14\t", *fmt(F14, 'G'), "\tF15\t", *fmt(F15, 'G'), "\n"); + print("F16\t", *fmt(F16, 'G'), "\tF17\t", *fmt(F17, 'G'), "\n"); + print("F18\t", *fmt(F18, 'G'), "\tF19\t", *fmt(F19, 'G'), "\n"); + print("F20\t", *fmt(F20, 'G'), "\tF21\t", *fmt(F21, 'G'), "\n"); + print("F22\t", *fmt(F22, 'G'), "\tF23\t", *fmt(F23, 'G'), "\n"); + print("F24\t", *fmt(F24, 'G'), "\tF25\t", *fmt(F25, 'G'), "\n"); + print("F26\t", *fmt(F26, 'G'), "\tF27\t", *fmt(F27, 'G'), "\n"); + print("F28\t", *fmt(F28, 'G'), "\tF29\t", *fmt(F29, 'G'), "\n"); + print("F30\t", *fmt(F30, 'G'), "\tF31\t", *fmt(F31, 'G'), "\n"); +} + +defn spr() // print special processor registers +{ + local pc, link, cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + + link = *R26; + print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " "); + pfl(link); + + cause = *TYPE; + print("STATUS\t", *STATUS, "\tTYPE\t", cause, " ", reason(cause), "\n"); + print("A0\t", *A0, " A1\t", *A1, " A2\t", *A2, "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l, pc; + + pc = *PC; + + print(pid,": ", reason(*TYPE), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +sizeofUreg = 296; +aggr Ureg +{ + 'W' 0 type; + 'W' 8 a0; + 'W' 16 a1; + 'W' 24 a2; + 'W' 32 r0; + 'W' 40 r1; + 'W' 48 r2; + 'W' 56 r3; + 'W' 64 r4; + 'W' 72 r5; + 'W' 80 r6; + 'W' 88 r7; + 'W' 96 r8; + 'W' 104 r9; + 'W' 112 r10; + 'W' 120 r11; + 'W' 128 r12; + 'W' 136 r13; + 'W' 144 r14; + 'W' 152 r15; + 'W' 160 r19; + 'W' 168 r20; + 'W' 176 r21; + 'W' 184 r22; + 'W' 192 r23; + 'W' 200 r24; + 'W' 208 r25; + 'W' 216 r26; + 'W' 224 r27; + 'W' 232 r28; + { + 'W' 240 r30; + 'W' 240 usp; + 'W' 240 sp; + }; + 'W' 248 status; + 'W' 256 pc; + 'W' 264 r29; + 'W' 272 r16; + 'W' 280 r17; + 'W' 288 r18; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" type ", addr.type, "\n"); + print(" a0 ", addr.a0, "\n"); + print(" a1 ", addr.a1, "\n"); + print(" a2 ", addr.a2, "\n"); + print(" r0 ", addr.r0, "\n"); + print(" r1 ", addr.r1, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" r8 ", addr.r8, "\n"); + print(" r9 ", addr.r9, "\n"); + print(" r10 ", addr.r10, "\n"); + print(" r11 ", addr.r11, "\n"); + print(" r12 ", addr.r12, "\n"); + print(" r13 ", addr.r13, "\n"); + print(" r14 ", addr.r14, "\n"); + print(" r15 ", addr.r15, "\n"); + print(" r19 ", addr.r19, "\n"); + print(" r20 ", addr.r20, "\n"); + print(" r21 ", addr.r21, "\n"); + print(" r22 ", addr.r22, "\n"); + print(" r23 ", addr.r23, "\n"); + print(" r24 ", addr.r24, "\n"); + print(" r25 ", addr.r25, "\n"); + print(" r26 ", addr.r26, "\n"); + print(" r27 ", addr.r27, "\n"); + print(" r28 ", addr.r28, "\n"); + print("_12_ {\n"); + _12_(addr+240); + print("}\n"); + print(" status ", addr.status, "\n"); + print(" pc ", addr.pc, "\n"); + print(" r29 ", addr.r29, "\n"); + print(" r16 ", addr.r16, "\n"); + print(" r17 ", addr.r17, "\n"); + print(" r18 ", addr.r18, "\n"); +}; + +defn linkreg(addr) +{ + complex Ureg addr; + return addr.r26\X; +} + +print(acidfile); + diff --git a/acid/arm b/acid/arm new file mode 100644 index 00000000..01599978 --- /dev/null +++ b/acid/arm @@ -0,0 +1,104 @@ +// ARM7500 support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'b'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/arm/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn linkreg(addr) +{ + return 0; +} + +defn stk() // trace +{ + _stk(*PC, *SP, 0, 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *SP, 0, 1); +} + +defn gpr() // print general purpose registers +{ + print("R0\t", *R0, " R1\t", *R1, " R2\t", *R2, "\n"); + print("R3\t", *R3, " R4\t", *R4, " R5\t", *R5, "\n"); + print("R6\t", *R6, " R7\t", *R7, " R8\t", *R8, "\n"); + print("R9\t", *R9, " R10\t", *R10, " R11\t", *R11, "\n"); + print("R12\t", *R12, " R13\t", *R13, " R14\t", *R14, "\n"); + print("R15\t", *R15, "\n"); +} + +defn regs() // print all registers +{ + gpr(); +} + +defn pstop(pid) +{ + return 0; +} + +aggr Ureg +{ + 'U' 0 r0; + 'U' 4 r1; + 'U' 8 r2; + 'U' 12 r3; + 'U' 16 r4; + 'U' 20 r5; + 'U' 24 r6; + 'U' 28 r7; + 'U' 32 r8; + 'U' 36 r9; + 'U' 40 r10; + 'U' 44 r11; + 'U' 48 r12; + 'U' 52 r13; + 'U' 56 r14; + 'U' 60 type; + 'U' 64 psr; + 'U' 68 pc; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" r0 ", addr.r0, "\n"); + print(" r1 ", addr.r1, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" r8 ", addr.r8, "\n"); + print(" r9 ", addr.r9, "\n"); + print(" r10 ", addr.r10, "\n"); + print(" r11 ", addr.r11, "\n"); + print(" r12 ", addr.r12, "\n"); + print(" r13 ", addr.r13, "\n"); + print(" r14 ", addr.r14, "\n"); + print(" type ", addr.type, "\n"); + print(" psr ", addr.psr, "\n"); + print(" pc ", addr.pc, "\n"); +}; + +defn acornmap() +{ + map({"text", _startup, end, 0x20}); +} + +print(acidfile); diff --git a/acid/core b/acid/core new file mode 100644 index 0000000000000000000000000000000000000000..16b613a7a97489c61244d3c7807e9ebca0bd2d64 GIT binary patch literal 122880 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 0 then { + pc = fmt(pc, bpfmt); + *pc = @pc; + bblock = delete bblock, n; + } + else { + pstop(pid); + return {}; + } + } +} + +defn eblock(addr) +{ + addr = addr\i; + + while addr < etext do { + if (tail follow(addr)) != {} then + return pcline(addr); + addr++; + } + return 0; +} + +defn basic(stsrc, ensrc, file) +{ + local src, text; + + if stsrc >= ensrc then + return {}; + + print(file, ":", stsrc, ",", ensrc, "\n"); + src = match(file, srcfiles); + + if src >= 0 then + src = srctext[src]; + else + src = findsrc(file); + + if src == {} then + print("no source for ", file, "\n"); + else { + while stsrc <= ensrc do { + text = src[stsrc]; + if text != {} then + print("\t", stsrc, ":", text, "\n"); + stsrc = stsrc+1; + } + } +} + +defn analyse(fnaddr) +{ + local addr, l, tfn; + + new(); + + tfn = fnbound(fnaddr); + + l = bblock; + while l do { + addr = head l; + + if addr >= tfn[0] && addr < tfn[1] then + basic(pcline(addr), eblock(addr), pcfile(addr)); + + l = tail l; + } + kill(pid); +} + +defn report() +{ + local addr, l; + + new(); + + l = bblock; + while l do { + addr = head l; + + basic(pcline(addr), eblock(addr), pcfile(addr)); + + l = tail l; + } + kill(pid); +} + +defn stopped(pid) +{ + return {}; +} + +print(acidfile); diff --git a/acid/elflink b/acid/elflink new file mode 100644 index 00000000..8e9f2e76 --- /dev/null +++ b/acid/elflink @@ -0,0 +1,54 @@ +aggr Rdebug +{ + 'X' 0 version; + 'X' 4 map; +}; + +aggr Rmap +{ + 'X' 0 addr; + 'X' 4 name; + 'X' 8 dynsect; + 'X' 12 next; + 'X' 16 prev; +}; + +defn +rdebug() +{ + local a; + + a = _DYNAMIC; + while *a != 0 do { + if *a == 21 then // 21 == DT_DEBUG + return *(a+4); + a = a+8; + } + return 0; +} + +defn +rlink() +{ + local r, m, n; + + r = rdebug(); + if r == 0 then + return {}; + complex Rdebug r; + print("version ", r.version, "\n"); + + m = r.map; + n = 0; + while m != 0 && n < 100 do { + complex Rmap m; + print("map ", m\X, " base ", m.addr\X, " next ", m.next\X, " name "); + if m.name then + print(*(m.name\s)); + else + print("''"); + print("\n"); + m = m.next; + n = n+1; + } +} diff --git a/acid/kernel b/acid/kernel new file mode 100644 index 00000000..494ab9c3 --- /dev/null +++ b/acid/kernel @@ -0,0 +1,295 @@ +include("/sys/lib/acid/syscall"); + +// print various /proc files +defn fd() { + rc("cat /proc/"+itoa(pid)+"/fd"); +} + +defn segment() { + rc("cat /proc/"+itoa(pid)+"/segment"); +} + +defn ns() { + rc("cat /proc/"+itoa(pid)+"/ns"); +} + +defn qid(qid) { + complex Qid qid; + return itoa(qid.path\X)+"."+itoa(qid.vers\X); +} + +defn cname(c) { + complex Cname c; + if c != 0 then { + return *(c.s\s); + } else + return ""; +} + +// print Image cache contents +// requires include("/sys/src/9/xxx/segment.acid") +IHASHSIZE = 64; +defn imagecacheline(h) { + while h != 0 do { + complex Image h; + print (h\X, " ", qid(h.qid), " type ", h.type\D, " ref ", h.ref, " next ", h.next\X, " ", cname(h.c.name), "\n"); + h = h.hash; + } +} + +defn imagecache() { + local i; + + i=0; loop 1,IHASHSIZE do { + imagecacheline(imagealloc.free[i]); + i = i+1; + } +} + +// dump channels +defn chan(c) { + local d, q; + + c = (Chan)c; + d=(Dev)(*(devtab+4*c.type)); + q=c.qid; + print(c\X, " ref=", c.ref\D, " #", d.dc\r, c.dev\D, " (", q.path, " ", q.vers\D, " ", q.type\X, ")"); + print(" fid=", c.fid\D, " iounit=", c.iounit\D); + if c.ref != 0 then { + print(" ", cname(c.name), " mchan=", c.mchan\X); + if c.mchan != 0 then { + print(" ", cname(c.mchan.name)); + } + } + print("\n"); +} + +defn chans() { + local c; + + c = (Chan)chanalloc.list; + while c != 0 do { + chan(c); + c=(Chan)c.link; + } +} + +// manipulate processes +defn proctab(x) { + return procalloc.arena+sizeofProc*x; +} + +defn proc(p) { + complex Proc p; + local s, i; + + if p.state != 0 then { // 0 is Dead + s = p.psstate; + if s == 0 then { + s = "kproc"; + } else { + s = *(s\s); + } + print(p\X, " ", p.pid, ": ", *(p.text\s), " ", *(p.user\s), " pc ", p.pc\X, " ", s, " (", *(statename[p.state]\s), ") ut ", p.time[0]\D, " st ", p.time[1]\D, " qpc ", p.qpc\X, "\n"); + } +} + +defn procenv(p) { + complex Proc p; + local e, v; + + e = p.egrp; + complex Egrp e; + v = e.entries; + while v != 0 do { + complex Evalue v; + print(*(v.name\s), "="); + printstringn(v.value, v.len); + print("\n"); + v = v.link; + } +} + +KSTACK=4096; + +defn procstksize(p) { + complex Proc p; + local top, sp; + + if p.state != 0 then { // 0 is Dead + top = p.kstack+KSTACK; + sp = *p.sched; + print(top-sp\D, "\n"); + } +} + +defn procstk(p) { + complex Proc p; + local l; + + if p.state != 0 then { // 0 is Dead + l = p.sched; + if objtype=="386" then + _stk(gotolabel, *l, linkreg(0), 0); + else + _stk(*(l+4), *l, linkreg(0), 0); + } +} + +defn procs() { + local i; + + i=0; loop 1,conf.nproc do { + proc(proctab(i)); + i = i+1; + } +} + +defn stacks() { + local i, p; + + i=0; loop 1,conf.nproc do { + p = (Proc)proctab(i); + if p.state != 0 then { + print("=========================================================\n"); + proc(p); + procstk(p); + } + i = i+1; + } +} + +defn stacksizes() { + local i; + + i=0; loop 1,conf.nproc do { + procstksize(proctab(i)); + i = i+1; + } +} + +// segment-related +defn procsegs(p) { + complex Proc p; + local i; + + i=0; loop 1,NSEG do { + psegment(p.seg[i]); + i = i+1; + } +} + +segtypes = { "text", "data", "bss", "stack", "shared", "physical", "shdata", "map" }; +defn psegment(s) { + complex Segment s; + + if s != 0 then { + print(s\X, " ", segtypes[s.type&SG_TYPE], " ", s.base\X, "-", s.top\X, " image ", s.image\X, "\n"); + } +} + +// find physical address for an address in a given process +defn procaddr(p, a) { + complex Proc p; + local i, s, r; + + r = 0; + i=0; loop 1,NSEG do { + s = p.seg[i]; + if s != 0 then { + complex Segment s; + if s.base <= a && a < s.top then { + r = segaddr(s, a); + } + } + i = i+1; + } + return r; +} + +// find an address in a given segment +defn segaddr(s, a) { + complex Segment s; + local pte, pg; + + a = a - s.base; + if s.map == 0 || s.mapsize < a/PTEMAPMEM then { + return 0; + } + + pte = s.map[a/PTEMAPMEM]; + if pte == 0 then { + return 0; + } + + complex Pte pte; + pg = pte.pages[(a%PTEMAPMEM)/BY2PG]; + if pg == 0 then { + return 0; + } + + if pg & 1 then { // swapped out, return disk address + return pg&~1; + } + + complex Page pg; + return (0x80000000|(pg.pa+(a%BY2PG)))\X; +} + +// PC only +MACHADDR = 0x80004000; +PTEMAPMEM = (1024*1024); +BY2PG = 4096; +PTEPERTAB = (PTEMAPMEM/BY2PG); +defn up() { + local mach; + + mach = MACHADDR; + complex Mach mach; + return mach.externup; +} + +defn intrcount() { + local p, pp, t, i, j; + + p = intrtimes; + i=0; + loop 1,256 do { + pp = p[i]; + i=i+1; + if pp != 0 then { + j=0; + t=0; + loop 1,1000 do { + t = t+pp[j]; + j=j+1; + } + print(itoa(i, "%5d"), " ", itoa(t, "%11d"), "\n"); + } + } +} + +print(acidfile); + +defn needacid(s){ + print("\trc(\"cd /sys/src/9/", kdir, "; mk ", s, ".acid\")\n"); + print("\tinclude(\"/sys/src/9/", kdir, "/", s, ".acid\")\n"); +} + +if (map()[2]) != {} then { // map has more than two elements -> active proc + kdir = "unknown"; + + if objtype == "386" then { + map({"*data", 0x80000000, 0xffffffff, 0x80000000}); + kdir="pc"; + } + if (objtype == "mips" || objtype == "mips2") then { + kdir = "ch"; + } + if objtype == "alpha" then { + map({"*data", 0x80000000, 0xffffffff, 0x80000000}); + kdir = "alpha"; + } + needacid("proc"); +} + diff --git a/acid/leak b/acid/leak new file mode 100644 index 00000000..6231f950 --- /dev/null +++ b/acid/leak @@ -0,0 +1,138 @@ +// +// usage: acid -l pool -l leak +// +include("/sys/src/libc/port/pool.acid"); + +defn +dumppool(p) +{ + complex Pool p; + a = p.arenalist; + + while a != 0 && a < 0x60000000 do { + complex Arena a; + dumparena(a); + a = a.down; + } +} + +defn +dumparena(arena) +{ + local atail, b, nb; + + atail = A2TB(arena); + complex Bhdr arena; + b = a; + while b < atail && b.magic != ARENATAIL_MAGIC do { + dumpblock(b); + nb = B2NB(b); + if nb == b then { + print("B2NB(", b\X, ") = b\n"); + b = atail; // end loop + } + if nb > atail then { + b = (Bhdr)(b+4); + print("lost at block ", (b-4)\X, ", scanning forward\n"); + while b < atail && b.magic != KEMPT_MAGIC && b.magic != FREE_MAGIC do + b = (Bhdr)(b+4); + print("stopped at ", b\X, " ", *b\X, "\n"); + }else + b = nb; + } + if b != atail then + print("found wrong tail to arena ", arena\X, " wanted ", atail\X, "\n"); +} + +defn +isptr(a) +{ + if end <= a && a < xbloc then + return 1; + if 0x7efff000 <= a && a < 0x7ffff000 then + return 1; + return 0; +} + +defn +dumpblock(addr) +{ + complex Bhdr addr; + + if addr.magic == KEMPT_MAGIC || addr.magic == FREE_MAGIC then { + local a, x, s; + + a = addr; + complex Alloc a; + + x = addr+8; + if addr.magic == KEMPT_MAGIC then + s = "block"; + else + s = "free"; + print(s, " ", addr\X, " ", a.size\X, " "); + print(*(addr+8)\X, " ", *(addr+12)\X, "\n"); + } +} + +defn +dumprange(s, e, type) +{ + local x, y; + + print("range ", type, " ", s\X, " ", e\X, "\n"); + x = s; + while x < e do { + y = *x; + if isptr(y) then print("data ", x\X, " ", y\X, " ", type, "\n"); + x = x + 4; + } +} + +defn +dumpmem() +{ + local s; + + xbloc = *bloc; + // assume map()[1] is "data" + dumprange(map()[1][1], end, "bss"); // bss + dumprange(end, xbloc, "alloc"); // allocated + + if 0x7efff000 < *SP && *SP < 0x7ffff000 then + s = *SP; + else + s = 0x7fff7000; // 32 k + + dumprange(s, 0x7ffff000, "stack"); +} + +defn +dumpregs() +{ + dumprange(0, sizeofUreg, "reg"); +} + + +defn +leakdump(l) +{ + print("==LEAK BEGIN==\n"); + dumppool(sbrkmem); + dumpmem(); + dumpregs(); + while l != {} do { + setproc(head l); + dumpregs(); + l = tail l; + } + print("==LEAK END==\n"); +} + +defn +blockdump() +{ + print("==BLOCK BEGIN==\n"); + dumppool(sbrkmem); + print("==BLOCK END==\n"); +} diff --git a/acid/mips b/acid/mips new file mode 100644 index 00000000..6ce15e75 --- /dev/null +++ b/acid/mips @@ -0,0 +1,217 @@ +// Mips support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'X'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/mips/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn stk() // trace +{ + _stk(*PC, *SP, linkreg(0), 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *SP, linkreg(0), 1); +} + +defn gpr() // print general purpose registers +{ + print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n"); + print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n"); + print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n"); + print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n"); + print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n"); + print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n"); + print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n"); + print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n"); + print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n"); + print("R28\t", *R28, " R29\t", *SP, " R30\t", *R30, "\n"); + print("R31\t", *R31, "\n"); +} + +defn Fpr() +{ + print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n"); + print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n"); + print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n"); + print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n"); + print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n"); + print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n"); + print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n"); + print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n"); +} + +defn fpr() +{ + print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n"); + print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n"); + print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n"); + print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n"); + print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n"); + print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n"); + print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n"); + print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n"); + print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n"); + print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n"); + print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n"); + print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n"); + print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n"); + print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n"); + print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n"); + print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n"); +} + +defn spr() // print special processor registers +{ + local pc, link, cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + + link = *R31; + print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " "); + pfl(link); + + cause = *CAUSE; + print("STATUS\t", *STATUS, "\tCAUSE\t", cause, " ", reason(cause), "\n"); + print("TLBVIR\t", *TLBVIRT, "\tBADVADR\t", *BADVADDR, "\n"); + + print("HI\t", *HI, "\tLO\t", *LO, "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l, pc; + + pc = *PC; + + print(pid,": ", reason(*CAUSE), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +sizeofUreg = 152; +aggr Ureg +{ + 'X' 0 status; + 'X' 4 pc; + { + 'X' 8 sp; + 'X' 8 usp; + }; + 'X' 12 cause; + 'X' 16 badvaddr; + 'X' 20 tlbvirt; + 'X' 24 hi; + 'X' 28 lo; + 'X' 32 r31; + 'X' 36 r30; + 'X' 40 r28; + 'X' 44 r27; + 'X' 48 r26; + 'X' 52 r25; + 'X' 56 r24; + 'X' 60 r23; + 'X' 64 r22; + 'X' 68 r21; + 'X' 72 r20; + 'X' 76 r19; + 'X' 80 r18; + 'X' 84 r17; + 'X' 88 r16; + 'X' 92 r15; + 'X' 96 r14; + 'X' 100 r13; + 'X' 104 r12; + 'X' 108 r11; + 'X' 112 r10; + 'X' 116 r9; + 'X' 120 r8; + 'X' 124 r7; + 'X' 128 r6; + 'X' 132 r5; + 'X' 136 r4; + 'X' 140 r3; + 'X' 144 r2; + 'X' 148 r1; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" status ", addr.status, "\n"); + print(" pc ", addr.pc, "\n"); + print(" sp ", addr.sp, "\n"); + print(" cause ", addr.cause, "\n"); + print(" badvaddr ", addr.badvaddr, "\n"); + print(" tlbvirt ", addr.tlbvirt, "\n"); + print(" hi ", addr.hi, "\n"); + print(" lo ", addr.lo, "\n"); + print(" r31 ", addr.r31, "\n"); + print(" r30 ", addr.r30, "\n"); + print(" r28 ", addr.r28, "\n"); + print(" r27 ", addr.r27, "\n"); + print(" r26 ", addr.r26, "\n"); + print(" r25 ", addr.r25, "\n"); + print(" r24 ", addr.r24, "\n"); + print(" r23 ", addr.r23, "\n"); + print(" r22 ", addr.r22, "\n"); + print(" r21 ", addr.r21, "\n"); + print(" r20 ", addr.r20, "\n"); + print(" r19 ", addr.r19, "\n"); + print(" r18 ", addr.r18, "\n"); + print(" r17 ", addr.r17, "\n"); + print(" r16 ", addr.r16, "\n"); + print(" r15 ", addr.r15, "\n"); + print(" r14 ", addr.r14, "\n"); + print(" r13 ", addr.r13, "\n"); + print(" r12 ", addr.r12, "\n"); + print(" r11 ", addr.r11, "\n"); + print(" r10 ", addr.r10, "\n"); + print(" r9 ", addr.r9, "\n"); + print(" r8 ", addr.r8, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r1 ", addr.r1, "\n"); +}; + +defn linkreg(addr) +{ + complex Ureg addr; + return addr.r31\X; +} + +print(acidfile); diff --git a/acid/network b/acid/network new file mode 100644 index 00000000..ea6f9922 --- /dev/null +++ b/acid/network @@ -0,0 +1,169 @@ +_ni=0; // network indent level + +defn +_ni() { + loop 1,_ni do { + print("\t"); + } +} + +defn +ipdev(n) { + _ipfs(*(ipfs+4*n)); +} + +// the funny _foo/foo pairs exist so that if we get +// interrupted in the middle of one of these, _ni will +// get reset to 0 next time an external call happens. + +defn +_ipfs(fs) { + complex Fs fs; + local i; + + print("ipfs(", fs\X, ") #I", fs.dev\D, "\n"); + i=0; + _ni = _ni+1; + while i < fs.np do { + _proto(*(fs.p+i*4)); + i = i + 1; + } + _ni = _ni-1; +} + +defn +ipfs(fs) { + _ni = 0; + _ipfs(fs); +} + +defn +_proto(p) { + local c; + complex Proto p; + _ni(); + print("proto(", p\X, ") ", *(p.name\s), "\n"); + _ni = _ni+1; + local i; + i = 0; + while i < p.nc do { + c = *(p.conv+i*4); + complex Conv c; + if c != 0 && c.inuse then + _conv(*(p.conv+i*4)); + i = i + 1; + } + _ni = _ni - 1; +} + +defn +proto(p) { + _ni = 0; + _proto(p); +} + +defn +_conv(c) { + complex Conv c; + _ni(); + local p; + p = c.p; + complex Proto p; + print("conv(", c\X, ") ", *(p.name\s), "/", c.x\D, " ", + iptostr(*(c.laddr+12)), "!", c.lport\D, " ", iptostr(*(c.raddr+12)), + "!", c.rport\D, " rq ", qtostr(c.rq), " wq ", qtostr(c.wq), + " eq ", qtostr(c.eq), "\n"); +} + +defn +conv(c) { + _ni = 0; + _conv(c); +} + +defn +iptostr(a) +{ + // BUG: little endian + return itoa(a&0xFF)+"."+itoa((a>>8)&0xFF)+"."+itoa((a>>16)&0xFF)+"."+itoa((a>>24)&0xFF); +} + +defn +qtostr(q) +{ + complex Queue q; + + return "queue("+itoa(q, "%lux")+") ["+itoa(q.len, "%d")+","+itoa(q.dlen, "%d")+","+itoa(qblocks(q), "%d")+"]"; +} + +defn +qblocks(q) +{ + complex Queue q; + local b, n; + + b = q.bfirst; + n = 0; + while b != 0 do { + n = n + 1; + complex Block b; + b = b.next; + } + return n; +} + +defn +_queue(q) +{ + complex Queue q; + local b; + + print("queue(", q\X, ") len ", q.len\D, " dlen ", q.dlen\D, " limit ", q.limit\D, " nblocks ", qblocks(q)\D); + if q.state & Qstarve then + print(" starve"); + if q.state & Qmsg then + print(" msg"); + if q.state & Qclosed then + print(" closed"); + if q.state & Qflow then + print(" flow"); + if q.state & Qcoalesce then + print(" coalesce"); + print("\n"); + + b = q.bfirst; + _ni = _ni+1; + while b != 0 do { + _block(b); + complex Block b; + b = b.next; + } + _ni = _ni - 1; +} + +defn +queue(q) +{ + _ni = 0; + _queue(q); +} + +defn +_block(b) +{ + complex Block b; + + _ni(); + print("block(", b\X, ") base ", b.base\X, " rp ", b.rp\X, "/", b.rp-b.base\D, " wp ", b.wp\X, "/", b.wp-b.base\D, " lim ", b.lim\X, "/", b.lim-b.base\D, "\n"); +} + +defn +block(b) +{ + _ni = 0; + block(b); +} + +print(acidfile); +needacid("tcp"); +needacid("qio"); diff --git a/acid/pool b/acid/pool new file mode 100644 index 00000000..d49c4ea1 --- /dev/null +++ b/acid/pool @@ -0,0 +1,306 @@ +include("/sys/src/libc/port/pool.acid"); + +aggr Byte { + 'b' 0 byte; +}; + +defn +byteat(addr) +{ + local x; + complex Byte addr; + x = addr.byte; + return x\d; +} + +defn +B2T(addr) { + complex Bhdr addr; + addr = addr+addr.size-sizeofBtail; + complex Btail addr; + return addr; +} + +defn +B2D(addr) { + local x; + x = addr+sizeofBhdr; + return x\X; +} + +defn +D2B(addr) { + local x; + x = addr-sizeofBhdr; + complex Bhdr x; + return x; +} + +defn +B2NB(addr) { + complex Bhdr addr; + addr = addr+addr.size; + complex Bhdr addr; + return addr; +} + +defn +A2TB(addr) { + local b; + complex Arena addr; + b = addr+addr.asize-sizeofBhdr; + complex Bhdr b; + return b; +} + +defn +A2B(addr) { + return B2NB(addr); +} + +defn +B2PT(addr) { + complex Bhdr addr; + addr = addr-sizeofBtail; + complex Btail addr; + return addr; +} + +defn +SHORT(addr) { + local hi, lo; + + hi = byteat(addr); + lo = byteat(addr+1); + return lo+hi*256; +} + +defn +Btail(addr) { + complex Btail addr; + print(" magic0 ", addr.magic0, "\n"); + print(" datadiff ", SHORT(addr.datasize), "\n"); + print(" magic1 ", addr.magic1, "\n"); + print(" size ", addr.size\X, "\n"); + print(" hdr ", addr+sizeofBtail-addr.size\X, "\n"); +}; + +defn +Tail(addr) +{ + print(" ", B2T(addr)\X, "\n"); + Btail(B2T(addr)); +} + +defn +Magic(m) +{ + if m == FREE_MAGIC then + return "free"; + if m == ARENA_MAGIC then + return "arena"; + if m == UNKEMPT_MAGIC then + return "unkempt"; + if m == KEMPT_MAGIC then + return "kempt"; + if m == ARENATAIL_MAGIC then + return "arenatail"; + if m == DEAD_MAGIC then + return "dead"; + return "unknown magic"; +} + +defn +Block(addr) +{ + complex Bhdr addr; + print(" ", Magic(addr.magic), "\n"); + print(" data ", B2D(addr), "\n"); + print(" datasize ", getdsize(addr), "\n"); + Bhdr(addr); + Tail(addr); +} + +defn +getdsize(addr) +{ + complex Bhdr addr; + local x; + + x = addr.size\d; + x = x-SHORT(B2T(addr).datasize); + return x\d; +} + +defn +datamagic(x) +{ + x = x%4; + if x == 0 then return 0xFE; + if x == 1 then return 0xF1; + if x == 2 then return 0xF0; + if x == 3 then return 0xFA; +} + +defn +checkblock(addr) +{ + local badmagic, datamagic, a, b, t, q, n, dsize, taddr, checked; + complex Bhdr addr; + taddr = B2T(addr); + complex Btail taddr; + + if addr.magic == FREE_MAGIC || addr.magic == UNKEMPT_MAGIC then { + if taddr.magic0 != TAIL_MAGIC0 || taddr.magic1 != TAIL_MAGIC1 then + print(addr\X, " corrupt tail magic\n"); + if taddr.size != addr.size then + print(addr\X, " corrupt tail header pointer\n"); + } + + if addr.magic == ARENA_MAGIC then { + taddr = A2TB(addr); + if taddr.magic != ARENATAIL_MAGIC then + print(addr\X, " arena with bad tail block\n"); + else + addr = taddr; + } + + if addr.magic == ARENATAIL_MAGIC then { + if addr.size != 0 then + print(addr\X, " bad size in arena tail\n"); + } + + if addr.magic == KEMPT_MAGIC then { + a = addr; + complex Alloc a; + if a.size > 1024*1024*1024 then + print(addr\X, " block ridiculously large\n"); + t = B2T(addr); + if t.magic0 != TAIL_MAGIC0 || t.magic1 != TAIL_MAGIC1 then + print(addr\X, " bad tail magic\n"); + if t.size != addr.size then + print(addr\X, " bad tail pointer\n"); + dsize = getdsize(a); + if dsize > a.size then + print(addr\X, " too much data in block\n"); + q = B2D(a)\X+dsize; + n = 4; + if q+4 > t then + n = t-q; + badmagic = 0; + loop 0,n-1 do { + if byteat(q) != datamagic(q) then { + badmagic=1; + } + q = q+1; + } + if badmagic then + print(addr\X, " size ", dsize, " user has overwritten boundary\n"); + } +} + +defn +checkarena(arena) +{ + local atail, b; + + atail = A2TB(arena); + complex Bhdr arena; + b = arena; + while b.magic != ARENATAIL_MAGIC && b < atail do { + checkblock(b); + if B2NB(b) == b then { + print("B2NB(", b\X, ") = b\n"); + b = atail; // end loop + } + b = B2NB(b); + } + + checkblock(b); + if b != atail then + print("found wrong tail to arena ", arena\X, "\n"); +} + +defn +checkpool(p) +{ + complex Pool p; + local a; + a = p.arenalist; + + while a != 0 do { + complex Arena a; + checkarena(a); + a = a.down; + } +} + +defn +gendumptree(f, in, s) +{ + complex Free f; + + loop 1,in do {print(" ");} + print(s, " size ", f.size\D, " left ", f.left\X, " right ", f.right\X, "\n"); + if f.left != 0 && f.left < 0x7FFFFFFF then + gendumptree(f.left, in+1, "l"); + if f.right != 0 && f.right < 0x7FFFFFFF then + gendumptree(f.right, in+1, "r"); +} + +defn +dumptree(f) +{ + gendumptree(f, 0, "*"); +} + +defn +poolwhopointsat(p, addr) +{ + complex Pool p; + local a; + + a = p.arenalist; + while a != 0 do { + complex Arena a; + arenawhopointsat(a, addr); + a = a.down; + } +} + +defn +arenawhopointsat(arena, addr) +{ + local atail, b; + + atail = A2TB(arena); + complex Bhdr arena; + b = arena; + while b < atail do { + if *b == addr then + print(b\X, "\n"); + b = b+4; + } +} + +defn +whopointsat(addr) +{ + poolwhopointsat(*mainmem, addr); +} + +defn +blockhdr(addr) +{ + addr = addr & ~3; + + while *addr != FREE_MAGIC + && *addr != ARENA_MAGIC + && *addr != UNKEMPT_MAGIC + && *addr != KEMPT_MAGIC + && *addr != ARENATAIL_MAGIC + do + addr = addr-4; + return addr; +} + diff --git a/acid/port b/acid/port new file mode 100644 index 00000000..d0d9107d --- /dev/null +++ b/acid/port @@ -0,0 +1,599 @@ +// 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 labstk(l) // trace from a label +{ + _stk({"PC", *(l+4), "SP", *l, linkreg(0)}, 0); +} + +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(regs, dolocals) +{ + local stk, pc, fn, callerpc, paramlist, locallist; + + stk = strace(regs); + if stkignore then { + while stk && tail stk && _stkign((head tail stk)[1]) do + stk = tail stk; + } + + callerpc = 0; + while stk 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 callerpc 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; + + 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 +{ + 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 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); +} + +defn new() +{ + bplist = {}; + 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 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; + + l = symbols; + while l do { + s = head l; + if regexp(pattern, s[0]) then + print(s[0], "\t", s[1], "\t", s[2], "\t", s[3], "\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); + } + } +} + +progargs=""; +print(acidfile); diff --git a/acid/power b/acid/power new file mode 100644 index 00000000..caa5aa48 --- /dev/null +++ b/acid/power @@ -0,0 +1,120 @@ +// Power PC support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'X'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/power/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn stk() // trace +{ + _stk(*PC, *SP, linkreg(0), 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *SP, linkreg(0), 1); +} + +defn gpr() // print general purpose registers +{ + print("SP\t", *SP, " R2\t", *R2, " R3\t", *R3, "\n"); + print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n"); + print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n"); + print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n"); + print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n"); + print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n"); + print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n"); + print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n"); + print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n"); + print("R28\t", *R28, " R29\t", *R29, " R30\t", *R30, "\n"); + print("R31\t", *R31, "\n"); +} + +defn Fpr() +{ + fpr(); +} + +defn fpr() +{ + print("F0\t", *fmt(F0, 'G'), "\tF1\t", *fmt(F1, 'G'), "\n"); + print("F2\t", *fmt(F2, 'G'), "\tF3\t", *fmt(F3, 'G'), "\n"); + print("F4\t", *fmt(F4, 'G'), "\tF5\t", *fmt(F5, 'G'), "\n"); + print("F6\t", *fmt(F6, 'G'), "\tF7\t", *fmt(F7, 'G'), "\n"); + print("F8\t", *fmt(F8, 'G'), "\tF9\t", *fmt(F9, 'G'), "\n"); + print("F10\t", *fmt(F10, 'G'), "\tF11\t", *fmt(F11, 'G'), "\n"); + print("F12\t", *fmt(F12, 'G'), "\tF13\t", *fmt(F13, 'G'), "\n"); + print("F14\t", *fmt(F14, 'G'), "\tF15\t", *fmt(F15, 'G'), "\n"); + print("F16\t", *fmt(F16, 'G'), "\tF17\t", *fmt(F17, 'G'), "\n"); + print("F18\t", *fmt(F18, 'G'), "\tF19\t", *fmt(F19, 'G'), "\n"); + print("F20\t", *fmt(F20, 'G'), "\tF21\t", *fmt(F21, 'G'), "\n"); + print("F22\t", *fmt(F22, 'G'), "\tF23\t", *fmt(F23, 'G'), "\n"); + print("F24\t", *fmt(F24, 'G'), "\tF25\t", *fmt(F25, 'G'), "\n"); + print("F26\t", *fmt(F26, 'G'), "\tF27\t", *fmt(F27, 'G'), "\n"); + print("F28\t", *fmt(F28, 'G'), "\tF29\t", *fmt(F29, 'G'), "\n"); + print("F30\t", *fmt(F30, 'G'), "\tF31\t", *fmt(F31, 'G'), "\n"); +} + +defn spr() // print special processor registers +{ + local pc, link, cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + + link = *R31; + print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " "); + pfl(link); + + cause = *CAUSE; + print("SRR1\t", *SRR1, "\tCAUSE\t", cause, " ", reason(cause), "\n"); + print("LR\t", *LR, "\tCR\t", *CR, "\n"); + + print("XER\t", *XER, "\tCTR\t", *CTR, "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l, pc; + + pc = *PC; + + print(pid,": ", reason(*CAUSE), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +defn linkreg(addr) +{ + return *LR; +} + +print(acidfile); diff --git a/acid/sparc b/acid/sparc new file mode 100644 index 00000000..9f6d496f --- /dev/null +++ b/acid/sparc @@ -0,0 +1,218 @@ +// Sparc support + +defn acidinit() // Called after all the init modules are loaded +{ + bplist = {}; + bpfmt = 'X'; + + srcpath = { + "./", + "/sys/src/libc/port/", + "/sys/src/libc/9sys/", + "/sys/src/libc/sparc/" + }; + + srcfiles = {}; // list of loaded files + srctext = {}; // the text of the files +} + +defn stk() // trace +{ + _stk(*PC, *R1, linkreg(0), 0); +} + +defn lstk() // trace with locals +{ + _stk(*PC, *R1, linkreg(0), 1); +} + +defn gpr() // print general purpose registers +{ + print("R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n"); + print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "\n"); + print("R7\t", *R7, "R8\t", *R8, "R9\t", *R9, "\n"); + print("R10\t", *R10, "R11\t", *R11, "R12\t", *R12, "\n"); + print("R13\t", *R13, "R14\t", *R14, "R15\t", *R15, "\n"); + print("R16\t", *R16, "R17\t", *R17, "R18\t", *R18, "\n"); + print("R19\t", *R19, "R20\t", *R20, "R21\t", *R21, "\n"); + print("R22\t", *R22, "R23\t", *R23, "R24\t", *R24, "\n"); + print("R25\t", *R25, "R26\t", *R26, "R27\t", *R27, "\n"); + print("R28\t", *R28, "R29\t", *R29, "R30\t", *R30, "\n"); + print("R31\t", *R31, "\n"); +} + +defn spr() // print special processor registers +{ + local pc; + local link; + local cause; + + pc = *PC; + print("PC\t", pc, " ", fmt(pc, 'a'), " "); + pfl(pc); + print("PSR\t", *PSR, "\n"); + + link = *R15; + print("SP\t", *R1, "\tLINK\t\t", link, " ", fmt(link, 'a')); + pfl(link); + + cause = *TBR; + print("Y\t", *Y, "\tCAUSE\t", *Y, cause, " ", reason(cause), "\n"); +} + +defn Fpr() +{ + print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n"); + print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n"); + print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n"); + print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n"); + print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n"); + print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n"); + print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n"); + print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n"); +} + +defn fpr() +{ + print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n"); + print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n"); + print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n"); + print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n"); + print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n"); + print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n"); + print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n"); + print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n"); + print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n"); + print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n"); + print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n"); + print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n"); + print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n"); + print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n"); + print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n"); + print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n"); +} + +defn regs() // print all registers +{ + spr(); + gpr(); +} + +defn pstop(pid) +{ + local l; + local pc; + + pc = *PC; + + print(pid,": ", reason(*TBR), "\t"); + print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n"); + + if notes then { + if notes[0] != "sys: breakpoint" then { + print("Notes pending:\n"); + l = notes; + while l do { + print("\t", head l, "\n"); + l = tail l; + } + } + } +} + +aggr Ureg +{ + 'U' 0 r0; + { + 'U' 4 sp; + 'U' 4 usp; + 'U' 4 r1; + }; + 'U' 8 r2; + 'U' 12 r3; + 'U' 16 r4; + 'U' 20 r5; + 'U' 24 r6; + 'U' 28 r7; + 'U' 32 r8; + 'U' 36 r9; + 'U' 40 r10; + 'U' 44 r11; + 'U' 48 r12; + 'U' 52 r13; + 'U' 56 r14; + 'U' 60 r15; + 'U' 64 r16; + 'U' 68 r17; + 'U' 72 r18; + 'U' 76 r19; + 'U' 80 r20; + 'U' 84 r21; + 'U' 88 r22; + 'U' 92 r23; + 'U' 96 r24; + 'U' 100 r25; + 'U' 104 r26; + 'U' 108 r27; + 'U' 112 r28; + 'U' 116 r29; + 'U' 120 r30; + 'U' 124 r31; + 'U' 128 y; + 'U' 132 tbr; + 'U' 136 psr; + 'U' 140 npc; + 'U' 144 pc; + 'U' 148 pad; +}; + +defn +Ureg(addr) { + complex Ureg addr; + print(" r0 ", addr.r0, "\n"); + print(" sp ", addr.sp, "\n"); + print(" r2 ", addr.r2, "\n"); + print(" r3 ", addr.r3, "\n"); + print(" r4 ", addr.r4, "\n"); + print(" r5 ", addr.r5, "\n"); + print(" r6 ", addr.r6, "\n"); + print(" r7 ", addr.r7, "\n"); + print(" r8 ", addr.r8, "\n"); + print(" r9 ", addr.r9, "\n"); + print(" r10 ", addr.r10, "\n"); + print(" r11 ", addr.r11, "\n"); + print(" r12 ", addr.r12, "\n"); + print(" r13 ", addr.r13, "\n"); + print(" r14 ", addr.r14, "\n"); + print(" r15 ", addr.r15, "\n"); + print(" r16 ", addr.r16, "\n"); + print(" r17 ", addr.r17, "\n"); + print(" r18 ", addr.r18, "\n"); + print(" r19 ", addr.r19, "\n"); + print(" r20 ", addr.r20, "\n"); + print(" r21 ", addr.r21, "\n"); + print(" r22 ", addr.r22, "\n"); + print(" r23 ", addr.r23, "\n"); + print(" r24 ", addr.r24, "\n"); + print(" r25 ", addr.r25, "\n"); + print(" r26 ", addr.r26, "\n"); + print(" r27 ", addr.r27, "\n"); + print(" r28 ", addr.r28, "\n"); + print(" r29 ", addr.r29, "\n"); + print(" r30 ", addr.r30, "\n"); + print(" r31 ", addr.r31, "\n"); + print(" y ", addr.y, "\n"); + print(" tbr ", addr.tbr, "\n"); + print(" psr ", addr.psr, "\n"); + print(" npc ", addr.npc, "\n"); + print(" pc ", addr.pc, "\n"); + print(" pad ", addr.pad, "\n"); +}; + +defn linkreg(addr) +{ + complex Ureg addr; + return addr.r15\X; +} + +print(acidfile); diff --git a/acid/syscall b/acid/syscall new file mode 100644 index 00000000..754b4449 --- /dev/null +++ b/acid/syscall @@ -0,0 +1,196 @@ +// print system calls +defn printstring(s) +{ + print("\"", s, "\""); +} + +defn printtextordata(addr, n) +{ + local a, i; + + a = addr\c; + i = 0; + loop 1, n do { + if (a[i]>=127) then { + print(fmt(addr, 'X'), ", ", n\D); + return {}; + } + i = i+1; + } + + print("\""); + printstringn(addr, n); + print("\""); +} + +defn printstringn(s, n) +{ + local m; + + m = n; + if (m > 100) then m = 100; + loop 1,m do { + print(*(s\c)); s=s+1; + } + if(m != n) then print("..."); +} + +defn printsyscall(name, fmt, arg) { + local f, i, a, argp, sl; + + print(name, "("); + i = 0; + a = eval arg; + while fmt[i] != 0 do { + if fmt[i] == 's' then { + if *a == 0 then + print("nil"); + else + printstring(*(*a\s)); + } else if fmt[i] == 'S' then { + argp = *a; + argl = {}; + while *argp != 0 do { + argl = append argl, *(*argp\s); + argp++; + } + print(argl); + } else if (fmt[i] == 'Z') && (~*a == 0) then { + print("-1"); + a++; // advance extra word for quadword + } else if (fmt[i] == 'Y') || (fmt[i] == 'V') then { + print(fmt(*a, fmt[i])); + a++; // advance extra word for quadword + } else if (fmt[i] == 'T') then { + if *a == 0 then + print("nil"); + else + printtextordata(*a, a[1]); + } else + print(fmt(*a, fmt[i])); + if fmt[i+1] != 0 then + print(", "); + i = i+1; + a++; + } + print(")\n"); +} + +defn code(*e) { return e; } + +syscalls = { + { 0, {"sysr1", "s", code(0)}}, + { 1, {"_errstr", "s", code(*sys_errstr:arg)}}, + { 2, {"bind", "ssX", code(*sysbind:arg)}}, + { 3, {"chdir", "s", code(*sysbind:arg)}}, + { 4, {"close", "D", code(*sysclose:arg)}}, + { 5, {"dup", "DD", code(*sysdup:arg)}}, + { 6, {"alarm", "D", code(*sysalarm:arg)}}, + { 7, {"exec", "sS", code(*sysexec:arg)}}, + { 8, {"exits", "s", code(*sysexits:arg)}}, + { 9, {"_fsession", "DX", code(*sys_fsession:arg)}}, + {10, {"fauth", "DX", code(*sysfauth:arg)}}, + {11, {"_fstat", "DX", code(*sys_fstat:arg)}}, + {12, {"segbrk", "XX", code(*syssegbrk:arg)}}, + {13, {"_mount", "DsXs", code(*sys_mount:arg)}}, + {14, {"open", "sD", code(*sysopen:arg)}}, + {15, {"_read", "DXD", code(*sys_read:arg)}}, + {16, {"oseek", "DDD", code(*sysoseek:arg)}}, + {17, {"sleep", "D", code(*syssleep:arg)}}, + {18, {"_stat", "sX", code(*sys_stat:arg)}}, + {19, {"rfork", "X", code(*sysstat:arg)}}, + {20, {"_write", "DXD", code(*sys_write:arg)}}, + {21, {"pipe", "X", code(*syspipe:arg)}}, + {22, {"create", "sDO", code(*syscreate:arg)}}, + {23, {"fd2path", "DXD", code(*sysfd2path:arg)}}, + {24, {"brk_", "X", code(*sysbrk_:arg)}}, + {25, {"remove", "s", code(*sysremove:arg)}}, + {26, {"_wstat", "sX", code(*sys_wstat:arg)}}, + {27, {"_fwstat", "DX", code(*sys_fwstat:arg)}}, + {28, {"notify", "X", code(*sysnotify:arg)}}, + {29, {"noted", "D", code(*sysnoted:arg)}}, + {30, {"segattach", "DsXD", code(*syssegattach:arg)}}, + {31, {"segdetach", "X", code(*syssegdetach:arg)}}, + {32, {"segfree", "XD", code(*syssegfree:arg)}}, + {33, {"segflush", "XD", code(*syssegflush:arg)}}, + {34, {"rendezvous", "XX", code(*sysrendezvous:arg)}}, + {35, {"unmount", "ss", code(*sysunmount:arg)}}, + {36, {"_wait", "X", code(*sys_wait:arg)}}, + {39, {"seek", "XDVD", code(*sysseek:arg)}}, + {40, {"fversion", "DDsD", code(*sysfversion:arg)}}, + {41, {"errstr", "TD", code(*syserrstr:arg)}}, + {42, {"stat", "sXD", code(*sysstat:arg)}}, + {43, {"fstat", "DXD", code(*sysfstat:arg)}}, + {44, {"wstat", "sXD", code(*syswstat:arg)}}, + {45, {"fwstat", "DXD", code(*sysfwstat:arg)}}, + {46, {"mount", "DDsXs", code(*sysmount:arg)}}, + {47, {"await", "TD", code(*sysawait:arg)}}, + {50, {"pread", "DXDZ", code(*syspread:arg)}}, + {51, {"pwrite", "DTDZ", code(*syspwrite:arg)}}, +}; + +defn syscall() { + local n, sl, h, p; + + map({"*data", 0, 0xffffffff, 0}); + n = *syscall:scallnr; + sl = syscalls; + while sl != {} do { + h = head sl; + sl = tail sl; + + if n == h[0] then { + p = h[1]; + printsyscall(p[0], p[1], p[2]); + } + } +} + +defn UPCSPRET() { + // return sys call number, address of first argument, location of syscall return value + if objtype == "386" then + return { code(*(*PC-4)), code(*SP+4), code(*AX) }; + if (objtype == "mips") || (objtype == "mips2") then + return { code(*(*PC-4) & 0xffff), code(*SP+4), code(*R1) }; + if objtype == "arm" then + return { code(*(*PC-4) & 0xffff), code(*SP+4), code(*R0) }; // untested + if objtype == "alpha" then + return { code(*(*PC-4) & 0xffff), code(*SP+4), code(*R0) }; // untested +} + +defn trapoffset() { + // return offset from entry point to trap instr + if objtype == "386" then return 5; + if objtype == "mips" then return 8; + if objtype == "mips2" then return 8; + if objtype == "arm" then return 8; // untested + if objtype == "alpha" then return 8; // untested +} + +defn trapreason() { + // return reason for trap + if objtype == "386" then return reason(*TRAP); + if objtype == "mips" then return reason(*CAUSE); + if objtype == "mips2" then return reason(*CAUSE); + if objtype == "arm" then return "unknown trap"; // untested + if objtype == "alpha" then return reason(cause); // untested +} + + +defn usyscall() { // gives args for system call in user level; not useful with -k + local n, sl, h, p; + + // stopped at TRAP instruction in system call library + pcsp = UPCSPRET(); + n = eval pcsp[0]; + sl = syscalls; + while sl != {} do { + h = head sl; + sl = tail sl; + + if n == h[0] then { + p = h[1]; + printsyscall(p[0], p[1], pcsp[1]); + } + } +} diff --git a/acid/thread b/acid/thread new file mode 100644 index 00000000..ac4cce8a --- /dev/null +++ b/acid/thread @@ -0,0 +1,365 @@ + +defn labpc(l) +{ + if objtype == "386" then + return longjmp; + return *(l+4); +} + +defn labsp(l) +{ + return *l; +} + +defn labstk(l) +{ + _stk(labpc(l), labsp(l), 0, 0); +} + +defn lablstk(l) +{ + _stk(labpc(l), labsp(l), 0, 1); +} + +defn altfmt(A){ + local i, s, yes; + complex Alt A; + + s = "alt("; + s = s + "tag(*" + itoa(A.tag, "%x") + "=" + itoa(*A.tag, "%x") + ") "; + i = 0; + yes = 0; + while A.op != CHANEND && A.op != CHANNOBLK do{ + if A.op != CHANNOP then{ + if yes then s = s + " "; + s = s + itoa(i, "%d"); + s = s + ":"; + if A.op == CHANSND then s = s + "send"; + if A.op == CHANRCV then s = s + "recv"; + s = s + "(channel("; + s = s + itoa(A.c, "%x"); + s = s + "))"; + yes = 1; + } + i = i + 1; + A = (Alt)(A + sizeofAlt); + } + if A.op==CHANNOBLK then{ + if yes then s = s + " "; + s = s + "noblock"; + } + s = s + ")"; + return s; +} + +defn alt(A){ + print(altfmt(A), "\n"); +} + +threadignsrc = { + "^/sys/src/libc", + "^/sys/src/libthread", +}; + +defn fnname(a){ + local sym, s; + + s = symbols; + while s do { + sym = head s; + if sym[2] == a then + return sym[0]; + s = tail s; + } + return itoa(a, "%x"); +} + +stkignorelist = {}; + +defn stkignore(s){ + append stkignorelist, s; +} + +defn threadstkline(T){ + local stk, frame, pc, pc0, file, lastpc0, s, sym, i, stop; + + if T.state == Running then{ + pc = *PC; + stk = strace(*PC, *SP, linkreg(0)); + }else{ + pc = labpc(T.sched); + stk = strace(labpc(T.sched), labsp(T.sched), 0); + } + lastpc0 = 0; + pc0 = 0; + stop = 0; + while stk && !stop do { + file = pcfile(pc); + if !regexp("^/sys/src/libc/", file) + && !regexp("^/sys/src/libthread/", file) + && match(file, stkignore)==-1 then + stop = 1; + else{ + lastpc0 = pc0; + frame = head stk; + stk = tail stk; + nextframe = head stk; + pc = frame[1]; + pc0 = nextframe[0]; + } + } + file = pcfile(pc); + s = file+":"+itoa(pcline(pc), "%d"); + if pc0 != 0 then + s = s + " "+fnname(pc0); + return s; +} + +defn threadfmt(T){ + complex Thread T; + local A, yes, i, P, s; + + P = (Proc)T.proc; + s = "t=(Thread)"+itoa(T, "%-10x")+" "; + + if T.state == Running then + s = s + "Running "; + else if T.state == Ready then + s = s + "Ready "; + else if T.state == Rendezvous then + s = s + "Rendez "; + else + s = s + "Bad state "+itoa(T.state, "%x")+" "; + + A = (Alt)T.alt; + if 1 then + s = s + threadstkline(T); + else if T.chan == Chanalt then + s = s + altfmt(T.alt); + else if T.chan == Chansend then + s = s + "send(Channel("+itoa(A.c, "%x")+"))"; + else if T.chan == Chanrecv then + s = s + "recv(Channel("+itoa(A.c, "%x")+"))"; + else + s = s + threadstkline(T); + + if T.moribund == 1 then + s = s + " Moribund"; + if T.cmdname != 0 then + s = s + " ["+*(T.cmdname\s)+"]"; + return s; +} + +defn thread(T){ + print(threadfmt(T), "\n"); +} + +defn pthreads(P){ + complex Proc P; + local T, Tq, mainpid; + + mainpid = pid; + setproc(P.pid); + Tq = (Tqueue)P.threads; + T = (Thread)Tq.$head; + while T != 0 do{ + print("\t"); + thread(T); + T = T.nextt; + } + setproc(mainpid); +} + +defn threads(){ + local P; + + P = (Proc)_threadpq.$head; + while P != 0 do{ + if P != (Proc)_threadpq.$head then print("\n"); + lproc(P); + P = P.next; + } +} + +defn stacks(){ + local P, mainpid; + + mainpid = pid; + P = (Proc)_threadpq.$head; + while P != 0 do{ + proc(P); + // setproc(P.pid); + // if P.thread==0 then{ + // print("=== thread scheduler stack\n"); + // stk(); + // } + // print("threadstks(", P\X, ")\n"); + threadstks(P); + P = P.next; + print("\n"); + } + setproc(mainpid); +} + +defn stacksizes(){ + local P, T, Tq, top, sp, mainpid; + + mainpid = pid; + P = (Proc)_threadpq.$head; + while P != 0 do{ + P = (Proc)P; + Tq = (Tqueue)P.threads; + T = (Thread)Tq.$head; + while T != 0 do{ + top = T.stk+T.stksize; + if T.state==Running then { + sp = *SP; + }else{ + sp = *(T.sched); + } + sp = *(T.sched); + print(top-sp\D, "\n"); + T = T.nextt; + } + P = P.next; + } + setproc(mainpid); +} + +defn lproc(P){ + proc(P); + pthreads(P); +} + +defn threadstks(P){ + complex Proc P; + local T, Tq, mainpid, pref, ign; + + mainpid = pid; + pref = stkprefix; + stkprefix = pref+"\t\t"; + ign = stkignore; + stkignore = { + "^/sys/src/libthread/", + "^/sys/src/libc/(386|arm|alpha|sparc|power|mips)/" + }; + setproc(P.pid); + Tq = (Tqueue)P.threads; + T = (Thread)Tq.$head; + while T != 0 do{ + // print("=============================\n"); + // print(" thread(", T\X, ")\n"); + print("\t"); + thread(T); + threadstk(T); + T = T.nextt; + print("\n"); + } + setproc(mainpid); + stkprefix = pref; + stkignore = ign; +} + +defn proc(P){ + complex Proc P; + + print("p=(Proc)", itoa(P, "%-10x"), " pid ", P.pid\D, " "); + if P.thread==0 then + print(" Sched"); + else + print(" Running"); + print("\n"); +} + +defn procs(){ + local P; + + P = (Proc)_threadpq.$head; + while P != 0 do{ + proc(P); + P = P.next; + } +} + +defn threadlstk(T){ + complex Thread T; + local P, mainpid; + + P = (Proc)T.proc; + mainpid = pid; + setproc(P.pid); + + if T.state == Running then{ + lstk(); + } else { + lablstk(T.sched); + } + setproc(mainpid); +} + +defn threadstk(T){ + complex Thread T; + local P, mainpid; + + P = (Proc)T.proc; + mainpid = pid; + setproc(P.pid); + + if T.state == Running then{ + stk(); + } else { + labstk(T.sched); + } + setproc(mainpid); +} + +defn tqueue(Q) { + complex Tqueue Q; + + while Q != 0 do { + print(Q.$head\X, " "); + Q = *(Q.$tail); + + } + print("#\n"); +} + +defn channel(C) { + complex Channel C; + local i, p; + + print("channel ", C\X); + if C.freed then { + print(" (moribund)"); + } + print("\n"); + print("\telementsize=", C.e\D, " buffersize=", C.s, "\n"); + if C.s then { + print("\t", C.n\D, " values in channel:\n"); + print("\t"); + p = C.v+C.e*(C.f%C.s); + loop 1,C.n do { + if C.e==4 then { + print((*p)\X, " "); + }else { + print("data(", (*p)\X, ") "); + } + p = p+C.e; + if p == C.v+C.s*C.e then { + p = C.v; + } + } + } + print("\n"); + print(C.nentry\D, " queue slots:\n"); + i=0; + loop 1,C.nentry do { + if C.qentry[i] then + print("\t", altfmt(C.qentry[i]), "\n"); + else + print("\t\n"); + i=i+1; + } +} + +print(acidfile); diff --git a/acid/transcript b/acid/transcript new file mode 100755 index 00000000..023dabda --- /dev/null +++ b/acid/transcript @@ -0,0 +1,33 @@ +#!/bin/rc +switch($#*){ +case 0 1 2 + echo usage: window '''minx miny maxx maxy''' '''minx miny maxx maxy''' cmd args ... + exit usage +} + +rfork ns + +if(mount $wsys /mnt/acid N`{{echo $pid $1 }| sed 's/^ //g;s/ +/,/g'}){ + winid=`{cat /dev/winid} + echo transcript > /mnt/acid/label + echo transcript > /mnt/acid/cons + shift +} +if not exit 0 + +if(mount $wsys /mnt/wsys N`{{echo $pid $1 }| sed 's/^ //g;s/ +/,/g'}){ + shift + bind -b /mnt/wsys /dev +} +if not exit 0 + +echo -n `{basename $1} > /dev/label >[2] /dev/null +@{ + echo hang > /proc/^`{cat /dev/ppid}^/ctl + $* < /dev/$winid/cons > /dev/$winid/cons >[2] /dev/$winid/cons & + exit $apid +} +ostatus = `{echo $status | sed 's/.*://'} +echo waitstop > /proc/$ostatus/ctl +echo nohang > /proc/$ostatus/ctl +exit $ostatus diff --git a/acid/trump b/acid/trump new file mode 100644 index 00000000..4921bfce --- /dev/null +++ b/acid/trump @@ -0,0 +1,171 @@ +// trace user malloc pool - trace malloc, realloc, and free calls +// if trumpsbrk is set, we trace sbrkalloc and sbrkmerge too. + +_stoprunning = 0; +trumphexaddrs = 0; +trumpsbrk = 0; + +defn stopped(pid) { + local l; + local pc; + pc = *PC; + if notes then { + if (notes[0]!="sys: breakpoint") then + { + print(pid,": ",reason(*TRAP),"\t"); + print(fmt(pc,97),"\t",fmt(pc,105),"\n"); + print("Notes pending:\n"); + l = notes; + while l do + { + print("\t",head l,"\n"); + l = tail l; + } + _stoprunning = 1; + } + } +} + +defn printstack() { + local frame, stk, pcs, lst, x; + + pcs = {*PC}; + stk = strace(*PC,*SP,0); + while stk do { + pcs = append pcs, stk[0][1]; + stk = tail stk; + } + + print(" #"); + lst = pcs; + while lst do { + if trumphexaddrs != 0 then + x = lst[0]\X; + else + x = lst[0]\a; + print(" src(", x, ");"); + lst = tail lst; + } + print("\n"); +} + +defn setuptrump() { + mallocPC = malloc; + malloczPC = mallocz; + freePC = free; + reallocPC = realloc; + sbrkallocPC = sbrkalloc; + sbrkmergePC = sbrkmerge; + + // linker might fill delay slot with first instruction + if objtype == "mips" then { + mallocPC = mallocPC+4; + malloczPC = malloczPC+4; + freePC = freePC+4; + reallocPC = reallocPC+4; + sbrkallocPC = sbrkallocPC+4; + sbrkmergePC = sbrkmergePC+4; + } + + bpset(mallocPC); + bpset(malloczPC); + bpset(freePC); + bpset(reallocPC); + if trumpsbrk then { + bpset(sbrkallocPC); + bpset(sbrkmergePC); + } +} + +defn cleantrump() { + stop(pid); + + bpdel(mallocPC); + bpdel(malloczPC); + bpdel(freePC); + bpdel(reallocPC); + bpdel(sbrkallocPC); + bpdel(sbrkmergePC); +} + +defn trumpflush() { + stop(pid); // already stopped, but flushes output +} + +defn new() { + bplist = {}; + newproc(progargs); + bpset(follow(main)[0]); + cont(); + bpdel(*PC); + // clear the hang bit, which is left set by newproc, so programs we fork/exec don't hang + printto("/proc/"+itoa(pid)+"/ctl", "nohang"); +} + +defn trumpfninfo() { + local arg0, arg1, stk, retpc, params; + + stk = strace(*PC, *SP, 0); + retpc = stk[0][1]; + params = stk[0][2]; + arg0 = params[0][1]; + arg1 = 0; + if tail params != {} then + arg1 = params[1][1]; + return {arg0, arg1, retpc}; +} + +defn trumpretval() { + if objtype=="386" then + return *AX; + if objtype=="mips" then + return *R1; + if objtype=="power" || objtype=="alpha" then + return *R0; +} + +defn trump() { + local arg0, arg1, pc, ret, x; + + stop(pid); + _stoprunning = 0; + setuptrump(); + while !_stoprunning do { + cont(); + if notes[0]!="sys: breakpoint" then { + cleantrump(); + return {}; + } + + pc = *PC; + x = trumpfninfo(); + arg0 = x[0]; + if pc == reallocPC || pc == sbrkmergePC then + arg1 = x[1]; + bpset(x[2]); + cont(); + bpdel(x[2]); + ret = trumpretval(); + if pc == mallocPC then + print(ret\X, " malloc ", arg0\D); + if pc == malloczPC then + print(ret\X, " mallocz ", arg0\D); + if pc == freePC then + print(arg0\X, " free"); + if pc == reallocPC then + print(ret\X, " realloc ", arg0\X, " ", arg1\D); + if pc == sbrkallocPC then + print(ret\X, " sbrkalloc ", arg0\D); + if pc == sbrkmergePC then + print("sbrkmerge ", arg0\X, " ", arg1\X, " = ", ret\D); + printstack(); + trumpflush(); + } +} + +defn untrump() { + cleantrump(); + start(pid); +} + +print(acidfile); diff --git a/acid/truss b/acid/truss new file mode 100644 index 00000000..5c4731f1 --- /dev/null +++ b/acid/truss @@ -0,0 +1,283 @@ +// poor emulation of SVR5 truss command - traces system calls + +include(acidfile); + +_stoprunning = 0; + +defn stopped(pid) { + local l; + local pc; + pc = *PC; + if notes then { + if (notes[0]!="sys: breakpoint") then + { + print(pid,": ",trapreason(),"\t"); + print(fmt(pc,97),"\t",fmt(pc,105),"\n"); + print("Notes pending:\n"); + l = notes; + while l do + { + print("\t",head l,"\n"); + l = tail l; + } + _stoprunning = 1; + } + } +} + +defn _addressof(pattern) { + local s, l; + l = symbols; + pattern = "^\\$*"+pattern+"$"; + while l do + { + s = head l; + if regexp(pattern, s[0]) && ((s[1] == 'T') || (s[1] == 'L')) then + return s[2]; + l = tail l; + } + return 0; +} + +stopPC = {}; +readPC = {}; +fd2pathPC = {}; +errstrPC = {}; +awaitPC = {}; +_waitPC = {}; +_errstrPC = {}; +trusscalls = { + "sysr1", + "_errstr", + "bind", + "chdir", + "close", + "dup", + "alarm", + "exec", + "_exits", + "_fsession", + "fauth", + "_fstat", + "segbrk", + "_mount", + "open", + "_read", + "oseek", + "sleep", + "_stat", + "rfork", + "_write", + "pipe", + "create", + "fd2path", + "brk_", + "remove", + "_wstat", + "_fwstat", + "notify", + "noted", + "segattach", + "segdetach", + "segfree", + "segflush", + "rendezvous", + "unmount", + "_wait", + "seek", + "fversion", + "errstr", + "stat", + "fstat", + "wstat", + "fwstat", + "mount", + "await", + "pread", + "pwrite", + }; + +trussapecalls = { + "_SYSR1", + "__ERRSTR", + "_BIND", + "_CHDIR", + "_CLOSE", + "_DUP", + "_ALARM", + "_EXEC", + "_EXITS", + "__FSESSION", + "_FAUTH", + "__FSTAT", + "_SEGBRK", + "__MOUNT", + "_OPEN", + "__READ", + "_OSEEK", + "_SLEEP", + "__STAT", + "_RFORK", + "__WRITE", + "_PIPE", + "_CREATE", + "_FD2PATH", + "_BRK_", + "_REMOVE", + "__WSTAT", + "__FWSTAT", + "_NOTIFY", + "_NOTED", + "_SEGATTACH", + "_SEGDETACH", + "_SEGFREE", + "_SEGFLUSH", + "_RENDEZVOUS", + "_UNMOUNT", + "__WAIT", + "_SEEK", + "__NFVERSION", + "__NERRSTR", + "_STAT", + "__NFSTAT", + "__NWSTAT", + "__NFWSTAT", + "__NMOUNT", + "__NAWAIT", + "_PREAD", + "_PWRITE", + }; + +defn addressof(pattern) { + // translate to ape system calls if we have an ape binary + if _addressof("_EXITS") == 0 then + return _addressof(pattern); + return _addressof(trussapecalls[match(pattern, trusscalls)]); +} + +defn setuptruss() { + local lst, offset, name, addr; + + trussbpt = {}; + offset = trapoffset(); + lst = trusscalls; + while lst do + { + name = head lst; + lst = tail lst; + addr = addressof(name); + if addr then + { + bpset(addr+offset); + trussbpt = append trussbpt, (addr+offset); + // sometimes _exits is renamed $_exits + if(regexp("exits|exec", name)) then stopPC = append stopPC, (addr+offset); + if(regexp("read", name)) then readPC = append readPC, (addr+offset); + if(regexp("fd2path", name)) then fd2pathPC = append fd2pathPC, (addr+offset); + if(regexp("^\\$*await", name)) then awaitPC = append awaitPC, (addr+offset); + if(regexp("^\\$*errstr", name)) then errstrPC = append errstrPC, (addr+offset); + // compatibility hacks for old kernel + if(regexp("_wait", name)) then _waitPC = append _waitPC, (addr+offset); + if(regexp("_errstr", name)) then _errstrPC = append _errstrPC, (addr+offset); + } + } +} + +defn trussflush() { + stop(pid); // already stopped, but flushes output +} + +defn new() { + bplist = {}; + newproc(progargs); + bpset(follow(main)[0]); + cont(); + bpdel(*PC); + // clear the hang bit, which is left set by newproc, so programs we fork/exec don't hang + printto("/proc/"+itoa(pid)+"/ctl", "nohang"); +} + +defn truss() { + local pc, lst, offset, prevpc, pcspret, ret; + + offset = trapoffset(); + + stop(pid); + _stoprunning = 0; + setuptruss(); + pcspret = UPCSPRET(); + + while !_stoprunning do { + cont(); + if notes[0]!="sys: breakpoint" then { + cleantruss(); + return {}; + } + pc = *PC; + if match(*PC, stopPC)>=0 then { + print(pid,": ",trapreason(),"\t"); + print(fmt(pc,'a'),"\t",fmt(pc,'i'),"\n"); + cleantruss(); + return {}; + } + if match(*PC, trussbpt)>=0 then { + usyscall(); + trussflush(); + prevpc = *PC; + step(); + ret = eval pcspret[2]; + print("\treturn value: ", ret\D, "\n"); + if (ret>=0) && (match(prevpc, readPC)>=0) then { + print("\tdata: "); + printtextordata(*((eval pcspret[1])+4), ret); + print("\n"); + } + if (ret>=0) && (match(prevpc, fd2pathPC)>=0) then { + print("\tdata: \"", *(*((eval pcspret[1])+4)\s), "\"\n"); + } + if (ret>=0) && (match(prevpc, errstrPC)>=0) then { + print("\tdata: \"", *(*(eval pcspret[1])\s), "\"\n"); + } + if (ret>=0) && (match(prevpc, awaitPC)>=0) then { + print("\tdata: "); + printtextordata(*(eval pcspret[1]), ret); + print("\n"); + } + // compatibility hacks for old kernel: + if (ret>=0) && (match(prevpc, _waitPC)>=0) then { + print("\tdata: "); + printtextordata(*(eval pcspret[1]), 12+3*12+64); + print("\n"); + } + if (ret>=0) && (match(prevpc, _errstrPC)>=0) then { + print("\tdata: "); + printtextordata(*(eval pcspret[1]), 64); + print("\n"); + } + } + trussflush(); + } +} + +defn cleantruss() { + local lst, offset, addr; + + stop(pid); + offset = trapoffset(); + lst = trussbpt; + while lst do + { + addr = head lst; + lst = tail lst; + bpdel(addr); + } + trussbpt = {}; + **PC = @*PC; // repair current instruction +} + +defn untruss() { + cleantruss(); + start(pid); +} + +print("/sys/lib/acid/truss"); diff --git a/acid/window b/acid/window new file mode 100755 index 00000000..d5c08a45 --- /dev/null +++ b/acid/window @@ -0,0 +1,23 @@ +#!/bin/rc +switch($#*){ +case 0 1 + echo usage: window '''minx miny maxx maxy''' cmd args ... + exit usage +} + +rfork ns +if(mount $wsys /mnt/wsys N`{{echo $pid $1 }| sed 's/^ //g;s/ +/,/g'}){ + shift + bind -b /mnt/wsys /dev + echo -n `{basename $1} > /dev/label >[2] /dev/null + @{ + echo hang > /proc/^`{cat /dev/ppid}^/ctl + $* < /dev/cons > /dev/cons >[2] /dev/cons & + exit $apid + } + ostatus = `{echo $status | sed 's/.*://'} + echo waitstop > /proc/$ostatus/ctl + echo nohang > /proc/$ostatus/ctl + exit $ostatus +} +exit 0