ref: fe53c0930e8595a2e8b5aa71e907a1f2bec6059b
dir: /sys/lib/acid/leak/
// // 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");