337 lines
6.4 KiB
C
337 lines
6.4 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
|
|
void*
|
|
emalloc(ulong sz)
|
|
{
|
|
void *v;
|
|
|
|
v = malloc(sz);
|
|
if(v == nil)
|
|
sysfatal("malloc %lud fails", sz);
|
|
memset(v, 0, sz);
|
|
return v;
|
|
}
|
|
|
|
void*
|
|
erealloc(void *v, ulong sz)
|
|
{
|
|
v = realloc(v, sz);
|
|
if(v == nil)
|
|
sysfatal("realloc %lud fails", sz);
|
|
return v;
|
|
}
|
|
|
|
char*
|
|
estrdup(char* s)
|
|
{
|
|
char *r;
|
|
|
|
r = strdup(s);
|
|
if(r == nil)
|
|
sysfatal("strdup fails");
|
|
return r;
|
|
}
|
|
|
|
typedef struct Block Block;
|
|
typedef struct Data Data;
|
|
struct Block {
|
|
ulong addr;
|
|
ulong size;
|
|
ulong w0;
|
|
ulong w1;
|
|
char *s0;
|
|
char *s1;
|
|
int mark;
|
|
int free;
|
|
Data *d;
|
|
};
|
|
|
|
struct Data {
|
|
ulong addr;
|
|
ulong val;
|
|
uchar type;
|
|
Block *b;
|
|
};
|
|
|
|
Block *block;
|
|
uint nblock;
|
|
uint ablock;
|
|
|
|
Data *data;
|
|
Data *edata;
|
|
uint ndata;
|
|
uint adata;
|
|
|
|
int
|
|
addrcmp(void *va, void *vb)
|
|
{
|
|
ulong *a, *b;
|
|
|
|
a = va;
|
|
b = vb;
|
|
if(*a < *b)
|
|
return -1;
|
|
if(*a > *b)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
Block*
|
|
findblock(ulong addr)
|
|
{
|
|
int lo, hi, m;
|
|
|
|
lo = 0;
|
|
hi = nblock;
|
|
|
|
while(lo < hi) {
|
|
m = (lo+hi)/2;
|
|
if(block[m].addr < addr)
|
|
lo = m+1;
|
|
else if(addr < block[m].addr)
|
|
hi = m;
|
|
else
|
|
return &block[m];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
Data*
|
|
finddata(ulong addr)
|
|
{
|
|
int lo, hi, m;
|
|
|
|
lo = 0;
|
|
hi = ndata;
|
|
|
|
while(lo < hi) {
|
|
m = (lo+hi)/2;
|
|
if(data[m].addr < addr)
|
|
lo = m+1;
|
|
else if(addr < data[m].addr)
|
|
hi = m;
|
|
else
|
|
return &data[m];
|
|
}
|
|
if(0 <= lo && lo < ndata)
|
|
return &data[lo];
|
|
return nil;
|
|
}
|
|
|
|
int nmark;
|
|
|
|
int
|
|
markblock(ulong from, ulong fromval, Block *b)
|
|
{
|
|
Data *d;
|
|
ulong top;
|
|
Block *nb;
|
|
|
|
USED(from, fromval);
|
|
//print("trace 0x%.8lux from 0x%.8lux (%d)\n", b->addr, from, b->mark);
|
|
if(b->free){
|
|
// fprint(2, "possible dangling pointer *0x%.8lux = 0x%.8lux\n", from, fromval);
|
|
return 0;
|
|
}
|
|
if(b->mark)
|
|
return 0;
|
|
b->mark = 1;
|
|
nmark++;
|
|
|
|
if(d = finddata(b->addr)) {
|
|
assert(d->addr >= b->addr);
|
|
b->d = d;
|
|
top = b->addr+b->size;
|
|
for(; d < edata && d->addr < top; d++) {
|
|
assert(d->b == 0);
|
|
d->b = b;
|
|
if((nb = findblock(d->val-8)) || (nb = findblock(d->val-8-8)))
|
|
markblock(d->addr, d->val, nb);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
enum {
|
|
AllocColor = 2, // dark blue: completely allocated region
|
|
HdrColor = 54, // bright blue: region with header
|
|
LeakColor = 205, // dark red: region with leak
|
|
LeakHdrColor = 240, // bright red: region with leaked header
|
|
FreeColor = 252, // bright yellow: completely free region
|
|
NoColor = 255, // padding, white
|
|
};
|
|
|
|
int
|
|
rXr(int as, int ae, int bs, int be)
|
|
{
|
|
return bs < ae && as < be;
|
|
}
|
|
|
|
void
|
|
main(int argc, char **argv)
|
|
{
|
|
Biobuf bio;
|
|
char *p, *f[10];
|
|
int bitmap, c, nf, resolution, n8, n16, hdr, nhdr, nlhdr, nleak, x, y, nb;
|
|
ulong allocstart, allocend, len, u;
|
|
Data *d, *ed;
|
|
Block *b, *eb;
|
|
|
|
bitmap = 0;
|
|
resolution = 8;
|
|
x = 512;
|
|
ARGBEGIN{
|
|
case 'b':
|
|
bitmap=1;
|
|
break;
|
|
case 'r':
|
|
resolution = atoi(EARGF(sysfatal("usage")));
|
|
break;
|
|
case 'x':
|
|
x = atoi(EARGF(sysfatal("usage")));
|
|
break;
|
|
}ARGEND
|
|
|
|
n8 = n16 = 0;
|
|
allocstart = allocend = 0;
|
|
Binit(&bio, 0, OREAD);
|
|
while(p=Brdline(&bio, '\n')) {
|
|
p[Blinelen(&bio)-1] = '\0';
|
|
nf = tokenize(p, f, nelem(f));
|
|
if(nf >= 4 && strcmp(f[0], "data") == 0) {
|
|
if(ndata >= adata){
|
|
if(adata == 0)
|
|
adata = 4096;
|
|
else
|
|
adata += adata / 4; /* increase 25% */
|
|
data = erealloc(data, adata * sizeof(Data));
|
|
}
|
|
data[ndata].addr = strtoul(f[1], nil, 0);
|
|
data[ndata].val = strtoul(f[2], nil, 0);
|
|
data[ndata].type = f[3][0];
|
|
data[ndata].b = 0;
|
|
ndata++;
|
|
}
|
|
if(nf >= 5 &&
|
|
(strcmp(f[0], "block") == 0 || strcmp(f[0], "free") == 0)) {
|
|
if(nblock >= ablock){
|
|
if(ablock == 0)
|
|
ablock = 4096;
|
|
else
|
|
ablock += ablock / 4; /* increase 25% */
|
|
block = erealloc(block, ablock * sizeof(Block));
|
|
}
|
|
block[nblock].addr = strtoul(f[1], nil, 0);
|
|
block[nblock].size = strtoul(f[2], nil, 0);
|
|
block[nblock].w0 = strtoul(f[3], nil, 0);
|
|
block[nblock].w1 = strtoul(f[4], nil, 0);
|
|
if (nf >= 7) {
|
|
block[nblock].s0 = estrdup(f[5]);
|
|
block[nblock].s1 = estrdup(f[6]);
|
|
} else {
|
|
block[nblock].s0 = "";
|
|
block[nblock].s1 = "";
|
|
}
|
|
block[nblock].mark = 0;
|
|
block[nblock].d = 0;
|
|
block[nblock].free = strcmp(f[0], "free") == 0;
|
|
nblock++;
|
|
}
|
|
if(nf >= 4 && strcmp(f[0], "range") == 0 && strcmp(f[1], "alloc") == 0) {
|
|
allocstart = strtoul(f[2], 0, 0)&~15;
|
|
allocend = strtoul(f[3], 0, 0);
|
|
}
|
|
}
|
|
|
|
qsort(block, nblock, sizeof(Block), addrcmp);
|
|
qsort(data, ndata, sizeof(Data), addrcmp);
|
|
|
|
ed = edata = data+ndata;
|
|
for(d=data; d<ed; d++) {
|
|
if(d->type == 'a')
|
|
continue;
|
|
if(b = findblock(d->val-8)) // pool header 2 words
|
|
n8 += markblock(d->addr, d->val, b);
|
|
else if(b = findblock(d->val-8-8)) // sometimes malloc header 2 words
|
|
n16 += markblock(d->addr, d->val, b);
|
|
else
|
|
{}//print("noblock %.8lux\n", d->val);
|
|
}
|
|
|
|
Binit(&bio, 1, OWRITE);
|
|
if(bitmap){
|
|
if(n8 > n16) // guess size of header
|
|
hdr = 8;
|
|
else
|
|
hdr = 16;
|
|
|
|
for(d=data; d<ed; d++)
|
|
if(d->type=='a')
|
|
break;
|
|
if(d==ed)
|
|
sysfatal("no allocated data region");
|
|
|
|
len = (allocend-allocstart+resolution-1)/resolution;
|
|
y = (len+x-1)/x;
|
|
Bprint(&bio, "%11s %11d %11d %11d %11d ", "m8", 0, 0, x, y);
|
|
|
|
//fprint(2, "alloc %lux %lux x %d y %d res %d\n", allocstart, allocend, x, y, resolution);
|
|
|
|
b = block;
|
|
eb = block+nblock;
|
|
for(u = allocstart; u<allocend; u+=resolution){
|
|
//fprint(2, "u %lux %lux baddr %lux\n", u, u+resolution, b->addr);
|
|
while(b->addr+b->size <= u && b < eb)
|
|
//{
|
|
//fprint(2, "\tskip %lux %lux\n", b->addr, b->addr+b->size);
|
|
b++;
|
|
//}
|
|
nhdr = 0;
|
|
nleak = 0;
|
|
nb = 0;
|
|
nlhdr = 0;
|
|
if(block < b && u < (b-1)->addr+(b-1)->size)
|
|
b--;
|
|
|
|
for(; b->addr < u+resolution && b < eb; b++){
|
|
//fprint(2, "\tblock %lux %lux %d\n", b->addr, b->addr+b->size, b->mark);
|
|
if(rXr(b->addr, b->addr+hdr, u, u+resolution)
|
|
|| rXr(b->addr+b->size-8, b->addr+b->size, u, u+resolution)){
|
|
if(b->mark == 0 && !b->free)
|
|
nlhdr++;
|
|
else
|
|
nhdr++;
|
|
}
|
|
if(b->mark == 0 && !b->free)
|
|
nleak++;
|
|
nb++;
|
|
}
|
|
if(nhdr)
|
|
c = HdrColor;
|
|
else if(nlhdr)
|
|
c = LeakHdrColor;
|
|
else if(nleak)
|
|
c = LeakColor;
|
|
else if(nb)
|
|
c = AllocColor;
|
|
else
|
|
c = FreeColor;
|
|
//fprint(2, "\t%d\n", c);
|
|
Bputc(&bio, c);
|
|
}
|
|
allocend = allocstart+x*y*resolution;
|
|
for(; u < allocend; u+=resolution)
|
|
Bputc(&bio, NoColor);
|
|
}else{
|
|
eb = block+nblock;
|
|
for(b=block; b<eb; b++)
|
|
if(b->mark == 0 && !b->free)
|
|
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);
|
|
}
|
|
Bterm(&bio);
|
|
exits(nil);
|
|
}
|