Reworked tree support

This commit is contained in:
kipp%netscape.com 1999-09-30 01:51:20 +00:00
parent fd63be5bc1
commit d44f8afe43
9 changed files with 286 additions and 226 deletions

View File

@ -41,6 +41,15 @@ LIBS = \
-liberty \
$(NULL)
RESOURCES = \
leaky.css \
leaky.js \
open.gif \
open-over.gif \
close.gif \
close-over.gif \
$(NULL)
# Stuff to build the library used to wrap malloc
LIBMALLOC_CPPSRCS = libmalloc.cpp
LIBMALLOC_OBJECTS = $(LIBMALLOC_CPPSRCS:.cpp=.o)
@ -53,10 +62,27 @@ LIBPRELOAD = libpreload.so
# include $(topsrcdir)/config/config.mk
SHARED_LIBRARY = $(LIBMALLOC) $(LIBPRELOAD)
OTHER_LIBRARIES = $(LIBMALLOC) $(LIBPRELOAD)
TARGETS := $(PROGRAM) $(SIMPLE_PROGRAMS) $(OTHER_LIBRARIES)
include $(topsrcdir)/config/rules.mk
# Make sure all depends on files that rules.mk doesn't know about.
all:: $(OTHER_LIBRARIES)
# Make sure install depends on files that rules.mk doesn't know about.
install:: $(OTHER_LIBRARIES)
# Make sure libs depends on files that rules.mk doesn't know about.
libs:: $(OTHER_LIBRARIES)
clobber::
rm -f $(LIBMALLOC_OBJECTS) $(LIBPRELOAD_OBJECTS)
rm -f $(LIBMALLOC) $(LIBPRELOAD)
clean::
rm -f $(LIBMALLOC_OBJECTS) $(LIBPRELOAD_OBJECTS)
$(LIBMALLOC): $(LIBMALLOC_OBJECTS)
rm -f $@
$(MKSHLIB) -o $@ $(LIBMALLOC_OBJECTS)
@ -68,3 +94,7 @@ test:
@echo LIBMALLOC = $(LIBMALLOC)
@echo LIBPRELOAD = $(LIBPRELOAD)
@echo TARGETS = $(TARGETS)
install::
$(INSTALL) -m 555 $(OTHER_LIBRARIES) $(DIST)/lib
$(INSTALL) $(RESOURCES) $(DIST)/bin/res/leaky

View File

@ -20,14 +20,30 @@
// A simple test program that dumps out the loaded shared
// libraries. This is essential for leaky to work properly when shared
// libraries are used.
static void ShowLibs(struct r_debug* rd)
{
link_map* map = rd->r_map;
while (NULL != map) {
printf("addr=%08x name=%s prev=%p next=%p\n", map->l_addr, map->l_name,
map->l_prev, map->l_next);
map = map->l_next;
}
}
int main(int argc, char** argv)
{
void* h = dlopen("/usr/X11R6/lib/libX11.so", RTLD_LAZY);
#ifdef linux
link_map* map = _r_debug.r_map;
while (NULL != map) {
printf("addr=%08x name=%s\n", map->l_addr, map->l_name);
map = map->l_next;
printf("Direct r_debug libs:\n");
ShowLibs(&_r_debug);
printf("_DYNAMICE r_debug libs:\n");
ElfW(Dyn)* dp;
for (dp = _DYNAMIC; dp->d_tag != DT_NULL; dp++) {
if (dp->d_tag == DT_DEBUG) {
struct r_debug* rd = (struct r_debug*) dp->d_un.d_ptr;
ShowLibs(rd);
}
}
#endif
return 0;

View File

@ -38,10 +38,70 @@ void s4()
cp = cp;
}
// Test that mutually recrusive methods don't foul up the graph output
void s6(int recurse);
void s5(int recurse)
{
malloc(100);
if (recurse > 0) {
s6(recurse - 1);
}
}
void s6(int recurse)
{
malloc(100);
if (recurse > 0) {
s5(recurse - 1);
}
}
// Test that two pathways through the same node don't cause replicated
// descdendants (A -> B -> C, X -> B -> D shouldn't produce a graph
// that shows A -> B -> D!)
void C()
{
malloc(10);
}
void D()
{
malloc(10);
}
void B(int way)
{
malloc(10);
if (way) {
C();
C();
C();
} else {
D();
}
}
void A()
{
malloc(10);
B(1);
}
void X()
{
malloc(10);
B(0);
}
int main()
{
s1(1, 2);
s2();
s3();
s4();
s5(10);
A();
X();
}

View File

@ -31,23 +31,23 @@ void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress)
bfd_init ();
}
bfd* bfd = bfd_openr(aFileName, NULL);
if (NULL == bfd) {
bfd* lib = bfd_openr(aFileName, NULL);
if (NULL == lib) {
return;
}
char **matching;
if (!bfd_check_format_matches(bfd, bfd_object, &matching)) {
bfd_close(bfd);
if (!bfd_check_format_matches(lib, bfd_object, &matching)) {
bfd_close(lib);
return;
}
asymbol* store;
store = bfd_make_empty_symbol(bfd);
store = bfd_make_empty_symbol(lib);
// read mini symbols
PTR minisyms;
unsigned int size;
long symcount = bfd_read_minisymbols(bfd, kDynamic, &minisyms, &size);
long symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size);
int initialSymbols = usefulSymbols;
if (NULL == externalSymbols) {
@ -55,17 +55,17 @@ void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress)
numExternalSymbols = 10000;
}
Symbol* sp = externalSymbols + usefulSymbols;
Symbol* last = externalSymbols + numExternalSymbols;
Symbol* lastSymbol = externalSymbols + numExternalSymbols;
// Scan symbols
bfd_byte* from = (bfd_byte *) minisyms;
bfd_byte* fromend = from + symcount * size;
for (; from < fromend; from += size) {
asymbol *sym;
sym = bfd_minisymbol_to_symbol(bfd, kDynamic, (const PTR) from, store);
sym = bfd_minisymbol_to_symbol(lib, kDynamic, (const PTR) from, store);
symbol_info syminfo;
bfd_get_symbol_info (bfd, sym, &syminfo);
bfd_get_symbol_info (lib, sym, &syminfo);
// if ((syminfo.type == 'T') || (syminfo.type == 't')) {
const char* nm = bfd_asymbol_name(sym);
@ -74,11 +74,11 @@ void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress)
// sp->name = dnm ? dnm : strdup(nm);
sp->Init(nm, syminfo.value + aBaseAddress);
sp++;
if (sp >= last) {
if (sp >= lastSymbol) {
long n = numExternalSymbols + 10000;
externalSymbols = (Symbol*)
realloc(externalSymbols, (size_t) (sizeof(Symbol) * n));
last = externalSymbols + n;
lastSymbol = externalSymbols + n;
sp = externalSymbols + numExternalSymbols;
numExternalSymbols = n;
}
@ -87,7 +87,7 @@ void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress)
}
bfd_close(bfd);
bfd_close(lib);
int interesting = sp - externalSymbols;
if (!quiet) {

View File

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

View File

@ -54,14 +54,14 @@ leaky::leaky()
sortByFrequency = FALSE;
dumpAll = FALSE;
dumpGraph = FALSE;
dumpXML = FALSE;
dumpHTML = FALSE;
quiet = FALSE;
showAll = FALSE;
showAddress = FALSE;
stackDepth = 100000;
fd = -1;
base = last = 0;
mappedLogFile = -1;
firstLogEntry = lastLogEntry = 0;
buckets = DefaultBuckets;
dict = 0;
@ -148,7 +148,7 @@ void leaky::initialize(int argc, char** argv)
}
break;
case 'x':
dumpXML = TRUE;
dumpHTML = TRUE;
break;
case 'q':
quiet = TRUE;
@ -216,14 +216,14 @@ void leaky::open()
setupSymbols(progFile);
// open up the log file
fd = ::open(logFile, O_RDONLY);
if (fd < 0) {
mappedLogFile = ::open(logFile, O_RDONLY);
if (mappedLogFile < 0) {
perror("open");
exit(-1);
}
off_t size;
base = (malloc_log_entry*) mapFile(fd, PROT_READ, &size);
last = (malloc_log_entry*)((char*)base + size);
firstLogEntry = (malloc_log_entry*) mapFile(mappedLogFile, PROT_READ, &size);
lastLogEntry = (malloc_log_entry*)((char*)firstLogEntry + size);
analyze();
@ -320,7 +320,7 @@ int leaky::excluded(malloc_log_entry* lep)
//----------------------------------------------------------------------
void leaky::displayStackTrace(malloc_log_entry* lep)
void leaky::displayStackTrace(FILE* out, malloc_log_entry* lep)
{
char** pcp = &lep->pcs[0];
u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth;
@ -337,13 +337,13 @@ void leaky::displayStackTrace(malloc_log_entry* lep)
symbolName = buf;
}
if (showAddress) {
printf("%s[%p] ", symbolName, *pcp);
fprintf(out, "%s[%p] ", symbolName, *pcp);
}
else {
printf("%s ", symbolName);
fprintf(out, "%s ", symbolName);
}
}
printf("\n");
fprintf(out, "\n");
}
char* typeFromLog[] = {
@ -362,14 +362,14 @@ void leaky::dumpEntryToLog(malloc_log_entry* lep)
typeFromLog[lep->type],
lep->address, lep->size, lep->oldaddress,
lep->numpcs);
displayStackTrace(lep);
displayStackTrace(stdout, lep);
}
void leaky::dumpLog()
{
if (showAll) {
malloc_log_entry* lep = base;
while (lep < last) {
malloc_log_entry* lep = firstLogEntry;
while (lep < lastLogEntry) {
dumpEntryToLog(lep);
lep = (malloc_log_entry*) &lep->pcs[lep->numpcs];
}
@ -393,7 +393,7 @@ void leaky::insertAddress(u_long address, malloc_log_entry* lep)
assert(*lepp);
if (!quiet) {
printf("Address %lx allocated twice\n", address);
displayStackTrace(lep);
displayStackTrace(stdout, lep);
}
errors++;
} else {
@ -407,7 +407,7 @@ void leaky::removeAddress(u_long address, malloc_log_entry* lep)
if (!lepp) {
if (!quiet) {
printf("Free of unallocated %lx\n", address);
displayStackTrace(lep);
displayStackTrace(stdout, lep);
}
errors++;
} else {
@ -417,8 +417,8 @@ void leaky::removeAddress(u_long address, malloc_log_entry* lep)
void leaky::analyze()
{
malloc_log_entry* lep = base;
while (lep < last) {
malloc_log_entry* lep = firstLogEntry;
while (lep < lastLogEntry) {
switch (lep->type) {
case malloc_log_malloc:
case malloc_log_new:
@ -473,28 +473,39 @@ void leaky::buildLeakGraph()
malloc_log_entry* lep;
dict->rewind();
while (NULL != (lep = dict->next())) {
Symbol* prevSymbol = NULL;
char** basepcp = &lep->pcs[0];
char** pcp = &lep->pcs[lep->numpcs - 1];
// 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);
}
// Find root for this allocation
Symbol* sym = findSymbol((u_long) *pcp);
TreeNode* node = sym->root;
if (!node) {
displayStackTrace(stderr, lep);
sym->root = node = new TreeNode(sym);
}
pcp--;
// Build tree underneath the root
for (; pcp >= basepcp; pcp--) {
// Share nodes in the tree until there is a divergence
sym = findSymbol((u_long) *pcp);
if (!sym) {
break;
}
prevSymbol = currentSymbol;
TreeNode* nextNode = node->GetDirectDescendant(sym);
if (!nextNode) {
// Make a new node at the point of divergence
nextNode = node->AddDescendant(sym);
}
if (pcp == basepcp) {
nextNode->bytesLeaked += lep->size;
}
else {
node->descendantBytesLeaked += lep->size;
}
node = nextNode;
}
}
}
@ -502,7 +513,7 @@ void leaky::buildLeakGraph()
Symbol* leaky::findLeakGraphRoot(Symbol* aStart, Symbol* aEnd)
{
while (aStart < aEnd) {
if (aStart->leaker && !aStart->parents) {
if (aStart->root) {
return aStart;
}
aStart++;
@ -512,183 +523,118 @@ Symbol* leaky::findLeakGraphRoot(Symbol* aStart, Symbol* aEnd)
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
if (dumpHTML) {
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("<style src=\"resource:/res/leaky/leaky.css\"></style>\n");
printf("<script src=\"resource:/res/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;
Symbol* sym = findLeakGraphRoot(base, end);
if (!sym) break;
dumpLeakTree(sym->root, 0);
base = sym + 1;
}
if (dumpXML) {
#ifdef USE_XML
printf("</root>\n");
#else
if (dumpHTML) {
printf("</body></html>\n");
#endif
}
}
void leaky::dumpLeakTree(Symbol* aSymbol, int aIndent, bool aEven)
void leaky::dumpLeakTree(TreeNode* aNode, int aIndent)
{
#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\"/>"
Symbol* sym = aNode->symbol;
if (dumpHTML) {
printf("<div class=\"n\">\n");
if (aNode->HasDescendants()) {
printf("<img onmouseout=\"O(event);\" onmouseover=\"I(event);\" ");
printf("onclick=\"C(event);\" src=\"resource:/res/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
printf("<span class=s>%s</span><span class=b>%ld</span>",
sym->name,
aNode->bytesLeaked);
printf("<span class=d>%ld</span>\n",
aNode->descendantBytesLeaked);
}
else {
indentBy(aIndent);
printf("%s bytesLeaked=%ld (%ld from kids)\n",
aSymbol->name,
aSymbol->bytesDirectlyLeaked,
aSymbol->childBytesLeaked);
sym->name,
aNode->bytesLeaked,
aNode->descendantBytesLeaked);
}
node = aSymbol->children;
TreeNode* node = aNode->descendants;
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;
sym = node->symbol;
dumpLeakTree(node, aIndent + 1);
kidNum++;
node = node->nextSibling;
}
if (dumpXML) {
#ifdef USE_XML
printf("</n>");
#else
if (dumpHTML) {
printf("</div>");
#endif
}
}
//----------------------------------------------------------------------
SymbolNode* SymbolNode::freeList;
TreeNode* TreeNode::freeList;
void* SymbolNode::operator new(size_t size)
void* TreeNode::operator new(size_t size)
{
if (!freeList) {
SymbolNode* newNodes = (SymbolNode*) new char[sizeof(SymbolNode) * 5000];
TreeNode* newNodes = (TreeNode*) new char[sizeof(TreeNode) * 5000];
if (!newNodes) {
return NULL;
}
SymbolNode* n = newNodes;
SymbolNode* end = newNodes + 5000 - 1;
TreeNode* n = newNodes;
TreeNode* end = newNodes + 5000 - 1;
while (n < end) {
n->next = n + 1;
n->nextSibling = n + 1;
n++;
}
n->next = NULL;
n->nextSibling = NULL;
freeList = newNodes;
}
SymbolNode* rv = freeList;
freeList = rv->next;
TreeNode* rv = freeList;
freeList = rv->nextSibling;
return (void*) rv;
}
void SymbolNode::operator delete(void* ptr)
void TreeNode::operator delete(void* ptr)
{
SymbolNode* node = (SymbolNode*) ptr;
TreeNode* node = (TreeNode*) ptr;
if (node) {
node->next = freeList;
node->nextSibling = freeList;
freeList = node;
}
}
//----------------------------------------------------------------------
void Symbol::Init(const char* aName, u_long aAddress)
TreeNode* TreeNode::GetDirectDescendant(Symbol* aSymbol)
{
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;
TreeNode* node = descendants;
while (node) {
if (node->symbol == aSymbol) {
return node;
}
node = node->nextSibling;
}
return NULL;
}
void Symbol::AddChild(Symbol* aChild)
TreeNode* TreeNode::AddDescendant(Symbol* aSymbol)
{
SymbolNode* node = new SymbolNode(aChild);
if (node) {
node->next = children;
children = node;
}
TreeNode* node = new TreeNode(aSymbol);
node->nextSibling = descendants;
descendants = node;
return node;
}

View File

@ -1,51 +1,53 @@
root {
display: block;
margin: 1em 1em;
body {
background-color: white;
line-height: 1.1;
margin: 1em;
font-size: 10pt;
font-family: "Arial", "Times New Roman", "Times Roman", serif;
}
root > n, root > n > n, root > n > n > n {
display: block;
}
body > .n, body > .n > .n, body > .n > .n > .n {
display: block;
}
key, .key {
.key {
display: block;
margin: 1em;
border: 2px solid green;
width: 50%;
margin: 0 auto 1em auto;
font-size: 130%;
}
key b, key k, .key .b, .key .d { margin: 0 0 0 2em; padding: 0; }
n, .n {
.key .b, .key .d {
margin: 0 0 0 2em;
padding: 0;
}
.n {
display: none;
margin: 0 1em;
margin: 0 0 0 1em;
white-space: nowrap;
}
n.e, .n.e {
background-color: orange;
.n.e {
background-color: rgb(180,180,180);
}
s, .s {
.s {
display: inline;
margin-left: 5px;
}
b, .b {
.b {
display: inline;
background-color: yellow;
margin: 0 1em;
padding: 0 1em;
margin: 0 1em 0 1em;
padding: 0 5px;
}
k, .d {
.d {
display: inline;
background-color: khaki;
padding: 0 1em;
padding: 0 5px;
}

View File

@ -15,6 +15,7 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "dict.h"
#include "strset.h"
@ -23,43 +24,44 @@ typedef unsigned int u_int;
struct Symbol;
struct SymbolNode {
SymbolNode(Symbol* aSymbol) {
struct TreeNode {
TreeNode(Symbol* aSymbol) {
symbol = aSymbol;
next = NULL;
nextSibling = NULL;
descendants = NULL;
}
TreeNode* GetDirectDescendant(Symbol* aSymbol);
bool HasDescendants() const {
return NULL != descendants;
}
TreeNode* AddDescendant(Symbol* aSymbol);
TreeNode* descendants;
TreeNode* nextSibling;
Symbol* symbol;
u_long bytesLeaked;
u_long descendantBytesLeaked;
void* operator new(size_t size);
void operator delete(void* ptr);
Symbol* symbol;
SymbolNode* next;
static SymbolNode* freeList;
static TreeNode* freeList;
};
struct Symbol {
char* name;
u_long address;
bool dumped;
bool leaker;
u_long calls;
SymbolNode* parents;
SymbolNode* children;
u_long bytesDirectlyLeaked;
u_long childBytesLeaked;
TreeNode* root;
bool NotDumped() const {
return 0 == dumped;
void Init(const char* aName, u_long aAddress) {
name = aName ? strdup(aName) : "";
address = aAddress;
root = NULL;
}
void SetDumped() {
dumped = 1;
}
void Init(const char* aName, u_long aAddress);
void AddParent(Symbol* aParent);
void AddChild(Symbol* aChild);
};
struct LoadMapEntry {
@ -82,15 +84,15 @@ struct leaky {
int sortByFrequency;
int dumpAll;
int dumpGraph;
int dumpXML;
int dumpHTML;
int quiet;
int showAll;
int showAddress;
u_int stackDepth;
int fd;
malloc_log_entry* base;
malloc_log_entry* last;
int mappedLogFile;
malloc_log_entry* firstLogEntry;
malloc_log_entry* lastLogEntry;
u_int buckets;
MallocDict* dict;
@ -128,7 +130,7 @@ struct leaky {
void insertAddress(u_long address, malloc_log_entry* lep);
void removeAddress(u_long address, malloc_log_entry* lep);
void displayStackTrace(malloc_log_entry* lep);
void displayStackTrace(FILE* out, malloc_log_entry* lep);
void ReadSymbols(const char* fileName, u_long aBaseAddress);
void ReadSharedLibrarySymbols();
@ -139,7 +141,7 @@ struct leaky {
void buildLeakGraph();
Symbol* findLeakGraphRoot(Symbol* aStart, Symbol* aEnd);
void dumpLeakGraph();
void dumpLeakTree(Symbol* aRoot, int aIndent, bool aEven);
void dumpLeakTree(TreeNode* aNode, int aIndent);
static void indentBy(int aCount) {
while (--aCount >= 0) fputs(" ", stdout);

View File

@ -97,6 +97,10 @@ static void DumpAddressMap()
mme.address = map->l_addr;
write(mfd, &mme, sizeof(mme));
write(mfd, map->l_name, mme.nameLen);
#if 0
write(1, map->l_name, mme.nameLen);
write(1, "\n", 1);
#endif
}
map = map->l_next;
}