diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in index db8be9e2c1ec..39fd8ac310d1 100644 --- a/toolkit/xre/Makefile.in +++ b/toolkit/xre/Makefile.in @@ -164,15 +164,6 @@ CMMSRCS = MacApplicationDelegate.mm endif ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH))) -STACKWALK_SRC_LCSRCS = \ - nsStackFrameUnix.cpp \ - nsStackFrameUnix.h \ - $(NULL) - -STACKWALK_CPPSRCS := $(addprefix $(topsrcdir)/xpcom/base/, $(STACKWALK_SRC_LCSRCS)) -ifndef MOZ_ENABLE_LIBXUL -CPPSRCS += nsStackFrameUnix.cpp -endif SHAREDCPPSRCS += nsSigHandlers.cpp endif @@ -181,10 +172,6 @@ ifeq ($(OS_ARCH),WINNT) GARBAGE += $(addprefix $(srcdir)/,$(SHAREDCPPSRCS)) endif -ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH))) -GARBAGE += $(STACKWALK_SRC_LCSRCS) -endif - SHARED_LIBRARY_LIBS += ../profile/src/$(LIB_PREFIX)profile_s.$(LIB_SUFFIX) ifdef MOZ_ENABLE_XREMOTE @@ -254,7 +241,7 @@ ifdef WRAP_SYSTEM_INCLUDES DEFINES += -DWRAP_SYSTEM_INCLUDES endif -export:: $(addprefix $(topsrcdir)/xpfe/bootstrap/, $(SHAREDCPPSRCS)) $(STACKWALK_CPPSRCS) +export:: $(addprefix $(topsrcdir)/xpfe/bootstrap/, $(SHAREDCPPSRCS)) $(INSTALL) $^ . platform.ini: FORCE diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index 69e23cc7b4a3..78ffbd010530 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -65,6 +65,7 @@ CPPSRCS = \ nsUUIDGenerator.cpp \ nsSystemInfo.cpp \ nsCycleCollector.cpp \ + nsStackWalk.cpp \ $(NULL) ifdef GC_LEAK_DETECTOR @@ -85,6 +86,7 @@ EXPORTS = \ nsIAllocator.h \ nsIID.h \ nsISupportsObsolete.h \ + nsStackWalk.h \ nsTraceRefcntImpl.h \ nsWeakPtr.h \ nsInterfaceRequestorAgg.h \ @@ -95,11 +97,6 @@ ifdef MOZ_DEBUG CSRCS += pure_api.c EXPORTS += pure.h endif -CPPSRCS += nsStackFrameWin.cpp -endif - -ifneq ($(OS_ARCH),WINNT) -CPPSRCS += nsStackFrameUnix.cpp endif SDK_XPIDLSRCS = \ diff --git a/xpcom/base/nsStackFrameUnix.cpp b/xpcom/base/nsStackFrameUnix.cpp index c896302cf92e..6040e4942e74 100644 --- a/xpcom/base/nsStackFrameUnix.cpp +++ b/xpcom/base/nsStackFrameUnix.cpp @@ -37,11 +37,11 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsStackFrameUnix.h" #include #include #include #include "nscore.h" +#include // 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 @@ -86,9 +86,12 @@ void DemangleSymbol(const char * aSymbol, #if defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__)) // i386 or PPC Linux stackwalking code -void DumpStackToFile(FILE* aStream) +EXPORT_XPCOM_API(nsresult) +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; @@ -103,14 +106,15 @@ void DumpStackToFile(FILE* aStream) bp = (void**) __builtin_frame_address(0); #endif - int skip = 2; + int skip = aSkipFrames; for ( ; (void**)*bp > bp; bp = (void**)*bp) { void *pc = *(bp+1); - if (--skip <= 0) { + if (--skip < 0) { Dl_info info; int ok = dladdr(pc, &info); if (!ok) { - fprintf(aStream, "UNKNOWN %p\n", pc); + snprintf(buf, sizeof(buf), "UNKNOWN %p\n", pc); + (*aCallback)(buf, aClosure); continue; } @@ -119,8 +123,9 @@ void DumpStackToFile(FILE* aStream) const char * symbol = info.dli_sname; int len; if (!symbol || !(len = strlen(symbol))) { - fprintf(aStream, "UNKNOWN [%s +0x%08X]\n", - info.dli_fname, foff); + snprintf(buf, sizeof(buf), "UNKNOWN [%s +0x%08X]\n", + info.dli_fname, foff); + (*aCallback)(buf, aClosure); continue; } @@ -134,10 +139,12 @@ void DumpStackToFile(FILE* aStream) } PRUint32 off = (char*)pc - (char*)info.dli_saddr; - fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n", - symbol, off, info.dli_fname, foff); + snprintf(buf, sizeof(buf), "%s+0x%08X [%s +0x%08X]\n", + symbol, off, info.dli_fname, foff); + (*aCallback)(buf, aClosure); } } + return NS_OK; } #elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) @@ -152,16 +159,15 @@ void DumpStackToFile(FILE* aStream) #include #include -static int load_address ( void * pc, void * arg, FILE * aStream ); -static int write_address_file ( void * pc ); +static int load_address ( void * pc, void * arg ); static struct bucket * newbucket ( void * pc ); static struct frame * cs_getmyframeptr ( void ); static void cs_walk_stack ( void * (*read_func)(char * address), struct frame * fp, int (*operate_func)(void *, void *), - void * usrarg, FILE * aStream ); + void * usrarg ); static void cs_operate ( void (*operate_func)(void *, void *), - void * usrarg, FILE * aStream ); + void * usrarg ); #ifndef STACK_BIAS #define STACK_BIAS 0 @@ -190,9 +196,10 @@ struct bucket { struct bucket * next; }; -struct mybuf { - char * buffer; - int chars_left; +struct my_user_args { + NS_WalkStackCallback callback; + PRUint32 skipFrames; + void *closure; }; @@ -225,11 +232,12 @@ myinit() static int -write_address_file(void * pc, FILE* aStream) +load_address(void * pc, void * arg ) { static struct bucket table[2048]; static mutex_t lock; struct bucket * ptr; + struct my_user_args * args = (struct my_user_args *) arg; unsigned int val = NS_PTR_TO_INT32(pc); @@ -244,7 +252,6 @@ write_address_file(void * pc, FILE* aStream) if (ptr->next) { mutex_unlock(&lock); - return (ptr->next->index); } else { char buffer[4096], dembuff[4096]; Dl_info info; @@ -269,37 +276,12 @@ write_address_file(void * pc, FILE* aStream) if (strlen(dembuff)) { func = dembuff; } - fprintf(aStream, "%u %s:%s+0x%x\n", - ptr->next->index, - lib, - func, - (char *)pc - (char*)info.dli_saddr); - - return (ptr->next->index); + 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); } -} - - -static int -load_address(void * pc, void * arg, FILE * aStream) -{ - struct mybuf * buf = (struct mybuf *) arg; - - char name[80]; - int len; - - sprintf(name, " %u", write_address_file(pc, aStream)); - - len = strlen(name); - - if (len >= buf->chars_left) - return (1); - - strcat(buf->buffer, name); - - buf->chars_left -= len; - - return (0); + return 0; } @@ -336,12 +318,12 @@ csgetframeptr() static void cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), - void *usrarg, FILE * aStream) + void *usrarg) { while (fp != 0 && fp->fr_savpc != 0) { - if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0) + if (operate_func((void *)fp->fr_savpc, usrarg) != 0) break; /* * watch out - libthread stacks look funny at the top @@ -355,21 +337,24 @@ cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), static void -cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream) +cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg) { - cswalkstack(csgetframeptr(), operate_func, usrarg, aStream); + cswalkstack(csgetframeptr(), operate_func, usrarg); } -void DumpStackToFile(FILE* aStream) +EXPORT_XPCOM_API(nsresult) +NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure) { - char buffer[LOGSIZE]; - struct mybuf mybuf; + struct my_user_args args; if (!initialized) myinit(); - mybuf.chars_left = LOGSIZE - strlen(buffer)-1; - mybuf.buffer = buffer; - cs_operate(load_address, &mybuf, aStream); + args.callback = aCallback; + args.skipFrames = aSkipFrames; /* XXX Not handled! */ + args.closure = aClosure; + cs_operate(load_address, &args); + return NS_OK; } #endif diff --git a/xpcom/base/nsStackFrameWin.cpp b/xpcom/base/nsStackFrameWin.cpp index 4bfacb6fc32f..989faee3fe3d 100644 --- a/xpcom/base/nsStackFrameWin.cpp +++ b/xpcom/base/nsStackFrameWin.cpp @@ -39,8 +39,8 @@ * ***** END LICENSE BLOCK ***** */ #include "nscore.h" -#include "windows.h" -#include "stdio.h" +#include +#include #include "nsStackFrameWin.h" // Define these as static pointers so that we can load the DLL on the @@ -122,8 +122,8 @@ HANDLE hStackWalkMutex; PR_END_EXTERN_C // Routine to print an error message to standard error. -// Will also print to an additional stream if one is supplied. -void PrintError(char *prefix, FILE *out) +// Will also call callback with error, if data supplied. +void PrintError(char *prefix, WalkStackData *data) { LPVOID lpMsgBuf; DWORD lastErr = GetLastError(); @@ -136,9 +136,11 @@ void PrintError(char *prefix, FILE *out) 0, NULL ); - fprintf(stderr, "### ERROR: %s: %s", prefix, lpMsgBuf); - if (out) - fprintf(out, "### ERROR: %s: %s\n", prefix, lpMsgBuf); + char buf[512]; + _snprintf(buf, sizeof(buf), "### ERROR: %s: %s", prefix, lpMsgBuf); + fputs(buf, stderr); + if (data) + (*data->callback)(buf, data->closure); LocalFree( lpMsgBuf ); } @@ -443,16 +445,17 @@ EnsureSymInitialized() * whose in memory address doesn't match its in-file address. */ -void -DumpStackToFile(FILE* aStream) +EXPORT_XPCOM_API(nsresult) +NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure) { HANDLE myProcess = ::GetCurrentProcess(); HANDLE myThread, walkerThread; DWORD walkerReturn; - struct DumpStackToFileData data; + struct WalkStackData data; if (!EnsureSymInitialized()) - return; + return NS_ERROR_FAILURE; // Have to duplicate handle to get a real handle. ::DuplicateHandle( @@ -463,43 +466,45 @@ DumpStackToFile(FILE* aStream) THREAD_ALL_ACCESS, FALSE, 0 ); - data.stream = aStream; + data.callback = aCallback; + data.skipFrames = aSkipFrames; + data.closure = aClosure; data.thread = myThread; data.process = myProcess; - walkerThread = ::CreateThread( NULL, 0, DumpStackToFileThread, (LPVOID) &data, 0, NULL ) ; + walkerThread = ::CreateThread( NULL, 0, WalkStackThread, (LPVOID) &data, 0, NULL ) ; if (walkerThread) { walkerReturn = ::WaitForSingleObject(walkerThread, 2000); // no timeout is never a good idea if (walkerReturn != WAIT_OBJECT_0) { - PrintError("ThreadWait", aStream); + PrintError("ThreadWait", &data); } CloseHandle(myThread); } else { - PrintError("ThreadCreate", aStream); + PrintError("ThreadCreate", &data); } - return; + return NS_OK; } DWORD WINAPI -DumpStackToFileThread(LPVOID lpdata) +WalkStackThread(LPVOID lpdata) { - struct DumpStackToFileData *data = (DumpStackToFileData *)lpdata; + struct WalkStackData *data = (WalkStackData *)lpdata; DWORD ret ; // Suspend the calling thread, dump his stack, and then resume him. // 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->stream); + PrintError("ThreadSuspend", data); } else { if (_StackWalk64) - DumpStackToFileMain64(data); + WalkStackMain64(data); else - DumpStackToFileMain(data); + WalkStackMain(data); ret = ::ResumeThread(data->thread); if (ret == -1) { - PrintError("ThreadResume", data->stream); + PrintError("ThreadResume", data); } } @@ -507,7 +512,7 @@ DumpStackToFileThread(LPVOID lpdata) } void -DumpStackToFileMain64(struct DumpStackToFileData* data) +WalkStackMain64(struct WalkStackData* data) { #ifdef USING_WXP_VERSION // Get the context information for the thread. That way we will @@ -516,17 +521,17 @@ DumpStackToFileMain64(struct DumpStackToFileData* data) CONTEXT context; HANDLE myProcess = data->process; HANDLE myThread = data->thread; - FILE* aStream = data->stream; + char buf[512]; DWORD64 addr; STACKFRAME64 frame64; - int skip = 6; // skip our own stack walking frames + int skip = 3 + data->skipFrames; // skip our own stack walking frames BOOL ok; // Get a context for the specified thread. memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(myThread, &context)) { - PrintError("GetThreadContext", aStream); + PrintError("GetThreadContext", data); return; } @@ -545,7 +550,7 @@ DumpStackToFileMain64(struct DumpStackToFileData* data) frame64.AddrStack.Offset = context.SP; frame64.AddrFrame.Offset = context.RsBSP; #else - fprintf(aStream, "Unknown platform. No stack walking."); + PrintError("Unknown platform. No stack walking.", data); return; #endif frame64.AddrPC.Mode = AddrModeFlat; @@ -586,7 +591,7 @@ DumpStackToFileMain64(struct DumpStackToFileData* data) if (ok) addr = frame64.AddrPC.Offset; else - PrintError("WalkStack64", aStream); + PrintError("WalkStack64", data); if (!ok || (addr == 0)) { ReleaseMutex(hStackWalkMutex); // release our lock @@ -621,16 +626,17 @@ DumpStackToFileMain64(struct DumpStackToFileData* data) ReleaseMutex(hStackWalkMutex); if (ok) - fprintf(aStream, "%s!%s+0x%016X\n", modInfo.ModuleName, pSymbol->Name, displacement); + _snprintf(buf, sizeof(buf), "%s!%s+0x%016X\n", modInfo.ModuleName, pSymbol->Name, displacement); else - fprintf(aStream, "0x%016X\n", addr); + _snprintf(buf, sizeof(buf), "0x%016X\n", addr); + (*data->callback)(buf, data->closure); // Stop walking when we get to kernel32. if (strcmp(modInfo.ModuleName, "kernel32") == 0) break; } else { - PrintError("LockError64", aStream); + PrintError("LockError64", data); } } return; @@ -639,7 +645,7 @@ DumpStackToFileMain64(struct DumpStackToFileData* data) void -DumpStackToFileMain(struct DumpStackToFileData* data) +WalkStackMain(struct WalkStackData* data) { // Get the context information for the thread. That way we will // know where our sp, fp, pc, etc. are and can fill in the @@ -647,17 +653,17 @@ DumpStackToFileMain(struct DumpStackToFileData* data) CONTEXT context; HANDLE myProcess = data->process; HANDLE myThread = data->thread; - FILE* aStream = data->stream; + char buf[512]; DWORD addr; STACKFRAME frame; - int skip = 2; // skip our own stack walking frames + int skip = data->skipFrames; // skip our own stack walking frames BOOL ok; // Get a context for the specified thread. memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(myThread, &context)) { - PrintError("GetThreadContext", aStream); + PrintError("GetThreadContext", data); return; } @@ -671,7 +677,7 @@ DumpStackToFileMain(struct DumpStackToFileData* data) frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; #else - fprintf(aStream, "Unknown platform. No stack walking."); + PrintError("Unknown platform. No stack walking.", data); return; #endif @@ -700,7 +706,7 @@ DumpStackToFileMain(struct DumpStackToFileData* data) if (ok) addr = frame.AddrPC.Offset; else - PrintError("WalkStack", aStream); + PrintError("WalkStack", data); if (!ok || (addr == 0)) { ReleaseMutex(hStackWalkMutex); // release our lock @@ -750,9 +756,10 @@ DumpStackToFileMain(struct DumpStackToFileData* data) ReleaseMutex(hStackWalkMutex); if (ok) - fprintf(aStream, "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement); + _snprintf(buf, sizeof(buf), "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement); else - fprintf(aStream, "0x%08X\n", (DWORD) addr); + _snprintf(buf, sizeof(buf), "0x%08X\n", (DWORD) addr); + (*data->callback)(buf, data->closure); // Stop walking when we get to kernel32.dll. if (strcmp(modInfo.ImageName, "kernel32.dll") == 0) @@ -760,7 +767,7 @@ DumpStackToFileMain(struct DumpStackToFileData* data) } else { - PrintError("LockError", aStream); + PrintError("LockError", data); } } diff --git a/xpcom/base/nsStackFrameWin.h b/xpcom/base/nsStackFrameWin.h index b755b8151d2b..9867db22fc22 100644 --- a/xpcom/base/nsStackFrameWin.h +++ b/xpcom/base/nsStackFrameWin.h @@ -175,17 +175,18 @@ PRBool EnsureImageHlpInitialized(); */ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo); -struct DumpStackToFileData { - FILE *stream; +struct WalkStackData { + NS_WalkStackCallback callback; + PRUint32 skipFrames; + void *closure; HANDLE thread; HANDLE process; }; -void PrintError(char *prefix, FILE* out); -void DumpStackToFile(FILE* out); -DWORD WINAPI DumpStackToFileThread(LPVOID data); -void DumpStackToFileMain64(struct DumpStackToFileData* data); -void DumpStackToFileMain(struct DumpStackToFileData* data); +void PrintError(char *prefix, WalkStackData* data); +DWORD WINAPI WalkStackThread(LPVOID data); +void WalkStackMain64(struct WalkStackData* data); +void WalkStackMain(struct WalkStackData* data); PR_END_EXTERN_C diff --git a/xpcom/base/nsStackWalk.cpp b/xpcom/base/nsStackWalk.cpp new file mode 100644 index 000000000000..42a1a4e63d9a --- /dev/null +++ b/xpcom/base/nsStackWalk.cpp @@ -0,0 +1,59 @@ +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is NS_WalkTheStack. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron , Mozilla Corporation (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* API for getting a stack trace of the C/C++ stack on the current thread */ + +#include "nsStackWalk.h" + +#if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code +#include "nsStackFrameWin.cpp" + +// WIN32 x86 stack walking code +// i386 or PPC Linux stackwalking code or Solaris +#elif (defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))) +#include "nsStackFrameUnix.cpp" + +#else // unsupported platform. + +EXPORT_XPCOM_API(nsresult) +NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +#endif diff --git a/xpcom/base/nsStackWalk.h b/xpcom/base/nsStackWalk.h new file mode 100644 index 000000000000..83e075f0b9fd --- /dev/null +++ b/xpcom/base/nsStackWalk.h @@ -0,0 +1,74 @@ +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is NS_WalkTheStack. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron , Mozilla Corporation (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* API for getting a stack trace of the C/C++ stack on the current thread */ + +#ifndef nsStackWalk_h_ +#define nsStackWalk_h_ + +/* WARNING: This file is intended to be included from C or C++ files. */ + +#include "nscore.h" + +PR_BEGIN_EXTERN_C + +typedef void +(* PR_CALLBACK NS_WalkStackCallback)(char *aFrame, void *aClosure); + +/** + * Call aCallback for the C/C++ stack frames on the current thread, from + * the caller of NS_StackWalk to main (or above). + * + * @param aCallback Callback function, called once per frame. + * @param aSkipFrames Number of initial frames to skip. 0 means that + * the first callback will be for the caller of + * NS_StackWalk. + * @param aClosure Caller-supplied data passed through to aCallback. + * + * Returns NS_ERROR_NOT_IMPLEMENTED on platforms where it is + * unimplemented. + * + * May skip some stack frames due to compiler optimizations or code + * generation. + */ +XPCOM_API(nsresult) +NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, + void *aClosure); + +PR_END_EXTERN_C + +#endif /* !defined(nsStackWalk_h_) */ diff --git a/xpcom/base/nsTraceRefcntImpl.cpp b/xpcom/base/nsTraceRefcntImpl.cpp index a666c4755d87..5241ced52f68 100644 --- a/xpcom/base/nsTraceRefcntImpl.cpp +++ b/xpcom/base/nsTraceRefcntImpl.cpp @@ -48,9 +48,11 @@ #include "nsCOMPtr.h" #include "nsCRT.h" #include +#include "nsStackWalk.h" #if defined(_WIN32) #include +#include "nsStackFrameWin.h" // XXX LoadLibrarySymbols no longer belongs here #endif #ifdef HAVE_LIBDL @@ -825,34 +827,22 @@ static void InitTraceLog(void) #endif -#if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code -#include "nsStackFrameWin.h" -NS_COM void -nsTraceRefcntImpl::WalkTheStack(FILE* aStream) -{ - DumpStackToFile(aStream); -} +extern "C" { -// WIN32 x86 stack walking code -// i386 or PPC Linux stackwalking code or Solaris -#elif (defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))) -#include "nsStackFrameUnix.h" -NS_COM void -nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure) { - DumpStackToFile(aStream); + FILE *stream = (FILE*)aClosure; + fprintf(stream, aFrame); } -#else // unsupported platform. +} NS_COM void nsTraceRefcntImpl::WalkTheStack(FILE* aStream) { - fprintf(aStream, "write me, dammit!\n"); + NS_StackWalk(PrintStackFrame, 2, aStream); } -#endif - //---------------------------------------------------------------------- // This thing is exported by libstdc++ diff --git a/xpfe/bootstrap/nsSigHandlers.cpp b/xpfe/bootstrap/nsSigHandlers.cpp index acf387979f21..7b75dbb3a45f 100644 --- a/xpfe/bootstrap/nsSigHandlers.cpp +++ b/xpfe/bootstrap/nsSigHandlers.cpp @@ -114,7 +114,16 @@ void abnormal_exit_handler(int signum) #include #include "nsISupportsUtils.h" -#include "nsStackFrameUnix.h" +#include "nsStackWalk.h" + +extern "C" { + +PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure) +{ + fprintf(stdout, aFrame); +} + +} void ah_crap_handler(int signum) @@ -125,7 +134,7 @@ ah_crap_handler(int signum) signum); printf("Stack:\n"); - DumpStackToFile(stdout); + NS_StackWalk(PrintStackFrame, 2, nsnull); printf("Sleeping for %d seconds.\n",_gdb_sleep_duration); printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",