code: plan9front

ref: 403149d7de4dbe4cc4b1fd9cb3a164e51dbccc15
dir: /sys/lib/acid/leak/

View raw version
//
// usage: acid -l pool -l leak
//
include("/sys/src/libc/port/pool." + objtype + ".acid");

defn
dumppool(p, sum)
{
	complex Pool p;
	a = p.arenalist;

	allocsize = 0;

	print("A: ", p.arenalist\A, "\n");
	while a != 0 do {
		complex Arena a;
		dumparena(a, sum);
		a = a.down;
	}
	if sum then {
		emitsum();
	}

	if allocsize != p.curalloc then {
		print("found alloc size mismatch ", allocsize, " != ", p.curalloc, "\n");
	}
}

defn
dumparena(arena, sum)
{
	local atail, b, nb;

	atail = A2TB(arena);
	complex Bhdr arena;
	b = a;
	print("B: ", b\A, " ", atail\A, "\n");
	while b < atail && b.magic != ARENATAIL_MAGIC do {
		dumpblock(b, sum);
		nb = B2NB(b);
		if nb == b then {
			print("B2NB(", b\A, ") = b\n");
			b = atail;	// end loop
		} else if nb > atail then {
			b = (Bhdr)(b+4);
			print("lost at block ", (b-4)\A, ", scanning forward\n");
			while b < atail && b.magic != ALLOC_MAGIC && b.magic != FREE_MAGIC do
				b = (Bhdr)(b+4);
			print("stopped at ", b\A, " ", *b\A, "\n");
		}else
			b = nb;
	}
	if b != atail then
		print("found wrong tail to arena ", arena\A, " wanted ", atail\A, "\n");
}

defn
isptr(a)
{
	if end <= a && a < xbloc then
		return 1;
	if 0xdefff000 <= a && a < 0xdffff000 then
		return 1;
	return 0;
}

lastalloc = 0;
lastcount = 0;
lastsize = 0;
defn
emitsum()
{
	if lastalloc then
		print("summary ", lastalloc\a, " ", lastcount\D, " ", lastsize\D, "\n");
	lastalloc = 0;
	lastcount = 0;
	lastsize = 0;
}

defn
sxpc(addr)
{
	if objtype == "amd64" && addr & 0x80000000 then {
		return addr | 0xffffffff00000000;
	}
	return addr;
}

defn
dumpblock(addr, sum)
{
	complex Bhdr addr;

	if addr.magic == ALLOC_MAGIC || (!sum && addr.magic == FREE_MAGIC) then {
		local a, x, s, allocpc, reallocpc;

		a = addr;
		complex Alloc a;

		x = fmt(addr+sizeofBhdr, 'X');
		if addr.magic == ALLOC_MAGIC then {
			allocsize = allocsize+a.size;
			// for mallocalign()
			while *x == ALIGN_MAGIC do {
				x = x + 4;
			}
		}
		allocpc=sxpc(x[0]);
		reallocpc=sxpc(x[1]);
		if sum then {
			if allocpc != lastalloc then {
				emitsum();
				lastalloc = allocpc;
			}
			lastcount = lastcount+1;
			lastsize = lastsize+a.size;
		}else{
			if addr.magic == ALLOC_MAGIC then {
				s = "block";
			} else
				s = "free";
			print(s, " ", addr\A, " ", a.size\X, " ");
			print(x[0]\X, " ", x[1]\X, " ", allocpc\a, " ", reallocpc\a, "\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\X);
		if isptr(y) then print("data ", x\X, " ", y\X, " ", type, "\n");
		x = x + 4;
	}
}

defn
stacktop()
{
	local e, m;
	
	m = map();
	while m != {} do {
		e = head m;
		if e[0] == "*data" then
			return e[2];
		m = tail m;
	}
	return 0xdffff000;
}
			
defn
dumpmem()
{
	local s, top;

	xbloc = *bloc;
	// assume map()[1] is "data" 
	dumprange(map()[1][1], end, "bss");	// bss
	dumprange(end, xbloc, "alloc");	// allocated

	top = stacktop() - 8;
	if top-0x01000000 < *SP && *SP < top then
		s = *SP;
	else
		s = top-32*1024;

	dumprange(s, top, "stack");
}

defn
dumpregs()
{
	dumprange(0, sizeofUreg, "reg");
}


defn
leakdump(l)
{
	print("==LEAK BEGIN==\n");
	dumppool(*mainmem, 0);
	dumpmem();
	dumpregs();
	while l != {} do {
		setproc(head l);
		dumpregs();
		l = tail l;
	}
	print("==LEAK END==\n");
}

defn
blockdump()
{
	print("==BLOCK BEGIN==\n");
	dumppool(*mainmem, 0);
	print("==BLOCK END==\n");
}

defn
blocksummary()
{
	print("==BLOCK BEGIN==\n");
	dumppool(*mainmem, 1);
	print("==BLOCK END==\n");
}

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