From 64b491a3058052d47c7ad36f81c0cb14cfebcdbe Mon Sep 17 00:00:00 2001 From: "kipp%netscape.com" Date: Sun, 26 Sep 1999 06:31:18 +0000 Subject: [PATCH] Whacked to support a graph display format git-svn-id: svn://10.0.0.236/trunk@49081 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/tools/leaky/bfd.cpp | 3 +- mozilla/tools/leaky/config.h | 2 +- mozilla/tools/leaky/dict.h | 32 +- mozilla/tools/leaky/leaky.cpp | 774 ++++++++++++++++++++++------------ mozilla/tools/leaky/leaky.h | 53 ++- 5 files changed, 573 insertions(+), 291 deletions(-) diff --git a/mozilla/tools/leaky/bfd.cpp b/mozilla/tools/leaky/bfd.cpp index 2d067284093..761d48f62b0 100644 --- a/mozilla/tools/leaky/bfd.cpp +++ b/mozilla/tools/leaky/bfd.cpp @@ -72,8 +72,7 @@ void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress) if (nm) { // char* dnm = cplus_demangle(nm, 1); // sp->name = dnm ? dnm : strdup(nm); - sp->name = strdup(nm); - sp->address = syminfo.value + aBaseAddress; + sp->Init(nm, syminfo.value + aBaseAddress); sp++; if (sp >= last) { long n = numExternalSymbols + 10000; diff --git a/mozilla/tools/leaky/config.h b/mozilla/tools/leaky/config.h index ef50248fd7c..7a6be7d13ed 100644 --- a/mozilla/tools/leaky/config.h +++ b/mozilla/tools/leaky/config.h @@ -12,7 +12,7 @@ #ifndef config_h___ #define config_h___ -#define MAX_STACK_CRAWL 30 +#define MAX_STACK_CRAWL 100 #include diff --git a/mozilla/tools/leaky/dict.h b/mozilla/tools/leaky/dict.h index 5f4f822b381..4b568314835 100644 --- a/mozilla/tools/leaky/dict.h +++ b/mozilla/tools/leaky/dict.h @@ -16,26 +16,28 @@ #include #include "libmalloc.h" -// key is u_long value is malloc_log_entry* +// key is u_long +// value is malloc_log_entry* struct MallocDict { - MallocDict(int buckets); + MallocDict(int buckets); - void rewind(void); - malloc_log_entry* next(void); + void rewind(void); + malloc_log_entry* next(void); - malloc_log_entry** find(u_long addr); - void add(u_long addr, malloc_log_entry *log); - void remove(u_long addr); + malloc_log_entry** find(u_long addr); + void add(u_long addr, malloc_log_entry *log); + void remove(u_long addr); - struct MallocDictEntry { - u_long addr; - malloc_log_entry* logEntry; - MallocDictEntry* next; - } **buckets; - int numBuckets; + struct MallocDictEntry { + u_long addr; + malloc_log_entry* logEntry; + MallocDictEntry* next; + } **buckets; - int iterNextBucket; - MallocDictEntry* iterNextEntry; + int numBuckets; + + int iterNextBucket; + MallocDictEntry* iterNextEntry; }; #endif /* __dict_h_ */ diff --git a/mozilla/tools/leaky/leaky.cpp b/mozilla/tools/leaky/leaky.cpp index 6e53284c2c6..bd6acb36013 100644 --- a/mozilla/tools/leaky/leaky.cpp +++ b/mozilla/tools/leaky/leaky.cpp @@ -38,142 +38,146 @@ static const u_int MaxBuckets = 1000003; // arbitrary, but prime int main(int argc, char** argv) { - leaky* l = new leaky; + leaky* l = new leaky; - l->initialize(argc, argv); - l->open(); - return 0; + l->initialize(argc, argv); + l->open(); + return 0; } leaky::leaky() { - applicationName = NULL; - logFile = NULL; - progFile = NULL; + applicationName = NULL; + logFile = NULL; + progFile = NULL; - treeOutput = FALSE; - sortByFrequency = FALSE; - dumpAll = FALSE; - quiet = FALSE; - showAll = FALSE; - showAddress = FALSE; - stackDepth = 100000; + sortByFrequency = FALSE; + dumpAll = FALSE; + dumpGraph = FALSE; + dumpXML = FALSE; + quiet = FALSE; + showAll = FALSE; + showAddress = FALSE; + stackDepth = 100000; - fd = -1; - base = last = 0; - buckets = DefaultBuckets; - dict = 0; + fd = -1; + base = last = 0; + buckets = DefaultBuckets; + dict = 0; - mallocs = 0; - reallocs = 0; - frees = 0; - totalMalloced = 0; - errors = 0; - totalLeaked = 0; + mallocs = 0; + reallocs = 0; + frees = 0; + totalMalloced = 0; + errors = 0; + totalLeaked = 0; - sfd = -1; - externalSymbols = 0; - usefulSymbols = 0; - numExternalSymbols = 0; - lowestSymbolAddr = 0; - highestSymbolAddr = 0; + sfd = -1; + externalSymbols = 0; + usefulSymbols = 0; + numExternalSymbols = 0; + lowestSymbolAddr = 0; + highestSymbolAddr = 0; - loadMap = NULL; + loadMap = NULL; } leaky::~leaky() { - delete dict; + delete dict; } void leaky::usageError() { - fprintf(stderr, - "Usage: %s [-d|-t] [-e name] [-aAEfq] [-s depth] [-h hash-buckets] prog log\n", - (char*) applicationName); - exit(-1); + fprintf(stderr, + "Usage: %s [-aAEdfgqx] [-e name] [-s depth] [-h hash-buckets] prog log\n", + (char*) applicationName); + exit(-1); } void leaky::initialize(int argc, char** argv) { + applicationName = argv[0]; + applicationName = strrchr(applicationName, '/'); + if (!applicationName) { applicationName = argv[0]; - applicationName = strrchr(applicationName, '/'); - if (!applicationName) { - applicationName = argv[0]; - } else { - applicationName++; - } + } else { + applicationName++; + } - int arg; - int errflg = 0; - while ((arg = getopt(argc, argv, "adEe:fh:s:tq")) != -1) { - switch (arg) { - case '?': - errflg++; - break; - case 'a': - showAll = TRUE; - break; - case 'A': - showAddress = TRUE; - break; - case 'd': - dumpAll = TRUE; - if (treeOutput) errflg++; - break; - case 'e': - exclusions.add(optarg); - break; - case 'f': - sortByFrequency = TRUE; - break; - case 'h': - buckets = atoi(optarg); - if ((buckets < 0) || (buckets > MaxBuckets)) { - buckets = MaxBuckets; - fprintf(stderr, "%s: buckets is invalid, using %d\n", - (char*) applicationName, - buckets); - } - break; - case 's': - stackDepth = atoi(optarg); - if (stackDepth < 2) { - stackDepth = 2; - } - break; - case 't': - treeOutput = TRUE; - if (dumpAll) errflg++; - break; - case 'q': - quiet = TRUE; - break; + int arg; + int errflg = 0; + while ((arg = getopt(argc, argv, "adEe:fgh:s:tqx")) != -1) { + switch (arg) { + case '?': + errflg++; + break; + case 'a': + showAll = TRUE; + break; + case 'A': + showAddress = TRUE; + break; + case 'd': + dumpAll = TRUE; + if (dumpGraph) errflg++; + break; + case 'e': + exclusions.add(optarg); + break; + case 'f': + sortByFrequency = TRUE; + break; + case 'g': + dumpGraph = TRUE; + if (dumpAll) errflg++; + break; + case 'h': + buckets = atoi(optarg); + if ((buckets < 0) || (buckets > MaxBuckets)) { + buckets = MaxBuckets; + fprintf(stderr, "%s: buckets is invalid, using %d\n", + (char*) applicationName, + buckets); } + break; + case 's': + stackDepth = atoi(optarg); + if (stackDepth < 2) { + stackDepth = 2; + } + break; + case 'x': + dumpXML = TRUE; + break; + case 'q': + quiet = TRUE; + break; } - if (errflg || ((argc - optind) < 2)) { - usageError(); - } - progFile = argv[optind++]; - logFile = argv[optind]; + } + if (errflg || ((argc - optind) < 2)) { + usageError(); + } + progFile = argv[optind++]; + logFile = argv[optind]; - dict = new MallocDict(buckets); + dict = new MallocDict(buckets); } static void* mapFile(int fd, u_int flags, off_t* sz) { - struct stat sb; - if (fstat(fd, &sb) < 0) { - perror("fstat"); - exit(-1); - } - void* base = mmap(0, (int)sb.st_size, flags, MAP_PRIVATE, fd, 0); - if (!base) { - perror("mmap"); - exit(-1); - } - *sz = sb.st_size; - return base; + struct stat sb; + if (fstat(fd, &sb) < 0) { + perror("fstat"); + exit(-1); + } + void* base = mmap(0, (int)sb.st_size, flags, MAP_PRIVATE, fd, 0); + if (!base) { + perror("mmap"); + exit(-1); + } + *sz = sb.st_size; + return base; } void leaky::LoadMap() @@ -207,27 +211,30 @@ void leaky::LoadMap() void leaky::open() { - LoadMap(); + LoadMap(); - setupSymbols(progFile); + setupSymbols(progFile); - // open up the log file - fd = ::open(logFile, O_RDONLY); - if (fd < 0) { - perror("open"); - exit(-1); - } - off_t size; - base = (malloc_log_entry*) mapFile(fd, PROT_READ, &size); - last = (malloc_log_entry*)((char*)base + size); + // open up the log file + fd = ::open(logFile, O_RDONLY); + if (fd < 0) { + perror("open"); + exit(-1); + } + off_t size; + base = (malloc_log_entry*) mapFile(fd, PROT_READ, &size); + last = (malloc_log_entry*)((char*)base + size); - analyze(); + analyze(); - if (dumpAll) dumpLog(); -#if 0 - if (treeOutput) dumpToTree(); -#endif - exit(0); + if (dumpAll) { + dumpLog(); + } + else if (dumpGraph) { + buildLeakGraph(); + dumpLeakGraph(); + } + exit(0); } //---------------------------------------------------------------------- @@ -235,9 +242,9 @@ void leaky::open() static ptrdiff_t symbolOrder(void const* a, void const* b) { - Symbol const* ap = (Symbol const *)a; - Symbol const* bp = (Symbol const *)b; - return ap->address - bp->address; + Symbol const* ap = (Symbol const *)a; + Symbol const* bp = (Symbol const *)b; + return ap->address - bp->address; } void leaky::ReadSharedLibrarySymbols() @@ -251,93 +258,92 @@ void leaky::ReadSharedLibrarySymbols() void leaky::setupSymbols(const char *fileName) { - // Read in symbols from the program - ReadSymbols(fileName, 0); + // Read in symbols from the program + ReadSymbols(fileName, 0); - // Read in symbols from the .so's - ReadSharedLibrarySymbols(); + // Read in symbols from the .so's + ReadSharedLibrarySymbols(); - if (!quiet) { - printf("A total of %d symbols were loaded\n", usefulSymbols); - } + if (!quiet) { + printf("A total of %d symbols were loaded\n", usefulSymbols); + } - // Now sort them - qsort(externalSymbols, usefulSymbols, sizeof(Symbol), symbolOrder); - lowestSymbolAddr = externalSymbols[0].address; - highestSymbolAddr = externalSymbols[usefulSymbols-1].address; + // Now sort them + qsort(externalSymbols, usefulSymbols, sizeof(Symbol), symbolOrder); + lowestSymbolAddr = externalSymbols[0].address; + highestSymbolAddr = externalSymbols[usefulSymbols-1].address; } -char const* leaky::findSymbol(u_long addr) +// Binary search the table, looking for a symbol that covers this +// address. +Symbol* leaky::findSymbol(u_long addr) { - if ((addr < lowestSymbolAddr) || - (addr > highestSymbolAddr)) { - static char buf[20]; - sprintf(buf, "<0x%lx>", addr); - return buf; - } - - // binary search the table, looking for a symbol that covers this - // address. - u_int base = 0; - u_int limit = usefulSymbols - 1; - Symbol* end = &externalSymbols[limit]; - while (base <= limit) { - u_int midPoint = (base + limit)>>1; - Symbol* sp = &externalSymbols[midPoint]; - if (addr < sp->address) { - if (midPoint == 0) { - return 0; - } - limit = midPoint - 1; - } else { - if (sp+1 < end) { - if (addr < (sp+1)->address) { - return sp->name; - } - } else { - return sp->name; - } - base = midPoint + 1; + u_int base = 0; + u_int limit = usefulSymbols - 1; + Symbol* end = &externalSymbols[limit]; + while (base <= limit) { + u_int midPoint = (base + limit)>>1; + Symbol* sp = &externalSymbols[midPoint]; + if (addr < sp->address) { + if (midPoint == 0) { + return NULL; + } + limit = midPoint - 1; + } else { + if (sp+1 < end) { + if (addr < (sp+1)->address) { + return sp; } + } else { + return sp; + } + base = midPoint + 1; } - - return 0; + } + return NULL; } //---------------------------------------------------------------------- int leaky::excluded(malloc_log_entry* lep) { - char** pcp = &lep->pcs[0]; - u_int n = lep->numpcs; - for (u_int i = 0; i < n; i++, pcp++) { - char const* sym = findSymbol((u_long) *pcp); - if (exclusions.contains(sym)) { - return TRUE; - } + char** pcp = &lep->pcs[0]; + u_int n = lep->numpcs; + for (u_int i = 0; i < n; i++, pcp++) { + Symbol* sp = findSymbol((u_long) *pcp); + if (sp && exclusions.contains(sp->name)) { + return TRUE; } - return FALSE; + } + return FALSE; } //---------------------------------------------------------------------- void leaky::displayStackTrace(malloc_log_entry* lep) { - char** pcp = &lep->pcs[0]; - u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; - for (u_int i = 0; i < n; i++, pcp++) { - char const* sym = findSymbol((u_long) *pcp); - if (!sym) { - break; - } - if (showAddress) { - printf("%s[%p] ", sym, *pcp); - } - else { - printf("%s ", sym); - } + char** pcp = &lep->pcs[0]; + u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; + for (u_int i = 0; i < n; i++, pcp++) { + u_long addr = (u_long) *pcp; + static char buf[20]; + char* symbolName; + Symbol* sp = findSymbol(addr); + if (sp) { + symbolName = sp->name; } - printf("\n"); + else { + sprintf(buf, "<0x%lx>", addr); + symbolName = buf; + } + if (showAddress) { + printf("%s[%p] ", symbolName, *pcp); + } + else { + printf("%s ", symbolName); + } + } + printf("\n"); } char* typeFromLog[] = { @@ -352,109 +358,337 @@ char* typeFromLog[] = { void leaky::dumpEntryToLog(malloc_log_entry* lep) { - printf("%-10s %08lx %5ld %08lx (%ld)-->", - typeFromLog[lep->type], - lep->address, lep->size, lep->oldaddress, - lep->numpcs); - displayStackTrace(lep); + printf("%-10s %08lx %5ld %08lx (%ld)-->", + typeFromLog[lep->type], + lep->address, lep->size, lep->oldaddress, + lep->numpcs); + displayStackTrace(lep); } void leaky::dumpLog() { - if (showAll) { - malloc_log_entry* lep = base; - while (lep < last) { - dumpEntryToLog(lep); - lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; - } - } else { - malloc_log_entry* lep; - dict->rewind(); - while (NULL != (lep = dict->next())) { - if (!excluded(lep)) { - dumpEntryToLog(lep); - } - } + if (showAll) { + malloc_log_entry* lep = base; + while (lep < last) { + dumpEntryToLog(lep); + lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; } + } else { + malloc_log_entry* lep; + dict->rewind(); + while (NULL != (lep = dict->next())) { + if (!excluded(lep)) { + dumpEntryToLog(lep); + } + } + } } //---------------------------------------------------------------------- void leaky::insertAddress(u_long address, malloc_log_entry* lep) { - malloc_log_entry** lepp = dict->find(address); - if (lepp) { - assert(*lepp); - if (!quiet) { - printf("Address %lx allocated twice\n", address); - displayStackTrace(lep); - } - errors++; - } else { - dict->add(address, lep); + malloc_log_entry** lepp = dict->find(address); + if (lepp) { + assert(*lepp); + if (!quiet) { + printf("Address %lx allocated twice\n", address); + displayStackTrace(lep); } + errors++; + } else { + dict->add(address, lep); + } } void leaky::removeAddress(u_long address, malloc_log_entry* lep) { - malloc_log_entry** lepp = dict->find(address); - if (!lepp) { - if (!quiet) { - printf("Free of unallocated %lx\n", address); - displayStackTrace(lep); - } - errors++; - } else { - dict->remove(address); + malloc_log_entry** lepp = dict->find(address); + if (!lepp) { + if (!quiet) { + printf("Free of unallocated %lx\n", address); + displayStackTrace(lep); } + errors++; + } else { + dict->remove(address); + } } void leaky::analyze() { - malloc_log_entry* lep = base; - while (lep < last) { - switch (lep->type) { - case malloc_log_malloc: - case malloc_log_new: - mallocs++; - if (lep->address) { - totalMalloced += lep->size; - insertAddress((u_long) lep->address, lep); - } - break; - case malloc_log_realloc: - if (lep->oldaddress) { - removeAddress((u_long) lep->oldaddress, lep); - } - if (lep->address) { - insertAddress((u_long) lep->address, lep); - } - reallocs++; - break; - case malloc_log_free: - case malloc_log_delete: - if (lep->address) { - removeAddress((u_long) lep->address, lep); - } - frees++; - break; + malloc_log_entry* lep = base; + while (lep < last) { + switch (lep->type) { + case malloc_log_malloc: + case malloc_log_new: + mallocs++; + if (lep->address) { + totalMalloced += lep->size; + insertAddress((u_long) lep->address, lep); } - lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; - } + break; - dict->rewind(); - while (NULL != (lep = dict->next())) { - totalLeaked += lep->size; - } + case malloc_log_realloc: + if (lep->oldaddress) { + removeAddress((u_long) lep->oldaddress, lep); + } + if (lep->address) { + insertAddress((u_long) lep->address, lep); + } + reallocs++; + break; - if (!quiet) { - printf("# of mallocs = %ld\n", mallocs); - printf("# of reallocs = %ld\n", reallocs); - printf("# of frees = %ld\n", frees); - printf("# of errors = %ld\n", errors); - printf("Total bytes allocated = %ld\n", totalMalloced); - printf("Total bytes leaked = %ld\n", totalLeaked); - printf("Average bytes per malloc = %g\n", - float(totalMalloced)/mallocs); + case malloc_log_free: + case malloc_log_delete: + if (lep->address) { + removeAddress((u_long) lep->address, lep); + } + frees++; + break; } + lep = (malloc_log_entry*) &lep->pcs[lep->numpcs]; + } + + dict->rewind(); + while (NULL != (lep = dict->next())) { + totalLeaked += lep->size; + } + + if (!quiet) { + printf("# of mallocs = %ld\n", mallocs); + printf("# of reallocs = %ld\n", reallocs); + printf("# of frees = %ld\n", frees); + printf("# of errors = %ld\n", errors); + printf("Total bytes allocated = %ld\n", totalMalloced); + printf("Total bytes leaked = %ld\n", totalLeaked); + printf("Average bytes per malloc = %g\n", + float(totalMalloced)/mallocs); + } } + +void leaky::buildLeakGraph() +{ + // For each leak + malloc_log_entry* lep; + dict->rewind(); + while (NULL != (lep = dict->next())) { + Symbol* prevSymbol = NULL; + + // For each pc in the leak + char** pcp = &lep->pcs[0]; + u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; + for (u_int i = 0; i < n; i++, pcp++) { + Symbol* currentSymbol = findSymbol((u_long) *pcp); + if (currentSymbol) { + currentSymbol->leaker = true; + currentSymbol->calls++; + if (i == 0) { + currentSymbol->bytesDirectlyLeaked += lep->size; + } + else { + currentSymbol->childBytesLeaked += lep->size; + } + if (prevSymbol) { + currentSymbol->AddChild(prevSymbol); + prevSymbol->AddParent(currentSymbol); + } + } + prevSymbol = currentSymbol; + } + } +} + +Symbol* leaky::findLeakGraphRoot(Symbol* aStart, Symbol* aEnd) +{ + while (aStart < aEnd) { + if (aStart->leaker && !aStart->parents) { + return aStart; + } + aStart++; + } + return NULL; +} + +void leaky::dumpLeakGraph() +{ + if (dumpXML) { +#ifdef USE_XML + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("Key:\n"); + printf("Bytes directly leaked\n"); + printf("Bytes leaked by descendants\n"); +#else + printf("Leaky Graph\n"); + printf("\n"); + printf("\n"); + printf("
\n"); + printf("Key:
\n"); + printf("Bytes directly leaked
\n"); + printf("Bytes leaked by descendants
\n"); +#endif + } + Symbol* base = externalSymbols; + Symbol* end = externalSymbols + usefulSymbols; + while (base < end) { + Symbol* root = findLeakGraphRoot(base, end); + if (!root) break; + if (root->NotDumped()) { + root->SetDumped(); + dumpLeakTree(root, 0, true); + } + base = root + 1; + } + if (dumpXML) { +#ifdef USE_XML + printf("
\n"); +#else + printf("\n"); +#endif + } +} + +void leaky::dumpLeakTree(Symbol* aSymbol, int aIndent, bool aEven) +{ +#if 0 + float avgBytesLeaked = + (float) (aSymbol->bytesDirectlyLeaked + aSymbol->childBytesLeaked) / + (float) aSymbol->calls; +#endif + + bool haveVisibleDescendants = false; + SymbolNode* node = aSymbol->children; + while (node) { + Symbol* kid = node->symbol; + if (kid && kid->NotDumped()) { + haveVisibleDescendants = true; + break; + } + node = node->next; + } + + if (dumpXML) { +#ifdef USE_XML + printf("", aEven ? "e" : "o"); + if (haveVisibleDescendants) { + printf("" + aIndent > 1 ? "close" : "open"); + } + printf("%s%ld%ld\n", + aSymbol->name, + aSymbol->bytesDirectlyLeaked, + aSymbol->childBytesLeaked); +#else + printf("
\n", aEven ? 'e' : 'o'); + if (haveVisibleDescendants) { + printf("", + aIndent > 1 ? "close" : "open"); + } + printf("%s%ld%ld\n", + aSymbol->name, + aSymbol->bytesDirectlyLeaked, + aSymbol->childBytesLeaked); +#endif + } + else { + indentBy(aIndent); + printf("%s bytesLeaked=%ld (%ld from kids)\n", + aSymbol->name, + aSymbol->bytesDirectlyLeaked, + aSymbol->childBytesLeaked); + } + + node = aSymbol->children; + int kidNum = 0; + while (node) { + Symbol* kid = node->symbol; + if (kid && kid->NotDumped()) { + kid->SetDumped(); + dumpLeakTree(kid, aIndent + 1, 0 == (kidNum & 1)); + kidNum++; + } + node = node->next; + } + + if (dumpXML) { +#ifdef USE_XML + printf(""); +#else + printf("
"); +#endif + } +} + +//---------------------------------------------------------------------- + +SymbolNode* SymbolNode::freeList; + +void* SymbolNode::operator new(size_t size) +{ + if (!freeList) { + SymbolNode* newNodes = (SymbolNode*) new char[sizeof(SymbolNode) * 5000]; + if (!newNodes) { + return NULL; + } + SymbolNode* n = newNodes; + SymbolNode* end = newNodes + 5000 - 1; + while (n < end) { + n->next = n + 1; + n++; + } + n->next = NULL; + freeList = newNodes; + } + + SymbolNode* rv = freeList; + freeList = rv->next; + + return (void*) rv; +} + +void SymbolNode::operator delete(void* ptr) +{ + SymbolNode* node = (SymbolNode*) ptr; + if (node) { + node->next = freeList; + freeList = node; + } +} + +//---------------------------------------------------------------------- + +void Symbol::Init(const char* aName, u_long aAddress) +{ + name = aName ? strdup(aName) : ""; + address = aAddress; + dumped = false; + leaker = false; + calls = 0; + parents = NULL; + children = NULL; + bytesDirectlyLeaked = 0; + childBytesLeaked = 0; +} + +void Symbol::AddParent(Symbol* aParent) +{ + SymbolNode* node = new SymbolNode(aParent); + if (node) { + node->next = parents; + parents = node; + } +} + +void Symbol::AddChild(Symbol* aChild) +{ + SymbolNode* node = new SymbolNode(aChild); + if (node) { + node->next = children; + children = node; + } +} + diff --git a/mozilla/tools/leaky/leaky.h b/mozilla/tools/leaky/leaky.h index f41284ad40b..c2921afbf55 100644 --- a/mozilla/tools/leaky/leaky.h +++ b/mozilla/tools/leaky/leaky.h @@ -14,15 +14,52 @@ #define __leaky_h_ #include "config.h" +#include #include #include "dict.h" #include "strset.h" typedef unsigned int u_int; +struct Symbol; + +struct SymbolNode { + SymbolNode(Symbol* aSymbol) { + symbol = aSymbol; + next = NULL; + } + + void* operator new(size_t size); + void operator delete(void* ptr); + + Symbol* symbol; + SymbolNode* next; + + static SymbolNode* freeList; +}; + struct Symbol { - char *name; + char* name; u_long address; + bool dumped; + bool leaker; + u_long calls; + SymbolNode* parents; + SymbolNode* children; + u_long bytesDirectlyLeaked; + u_long childBytesLeaked; + + bool NotDumped() const { + return 0 == dumped; + } + + void SetDumped() { + dumped = 1; + } + + void Init(const char* aName, u_long aAddress); + void AddParent(Symbol* aParent); + void AddChild(Symbol* aChild); }; struct LoadMapEntry { @@ -42,9 +79,10 @@ struct leaky { char* logFile; char* progFile; - int treeOutput; int sortByFrequency; int dumpAll; + int dumpGraph; + int dumpXML; int quiet; int showAll; int showAddress; @@ -95,8 +133,17 @@ struct leaky { void ReadSymbols(const char* fileName, u_long aBaseAddress); void ReadSharedLibrarySymbols(); void setupSymbols(const char* fileName); - char const* findSymbol(u_long address); + Symbol* findSymbol(u_long address); int excluded(malloc_log_entry* lep); + + void buildLeakGraph(); + Symbol* findLeakGraphRoot(Symbol* aStart, Symbol* aEnd); + void dumpLeakGraph(); + void dumpLeakTree(Symbol* aRoot, int aIndent, bool aEven); + + static void indentBy(int aCount) { + while (--aCount >= 0) fputs(" ", stdout); + } }; #endif /* __leaky_h_ */