зеркало из https://github.com/mozilla/gecko-dev.git
Export a stack walking API (usable from C or C++) from XPCOM. b=374689 r=bsmedberg a=bzbarsky
This commit is contained in:
Родитель
5307ebca39
Коммит
103f60636e
|
@ -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
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -37,11 +37,11 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsStackFrameUnix.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "nscore.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// On glibc 2.1, the Dl_info api defined in <dlfcn.h> 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 <sys/regset.h>
|
||||
#include <sys/stack.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nscore.h"
|
||||
#include "windows.h"
|
||||
#include "stdio.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <dbaron@dbaron.org>, 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
|
|
@ -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 <dbaron@dbaron.org>, 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_) */
|
|
@ -48,9 +48,11 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include <math.h>
|
||||
#include "nsStackWalk.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#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)
|
||||
extern "C" {
|
||||
|
||||
PR_STATIC_CALLBACK(void) PrintStackFrame(char *aFrame, void *aClosure)
|
||||
{
|
||||
DumpStackToFile(aStream);
|
||||
FILE *stream = (FILE*)aClosure;
|
||||
fprintf(stream, aFrame);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
DumpStackToFile(aStream);
|
||||
}
|
||||
|
||||
#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++
|
||||
|
|
|
@ -114,7 +114,16 @@ void abnormal_exit_handler(int signum)
|
|||
|
||||
#include <unistd.h>
|
||||
#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",
|
||||
|
|
Загрузка…
Ссылка в новой задаче