Whacked to support a graph display format

This commit is contained in:
kipp%netscape.com 1999-09-26 06:31:18 +00:00
Родитель 48e53dfd90
Коммит efd9beedfb
5 изменённых файлов: 573 добавлений и 291 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -12,7 +12,7 @@
#ifndef config_h___
#define config_h___
#define MAX_STACK_CRAWL 30
#define MAX_STACK_CRAWL 100
#include <malloc.h>

Просмотреть файл

@ -16,26 +16,28 @@
#include <sys/types.h>
#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_ */

Просмотреть файл

@ -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("<?xml version=\"1.0\"?>\n");
printf("<?xml-stylesheet href=\"http://klink/leaky/leaky.css\" type=\"text/css\"?>\n");
printf("<root xmlns:html=\"http://www.w3.org/TR/REC-html40\">\n");
printf("<html:script src=\"http://klink/leaky/leaky.js\"/>\n");
printf("<key>\n");
printf("Key:<html:br/>\n");
printf("<b>Bytes directly leaked</b><html:br/>\n");
printf("<k>Bytes leaked by descendants</k></key>\n");
#else
printf("<html><head><title>Leaky Graph</title>\n");
printf("<style src=\"http://klink/leaky/leaky.css\"></style>\n");
printf("<script src=\"http://klink/leaky/leaky.js\"/></script>\n");
printf("</head><body><div class=\"key\">\n");
printf("Key:<br>\n");
printf("<span class=b>Bytes directly leaked</span><br>\n");
printf("<span class=d>Bytes leaked by descendants</span></div>\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("</root>\n");
#else
printf("</body></html>\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("<n class=\"%s\">", aEven ? "e" : "o");
if (haveVisibleDescendants) {
printf("<html:img onmouseout=\"O(event);\" onmouseover=\"I(event);\" onclick=\"C(event);\" src=\"http://klink/leaky/%s.gif\"/>"
aIndent > 1 ? "close" : "open");
}
printf("<s>%s</s><b>%ld</b><k>%ld</k>\n",
aSymbol->name,
aSymbol->bytesDirectlyLeaked,
aSymbol->childBytesLeaked);
#else
printf("<div class=\"n %c\">\n", aEven ? 'e' : 'o');
if (haveVisibleDescendants) {
printf("<img onmouseout=\"O(event);\" onmouseover=\"I(event);\" onclick=\"C(event);\" src=\"http://klink/leaky/%s.gif\">",
aIndent > 1 ? "close" : "open");
}
printf("<span class=s>%s</span><span class=b>%ld</span><span class=d>%ld</span>\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("</n>");
#else
printf("</div>");
#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;
}
}

Просмотреть файл

@ -14,15 +14,52 @@
#define __leaky_h_
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#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_ */