// // usage: acid -l pool -l leak // include("/sys/src/libc/port/pool.acid"); defn dumppool(p) { complex Pool p; a = p.arenalist; while a != 0 && a < 0x60000000 do { complex Arena a; dumparena(a); a = a.down; } } defn dumparena(arena) { local atail, b, nb; atail = A2TB(arena); complex Bhdr arena; b = a; while b < atail && b.magic != ARENATAIL_MAGIC do { dumpblock(b); nb = B2NB(b); if nb == b then { print("B2NB(", b\X, ") = b\n"); b = atail; // end loop } if nb > atail then { b = (Bhdr)(b+4); print("lost at block ", (b-4)\X, ", scanning forward\n"); while b < atail && b.magic != KEMPT_MAGIC && b.magic != FREE_MAGIC do b = (Bhdr)(b+4); print("stopped at ", b\X, " ", *b\X, "\n"); }else b = nb; } if b != atail then print("found wrong tail to arena ", arena\X, " wanted ", atail\X, "\n"); } defn isptr(a) { if end <= a && a < xbloc then return 1; if 0x7efff000 <= a && a < 0x7ffff000 then return 1; return 0; } defn dumpblock(addr) { complex Bhdr addr; if addr.magic == KEMPT_MAGIC || addr.magic == FREE_MAGIC then { local a, x, s; a = addr; complex Alloc a; x = addr+8; if addr.magic == KEMPT_MAGIC then s = "block"; else s = "free"; print(s, " ", addr\X, " ", a.size\X, " "); print(*(addr+8)\X, " ", *(addr+12)\X, "\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; if isptr(y) then print("data ", x\X, " ", y\X, " ", type, "\n"); x = x + 4; } } defn dumpmem() { local s; xbloc = *bloc; // assume map()[1] is "data" dumprange(map()[1][1], end, "bss"); // bss dumprange(end, xbloc, "alloc"); // allocated if 0x7efff000 < *SP && *SP < 0x7ffff000 then s = *SP; else s = 0x7fff7000; // 32 k dumprange(s, 0x7ffff000, "stack"); } defn dumpregs() { dumprange(0, sizeofUreg, "reg"); } defn leakdump(l) { print("==LEAK BEGIN==\n"); dumppool(sbrkmem); dumpmem(); dumpregs(); while l != {} do { setproc(head l); dumpregs(); l = tail l; } print("==LEAK END==\n"); } defn blockdump() { print("==BLOCK BEGIN==\n"); dumppool(sbrkmem); print("==BLOCK END==\n"); }