Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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