tacid files - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 0a61c07d591273b76da21fb8386b669989da3707
 (DIR) parent c8af1ab17b72f500c27688598dbb893f09f62c53
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 19 Apr 2004 18:18:37 +0000
       
       acid files
       
       Diffstat:
         A acid/386                            |     210 +++++++++++++++++++++++++++++++
         A acid/68020                          |     137 +++++++++++++++++++++++++++++++
         A acid/acme                           |     133 +++++++++++++++++++++++++++++++
         A acid/alef                           |     147 +++++++++++++++++++++++++++++++
         A acid/alpha                          |     205 ++++++++++++++++++++++++++++++
         A acid/arm                            |     104 +++++++++++++++++++++++++++++++
         A acid/core                           |       0 
         A acid/coverage                       |     128 +++++++++++++++++++++++++++++++
         A acid/elflink                        |      54 +++++++++++++++++++++++++++++++
         A acid/kernel                         |     295 ++++++++++++++++++++++++++++++
         A acid/leak                           |     138 ++++++++++++++++++++++++++++++
         A acid/mips                           |     217 +++++++++++++++++++++++++++++++
         A acid/network                        |     169 +++++++++++++++++++++++++++++++
         A acid/pool                           |     306 +++++++++++++++++++++++++++++++
         A acid/port                           |     599 +++++++++++++++++++++++++++++++
         A acid/power                          |     120 +++++++++++++++++++++++++++++++
         A acid/sparc                          |     218 +++++++++++++++++++++++++++++++
         A acid/syscall                        |     196 +++++++++++++++++++++++++++++++
         A acid/thread                         |     365 +++++++++++++++++++++++++++++++
         A acid/transcript                     |      33 +++++++++++++++++++++++++++++++
         A acid/trump                          |     171 +++++++++++++++++++++++++++++++
         A acid/truss                          |     283 +++++++++++++++++++++++++++++++
         A acid/window                         |      23 +++++++++++++++++++++++
       
       23 files changed, 4251 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/acid/386 b/acid/386
       t@@ -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);
 (DIR) diff --git a/acid/68020 b/acid/68020
       t@@ -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);
 (DIR) diff --git a/acid/acme b/acid/acme
       t@@ -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);
 (DIR) diff --git a/acid/alef b/acid/alef
       t@@ -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);
 (DIR) diff --git a/acid/alpha b/acid/alpha
       t@@ -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);
       +
 (DIR) diff --git a/acid/arm b/acid/arm
       t@@ -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);
 (DIR) diff --git a/acid/core b/acid/core
       Binary files differ.
 (DIR) diff --git a/acid/coverage b/acid/coverage
       t@@ -0,0 +1,128 @@
       +// Coverage library
       +
       +defn coverage()
       +{
       +        local lmap, lp, e, pc, n, l;
       +
       +        new();
       +
       +        bblock = {};
       +
       +        // find the first location in the text
       +        e = (map()[0][1])\i;
       +
       +        while e < etext-4 do {
       +                l = follow(e);
       +                if tail l != {} then {
       +                        if match(l[0], bblock) < 0 then
       +                                bblock = append bblock, l[0];
       +                        if match(l[1], bblock) < 0 then
       +                                bblock = append bblock, l[1];
       +                }
       +                e++;
       +        }
       +
       +        l = bblock;
       +        while l != {} do {
       +                *fmt(head l, bpfmt) = bpinst;
       +                l = tail l;
       +        }
       +
       +        while 1 do {
       +                cont();
       +                pc = *PC;
       +                n = match(pc, bblock);
       +                if n >= 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);
 (DIR) diff --git a/acid/elflink b/acid/elflink
       t@@ -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;
       +        }
       +}
 (DIR) diff --git a/acid/kernel b/acid/kernel
       t@@ -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 "<null>";
       +}
       +
       +// 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");
       +}
       +
 (DIR) diff --git a/acid/leak b/acid/leak
       t@@ -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");
       +}
 (DIR) diff --git a/acid/mips b/acid/mips
       t@@ -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);
 (DIR) diff --git a/acid/network b/acid/network
       t@@ -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");
 (DIR) diff --git a/acid/pool b/acid/pool
       t@@ -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;
       +}
       +
 (DIR) diff --git a/acid/port b/acid/port
       t@@ -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);
 (DIR) diff --git a/acid/power b/acid/power
       t@@ -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);
 (DIR) diff --git a/acid/sparc b/acid/sparc
       t@@ -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);
 (DIR) diff --git a/acid/syscall b/acid/syscall
       t@@ -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]);
       +                }
       +        }
       +}
 (DIR) diff --git a/acid/thread b/acid/thread
       t@@ -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<empty>\n");
       +                i=i+1;
       +        }
       +}
       +
       +print(acidfile);
 (DIR) diff --git a/acid/transcript b/acid/transcript
       t@@ -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
 (DIR) diff --git a/acid/trump b/acid/trump
       t@@ -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);
 (DIR) diff --git a/acid/truss b/acid/truss
       t@@ -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");
 (DIR) diff --git a/acid/window b/acid/window
       t@@ -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