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");
}