xref: /plan9/sys/src/cmd/aux/acidleak.c (revision bfb6eab9346d861b5f68a2b1af55a1768a8fe25b)
159cc4ca5SDavid du Colombier #include <u.h>
259cc4ca5SDavid du Colombier #include <libc.h>
359cc4ca5SDavid du Colombier #include <bio.h>
459cc4ca5SDavid du Colombier 
559cc4ca5SDavid du Colombier void*
emalloc(ulong sz)659cc4ca5SDavid du Colombier emalloc(ulong sz)
759cc4ca5SDavid du Colombier {
859cc4ca5SDavid du Colombier 	void *v;
959cc4ca5SDavid du Colombier 
1059cc4ca5SDavid du Colombier 	v = malloc(sz);
1159cc4ca5SDavid du Colombier 	if(v == nil)
1214cc0f53SDavid du Colombier 		sysfatal("malloc %lud fails", sz);
1359cc4ca5SDavid du Colombier 	memset(v, 0, sz);
1459cc4ca5SDavid du Colombier 	return v;
1559cc4ca5SDavid du Colombier }
1659cc4ca5SDavid du Colombier 
1759cc4ca5SDavid du Colombier void*
erealloc(void * v,ulong sz)1859cc4ca5SDavid du Colombier erealloc(void *v, ulong sz)
1959cc4ca5SDavid du Colombier {
2059cc4ca5SDavid du Colombier 	v = realloc(v, sz);
2159cc4ca5SDavid du Colombier 	if(v == nil)
2214cc0f53SDavid du Colombier 		sysfatal("realloc %lud fails", sz);
2359cc4ca5SDavid du Colombier 	return v;
2459cc4ca5SDavid du Colombier }
2559cc4ca5SDavid du Colombier 
26d95be1c0SDavid du Colombier char*
estrdup(char * s)27d95be1c0SDavid du Colombier estrdup(char* s)
28d95be1c0SDavid du Colombier {
29d95be1c0SDavid du Colombier 	char *r;
30d95be1c0SDavid du Colombier 
31d95be1c0SDavid du Colombier 	r = strdup(s);
32d95be1c0SDavid du Colombier 	if(r == nil)
3314cc0f53SDavid du Colombier 		sysfatal("strdup fails");
34d95be1c0SDavid du Colombier 	return r;
35d95be1c0SDavid du Colombier }
36d95be1c0SDavid du Colombier 
3759cc4ca5SDavid du Colombier typedef struct Block Block;
3859cc4ca5SDavid du Colombier typedef struct Data Data;
3959cc4ca5SDavid du Colombier struct Block {
4059cc4ca5SDavid du Colombier 	ulong addr;
4159cc4ca5SDavid du Colombier 	ulong size;
4259cc4ca5SDavid du Colombier 	ulong w0;
4359cc4ca5SDavid du Colombier 	ulong w1;
44d95be1c0SDavid du Colombier 	char *s0;
45d95be1c0SDavid du Colombier 	char *s1;
4659cc4ca5SDavid du Colombier 	int mark;
47fb7f0c93SDavid du Colombier 	int free;
4859cc4ca5SDavid du Colombier 	Data *d;
4959cc4ca5SDavid du Colombier };
5059cc4ca5SDavid du Colombier 
5159cc4ca5SDavid du Colombier struct Data {
5259cc4ca5SDavid du Colombier 	ulong addr;
5359cc4ca5SDavid du Colombier 	ulong val;
5459cc4ca5SDavid du Colombier 	uchar type;
5559cc4ca5SDavid du Colombier 	Block *b;
5659cc4ca5SDavid du Colombier };
5759cc4ca5SDavid du Colombier 
5859cc4ca5SDavid du Colombier Block *block;
59*bfb6eab9SDavid du Colombier uint nblock;
60*bfb6eab9SDavid du Colombier uint ablock;
6159cc4ca5SDavid du Colombier 
6259cc4ca5SDavid du Colombier Data *data;
6359cc4ca5SDavid du Colombier Data *edata;
64*bfb6eab9SDavid du Colombier uint ndata;
65*bfb6eab9SDavid du Colombier uint adata;
6659cc4ca5SDavid du Colombier 
6759cc4ca5SDavid du Colombier int
addrcmp(void * va,void * vb)6859cc4ca5SDavid du Colombier addrcmp(void *va, void *vb)
6959cc4ca5SDavid du Colombier {
7059cc4ca5SDavid du Colombier 	ulong *a, *b;
7159cc4ca5SDavid du Colombier 
7259cc4ca5SDavid du Colombier 	a = va;
7359cc4ca5SDavid du Colombier 	b = vb;
7459cc4ca5SDavid du Colombier 	if(*a < *b)
7559cc4ca5SDavid du Colombier 		return -1;
7659cc4ca5SDavid du Colombier 	if(*a > *b)
7759cc4ca5SDavid du Colombier 		return 1;
7859cc4ca5SDavid du Colombier 	return 0;
7959cc4ca5SDavid du Colombier }
8059cc4ca5SDavid du Colombier 
8159cc4ca5SDavid du Colombier Block*
findblock(ulong addr)8259cc4ca5SDavid du Colombier findblock(ulong addr)
8359cc4ca5SDavid du Colombier {
8459cc4ca5SDavid du Colombier 	int lo, hi, m;
8559cc4ca5SDavid du Colombier 
8659cc4ca5SDavid du Colombier 	lo = 0;
8759cc4ca5SDavid du Colombier 	hi = nblock;
8859cc4ca5SDavid du Colombier 
8959cc4ca5SDavid du Colombier 	while(lo < hi) {
9059cc4ca5SDavid du Colombier 		m = (lo+hi)/2;
9159cc4ca5SDavid du Colombier 		if(block[m].addr < addr)
9259cc4ca5SDavid du Colombier 			lo = m+1;
9359cc4ca5SDavid du Colombier 		else if(addr < block[m].addr)
9459cc4ca5SDavid du Colombier 			hi = m;
9559cc4ca5SDavid du Colombier 		else
9659cc4ca5SDavid du Colombier 			return &block[m];
9759cc4ca5SDavid du Colombier 	}
9859cc4ca5SDavid du Colombier 	return nil;
9959cc4ca5SDavid du Colombier }
10059cc4ca5SDavid du Colombier 
10159cc4ca5SDavid du Colombier Data*
finddata(ulong addr)10259cc4ca5SDavid du Colombier finddata(ulong addr)
10359cc4ca5SDavid du Colombier {
10459cc4ca5SDavid du Colombier 	int lo, hi, m;
10559cc4ca5SDavid du Colombier 
10659cc4ca5SDavid du Colombier 	lo = 0;
10759cc4ca5SDavid du Colombier 	hi = ndata;
10859cc4ca5SDavid du Colombier 
10959cc4ca5SDavid du Colombier 	while(lo < hi) {
11059cc4ca5SDavid du Colombier 		m = (lo+hi)/2;
11159cc4ca5SDavid du Colombier 		if(data[m].addr < addr)
11259cc4ca5SDavid du Colombier 			lo = m+1;
11359cc4ca5SDavid du Colombier 		else if(addr < data[m].addr)
11459cc4ca5SDavid du Colombier 			hi = m;
11559cc4ca5SDavid du Colombier 		else
11659cc4ca5SDavid du Colombier 			return &data[m];
11759cc4ca5SDavid du Colombier 	}
11859cc4ca5SDavid du Colombier 	if(0 <= lo && lo < ndata)
11959cc4ca5SDavid du Colombier 		return &data[lo];
120ec46fab0SDavid du Colombier 	return nil;
12159cc4ca5SDavid du Colombier }
12259cc4ca5SDavid du Colombier 
12359cc4ca5SDavid du Colombier int nmark;
12459cc4ca5SDavid du Colombier 
12580ee5cbfSDavid du Colombier int
markblock(ulong from,ulong fromval,Block * b)126fb7f0c93SDavid du Colombier markblock(ulong from, ulong fromval, Block *b)
12759cc4ca5SDavid du Colombier {
12859cc4ca5SDavid du Colombier 	Data *d;
12959cc4ca5SDavid du Colombier 	ulong top;
13059cc4ca5SDavid du Colombier 	Block *nb;
13159cc4ca5SDavid du Colombier 
13287bc2094SDavid du Colombier USED(from, fromval);
13359cc4ca5SDavid du Colombier //print("trace 0x%.8lux from 0x%.8lux (%d)\n", b->addr, from, b->mark);
134fb7f0c93SDavid du Colombier 	if(b->free){
135fb7f0c93SDavid du Colombier 	//	fprint(2, "possible dangling pointer *0x%.8lux = 0x%.8lux\n", from, fromval);
136fb7f0c93SDavid du Colombier 		return 0;
137fb7f0c93SDavid du Colombier 	}
13859cc4ca5SDavid du Colombier 	if(b->mark)
13980ee5cbfSDavid du Colombier 		return 0;
14059cc4ca5SDavid du Colombier 	b->mark = 1;
14159cc4ca5SDavid du Colombier 	nmark++;
14259cc4ca5SDavid du Colombier 
14359cc4ca5SDavid du Colombier 	if(d = finddata(b->addr)) {
14459cc4ca5SDavid du Colombier 		assert(d->addr >= b->addr);
14559cc4ca5SDavid du Colombier 		b->d = d;
14659cc4ca5SDavid du Colombier 		top = b->addr+b->size;
14759cc4ca5SDavid du Colombier 		for(; d < edata && d->addr < top; d++) {
14859cc4ca5SDavid du Colombier 			assert(d->b == 0);
14959cc4ca5SDavid du Colombier 			d->b = b;
15059cc4ca5SDavid du Colombier 			if((nb = findblock(d->val-8)) || (nb = findblock(d->val-8-8)))
151fb7f0c93SDavid du Colombier 				markblock(d->addr, d->val, nb);
15259cc4ca5SDavid du Colombier 		}
15380ee5cbfSDavid du Colombier 		return 1;
15459cc4ca5SDavid du Colombier 	}
15580ee5cbfSDavid du Colombier 	return 0;
15680ee5cbfSDavid du Colombier }
15780ee5cbfSDavid du Colombier 
15880ee5cbfSDavid du Colombier enum {
15980ee5cbfSDavid du Colombier 	AllocColor = 2,	// dark blue: completely allocated region
16080ee5cbfSDavid du Colombier 	HdrColor = 54,		// bright blue: region with header
16180ee5cbfSDavid du Colombier 	LeakColor = 205,	// dark red: region with leak
16280ee5cbfSDavid du Colombier 	LeakHdrColor = 240,	// bright red: region with leaked header
16380ee5cbfSDavid du Colombier 	FreeColor = 252,	// bright yellow: completely free region
16480ee5cbfSDavid du Colombier 	NoColor = 255,		// padding, white
16580ee5cbfSDavid du Colombier };
16680ee5cbfSDavid du Colombier 
16780ee5cbfSDavid du Colombier int
rXr(int as,int ae,int bs,int be)16880ee5cbfSDavid du Colombier rXr(int as, int ae, int bs, int be)
16980ee5cbfSDavid du Colombier {
17080ee5cbfSDavid du Colombier 	return bs < ae && as < be;
17159cc4ca5SDavid du Colombier }
17259cc4ca5SDavid du Colombier 
17359cc4ca5SDavid du Colombier void
main(int argc,char ** argv)17480ee5cbfSDavid du Colombier main(int argc, char **argv)
17559cc4ca5SDavid du Colombier {
17659cc4ca5SDavid du Colombier 	Biobuf bio;
17759cc4ca5SDavid du Colombier 	char *p, *f[10];
17880ee5cbfSDavid du Colombier 	int bitmap, c, nf, resolution, n8, n16, hdr, nhdr, nlhdr, nleak, x, y, nb;
17980ee5cbfSDavid du Colombier 	ulong allocstart, allocend, len, u;
18059cc4ca5SDavid du Colombier 	Data *d, *ed;
18159cc4ca5SDavid du Colombier 	Block *b, *eb;
18259cc4ca5SDavid du Colombier 
18380ee5cbfSDavid du Colombier 	bitmap = 0;
18480ee5cbfSDavid du Colombier 	resolution = 8;
18580ee5cbfSDavid du Colombier 	x = 512;
18680ee5cbfSDavid du Colombier 	ARGBEGIN{
18780ee5cbfSDavid du Colombier 	case 'b':
18880ee5cbfSDavid du Colombier 		bitmap=1;
18980ee5cbfSDavid du Colombier 		break;
19080ee5cbfSDavid du Colombier 	case 'r':
19180ee5cbfSDavid du Colombier 		resolution = atoi(EARGF(sysfatal("usage")));
19280ee5cbfSDavid du Colombier 		break;
19380ee5cbfSDavid du Colombier 	case 'x':
19480ee5cbfSDavid du Colombier 		x = atoi(EARGF(sysfatal("usage")));
19580ee5cbfSDavid du Colombier 		break;
19680ee5cbfSDavid du Colombier 	}ARGEND
19780ee5cbfSDavid du Colombier 
19880ee5cbfSDavid du Colombier 	n8 = n16 = 0;
19980ee5cbfSDavid du Colombier 	allocstart = allocend = 0;
20059cc4ca5SDavid du Colombier 	Binit(&bio, 0, OREAD);
20159cc4ca5SDavid du Colombier 	while(p=Brdline(&bio, '\n')) {
20259cc4ca5SDavid du Colombier 		p[Blinelen(&bio)-1] = '\0';
20359cc4ca5SDavid du Colombier 		nf = tokenize(p, f, nelem(f));
20459cc4ca5SDavid du Colombier 		if(nf >= 4 && strcmp(f[0], "data") == 0) {
205*bfb6eab9SDavid du Colombier 			if(ndata >= adata){
206*bfb6eab9SDavid du Colombier 				if(adata == 0)
207*bfb6eab9SDavid du Colombier 					adata = 4096;
208*bfb6eab9SDavid du Colombier 				else
209*bfb6eab9SDavid du Colombier 					adata += adata / 4;  /* increase 25% */
210*bfb6eab9SDavid du Colombier 				data = erealloc(data, adata * sizeof(Data));
211*bfb6eab9SDavid du Colombier 			}
21259cc4ca5SDavid du Colombier 			data[ndata].addr = strtoul(f[1], nil, 0);
21359cc4ca5SDavid du Colombier 			data[ndata].val = strtoul(f[2], nil, 0);
21459cc4ca5SDavid du Colombier 			data[ndata].type = f[3][0];
21559cc4ca5SDavid du Colombier 			data[ndata].b = 0;
21659cc4ca5SDavid du Colombier 			ndata++;
21759cc4ca5SDavid du Colombier 		}
218*bfb6eab9SDavid du Colombier 		if(nf >= 5 &&
219*bfb6eab9SDavid du Colombier 		    (strcmp(f[0], "block") == 0 || strcmp(f[0], "free") == 0)) {
220*bfb6eab9SDavid du Colombier 			if(nblock >= ablock){
221*bfb6eab9SDavid du Colombier 				if(ablock == 0)
222*bfb6eab9SDavid du Colombier 					ablock = 4096;
223*bfb6eab9SDavid du Colombier 				else
224*bfb6eab9SDavid du Colombier 					ablock += ablock / 4; /* increase 25% */
225*bfb6eab9SDavid du Colombier 				block = erealloc(block, ablock * sizeof(Block));
226*bfb6eab9SDavid du Colombier 			}
22759cc4ca5SDavid du Colombier 			block[nblock].addr = strtoul(f[1], nil, 0);
22859cc4ca5SDavid du Colombier 			block[nblock].size = strtoul(f[2], nil, 0);
22959cc4ca5SDavid du Colombier 			block[nblock].w0 = strtoul(f[3], nil, 0);
23059cc4ca5SDavid du Colombier 			block[nblock].w1 = strtoul(f[4], nil, 0);
231d95be1c0SDavid du Colombier 			if (nf >= 7) {
232d95be1c0SDavid du Colombier 				block[nblock].s0 = estrdup(f[5]);
233d95be1c0SDavid du Colombier 				block[nblock].s1 = estrdup(f[6]);
234d95be1c0SDavid du Colombier 			} else {
235d95be1c0SDavid du Colombier 				block[nblock].s0 = "";
236d95be1c0SDavid du Colombier 				block[nblock].s1 = "";
237d95be1c0SDavid du Colombier 			}
23859cc4ca5SDavid du Colombier 			block[nblock].mark = 0;
23959cc4ca5SDavid du Colombier 			block[nblock].d = 0;
240fb7f0c93SDavid du Colombier 			block[nblock].free = strcmp(f[0], "free") == 0;
24159cc4ca5SDavid du Colombier 			nblock++;
24259cc4ca5SDavid du Colombier 		}
24380ee5cbfSDavid du Colombier 		if(nf >= 4 && strcmp(f[0], "range") == 0 && strcmp(f[1], "alloc") == 0) {
24480ee5cbfSDavid du Colombier 			allocstart = strtoul(f[2], 0, 0)&~15;
24580ee5cbfSDavid du Colombier 			allocend = strtoul(f[3], 0, 0);
24680ee5cbfSDavid du Colombier 		}
24759cc4ca5SDavid du Colombier 	}
24859cc4ca5SDavid du Colombier 
24959cc4ca5SDavid du Colombier 	qsort(block, nblock, sizeof(Block), addrcmp);
25059cc4ca5SDavid du Colombier 	qsort(data, ndata, sizeof(Data), addrcmp);
25159cc4ca5SDavid du Colombier 
25259cc4ca5SDavid du Colombier 	ed = edata = data+ndata;
25359cc4ca5SDavid du Colombier 	for(d=data; d<ed; d++) {
25459cc4ca5SDavid du Colombier 		if(d->type == 'a')
25559cc4ca5SDavid du Colombier 			continue;
25659cc4ca5SDavid du Colombier 		if(b = findblock(d->val-8))		// pool header 2 words
257fb7f0c93SDavid du Colombier 			n8 += markblock(d->addr, d->val, b);
25859cc4ca5SDavid du Colombier 		else if(b = findblock(d->val-8-8))	// sometimes malloc header 2 words
259fb7f0c93SDavid du Colombier 			n16 += markblock(d->addr, d->val, b);
26059cc4ca5SDavid du Colombier 		else
2619a747e4fSDavid du Colombier 			{}//print("noblock %.8lux\n", d->val);
26259cc4ca5SDavid du Colombier 	}
26359cc4ca5SDavid du Colombier 
26459cc4ca5SDavid du Colombier 	Binit(&bio, 1, OWRITE);
26580ee5cbfSDavid du Colombier 	if(bitmap){
26680ee5cbfSDavid du Colombier 		if(n8 > n16)		// guess size of header
26780ee5cbfSDavid du Colombier 			hdr = 8;
26880ee5cbfSDavid du Colombier 		else
26980ee5cbfSDavid du Colombier 			hdr = 16;
27080ee5cbfSDavid du Colombier 
27180ee5cbfSDavid du Colombier 		for(d=data; d<ed; d++)
27280ee5cbfSDavid du Colombier 			if(d->type=='a')
27380ee5cbfSDavid du Colombier 				break;
27480ee5cbfSDavid du Colombier 		if(d==ed)
27580ee5cbfSDavid du Colombier 			sysfatal("no allocated data region");
27680ee5cbfSDavid du Colombier 
27780ee5cbfSDavid du Colombier 		len = (allocend-allocstart+resolution-1)/resolution;
27880ee5cbfSDavid du Colombier 		y = (len+x-1)/x;
27980ee5cbfSDavid du Colombier 		Bprint(&bio, "%11s %11d %11d %11d %11d ", "m8", 0, 0, x, y);
28080ee5cbfSDavid du Colombier 
28180ee5cbfSDavid du Colombier //fprint(2, "alloc %lux %lux x %d y %d res %d\n", allocstart, allocend, x, y, resolution);
28280ee5cbfSDavid du Colombier 
28380ee5cbfSDavid du Colombier 		b = block;
28480ee5cbfSDavid du Colombier 		eb = block+nblock;
28580ee5cbfSDavid du Colombier 		for(u = allocstart; u<allocend; u+=resolution){
28680ee5cbfSDavid du Colombier //fprint(2, "u %lux %lux baddr %lux\n", u, u+resolution, b->addr);
28780ee5cbfSDavid du Colombier 			while(b->addr+b->size <= u && b < eb)
28880ee5cbfSDavid du Colombier //{
28980ee5cbfSDavid du Colombier //fprint(2, "\tskip %lux %lux\n", b->addr, b->addr+b->size);
29080ee5cbfSDavid du Colombier 				b++;
29180ee5cbfSDavid du Colombier //}
29280ee5cbfSDavid du Colombier 			nhdr = 0;
29380ee5cbfSDavid du Colombier 			nleak = 0;
29480ee5cbfSDavid du Colombier 			nb = 0;
29580ee5cbfSDavid du Colombier 			nlhdr = 0;
29680ee5cbfSDavid du Colombier 			if(block < b && u < (b-1)->addr+(b-1)->size)
29780ee5cbfSDavid du Colombier 				b--;
29880ee5cbfSDavid du Colombier 
29980ee5cbfSDavid du Colombier 			for(; b->addr < u+resolution && b < eb; b++){
30080ee5cbfSDavid du Colombier //fprint(2, "\tblock %lux %lux %d\n", b->addr, b->addr+b->size, b->mark);
30180ee5cbfSDavid du Colombier 				if(rXr(b->addr, b->addr+hdr, u, u+resolution)
30280ee5cbfSDavid du Colombier 				|| rXr(b->addr+b->size-8, b->addr+b->size, u, u+resolution)){
30341eff910SDavid du Colombier 					if(b->mark == 0 && !b->free)
30480ee5cbfSDavid du Colombier 						nlhdr++;
30580ee5cbfSDavid du Colombier 					else
30680ee5cbfSDavid du Colombier 						nhdr++;
30780ee5cbfSDavid du Colombier 				}
3086b8ae015SDavid du Colombier 				if(b->mark == 0 && !b->free)
30980ee5cbfSDavid du Colombier 					nleak++;
31080ee5cbfSDavid du Colombier 				nb++;
31180ee5cbfSDavid du Colombier 			}
31280ee5cbfSDavid du Colombier 			if(nhdr)
31380ee5cbfSDavid du Colombier 				c = HdrColor;
31480ee5cbfSDavid du Colombier 			else if(nlhdr)
31580ee5cbfSDavid du Colombier 				c = LeakHdrColor;
31680ee5cbfSDavid du Colombier 			else if(nleak)
31780ee5cbfSDavid du Colombier 				c = LeakColor;
31880ee5cbfSDavid du Colombier 			else if(nb)
31980ee5cbfSDavid du Colombier 				c = AllocColor;
32080ee5cbfSDavid du Colombier 			else
32180ee5cbfSDavid du Colombier 				c = FreeColor;
32280ee5cbfSDavid du Colombier //fprint(2, "\t%d\n", c);
32380ee5cbfSDavid du Colombier 			Bputc(&bio, c);
32480ee5cbfSDavid du Colombier 		}
32580ee5cbfSDavid du Colombier 		allocend = allocstart+x*y*resolution;
32680ee5cbfSDavid du Colombier 		for(; u < allocend; u+=resolution)
32780ee5cbfSDavid du Colombier 			Bputc(&bio, NoColor);
32880ee5cbfSDavid du Colombier 	}else{
32959cc4ca5SDavid du Colombier 		eb = block+nblock;
33059cc4ca5SDavid du Colombier 		for(b=block; b<eb; b++)
331fb7f0c93SDavid du Colombier 			if(b->mark == 0 && !b->free)
332d95be1c0SDavid du Colombier 				Bprint(&bio, "block 0x%.8lux 0x%.8lux 0x%.8lux 0x%.8lux %s %s\n", b->addr, b->size, b->w0, b->w1, b->s0, b->s1);
33380ee5cbfSDavid du Colombier 	}
33459cc4ca5SDavid du Colombier 	Bterm(&bio);
335*bfb6eab9SDavid du Colombier 	exits(nil);
33659cc4ca5SDavid du Colombier }
337