// print system calls
defn printstring(s)
{
	print("\"", s, "\"");
}

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
			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(*syserrstr: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(*sysfsession:arg)}},
	{10, {"fauth",		"DX",		code(*sysfauth:arg)}},
	{11, {"fstat",		"DX",		code(*sysfstat:arg)}},
	{12, {"segbrk",		"XX",		code(*syssegbrk:arg)}},
	{13, {"mount",		"DsXs",		code(*sysmount:arg)}},
	{14, {"open",		"sD",		code(*sysopen:arg)}},
	{15, {"read",		"DXD",		code(*sysread:arg)}},
	{16, {"oseek",		"DDD",		code(*sysoseek:arg)}},
	{17, {"sleep",		"D",		code(*syssleep:arg)}},
	{18, {"stat",		"sX",		code(*sysstat:arg)}},
	{19, {"rfork",		"X",		code(*sysstat:arg)}},
	{20, {"write",		"DXD",		code(*syswrite: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(*syswstat:arg)}},
	{27, {"fwstat",		"DX",		code(*sysfwstat: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(*syswait:arg)}},
	{37, {"read9p",		"DXD",		code(*sysread9p:arg)}},
	{38, {"write9p",	"DXD",		code(*syswrite9p:arg)}},
	{39, {"seek",		"DZD",		code(*sysseek: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]);
		}
	}
}

// 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;
	} 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;
	}
}

// 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 procs() {
	local i;

	i=0; loop 1,conf.nproc do {
		proc(proctab(i));
		i = i+1;
	}
}

// segment-related
defn procsegs(p) {
	complex Proc p;
	local i;

	i=0; loop 1,NSEG do {
		segment(p.seg[i]);
		i = i+1;
	}
}

segtypes = { "text", "data", "bss", "stack", "shared", "physical", "shdata", "map" };
defn segment(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;
}



print("/sys/lib/acid/kernel");
