Commit Diff


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