From 110f79280d2138aac37bacac407345c61b3e99a1 Mon Sep 17 00:00:00 2001 From: "dbaron@dbaron.org" Date: Fri, 10 Aug 2007 14:29:37 -0700 Subject: [PATCH] Split the address->symbol mapping from the rest of the stack walking code. b=374829 r=bsmedberg a=bzbarsky --- xpcom/base/nsStackFrameUnix.cpp | 165 ++++++++++++------- xpcom/base/nsStackFrameWin.cpp | 268 ++++++++++++++++++++----------- xpcom/base/nsStackWalk.cpp | 20 +++ xpcom/base/nsStackWalk.h | 56 ++++++- xpcom/base/nsTraceRefcntImpl.cpp | 9 +- xpfe/bootstrap/nsSigHandlers.cpp | 9 +- 6 files changed, 370 insertions(+), 157 deletions(-) diff --git a/xpcom/base/nsStackFrameUnix.cpp b/xpcom/base/nsStackFrameUnix.cpp index 6040e4942e74..8f34e7d53709 100644 --- a/xpcom/base/nsStackFrameUnix.cpp +++ b/xpcom/base/nsStackFrameUnix.cpp @@ -42,6 +42,7 @@ #include #include "nscore.h" #include +#include "plstr.h" // On glibc 2.1, the Dl_info api defined in is only exposed // if __USE_GNU is defined. I suppose its some kind of standards @@ -91,7 +92,6 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, void *aClosure) { // Stack walking code courtesy Kipp's "leaky". - char buf[512]; // Get the frame pointer void **bp; @@ -110,43 +110,68 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, for ( ; (void**)*bp > bp; bp = (void**)*bp) { void *pc = *(bp+1); if (--skip < 0) { - Dl_info info; - int ok = dladdr(pc, &info); - if (!ok) { - snprintf(buf, sizeof(buf), "UNKNOWN %p\n", pc); - (*aCallback)(buf, aClosure); - continue; - } - - PRUint32 foff = (char*)pc - (char*)info.dli_fbase; - - const char * symbol = info.dli_sname; - int len; - if (!symbol || !(len = strlen(symbol))) { - snprintf(buf, sizeof(buf), "UNKNOWN [%s +0x%08X]\n", - info.dli_fname, foff); - (*aCallback)(buf, aClosure); - continue; - } - - char demangled[4096] = "\0"; - - DemangleSymbol(symbol, demangled, sizeof(demangled)); - - if (strlen(demangled)) { - symbol = demangled; - len = strlen(symbol); - } - - PRUint32 off = (char*)pc - (char*)info.dli_saddr; - snprintf(buf, sizeof(buf), "%s+0x%08X [%s +0x%08X]\n", - symbol, off, info.dli_fname, foff); - (*aCallback)(buf, aClosure); + (*aCallback)(pc, aClosure); } } return NS_OK; } +EXPORT_XPCOM_API(nsresult) +NS_DescribeCodeAddress(void *aPC, nsCodeAddressDetails *aDetails) +{ + aDetails->library[0] = '\0'; + aDetails->loffset = 0; + aDetails->filename[0] = '\0'; + aDetails->lineno = 0; + aDetails->function[0] = '\0'; + aDetails->foffset = 0; + + Dl_info info; + int ok = dladdr(aPC, &info); + if (!ok) { + return NS_OK; + } + + PL_strncpyz(aDetails->library, info.dli_fname, sizeof(aDetails->library)); + aDetails->loffset = (char*)aPC - (char*)info.dli_fbase; + + const char * symbol = info.dli_sname; + int len; + if (!symbol || !(len = strlen(symbol))) { + return NS_OK; + } + + char demangled[4096] = "\0"; + + DemangleSymbol(symbol, demangled, sizeof(demangled)); + + if (strlen(demangled)) { + symbol = demangled; + len = strlen(symbol); + } + + PL_strncpyz(aDetails->function, symbol, sizeof(aDetails->function)); + aDetails->foffset = (char*)aPC - (char*)info.dli_saddr; + return NS_OK; +} + +EXPORT_XPCOM_API(nsresult) +NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, + char *aBuffer, PRUint32 aBufferSize) +{ + if (!aDetails->library[0]) { + snprintf(aBuffer, aBufferSize, "UNKNOWN %p\n", aPC); + } else if (!aDetails->function[0]) { + snprintf(aBuffer, aBufferSize, "UNKNOWN [%s +0x%08lX]\n", + aDetails->library, aDetails->loffset); + } else { + snprintf(aBuffer, aBufferSize, "%s+0x%08lX [%s +0x%08lX]\n", + aDetails->function, aDetails->foffset, + aDetails->library, aDetails->loffset); + } + return NS_OK; +} + #elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) /* @@ -253,33 +278,10 @@ load_address(void * pc, void * arg ) if (ptr->next) { mutex_unlock(&lock); } else { - char buffer[4096], dembuff[4096]; - Dl_info info; - const char *func = "??", *lib = "??"; + (*args.callback)(pc, args.closure); ptr->next = newbucket(pc); mutex_unlock(&lock); - - if (dladdr(pc, & info)) { - if (info.dli_fname) - lib = info.dli_fname; - if (info.dli_sname) - func = info.dli_sname; - } - -#ifdef __GNUC__ - DemangleSymbol(func, dembuff, sizeof(dembuff)); -#else - if (!demf || demf(func, dembuff, sizeof (dembuff))) - dembuff[0] = 0; -#endif /*__GNUC__*/ - if (strlen(dembuff)) { - func = dembuff; - } - snprintf(buffer, sizeof(buffer), "%u %s:%s+0x%x\n", - ptr->next->index, lib, func, - (char *)pc - (char*)info.dli_saddr); - (*args.callback)(buffer, args.closure); } return 0; } @@ -357,4 +359,53 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, cs_operate(load_address, &args); return NS_OK; } + +EXPORT_XPCOM_API(nsresult) +NS_DescribeCodeAddress(void *aPC, nsCodeAddressDetails *aDetails) +{ + aDetails->library[0] = '\0'; + aDetails->loffset = 0; + aDetails->filename[0] = '\0'; + aDetails->lineno = 0; + aDetails->function[0] = '\0'; + aDetails->foffset = 0; + + char dembuff[4096]; + Dl_info info; + + if (dladdr(aPC, & info)) { + if (info.dli_fname) { + PL_strncpyz(aDetails->library, info.dli_fname, + sizeof(aDetails->library)); + aDetails->loffset = (char*)aPC - (char*)info.dli_fbase; + } + if (info.dli_sname) { + aDetails->foffset = (char*)aPC - (char*)info.dli_saddr; +#ifdef __GNUC__ + DemangleSymbol(func, dembuff, sizeof(dembuff)); +#else + if (!demf || demf(func, dembuff, sizeof (dembuff))) + dembuff[0] = 0; +#endif /*__GNUC__*/ + PL_strncpyz(aDetails->function, + (dembuff[0] != '\0') ? dembuff : info.dli_sname, + sizeof(aDetails->function)); + } + } + + return NS_OK; +} + +EXPORT_XPCOM_API(nsresult) +NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, + char *aBuffer, PRUint32 aBufferSize) +{ + snprintf(aBuffer, aBufferSize, "%p %s:%s+0x%lx\n", + aPC, + aDetails->library[0] ? aDetails->library : "??", + aDetails->function[0] ? aDetails->function : "??", + aDetails->foffset); + return NS_OK; +} + #endif diff --git a/xpcom/base/nsStackFrameWin.cpp b/xpcom/base/nsStackFrameWin.cpp index 989faee3fe3d..6229b169c14b 100644 --- a/xpcom/base/nsStackFrameWin.cpp +++ b/xpcom/base/nsStackFrameWin.cpp @@ -42,6 +42,7 @@ #include #include #include "nsStackFrameWin.h" +#include "plstr.h" // Define these as static pointers so that we can load the DLL on the // fly (and not introduce a link-time dependency on it). Tip o' the @@ -123,7 +124,7 @@ PR_END_EXTERN_C // Routine to print an error message to standard error. // Will also call callback with error, if data supplied. -void PrintError(char *prefix, WalkStackData *data) +void PrintError(char *prefix) { LPVOID lpMsgBuf; DWORD lastErr = GetLastError(); @@ -139,8 +140,6 @@ void PrintError(char *prefix, WalkStackData *data) char buf[512]; _snprintf(buf, sizeof(buf), "### ERROR: %s: %s", prefix, lpMsgBuf); fputs(buf, stderr); - if (data) - (*data->callback)(buf, data->closure); LocalFree( lpMsgBuf ); } @@ -159,7 +158,7 @@ EnsureImageHlpInitialized() NULL); // unnamed mutex if (hStackWalkMutex == NULL) { - PrintError("CreateMutex", NULL); + PrintError("CreateMutex"); return PR_FALSE; } @@ -428,7 +427,7 @@ EnsureSymInitialized() _SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); retStat = _SymInitialize(GetCurrentPIDorHandle(), NULL, TRUE); if (!retStat) - PrintError("SymInitialize", NULL); + PrintError("SymInitialize"); gInitialized = retStat; /* XXX At some point we need to arrange to call _SymCleanup */ @@ -475,12 +474,12 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, if (walkerThread) { walkerReturn = ::WaitForSingleObject(walkerThread, 2000); // no timeout is never a good idea if (walkerReturn != WAIT_OBJECT_0) { - PrintError("ThreadWait", &data); + PrintError("ThreadWait"); } CloseHandle(myThread); } else { - PrintError("ThreadCreate", &data); + PrintError("ThreadCreate"); } return NS_OK; } @@ -495,7 +494,7 @@ WalkStackThread(LPVOID lpdata) // He's currently waiting for us to finish so now should be a good time. ret = ::SuspendThread( data->thread ); if (ret == -1) { - PrintError("ThreadSuspend", data); + PrintError("ThreadSuspend"); } else { if (_StackWalk64) @@ -504,7 +503,7 @@ WalkStackThread(LPVOID lpdata) WalkStackMain(data); ret = ::ResumeThread(data->thread); if (ret == -1) { - PrintError("ThreadResume", data); + PrintError("ThreadResume"); } } @@ -521,7 +520,6 @@ WalkStackMain64(struct WalkStackData* data) CONTEXT context; HANDLE myProcess = data->process; HANDLE myThread = data->thread; - char buf[512]; DWORD64 addr; STACKFRAME64 frame64; int skip = 3 + data->skipFrames; // skip our own stack walking frames @@ -531,7 +529,7 @@ WalkStackMain64(struct WalkStackData* data) memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(myThread, &context)) { - PrintError("GetThreadContext", data); + PrintError("GetThreadContext"); return; } @@ -550,7 +548,7 @@ WalkStackMain64(struct WalkStackData* data) frame64.AddrStack.Offset = context.SP; frame64.AddrFrame.Offset = context.RsBSP; #else - PrintError("Unknown platform. No stack walking.", data); + PrintError("Unknown platform. No stack walking."); return; #endif frame64.AddrPC.Mode = AddrModeFlat; @@ -588,55 +586,36 @@ WalkStackMain64(struct WalkStackData* data) 0 ); + ReleaseMutex(hStackWalkMutex); // release our lock + if (ok) addr = frame64.AddrPC.Offset; - else - PrintError("WalkStack64", data); + else { + addr = 0; + PrintError("WalkStack64"); + } if (!ok || (addr == 0)) { - ReleaseMutex(hStackWalkMutex); // release our lock break; } if (skip-- > 0) { - ReleaseMutex(hStackWalkMutex); // release our lock continue; } - // - // Attempt to load module info before we attempt to reolve the symbol. - // This just makes sure we get good info if available. - // - - IMAGEHLP_MODULE64 modInfo; - modInfo.SizeOfStruct = sizeof(modInfo); - BOOL modInfoRes; - modInfoRes = SymGetModuleInfoEspecial64(myProcess, addr, &modInfo, nsnull); - - ULONG64 buffer[(sizeof(SYMBOL_INFO) + - MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - - DWORD64 displacement; - ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol); - - // All done with debug calls so release our lock. - ReleaseMutex(hStackWalkMutex); - - if (ok) - _snprintf(buf, sizeof(buf), "%s!%s+0x%016X\n", modInfo.ModuleName, pSymbol->Name, displacement); - else - _snprintf(buf, sizeof(buf), "0x%016X\n", addr); - (*data->callback)(buf, data->closure); + (*data->callback)((void*)addr, data->closure); +#if 0 // Stop walking when we get to kernel32. if (strcmp(modInfo.ModuleName, "kernel32") == 0) break; +#else + if (frame64.AddrReturn.Offset == 0) + break; +#endif } else { - PrintError("LockError64", data); + PrintError("LockError64"); } } return; @@ -653,7 +632,6 @@ WalkStackMain(struct WalkStackData* data) CONTEXT context; HANDLE myProcess = data->process; HANDLE myThread = data->thread; - char buf[512]; DWORD addr; STACKFRAME frame; int skip = data->skipFrames; // skip our own stack walking frames @@ -663,7 +641,7 @@ WalkStackMain(struct WalkStackData* data) memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(myThread, &context)) { - PrintError("GetThreadContext", data); + PrintError("GetThreadContext"); return; } @@ -677,7 +655,7 @@ WalkStackMain(struct WalkStackData* data) frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; #else - PrintError("Unknown platform. No stack walking.", data); + PrintError("Unknown platform. No stack walking."); return; #endif @@ -703,71 +681,36 @@ WalkStackMain(struct WalkStackData* data) 0 // translate address routine ); + ReleaseMutex(hStackWalkMutex); // release our lock + if (ok) addr = frame.AddrPC.Offset; - else - PrintError("WalkStack", data); + else { + addr = 0; + PrintError("WalkStack"); + } if (!ok || (addr == 0)) { - ReleaseMutex(hStackWalkMutex); // release our lock break; } if (skip-- > 0) { - ReleaseMutex(hStackWalkMutex); // release the lock continue; } - // - // Attempt to load module info before we attempt to resolve the symbol. - // This just makes sure we get good info if available. - // - - IMAGEHLP_MODULE modInfo; - modInfo.SizeOfStruct = sizeof(modInfo); - BOOL modInfoRes; - modInfoRes = SymGetModuleInfoEspecial(myProcess, addr, &modInfo, nsnull); - -#ifdef USING_WXP_VERSION - ULONG64 buffer[(sizeof(SYMBOL_INFO) + - MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - - DWORD64 displacement; - - ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol); -#else - char buf[sizeof(IMAGEHLP_SYMBOL) + 512]; - PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) buf; - pSymbol->SizeOfStruct = sizeof(buf); - pSymbol->MaxNameLength = 512; - - DWORD displacement; - - ok = _SymGetSymFromAddr(myProcess, - frame.AddrPC.Offset, - &displacement, - pSymbol); -#endif - - // All done with debug calls so release our lock. - ReleaseMutex(hStackWalkMutex); - - if (ok) - _snprintf(buf, sizeof(buf), "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement); - else - _snprintf(buf, sizeof(buf), "0x%08X\n", (DWORD) addr); - (*data->callback)(buf, data->closure); + (*data->callback)((void*)addr, data->closure); +#if 0 // Stop walking when we get to kernel32.dll. if (strcmp(modInfo.ImageName, "kernel32.dll") == 0) break; - +#else + if (frame.AddrReturn.Offset == 0) + break; +#endif } else { - PrintError("LockError", data); + PrintError("LockError"); } } @@ -775,3 +718,138 @@ WalkStackMain(struct WalkStackData* data) return; } + +EXPORT_XPCOM_API(nsresult) +NS_DescribeCodeAddress(void *aPC, nsCodeAddressDetails *aDetails) +{ + aDetails->library[0] = '\0'; + aDetails->loffset = 0; + aDetails->filename[0] = '\0'; + aDetails->lineno = 0; + aDetails->function[0] = '\0'; + aDetails->foffset = 0; + + HANDLE myProcess = ::GetCurrentProcess(); + BOOL ok; + + // debug routines are not threadsafe, so grab the lock. + DWORD dwWaitResult; + dwWaitResult = WaitForSingleObject(hStackWalkMutex, INFINITE); + if (dwWaitResult != WAIT_OBJECT_0) + return NS_ERROR_UNEXPECTED; + +#ifdef USING_WXP_VERSION + if (_StackWalk64) { + // + // Attempt to load module info before we attempt to resolve the symbol. + // This just makes sure we get good info if available. + // + + DWORD64 addr = (DWORD64)aPC; + IMAGEHLP_MODULE64 modInfo; + modInfo.SizeOfStruct = sizeof(modInfo); + BOOL modInfoRes; + modInfoRes = SymGetModuleInfoEspecial64(myProcess, addr, &modInfo, nsnull); + + if (modInfoRes) { + PL_strncpyz(aDetails->library, modInfo.ModuleName, + sizeof(aDetails->library)); + aDetails->loffset = (char*) aPC - (char*) modInfo.BaseOfImage; + // XXX We could get filename/lineno information from + // SymGetModuleInfoEspecial64 + } + + ULONG64 buffer[(sizeof(SYMBOL_INFO) + + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + DWORD64 displacement; + ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol); + + if (ok) { + PL_strncpyz(aDetails->function, pSymbol->Name, + sizeof(aDetails->function)); + aDetails->foffset = displacement; + } + } else +#endif + { + // + // Attempt to load module info before we attempt to resolve the symbol. + // This just makes sure we get good info if available. + // + + DWORD addr = (DWORD)aPC; + IMAGEHLP_MODULE modInfo; + modInfo.SizeOfStruct = sizeof(modInfo); + BOOL modInfoRes; + modInfoRes = SymGetModuleInfoEspecial(myProcess, addr, &modInfo, nsnull); + + if (modInfoRes) { + PL_strncpyz(aDetails->library, modInfo.ModuleName, + sizeof(aDetails->library)); + aDetails->loffset = (char*) aPC - (char*) modInfo.BaseOfImage; + // XXX We could get filename/lineno information from + // SymGetModuleInfoEspecial + } + +#ifdef USING_WXP_VERSION + ULONG64 buffer[(sizeof(SYMBOL_INFO) + + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + DWORD64 displacement; + + ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol); +#else + char buf[sizeof(IMAGEHLP_SYMBOL) + 512]; + PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) buf; + pSymbol->SizeOfStruct = sizeof(buf); + pSymbol->MaxNameLength = 512; + + DWORD displacement; + + ok = _SymGetSymFromAddr(myProcess, + frame.AddrPC.Offset, + &displacement, + pSymbol); +#endif + + if (ok) { + PL_strncpyz(aDetails->function, pSymbol->Name, + sizeof(aDetails->function)); + aDetails->foffset = displacement; + } + } + + ReleaseMutex(hStackWalkMutex); // release our lock + return NS_OK; +} + +EXPORT_XPCOM_API(nsresult) +NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, + char *aBuffer, PRUint32 aBufferSize) +{ +#ifdef USING_WXP_VERSION + if (_StackWalk64) { + if (aDetails->function[0]) + _snprintf(aBuffer, aBufferSize, "%s!%s+0x%016lX\n", + aDetails->library, aDetails->function, aDetails->foffset); + else + _snprintf(aBuffer, aBufferSize, "0x%016lX\n", aPC); + } else { +#endif + if (aDetails->function[0]) + _snprintf(aBuffer, aBufferSize, "%s!%s+0x%08lX\n", + aDetails->library, aDetails->function, aDetails->foffset); + else + _snprintf(aBuffer, aBufferSize, "0x%08lX\n", aPC); +#ifdef USING_WXP_VERSION + } +#endif + return NS_OK; +} diff --git a/xpcom/base/nsStackWalk.cpp b/xpcom/base/nsStackWalk.cpp index 42a1a4e63d9a..6d7553e73b91 100644 --- a/xpcom/base/nsStackWalk.cpp +++ b/xpcom/base/nsStackWalk.cpp @@ -56,4 +56,24 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, return NS_ERROR_NOT_IMPLEMENTED; } +EXPORT_XPCOM_API(nsresult) +NS_DescribeCodeAddress(void *aPC, nsCodeAddressDetails *aDetails) +{ + aDetails->library[0] = '\0'; + aDetails->loffset = 0; + aDetails->filename[0] = '\0'; + aDetails->lineno = 0; + aDetails->function[0] = '\0'; + aDetails->foffset = 0; + return NS_ERROR_NOT_IMPLEMENTED; +} + +EXPORT_XPCOM_API(nsresult) +NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, + char *aBuffer, PRUint32 aBufferSize) +{ + aBuffer[0] = '\0'; + return NS_ERROR_NOT_IMPLEMENTED; +} + #endif diff --git a/xpcom/base/nsStackWalk.h b/xpcom/base/nsStackWalk.h index 83e075f0b9fd..e8c0ef206f14 100644 --- a/xpcom/base/nsStackWalk.h +++ b/xpcom/base/nsStackWalk.h @@ -47,7 +47,7 @@ PR_BEGIN_EXTERN_C typedef void -(* PR_CALLBACK NS_WalkStackCallback)(char *aFrame, void *aClosure); +(* PR_CALLBACK NS_WalkStackCallback)(void *aPC, void *aClosure); /** * Call aCallback for the C/C++ stack frames on the current thread, from @@ -69,6 +69,60 @@ XPCOM_API(nsresult) NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, void *aClosure); +typedef struct { + /* + * The name of the shared library or executable containing an + * address and the address's offset within that library, or empty + * string and zero if unknown. + */ + char library[256]; + unsigned long loffset; + /* + * The name of the file name and line number of the code + * corresponding to the address, or empty string and zero if + * unknown. + */ + char filename[256]; + unsigned long lineno; + /* + * The name of the function containing an address and the address's + * offset within that function, or empty string and zero if unknown. + */ + char function[256]; + unsigned long foffset; +} nsCodeAddressDetails; + +/** + * For a given pointer to code, fill in the pieces of information used + * when printing a stack trace. + * + * @param aPC The code address. + * @param aDetails A structure to be filled in with the result. + */ +XPCOM_API(nsresult) +NS_DescribeCodeAddress(void *aPC, nsCodeAddressDetails *aDetails); + +/** + * Format the information about a code address in a format suitable for + * stack traces on the current platform. When available, this string + * should contain the function name, source file, and line number. When + * these are not available, library and offset should be reported, if + * possible. + * + * @param aPC The code address. + * @param aDetails The value filled in by NS_DescribeCodeAddress(aPC). + * @param aBuffer A string to be filled in with the description. + * The string will always be null-terminated. + * @param aBufferSize The size, in bytes, of aBuffer, including + * room for the terminating null. If the information + * to be printed would be larger than aBuffer, it + * will be truncated so that aBuffer[aBufferSize-1] + * is the terminating null. + */ +XPCOM_API(nsresult) +NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails, + char *aBuffer, PRUint32 aBufferSize); + PR_END_EXTERN_C #endif /* !defined(nsStackWalk_h_) */ diff --git a/xpcom/base/nsTraceRefcntImpl.cpp b/xpcom/base/nsTraceRefcntImpl.cpp index 5241ced52f68..f5649374ec02 100644 --- a/xpcom/base/nsTraceRefcntImpl.cpp +++ b/xpcom/base/nsTraceRefcntImpl.cpp @@ -829,10 +829,15 @@ static void InitTraceLog(void) extern "C" { -PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure) +PR_STATIC_CALLBACK(void) PrintStackFrame(void *aPC, void *aClosure) { FILE *stream = (FILE*)aClosure; - fprintf(stream, aFrame); + nsCodeAddressDetails details; + char buf[1024]; + + NS_DescribeCodeAddress(aPC, &details); + NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf)); + fprintf(stream, buf); } } diff --git a/xpfe/bootstrap/nsSigHandlers.cpp b/xpfe/bootstrap/nsSigHandlers.cpp index 7b75dbb3a45f..ca5f1d84aa19 100644 --- a/xpfe/bootstrap/nsSigHandlers.cpp +++ b/xpfe/bootstrap/nsSigHandlers.cpp @@ -118,9 +118,14 @@ void abnormal_exit_handler(int signum) extern "C" { -PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure) +PR_STATIC_CALLBACK(void) PrintStackFrame(void *aPC, void *aClosure) { - fprintf(stdout, aFrame); + char buf[1024]; + nsCodeAddressDetails details; + + NS_DescribeCodeAddress(aPC, &details); + NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf)); + fprintf(stdout, buf); } }