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