Trace-Malloc records line number information on platforms which have it.
r=dp sr=alecf
This commit is contained in:
blythe%netscape.com 2002-01-09 19:03:01 +00:00
Родитель c7f72d0cc6
Коммит 00c321d9fb
13 изменённых файлов: 639 добавлений и 80 удалений

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

@ -82,27 +82,29 @@ static void compute_callsite_totals(tmcallsite *site)
static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp)
{
tmcallsite *parent;
tmgraphnode *meth, *pmeth, *comp, *pcomp, *lib, *plib;
tmgraphnode *comp, *pcomp, *lib, *plib;
tmmethodnode *meth, *pmeth;
int old_meth_low, old_comp_low, old_lib_low, nkids;
tmcallsite *kid;
parent = site->parent;
meth = comp = lib = NULL;
comp = lib = NULL;
meth = NULL;
if (parent) {
meth = site->method;
if (meth) {
pmeth = parent->method;
if (pmeth && pmeth != meth) {
if (!meth->low) {
meth->allocs.bytes.total += site->allocs.bytes.total;
meth->allocs.calls.total += site->allocs.calls.total;
if (!meth->graphnode.low) {
meth->graphnode.allocs.bytes.total += site->allocs.bytes.total;
meth->graphnode.allocs.calls.total += site->allocs.calls.total;
}
if (!tmgraphnode_connect(pmeth, meth, site))
if (!tmgraphnode_connect(&(pmeth->graphnode), &(meth->graphnode), site))
goto bad;
comp = meth->up;
comp = meth->graphnode.up;
if (comp) {
pcomp = pmeth->up;
pcomp = pmeth->graphnode.up;
if (pcomp && pcomp != comp) {
if (!comp->low) {
comp->allocs.bytes.total
@ -136,16 +138,16 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp
comp->low = level;
}
}
old_meth_low = meth->low;
old_meth_low = meth->graphnode.low;
if (!old_meth_low)
meth->low = level;
meth->graphnode.low = level;
}
}
if (do_tree_dump) {
fprintf(fp, "%c%*s%3d %3d %s %lu %ld\n",
site->kids ? '+' : '-', level, "", level, kidnum,
meth ? tmgraphnode_name(meth) : "???",
meth ? tmmethodnode_name(meth) : "???",
(unsigned long)site->allocs.bytes.direct,
(long)site->allocs.bytes.total);
}
@ -158,7 +160,7 @@ static void walk_callsite_tree(tmcallsite *site, int level, int kidnum, FILE *fp
if (meth) {
if (!old_meth_low)
meth->low = 0;
meth->graphnode.low = 0;
if (comp) {
if (!old_comp_low)
comp->low = 0;
@ -255,7 +257,7 @@ static int mean_size_compare(const void *p1, const void *p2)
div1 = (double)node1->allocs.calls.direct;
div2 = (double)node2->allocs.calls.direct;
if (div1 == 0 || div2 == 0)
return div2 - div1;
return (int)(div2 - div1);
key1 = (double)node1->allocs.bytes.direct / div1;
key2 = (double)node2->allocs.bytes.direct / div2;
if (key1 < key2)
@ -554,7 +556,7 @@ static void my_tmevent_handler(tmreader *tmr, tmevent *event)
tmreader_callsite(tmr, event->u.stats.calltree_maxkids_parent);
if (site && site->method) {
fprintf(stdout, "<p>callsite with the most kids: %s</p>",
tmgraphnode_name(site->method));
tmmethodnode_name(site->method));
}
}
@ -568,7 +570,7 @@ static void my_tmevent_handler(tmreader *tmr, tmevent *event)
while (site) {
fprintf(stdout,
"<tr><td>%s</td><td>0x%08lX</td></tr>\n",
site->method ? tmgraphnode_name(site->method) : "???",
site->method ? tmmethodnode_name(site->method) : "???",
(unsigned long) site->offset);
site = site->parent;
}

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

@ -116,8 +116,12 @@ dhwEnsureSymInitialized()
if (! gInitialized) {
if (! dhwEnsureImageHlpInitialized())
return PR_FALSE;
// dhwSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
dhwSymSetOptions(SYMOPT_UNDNAME);
dhwSymSetOptions(
#if defined(NS_TRACE_MALLOC)
SYMOPT_LOAD_LINES |
#endif
SYMOPT_UNDNAME);
// dhwSymSetOptions(SYMOPT_UNDNAME);
if (! dhwSymInitialize(::GetCurrentProcess(), NULL, TRUE))
return PR_FALSE;
gInitialized = PR_TRUE;

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

@ -392,6 +392,36 @@ static void log_string(logfile *fp, const char *str)
log_byte(fp, '\0');
}
static void log_filename(logfile* aFP, const char* aFilename)
{
int nameLen = strlen(aFilename);
if (512 > nameLen) {
const char* skipTry1 = "mozilla";
char* found = nsnull;
char* convert = nsnull;
char dup[512];
strcpy(dup, aFilename);
found = strstr(dup, skipTry1);
if (nsnull == found) {
found = dup;
}
for (convert = found; '\0' != *convert; convert++) {
if ('\\' == *convert) {
*convert = '/';
}
}
log_string(aFP, found);
}
else {
log_string(aFP, aFilename);
}
}
static void log_uint32(logfile *fp, uint32 ival)
{
if (ival < 0x80) {
@ -497,6 +527,7 @@ static uint32 library_serial_generator = 0;
static uint32 method_serial_generator = 0;
static uint32 callsite_serial_generator = 0;
static uint32 tmstats_serial_generator = 0;
static uint32 filename_serial_generator = 0;
/* Root of the tree of callsites, the sum of all (cycle-compressed) stacks. */
static callsite calltree_root = {0, 0, LFD_SET_STATIC_INITIALIZER, NULL, NULL, 0, NULL, NULL, NULL};
@ -581,6 +612,9 @@ static PLHashAllocOps lfdset_hashallocops = {
/* Table of library pathnames mapped to to logged 'L' record serial numbers. */
static PLHashTable *libraries = NULL;
/* Table of filename pathnames mapped to logged 'G' record serial numbers. */
static PLHashTable *filenames = nsnull;
/* Table mapping method names to logged 'N' record serial numbers. */
static PLHashTable *methods = NULL;
@ -617,6 +651,10 @@ static callsite *calltree(int skip)
PLHashEntry **hep, *he;
lfdset_entry *le;
char* noname = "noname";
IMAGEHLP_LINE imagehelpLine;
const char* filename = nsnull;
uint32 linenumber = 0;
uint32 filename_serial = 0;
imagehelp.SizeOfStruct = sizeof(imagehelp);
framenum = 0;
@ -736,12 +774,22 @@ static callsite *calltree(int skip)
* callsite info. XXX static syms are masked by nearest lower global
* Load up the info for the dll.
*/
memset(&imagehelpLine, 0, sizeof(imagehelpLine));
if (!SymGetModuleInfoEspecial(myProcess,
frame[framenum].AddrPC.Offset,
&imagehelp)) {
&imagehelp, &imagehelpLine)) {
library = noname;
filename = noname;
linenumber = 0;
} else {
library = imagehelp.ModuleName;
filename = imagehelpLine.FileName;
linenumber = imagehelpLine.LineNumber;
if ('\0' == filename) {
filename = noname;
linenumber = 0;
}
}
/* Check whether we need to emit a library trace record. */
@ -791,6 +839,49 @@ static callsite *calltree(int skip)
}
}
/* Check whether we need to emit a filename trace record. */
filename_serial = 0;
if (filename) {
if (!filenames) {
filenames = PL_NewHashTable(100, PL_HashString,
PL_CompareStrings, PL_CompareValues,
&lfdset_hashallocops, NULL);
if (nsnull == filenames) {
tmstats.btmalloc_failures++;
return nsnull;
}
}
hash = PL_HashString(filename);
hep = PL_HashTableRawLookup(filenames, hash, filename);
he = *hep;
if (he) {
filename_serial = (uint32) he->value;
le = (lfdset_entry *) he;
if (LFD_TEST(fp->lfd, &le->lfdset)) {
/* We already logged an event on fp for this filename. */
le = NULL;
}
} else {
filename = strdup(filename);
if (filename) {
filename_serial = ++filename_serial_generator;
he = PL_HashTableRawAdd(filenames, hep, hash, filename,
(void*) filename_serial);
}
if (!he) {
tmstats.btmalloc_failures++;
return NULL;
}
le = (lfdset_entry *) he;
}
if (le) {
/* Need to log an event to fp for this filename. */
log_event1(fp, TM_EVENT_FILENAME, filename_serial);
log_filename(fp, filename);
LFD_SET(fp->lfd, &le->lfdset);
}
}
symbol = (PIMAGEHLP_SYMBOL) buf;
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
symbol->MaxNameLength = sizeof(buf) - sizeof(IMAGEHLP_SYMBOL);
@ -858,7 +949,7 @@ static callsite *calltree(int skip)
le = (lfdset_entry *) he;
}
if (le) {
log_event2(fp, TM_EVENT_METHOD, method_serial, library_serial);
log_event4(fp, TM_EVENT_METHOD, method_serial, library_serial, filename_serial, linenumber);
log_string(fp, method);
LFD_SET(fp->lfd, &le->lfdset);
}
@ -930,6 +1021,9 @@ static callsite *calltree(uint32 *bp)
PLHashNumber hash;
PLHashEntry **hep, *he;
lfdset_entry *le;
uint32 filename_serial;
uint32 linenumber;
const char* filename;
/* Reverse the stack frame list to avoid recursion. */
bpup = NULL;
@ -1005,6 +1099,13 @@ static callsite *calltree(uint32 *bp)
return NULL;
}
/*
* One day, if someone figures out how to get filename and line
* number info, this is the place to fill it all in.
*/
filename = "noname";
linenumber = 0;
/* Check whether we need to emit a library trace record. */
library_serial = 0;
library = info.dli_fname;
@ -1052,6 +1153,48 @@ static callsite *calltree(uint32 *bp)
}
}
/* Check whether we need to emit a filename trace record. */
filename_serial = 0;
if (filename) {
if (!filenames) {
filenames = PL_NewHashTable(100, PL_HashString,
PL_CompareStrings, PL_CompareValues,
&lfdset_hashallocops, NULL);
if (nsnull == filenames) {
tmstats.btmalloc_failures++;
return nsnull;
}
}
hash = PL_HashString(filename);
hep = PL_HashTableRawLookup(filenames, hash, filename);
he = *hep;
if (he) {
filename_serial = (uint32) he->value;
le = (lfdset_entry *) he;
if (LFD_TEST(fp->lfd, &le->lfdset)) {
/* We already logged an event on fp for this filename. */
le = NULL;
}
} else {
if (filename) {
filename_serial = ++filename_serial_generator;
he = PL_HashTableRawAdd(filenames, hep, hash, filename,
(void*) filename_serial);
}
if (!he) {
tmstats.btmalloc_failures++;
return NULL;
}
le = (lfdset_entry *) he;
}
if (le) {
/* Need to log an event to fp for this filename. */
log_event1(fp, TM_EVENT_FILENAME, filename_serial);
log_filename(fp, filename);
LFD_SET(fp->lfd, &le->lfdset);
}
}
/* Now find the demangled method name and pc offset in it. */
symbol = info.dli_sname;
offset = (char*)pc - (char*)info.dli_saddr;
@ -1110,7 +1253,7 @@ static callsite *calltree(uint32 *bp)
le = (lfdset_entry *) he;
}
if (le) {
log_event2(fp, TM_EVENT_METHOD, method_serial, library_serial);
log_event4(fp, TM_EVENT_METHOD, method_serial, library_serial, filename_serial, linenumber);
log_string(fp, method);
LFD_SET(fp->lfd, &le->lfdset);
}

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

@ -45,7 +45,7 @@ PR_BEGIN_EXTERN_C
* NS_TraceMallocStartup comment (below) for magic number differences in log
* file structure.
*/
#define NS_TRACE_MALLOC_MAGIC "XPCOM\nTMLog07\r\n\032"
#define NS_TRACE_MALLOC_MAGIC "XPCOM\nTMLog08\r\n\032"
#define NS_TRACE_MALLOC_MAGIC_SIZE 16
/**
@ -122,9 +122,19 @@ typedef struct nsTMStats {
* old address, old size
* 'F' site serial, interval, address, free size
*
* Event Operands (magic TMLog07)
* no one documented their changes.
* best of luck....
*
* Event Operands (magic TMLog08)
* 'G' filename serial, source filename string.
* 'N' method serial, library serial, source filename serial,
* source file linenumber, demangled name string
*
* See tools/trace-malloc/bloatblame.c for an example log-file reader.
*/
#define TM_EVENT_LIBRARY 'L'
#define TM_EVENT_FILENAME 'G'
#define TM_EVENT_METHOD 'N'
#define TM_EVENT_CALLSITE 'S'
#define TM_EVENT_MALLOC 'M'

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

@ -1360,7 +1360,7 @@ int hasCallsiteMatch(tmcallsite* aCallsite, const char* aMatch, int aDirection)
do
{
methodName = tmgraphnode_name(aCallsite->method);
methodName = tmmethodnode_name(aCallsite->method);
if(NULL != methodName && NULL != strstr(methodName, aMatch))
{
/*
@ -2350,6 +2350,7 @@ void tmEventHandler(tmreader* aReader, tmevent* aEvent)
case TM_EVENT_METHOD:
case TM_EVENT_STATS:
case TM_EVENT_TIMESTAMP:
case TM_EVENT_FILENAME:
break;
/*
@ -2470,8 +2471,13 @@ void tmEventHandler(tmreader* aReader, tmevent* aEvent)
**
** Output an HTML anchor, or just the text depending on the mode.
*/
void htmlAnchor(const char* aHref, const char* aText)
void htmlAnchor(const char* aHref, const char* aText, const char* aTarget)
{
if(NULL == aTarget || '\0' == aTarget[0])
{
aTarget = "_st_content";
}
if(NULL != aHref && '\0' != *aHref && NULL != aText && '\0' != *aText)
{
int anchorLive = 1;
@ -2518,7 +2524,7 @@ void htmlAnchor(const char* aHref, const char* aText)
*/
if(0 != anchorLive)
{
PR_fprintf(globals.mRequest.mFD, "<a target=_content href=\"./%s\">%s</a>\n", aHref, aText);
PR_fprintf(globals.mRequest.mFD, "<a target=\"%s\" href=\"./%s\">%s</a>\n", aTarget, aHref, aText);
}
else
{
@ -2549,7 +2555,7 @@ void htmlAllocationAnchor(STAllocation* aAllocation, const char* aText)
*/
PR_snprintf(buffer, sizeof(buffer), "allocation_%u.html", aAllocation->mRunIndex);
htmlAnchor(buffer, aText);
htmlAnchor(buffer, aText, NULL);
}
else
{
@ -2557,6 +2563,39 @@ void htmlAllocationAnchor(STAllocation* aAllocation, const char* aText)
}
}
/*
** resolveSourceFile
**
** Easy way to get a readable/short name.
** NULL if not present, not resolvable.
*/
const char* resolveSourceFile(tmmethodnode* aMethod)
{
const char* retval = NULL;
if(NULL != aMethod)
{
const char* methodSays = NULL;
methodSays = aMethod->sourcefile;
if(NULL != methodSays && '\0' != methodSays[0] && 0 != strcmp("noname", methodSays))
{
retval = strrchr(methodSays, '/');
if(NULL != retval)
{
retval++;
}
else
{
retval = methodSays;
}
}
}
return retval;
}
/*
** htmlCallsiteAnchor
**
@ -2570,7 +2609,7 @@ void htmlCallsiteAnchor(tmcallsite* aCallsite, const char* aText, int aRealName)
{
if(NULL != aCallsite)
{
char textBuf[256];
char textBuf[512];
char hrefBuf[128];
tmcallsite* namesite = aCallsite;
@ -2611,23 +2650,44 @@ void htmlCallsiteAnchor(tmcallsite* aCallsite, const char* aText, int aRealName)
if(NULL == aText || '\0' == *aText)
{
const char* methodName = NULL;
const char* sourceFile = NULL;
if(NULL != namesite->method)
{
methodName = tmgraphnode_name(namesite->method);
methodName = tmmethodnode_name(namesite->method);
}
else
{
methodName = "==NONAME==";
}
PR_snprintf(textBuf, sizeof(textBuf), "%s+%u(%u)", methodName, namesite->offset, (PRUint32)namesite->entry.key);
/*
** Decide which format to use to identify the callsite.
** If we can detect availability, hook up the filename with lxr information.
*/
sourceFile = resolveSourceFile(namesite->method);
if(NULL != sourceFile && 0 == strncmp("mozilla/", namesite->method->sourcefile, 8))
{
char lxrHREFBuf[512];
PR_snprintf(lxrHREFBuf, sizeof(lxrHREFBuf), "<a href=\"http://lxr.mozilla.org/mozilla/source/%s#%u\" target=\"_st_lxr\">(%s:%u)</a>", namesite->method->sourcefile + 8, namesite->method->linenumber, sourceFile, namesite->method->linenumber);
PR_snprintf(textBuf, sizeof(textBuf), "<b>%s</b>%s", methodName, lxrHREFBuf);
}
else if(NULL != sourceFile)
{
PR_snprintf(textBuf, sizeof(textBuf), "<b>%s</b>(%s:%u)", methodName, sourceFile, namesite->method->linenumber);
}
else
{
PR_snprintf(textBuf, sizeof(textBuf), "<b>%s</b>+%u(%u)", methodName, namesite->offset, (PRUint32)namesite->entry.key);
}
aText = textBuf;
}
PR_snprintf(hrefBuf, sizeof(hrefBuf), "callsite_%u.html", (PRUint32)aCallsite->entry.key);
htmlAnchor(hrefBuf, aText);
htmlAnchor(hrefBuf, aText, NULL);
}
else
{
@ -2651,14 +2711,14 @@ void htmlHeader(const char* aTitle)
"<div align=right>\n"
, aTitle);
htmlAnchor("index.html", "[Index]");
htmlAnchor("options.html", "[Options]");
htmlAnchor("index.html", "[Index]", NULL);
htmlAnchor("options.html", "[Options]", NULL);
/*
** This is a dubious feature at best.
*/
#if WANT_QUIT
htmlAnchor("quit.html", "[Quit]");
htmlAnchor("quit.html", "[Quit]", NULL);
#endif
PR_fprintf(globals.mRequest.mFD, "</div>\n<hr>\n");
@ -3867,8 +3927,19 @@ int displayCallsiteDetails(tmcallsite* aCallsite)
{
STRun* sortedRun = NULL;
STRun* thisRun = CALLSITE_RUN(aCallsite);
const char* sourceFile = NULL;
PR_fprintf(globals.mRequest.mFD, "%s+%u(%u) Callsite Details:<p>\n", tmgraphnode_name(aCallsite->method), aCallsite->offset, (PRUint32)aCallsite->entry.key);
sourceFile = resolveSourceFile(aCallsite->method);
if(NULL != sourceFile)
{
PR_fprintf(globals.mRequest.mFD, "<b>%s</b>", tmmethodnode_name(aCallsite->method));
PR_fprintf(globals.mRequest.mFD, "<a href=\"http://lxr.mozilla.org/mozilla/source/%s#%u\" target=\"_st_lxr\">(%s:%u)</a>", aCallsite->method->sourcefile, aCallsite->method->linenumber, sourceFile, aCallsite->method->linenumber);
PR_fprintf(globals.mRequest.mFD, " Callsite Details:<p>\n");
}
else
{
PR_fprintf(globals.mRequest.mFD, "<b>%s</b>+%u(%u) Callsite Details:<p>\n", tmmethodnode_name(aCallsite->method), aCallsite->offset, (PRUint32)aCallsite->entry.key);
}
PR_fprintf(globals.mRequest.mFD, "<table border=0>\n");
PR_fprintf(globals.mRequest.mFD, "<tr><td>Composite Byte Size:</td><td align=right>%u</td></tr>\n", thisRun->mStats.mSize);
@ -5022,16 +5093,16 @@ int displayIndex(void)
PR_fprintf(globals.mRequest.mFD, "<ul>");
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("root_callsites.html", "Root Callsites");
htmlAnchor("root_callsites.html", "Root Callsites", NULL);
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("top_callsites.html", "Top Callsites Report");
htmlAnchor("top_callsites.html", "Top Callsites Report", NULL);
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("top_allocations.html", "Top Allocations Report");
htmlAnchor("top_allocations.html", "Top Allocations Report", NULL);
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("memory_leaks.html", "Memory Leak Report");
htmlAnchor("memory_leaks.html", "Memory Leak Report", NULL);
#if WANT_GRAPHS
PR_fprintf(globals.mRequest.mFD, "\n<li>Graphs");
@ -5039,16 +5110,16 @@ int displayIndex(void)
PR_fprintf(globals.mRequest.mFD, "<ul>");
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("footprint_graph.html", "Footprint");
htmlAnchor("footprint_graph.html", "Footprint", NULL);
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("lifespan_graph.html", "Allocation Lifespans");
htmlAnchor("lifespan_graph.html", "Allocation Lifespans", NULL);
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("times_graph.html", "Allocation Times");
htmlAnchor("times_graph.html", "Allocation Times", NULL);
PR_fprintf(globals.mRequest.mFD, "\n<li>");
htmlAnchor("weight_graph.html", "Allocation Weights");
htmlAnchor("weight_graph.html", "Allocation Weights", NULL);
PR_fprintf(globals.mRequest.mFD, "\n</ul>\n");
#endif /* WANT_GRAPHS */

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

@ -147,9 +147,20 @@ static int get_tmevent(FILE *fp, tmevent *event)
event->u.libname = s;
break;
case TM_EVENT_FILENAME:
s = get_string(fp);
if (!s)
return 0;
event->u.srcname = s;
break;
case TM_EVENT_METHOD:
if (!get_uint32(fp, &event->u.method.library))
return 0;
if (!get_uint32(fp, &event->u.method.filename))
return 0;
if (!get_uint32(fp, &event->u.method.linenumber))
return 0;
s = get_string(fp);
if (!s)
return 0;
@ -273,6 +284,11 @@ static void generic_freetable(void *pool, void *item)
free(item);
}
static PLHashEntry *filename_allocentry(void *pool, const void *key)
{
return calloc(1, sizeof(PLHashEntry));
}
static PLHashEntry *callsite_allocentry(void *pool, const void *key)
{
return calloc(1, sizeof(tmcallsite));
@ -295,6 +311,25 @@ static PLHashEntry *graphnode_allocentry(void *pool, const void *key)
return &node->entry;
}
static PLHashEntry *method_allocentry(void *pool, const void *key)
{
tmmethodnode *node = (tmmethodnode*) malloc(sizeof(tmmethodnode));
if (!node)
return NULL;
node->graphnode.in = node->graphnode.out = NULL;
node->graphnode.up = node->graphnode.down = node->graphnode.next = NULL;
node->graphnode.low = 0;
node->graphnode.allocs.bytes.direct = node->graphnode.allocs.bytes.total = 0;
node->graphnode.allocs.calls.direct = node->graphnode.allocs.calls.total = 0;
node->graphnode.frees.bytes.direct = node->graphnode.frees.bytes.total = 0;
node->graphnode.frees.calls.direct = node->graphnode.frees.calls.total = 0;
node->graphnode.sqsum = 0;
node->graphnode.sort = -1;
node->sourcefile = NULL;
node->linenumber = 0;
return &node->graphnode.entry;
}
static void graphnode_freeentry(void *pool, PLHashEntry *he, PRUintn flag)
{
/* Always free the value, which points to a strdup'd string. */
@ -316,6 +351,11 @@ static void component_freeentry(void *pool, PLHashEntry *he, PRUintn flag)
}
}
static PLHashAllocOps filename_hashallocops = {
generic_alloctable, generic_freetable,
filename_allocentry, graphnode_freeentry
};
static PLHashAllocOps callsite_hashallocops = {
generic_alloctable, generic_freetable,
callsite_allocentry, graphnode_freeentry
@ -326,6 +366,11 @@ static PLHashAllocOps graphnode_hashallocops = {
graphnode_allocentry, graphnode_freeentry
};
static PLHashAllocOps method_hashallocops = {
generic_alloctable, generic_freetable,
method_allocentry, graphnode_freeentry
};
static PLHashAllocOps component_hashallocops = {
generic_alloctable, generic_freetable,
graphnode_allocentry, component_freeentry
@ -349,11 +394,14 @@ tmreader *tmreader_new(const char *program, void *data)
tmr->libraries = PL_NewHashTable(100, hash_serial, PL_CompareValues,
PL_CompareStrings, &graphnode_hashallocops,
NULL);
tmr->filenames = PL_NewHashTable(100, hash_serial, PL_CompareValues,
PL_CompareStrings, &filename_hashallocops,
NULL);
tmr->components = PL_NewHashTable(10000, PL_HashString, PL_CompareStrings,
PL_CompareValues, &component_hashallocops,
NULL);
tmr->methods = PL_NewHashTable(10000, hash_serial, PL_CompareValues,
PL_CompareStrings, &graphnode_hashallocops,
PL_CompareStrings, &method_hashallocops,
NULL);
tmr->callsites = PL_NewHashTable(200000, hash_serial, PL_CompareValues,
PL_CompareValues, &callsite_hashallocops,
@ -361,7 +409,8 @@ tmreader *tmreader_new(const char *program, void *data)
tmr->calltree_root.entry.value = (void*) strdup("root");
if (!tmr->libraries || !tmr->components || !tmr->methods ||
!tmr->callsites || !tmr->calltree_root.entry.value) {
!tmr->callsites || !tmr->calltree_root.entry.value ||
!tmr->filenames) {
tmreader_destroy(tmr);
return NULL;
}
@ -372,6 +421,8 @@ void tmreader_destroy(tmreader *tmr)
{
if (tmr->libraries)
PL_HashTableDestroy(tmr->libraries);
if (tmr->filenames)
PL_HashTableDestroy(tmr->filenames);
if (tmr->components)
PL_HashTableDestroy(tmr->components);
if (tmr->methods)
@ -408,6 +459,7 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
strncmp(buf, magic, sizeof buf) != 0) {
fprintf(stderr, "%s: bad magic string %s at start of %s.\n",
tmr->program, buf, filename);
fprintf(stderr, "either the data file is out of date,\nor your tools are out of date.\n");
return 0;
}
@ -444,12 +496,34 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
break;
}
case TM_EVENT_METHOD: {
case TM_EVENT_FILENAME: {
const void *key;
PLHashNumber hash;
PLHashEntry **hep, *he;
key = (const void*) event.serial;
hash = hash_serial(key);
hep = PL_HashTableRawLookup(tmr->filenames, hash, key);
he = *hep;
PR_ASSERT(!he);
if (he) exit(2);
he = PL_HashTableRawAdd(tmr->filenames, hep, hash, key,
event.u.srcname);
if (!he) {
perror(tmr->program);
return -1;
}
break;
}
case TM_EVENT_METHOD: {
const void *key, *sourcekey;
PLHashNumber hash, sourcehash;
PLHashEntry **hep, *he, **sourcehep, *sourcehe;
char *name, *head, *mark, save;
tmgraphnode *meth, *comp, *lib;
tmgraphnode *comp, *lib;
tmmethodnode *meth;
key = (const void*) event.serial;
hash = hash_serial(key);
@ -464,7 +538,14 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
perror(tmr->program);
return -1;
}
meth = (tmgraphnode*) he;
meth = (tmmethodnode*) he;
meth->linenumber = event.u.method.linenumber;
sourcekey = (const void*)event.u.method.filename;
sourcehash = hash_serial(sourcekey);
sourcehep = PL_HashTableRawLookup(tmr->filenames, sourcehash, sourcekey);
sourcehe = *sourcehep;
meth->sourcefile = filename_name(sourcehe);
head = name;
mark = strchr(name, ':');
@ -512,9 +593,9 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
}
*mark = save;
meth->up = comp;
meth->next = comp->down;
comp->down = meth;
meth->graphnode.up = comp;
meth->graphnode.next = comp->down;
comp->down = &(meth->graphnode);
break;
}
@ -523,7 +604,7 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
PLHashNumber hash, mhash;
PLHashEntry **hep, *he;
tmcallsite *site, *parent;
tmgraphnode *meth;
tmmethodnode *meth;
key = (const void*) event.serial;
hash = hash_serial(key);
@ -558,7 +639,7 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
mkey = (const void*) event.u.site.method;
mhash = hash_serial(mkey);
meth = (tmgraphnode*)
meth = (tmmethodnode*)
*PL_HashTableRawLookup(tmr->methods, mhash, mkey);
site->method = meth;
site->offset = event.u.site.offset;
@ -575,7 +656,8 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
tmcallsite *site;
uint32 size, oldsize;
double delta, sqdelta, sqszdelta;
tmgraphnode *meth, *comp, *lib;
tmgraphnode *comp, *lib;
tmmethodnode *meth;
site = tmreader_callsite(tmr, event.serial);
if (!site) {
@ -592,17 +674,17 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
site->allocs.calls.direct++;
meth = site->method;
if (meth) {
meth->allocs.bytes.direct += delta;
meth->graphnode.allocs.bytes.direct += delta;
sqdelta = delta * delta;
if (event.type == TM_EVENT_REALLOC) {
sqszdelta = ((double)size * size)
- ((double)oldsize * oldsize);
meth->sqsum += sqszdelta;
meth->graphnode.sqsum += sqszdelta;
} else {
meth->sqsum += sqdelta;
meth->allocs.calls.direct++;
meth->graphnode.sqsum += sqdelta;
meth->graphnode.allocs.calls.direct++;
}
comp = meth->up;
comp = meth->graphnode.up;
if (comp) {
comp->allocs.bytes.direct += delta;
if (event.type == TM_EVENT_REALLOC) {
@ -629,7 +711,8 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
case TM_EVENT_FREE: {
tmcallsite *site;
uint32 size;
tmgraphnode *meth, *comp, *lib;
tmgraphnode *comp, *lib;
tmmethodnode *meth;
site = tmreader_callsite(tmr, event.serial);
if (!site) {
@ -642,9 +725,9 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
site->frees.calls.direct++;
meth = site->method;
if (meth) {
meth->frees.bytes.direct += size;
meth->frees.calls.direct++;
comp = meth->up;
meth->graphnode.frees.bytes.direct += size;
meth->graphnode.frees.calls.direct++;
comp = meth->graphnode.up;
if (comp) {
comp->frees.bytes.direct += size;
comp->frees.calls.direct++;
@ -678,6 +761,16 @@ tmgraphnode *tmreader_library(tmreader *tmr, uint32 serial)
return (tmgraphnode*) *PL_HashTableRawLookup(tmr->libraries, hash, key);
}
tmgraphnode *tmreader_filename(tmreader *tmr, uint32 serial)
{
const void *key;
PLHashNumber hash;
key = (const void*) serial;
hash = hash_serial(key);
return (tmgraphnode*) *PL_HashTableRawLookup(tmr->filenames, hash, key);
}
tmgraphnode *tmreader_component(tmreader *tmr, const char *name)
{
PLHashNumber hash;
@ -686,14 +779,14 @@ tmgraphnode *tmreader_component(tmreader *tmr, const char *name)
return (tmgraphnode*) *PL_HashTableRawLookup(tmr->components, hash, name);
}
tmgraphnode *tmreader_method(tmreader *tmr, uint32 serial)
tmmethodnode *tmreader_method(tmreader *tmr, uint32 serial)
{
const void *key;
PLHashNumber hash;
key = (const void*) serial;
hash = hash_serial(key);
return (tmgraphnode*) *PL_HashTableRawLookup(tmr->methods, hash, key);
return (tmmethodnode*) *PL_HashTableRawLookup(tmr->methods, hash, key);
}
tmcallsite *tmreader_callsite(tmreader *tmr, uint32 serial)

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

@ -49,14 +49,18 @@ typedef struct tmgraphlink tmgraphlink;
typedef struct tmgraphedge tmgraphedge;
typedef struct tmgraphnode tmgraphnode;
typedef struct tmcallsite tmcallsite;
typedef struct tmmethodnode tmmethodnode;
struct tmevent {
char type;
uint32 serial;
union {
char *libname;
char *srcname;
struct {
uint32 library;
uint32 filename;
uint32 linenumber;
char *name;
} method;
struct {
@ -105,10 +109,18 @@ struct tmgraphnode {
int sort; /* sorted index in node table, -1 if no table */
};
struct tmmethodnode {
tmgraphnode graphnode;
char *sourcefile;
uint32 linenumber;
};
#define tmgraphnode_name(node) ((char*) (node)->entry.value)
#define tmmethodnode_name(node) ((char*) (node)->graphnode.entry.value)
#define tmlibrary_serial(lib) ((uint32) (lib)->entry.key)
#define tmcomponent_name(comp) ((const char*) (comp)->entry.key)
#define filename_name(hashentry) ((char*)hashentry->value)
/* Half a graphedge, not including per-edge allocation stats. */
struct tmgraphlink {
@ -139,7 +151,7 @@ struct tmcallsite {
tmcallsite *parent; /* calling site */
tmcallsite *siblings; /* other sites reached from parent */
tmcallsite *kids; /* sites reached from here */
tmgraphnode *method; /* method node in tmr->methods graph */
tmmethodnode *method; /* method node in tmr->methods graph */
uint32 offset; /* pc offset from start of method */
tmallcounts allocs;
tmallcounts frees;
@ -152,6 +164,7 @@ struct tmreader {
const char *program;
void *data;
PLHashTable *libraries;
PLHashTable *filenames;
PLHashTable *components;
PLHashTable *methods;
PLHashTable *callsites;
@ -174,8 +187,9 @@ extern int tmreader_eventloop(tmreader *tmr, const char *filename,
/* Map serial number or name to graphnode or callsite. */
extern tmgraphnode *tmreader_library(tmreader *tmr, uint32 serial);
extern tmgraphnode *tmreader_filename(tmreader *tmr, uint32 serial);
extern tmgraphnode *tmreader_component(tmreader *tmr, const char *name);
extern tmgraphnode *tmreader_method(tmreader *tmr, uint32 serial);
extern tmmethodnode *tmreader_method(tmreader *tmr, uint32 serial);
extern tmcallsite *tmreader_callsite(tmreader *tmr, uint32 serial);
/*

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

@ -116,8 +116,12 @@ dhwEnsureSymInitialized()
if (! gInitialized) {
if (! dhwEnsureImageHlpInitialized())
return PR_FALSE;
// dhwSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
dhwSymSetOptions(SYMOPT_UNDNAME);
dhwSymSetOptions(
#if defined(NS_TRACE_MALLOC)
SYMOPT_LOAD_LINES |
#endif
SYMOPT_UNDNAME);
// dhwSymSetOptions(SYMOPT_UNDNAME);
if (! dhwSymInitialize(::GetCurrentProcess(), NULL, TRUE))
return PR_FALSE;
gInitialized = PR_TRUE;

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

@ -48,6 +48,9 @@
//
PR_BEGIN_EXTERN_C
typedef DWORD (__stdcall *SYMSETOPTIONSPROC)(DWORD);
extern SYMSETOPTIONSPROC _SymSetOptions;
typedef BOOL (__stdcall *SYMINITIALIZEPROC)(HANDLE, LPSTR, BOOL);
extern SYMINITIALIZEPROC _SymInitialize;
@ -86,6 +89,9 @@ extern SYMGETMODULEINFO _SymGetModuleInfo;
typedef BOOL ( __stdcall *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID);
extern ENUMLOADEDMODULES _EnumerateLoadedModules;
typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);
extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
PRBool EnsureSymInitialized();
/*
@ -96,8 +102,9 @@ PRBool EnsureSymInitialized();
* SymInitialize was called, and thus the module information
* and symbol information is not available.
* This code rectifies that problem.
* Line information is optional.
*/
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo);
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo);
PR_END_EXTERN_C

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

@ -392,6 +392,36 @@ static void log_string(logfile *fp, const char *str)
log_byte(fp, '\0');
}
static void log_filename(logfile* aFP, const char* aFilename)
{
int nameLen = strlen(aFilename);
if (512 > nameLen) {
const char* skipTry1 = "mozilla";
char* found = nsnull;
char* convert = nsnull;
char dup[512];
strcpy(dup, aFilename);
found = strstr(dup, skipTry1);
if (nsnull == found) {
found = dup;
}
for (convert = found; '\0' != *convert; convert++) {
if ('\\' == *convert) {
*convert = '/';
}
}
log_string(aFP, found);
}
else {
log_string(aFP, aFilename);
}
}
static void log_uint32(logfile *fp, uint32 ival)
{
if (ival < 0x80) {
@ -497,6 +527,7 @@ static uint32 library_serial_generator = 0;
static uint32 method_serial_generator = 0;
static uint32 callsite_serial_generator = 0;
static uint32 tmstats_serial_generator = 0;
static uint32 filename_serial_generator = 0;
/* Root of the tree of callsites, the sum of all (cycle-compressed) stacks. */
static callsite calltree_root = {0, 0, LFD_SET_STATIC_INITIALIZER, NULL, NULL, 0, NULL, NULL, NULL};
@ -581,6 +612,9 @@ static PLHashAllocOps lfdset_hashallocops = {
/* Table of library pathnames mapped to to logged 'L' record serial numbers. */
static PLHashTable *libraries = NULL;
/* Table of filename pathnames mapped to logged 'G' record serial numbers. */
static PLHashTable *filenames = nsnull;
/* Table mapping method names to logged 'N' record serial numbers. */
static PLHashTable *methods = NULL;
@ -617,6 +651,10 @@ static callsite *calltree(int skip)
PLHashEntry **hep, *he;
lfdset_entry *le;
char* noname = "noname";
IMAGEHLP_LINE imagehelpLine;
const char* filename = nsnull;
uint32 linenumber = 0;
uint32 filename_serial = 0;
imagehelp.SizeOfStruct = sizeof(imagehelp);
framenum = 0;
@ -736,12 +774,22 @@ static callsite *calltree(int skip)
* callsite info. XXX static syms are masked by nearest lower global
* Load up the info for the dll.
*/
memset(&imagehelpLine, 0, sizeof(imagehelpLine));
if (!SymGetModuleInfoEspecial(myProcess,
frame[framenum].AddrPC.Offset,
&imagehelp)) {
&imagehelp, &imagehelpLine)) {
library = noname;
filename = noname;
linenumber = 0;
} else {
library = imagehelp.ModuleName;
filename = imagehelpLine.FileName;
linenumber = imagehelpLine.LineNumber;
if ('\0' == filename) {
filename = noname;
linenumber = 0;
}
}
/* Check whether we need to emit a library trace record. */
@ -791,6 +839,49 @@ static callsite *calltree(int skip)
}
}
/* Check whether we need to emit a filename trace record. */
filename_serial = 0;
if (filename) {
if (!filenames) {
filenames = PL_NewHashTable(100, PL_HashString,
PL_CompareStrings, PL_CompareValues,
&lfdset_hashallocops, NULL);
if (nsnull == filenames) {
tmstats.btmalloc_failures++;
return nsnull;
}
}
hash = PL_HashString(filename);
hep = PL_HashTableRawLookup(filenames, hash, filename);
he = *hep;
if (he) {
filename_serial = (uint32) he->value;
le = (lfdset_entry *) he;
if (LFD_TEST(fp->lfd, &le->lfdset)) {
/* We already logged an event on fp for this filename. */
le = NULL;
}
} else {
filename = strdup(filename);
if (filename) {
filename_serial = ++filename_serial_generator;
he = PL_HashTableRawAdd(filenames, hep, hash, filename,
(void*) filename_serial);
}
if (!he) {
tmstats.btmalloc_failures++;
return NULL;
}
le = (lfdset_entry *) he;
}
if (le) {
/* Need to log an event to fp for this filename. */
log_event1(fp, TM_EVENT_FILENAME, filename_serial);
log_filename(fp, filename);
LFD_SET(fp->lfd, &le->lfdset);
}
}
symbol = (PIMAGEHLP_SYMBOL) buf;
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
symbol->MaxNameLength = sizeof(buf) - sizeof(IMAGEHLP_SYMBOL);
@ -858,7 +949,7 @@ static callsite *calltree(int skip)
le = (lfdset_entry *) he;
}
if (le) {
log_event2(fp, TM_EVENT_METHOD, method_serial, library_serial);
log_event4(fp, TM_EVENT_METHOD, method_serial, library_serial, filename_serial, linenumber);
log_string(fp, method);
LFD_SET(fp->lfd, &le->lfdset);
}
@ -930,6 +1021,9 @@ static callsite *calltree(uint32 *bp)
PLHashNumber hash;
PLHashEntry **hep, *he;
lfdset_entry *le;
uint32 filename_serial;
uint32 linenumber;
const char* filename;
/* Reverse the stack frame list to avoid recursion. */
bpup = NULL;
@ -1005,6 +1099,13 @@ static callsite *calltree(uint32 *bp)
return NULL;
}
/*
* One day, if someone figures out how to get filename and line
* number info, this is the place to fill it all in.
*/
filename = "noname";
linenumber = 0;
/* Check whether we need to emit a library trace record. */
library_serial = 0;
library = info.dli_fname;
@ -1052,6 +1153,48 @@ static callsite *calltree(uint32 *bp)
}
}
/* Check whether we need to emit a filename trace record. */
filename_serial = 0;
if (filename) {
if (!filenames) {
filenames = PL_NewHashTable(100, PL_HashString,
PL_CompareStrings, PL_CompareValues,
&lfdset_hashallocops, NULL);
if (nsnull == filenames) {
tmstats.btmalloc_failures++;
return nsnull;
}
}
hash = PL_HashString(filename);
hep = PL_HashTableRawLookup(filenames, hash, filename);
he = *hep;
if (he) {
filename_serial = (uint32) he->value;
le = (lfdset_entry *) he;
if (LFD_TEST(fp->lfd, &le->lfdset)) {
/* We already logged an event on fp for this filename. */
le = NULL;
}
} else {
if (filename) {
filename_serial = ++filename_serial_generator;
he = PL_HashTableRawAdd(filenames, hep, hash, filename,
(void*) filename_serial);
}
if (!he) {
tmstats.btmalloc_failures++;
return NULL;
}
le = (lfdset_entry *) he;
}
if (le) {
/* Need to log an event to fp for this filename. */
log_event1(fp, TM_EVENT_FILENAME, filename_serial);
log_filename(fp, filename);
LFD_SET(fp->lfd, &le->lfdset);
}
}
/* Now find the demangled method name and pc offset in it. */
symbol = info.dli_sname;
offset = (char*)pc - (char*)info.dli_saddr;
@ -1110,7 +1253,7 @@ static callsite *calltree(uint32 *bp)
le = (lfdset_entry *) he;
}
if (le) {
log_event2(fp, TM_EVENT_METHOD, method_serial, library_serial);
log_event4(fp, TM_EVENT_METHOD, method_serial, library_serial, filename_serial, linenumber);
log_string(fp, method);
LFD_SET(fp->lfd, &le->lfdset);
}

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

@ -45,7 +45,7 @@ PR_BEGIN_EXTERN_C
* NS_TraceMallocStartup comment (below) for magic number differences in log
* file structure.
*/
#define NS_TRACE_MALLOC_MAGIC "XPCOM\nTMLog07\r\n\032"
#define NS_TRACE_MALLOC_MAGIC "XPCOM\nTMLog08\r\n\032"
#define NS_TRACE_MALLOC_MAGIC_SIZE 16
/**
@ -122,9 +122,19 @@ typedef struct nsTMStats {
* old address, old size
* 'F' site serial, interval, address, free size
*
* Event Operands (magic TMLog07)
* no one documented their changes.
* best of luck....
*
* Event Operands (magic TMLog08)
* 'G' filename serial, source filename string.
* 'N' method serial, library serial, source filename serial,
* source file linenumber, demangled name string
*
* See tools/trace-malloc/bloatblame.c for an example log-file reader.
*/
#define TM_EVENT_LIBRARY 'L'
#define TM_EVENT_FILENAME 'G'
#define TM_EVENT_METHOD 'N'
#define TM_EVENT_CALLSITE 'S'
#define TM_EVENT_MALLOC 'M'

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

@ -862,6 +862,8 @@ static void InitTraceLog(void)
PR_BEGIN_EXTERN_C
SYMSETOPTIONSPROC _SymSetOptions;
SYMINITIALIZEPROC _SymInitialize;
SYMCLEANUPPROC _SymCleanup;
@ -882,6 +884,8 @@ SYMGETMODULEINFO _SymGetModuleInfo;
ENUMLOADEDMODULES _EnumerateLoadedModules;
SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
PR_END_EXTERN_C
static PRBool
@ -893,6 +897,9 @@ EnsureImageHlpInitialized()
HMODULE module = ::LoadLibrary("IMAGEHLP.DLL");
if (!module) return PR_FALSE;
_SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions");
if (!_SymSetOptions) return PR_FALSE;
_SymInitialize = (SYMINITIALIZEPROC) ::GetProcAddress(module, "SymInitialize");
if (!_SymInitialize) return PR_FALSE;
@ -923,6 +930,9 @@ EnsureImageHlpInitialized()
_EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules");
if (!_EnumerateLoadedModules) return PR_FALSE;
_SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr");
if (!_SymGetLineFromAddr) return PR_FALSE;
gInitialized = PR_TRUE;
}
@ -971,18 +981,25 @@ static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULON
* and symbol information is not available.
* This code rectifies that problem.
*/
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo)
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo)
{
BOOL retval = FALSE;
/*
* Init the vars if we have em.
*/
aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE);
if (nsnull != aLineInfo) {
aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE);
}
/*
* Give it a go.
* It may already be loaded.
*/
retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo);
if(FALSE == retval)
{
if (FALSE == retval) {
BOOL enumRes = FALSE;
/*
@ -1000,6 +1017,17 @@ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aMo
}
}
/*
* If we got module info, we may attempt line info as well.
* We will not report failure if this does not work.
*/
if (FALSE != retval && nsnull != aLineInfo && nsnull != _SymGetLineFromAddr) {
DWORD displacement = 0;
BOOL lineRes = FALSE;
lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo);
}
return retval;
}
@ -1011,6 +1039,7 @@ EnsureSymInitialized()
if (! gInitialized) {
if (! EnsureImageHlpInitialized())
return PR_FALSE;
_SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
gInitialized = _SymInitialize(GetCurrentProcess(), 0, TRUE);
}
return gInitialized;
@ -1100,7 +1129,7 @@ nsTraceRefcnt::WalkTheStack(FILE* aStream)
IMAGEHLP_MODULE modInfo;
modInfo.SizeOfStruct = sizeof(modInfo);
BOOL modInfoRes = TRUE;
modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo);
modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo, nsnull);
char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf;

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

@ -862,6 +862,8 @@ static void InitTraceLog(void)
PR_BEGIN_EXTERN_C
SYMSETOPTIONSPROC _SymSetOptions;
SYMINITIALIZEPROC _SymInitialize;
SYMCLEANUPPROC _SymCleanup;
@ -882,6 +884,8 @@ SYMGETMODULEINFO _SymGetModuleInfo;
ENUMLOADEDMODULES _EnumerateLoadedModules;
SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
PR_END_EXTERN_C
static PRBool
@ -893,6 +897,9 @@ EnsureImageHlpInitialized()
HMODULE module = ::LoadLibrary("IMAGEHLP.DLL");
if (!module) return PR_FALSE;
_SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions");
if (!_SymSetOptions) return PR_FALSE;
_SymInitialize = (SYMINITIALIZEPROC) ::GetProcAddress(module, "SymInitialize");
if (!_SymInitialize) return PR_FALSE;
@ -923,6 +930,9 @@ EnsureImageHlpInitialized()
_EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules");
if (!_EnumerateLoadedModules) return PR_FALSE;
_SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr");
if (!_SymGetLineFromAddr) return PR_FALSE;
gInitialized = PR_TRUE;
}
@ -971,18 +981,25 @@ static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULON
* and symbol information is not available.
* This code rectifies that problem.
*/
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo)
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo)
{
BOOL retval = FALSE;
/*
* Init the vars if we have em.
*/
aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE);
if (nsnull != aLineInfo) {
aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE);
}
/*
* Give it a go.
* It may already be loaded.
*/
retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo);
if(FALSE == retval)
{
if (FALSE == retval) {
BOOL enumRes = FALSE;
/*
@ -1000,6 +1017,17 @@ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aMo
}
}
/*
* If we got module info, we may attempt line info as well.
* We will not report failure if this does not work.
*/
if (FALSE != retval && nsnull != aLineInfo && nsnull != _SymGetLineFromAddr) {
DWORD displacement = 0;
BOOL lineRes = FALSE;
lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo);
}
return retval;
}
@ -1011,6 +1039,7 @@ EnsureSymInitialized()
if (! gInitialized) {
if (! EnsureImageHlpInitialized())
return PR_FALSE;
_SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
gInitialized = _SymInitialize(GetCurrentProcess(), 0, TRUE);
}
return gInitialized;
@ -1100,7 +1129,7 @@ nsTraceRefcnt::WalkTheStack(FILE* aStream)
IMAGEHLP_MODULE modInfo;
modInfo.SizeOfStruct = sizeof(modInfo);
BOOL modInfoRes = TRUE;
modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo);
modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo, nsnull);
char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf;