From 5d1f516686b17c7c8975f677f43aadbae14318d9 Mon Sep 17 00:00:00 2001 From: "timeless%mozdev.org" Date: Fri, 24 Jun 2005 02:32:05 +0000 Subject: [PATCH] Bug 297723 stackwalk code not working for WinXP patch by colin@theblakes.com (cenzic) r=dougt a=bsmedberg --- xpcom/base/nsStackFrameWin.cpp | 621 +++++++++++++++++++++++++-------- xpcom/base/nsStackFrameWin.h | 54 ++- 2 files changed, 530 insertions(+), 145 deletions(-) diff --git a/xpcom/base/nsStackFrameWin.cpp b/xpcom/base/nsStackFrameWin.cpp index 0c759ec185cb..84636c3d1e0f 100644 --- a/xpcom/base/nsStackFrameWin.cpp +++ b/xpcom/base/nsStackFrameWin.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -40,7 +40,6 @@ #include "nscore.h" #include "windows.h" -#include "imagehlp.h" #include "stdio.h" #include "nsStackFrameWin.h" @@ -61,36 +60,79 @@ SYMINITIALIZEPROC _SymInitialize; SYMCLEANUPPROC _SymCleanup; STACKWALKPROC _StackWalk; +STACKWALKPROC64 _StackWalk64; SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; +SYMFUNCTIONTABLEACCESSPROC64 _SymFunctionTableAccess64; SYMGETMODULEBASEPROC _SymGetModuleBase; +SYMGETMODULEBASEPROC64 _SymGetModuleBase64; -SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; +SYMFROMADDRPROC _SymFromAddr; SYMLOADMODULE _SymLoadModule; +SYMLOADMODULE64 _SymLoadModule64; SYMUNDNAME _SymUnDName; SYMGETMODULEINFO _SymGetModuleInfo; +SYMGETMODULEINFO64 _SymGetModuleInfo64; ENUMLOADEDMODULES _EnumerateLoadedModules; +ENUMLOADEDMODULES64 _EnumerateLoadedModules64; SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; +SYMGETLINEFROMADDRPROC64 _SymGetLineFromAddr64; + +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) +{ + LPVOID lpMsgBuf; + DWORD lastErr = GetLastError(); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(stderr, "### ERROR: %s: %s", prefix, lpMsgBuf); + if (out) + fprintf(out, "### ERROR: %s: %s\n", prefix, lpMsgBuf); + LocalFree( lpMsgBuf ); +} PRBool EnsureImageHlpInitialized() { - static PRBool gInitialized = PR_FALSE; + static PRBool gInitialized = PR_FALSE; - if (! gInitialized) { - HMODULE module = ::LoadLibrary("IMAGEHLP.DLL"); - if (!module) return PR_FALSE; + if (gInitialized) + return gInitialized; + + // Create a mutex with no initial owner. + hStackWalkMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (hStackWalkMutex == NULL) { + PrintError("CreateMutex", NULL); + return PR_FALSE; + } + + HMODULE module = ::LoadLibrary("DBGHELP.DLL"); + if (!module) { + module = ::LoadLibrary("IMAGEHLP.DLL"); + if (!module) return PR_FALSE; + } _SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions"); if (!_SymSetOptions) return PR_FALSE; @@ -101,46 +143,52 @@ EnsureImageHlpInitialized() _SymCleanup = (SYMCLEANUPPROC)GetProcAddress(module, "SymCleanup"); if (!_SymCleanup) return PR_FALSE; + _StackWalk64 = (STACKWALKPROC64)GetProcAddress(module, "StackWalk64"); _StackWalk = (STACKWALKPROC)GetProcAddress(module, "StackWalk"); - if (!_StackWalk) return PR_FALSE; + if (!_StackWalk64 && !_StackWalk) return PR_FALSE; + _SymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESSPROC64) GetProcAddress(module, "SymFunctionTableAccess64"); _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(module, "SymFunctionTableAccess"); - if (!_SymFunctionTableAccess) return PR_FALSE; + if (!_SymFunctionTableAccess64 && !_SymFunctionTableAccess) return PR_FALSE; + _SymGetModuleBase64 = (SYMGETMODULEBASEPROC64)GetProcAddress(module, "SymGetModuleBase64"); _SymGetModuleBase = (SYMGETMODULEBASEPROC)GetProcAddress(module, "SymGetModuleBase"); - if (!_SymGetModuleBase) return PR_FALSE; + if (!_SymGetModuleBase64 && !_SymGetModuleBase) return PR_FALSE; - _SymGetSymFromAddr = (SYMGETSYMFROMADDRPROC)GetProcAddress(module, "SymGetSymFromAddr"); - if (!_SymGetSymFromAddr) return PR_FALSE; + _SymFromAddr = (SYMFROMADDRPROC)GetProcAddress(module, "SymFromAddr"); + if (!_SymFromAddr) return PR_FALSE; + _SymLoadModule64 = (SYMLOADMODULE64)GetProcAddress(module, "SymLoadModule64"); _SymLoadModule = (SYMLOADMODULE)GetProcAddress(module, "SymLoadModule"); - if (!_SymLoadModule) return PR_FALSE; + if (!_SymLoadModule64 && !_SymLoadModule) return PR_FALSE; _SymUnDName = (SYMUNDNAME)GetProcAddress(module, "SymUnDName"); if (!_SymUnDName) return PR_FALSE; + _SymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress(module, "SymGetModuleInfo64"); _SymGetModuleInfo = (SYMGETMODULEINFO)GetProcAddress(module, "SymGetModuleInfo"); - if (!_SymGetModuleInfo) return PR_FALSE; + if (!_SymGetModuleInfo64 && !_SymGetModuleInfo) return PR_FALSE; + _EnumerateLoadedModules64 = (ENUMLOADEDMODULES64)GetProcAddress(module, "EnumerateLoadedModules64"); _EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules"); - if (!_EnumerateLoadedModules) return PR_FALSE; + if (!_EnumerateLoadedModules64 && !_EnumerateLoadedModules) return PR_FALSE; + _SymGetLineFromAddr64 = (SYMGETLINEFROMADDRPROC64)GetProcAddress(module, "SymGetLineFromAddr64"); _SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr"); - if (!_SymGetLineFromAddr) return PR_FALSE; + if (!_SymGetLineFromAddr64 && !_SymGetLineFromAddr) return PR_FALSE; - gInitialized = PR_TRUE; - } + return gInitialized = PR_TRUE; +} - return gInitialized; -} -/* - * Callback used by SymGetModuleInfoEspecial - */ -static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULONG aModuleSize, PVOID aUserContext) +static BOOL CALLBACK callbackEspecial( + LPSTR aModuleName, + DWORD aModuleBase, + ULONG aModuleSize, + PVOID aUserContext) { BOOL retval = TRUE; - DWORD addr = (DWORD)aUserContext; + DWORD addr = *(DWORD*)aUserContext; /* * You'll want to control this if we are running on an @@ -148,20 +196,44 @@ static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULON * Not sure this is even a realistic consideration. */ const BOOL addressIncreases = TRUE; - + + /* + * If it falls inside the known range, load the symbols. + */ + if (addressIncreases + ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize)) + : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize)) + ) { + retval = _SymLoadModule(GetCurrentProcess(), NULL, aModuleName, NULL, aModuleBase, aModuleSize); + } + + return retval; +} + +static BOOL CALLBACK callbackEspecial64( + PTSTR aModuleName, + DWORD64 aModuleBase, + ULONG aModuleSize, + PVOID aUserContext) +{ + BOOL retval = TRUE; + DWORD64 addr = *(DWORD64*)aUserContext; + + /* + * You'll want to control this if we are running on an + * architecture where the addresses go the other direction. + * Not sure this is even a realistic consideration. + */ + const BOOL addressIncreases = TRUE; + /* * If it falls in side the known range, load the symbols. */ - if(addressIncreases + if (addressIncreases ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize)) : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize)) - ) - { - BOOL loadRes = FALSE; - HANDLE process = GetCurrentProcess(); - - loadRes = _SymLoadModule(process, NULL, aModuleName, NULL, aModuleBase, aModuleSize); - PR_ASSERT(FALSE != loadRes); + ) { + retval = _SymLoadModule64(GetCurrentProcess(), NULL, aModuleName, NULL, aModuleBase, aModuleSize); } return retval; @@ -201,8 +273,8 @@ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aMo * Not loaded, here's the magic. * Go through all the modules. */ - enumRes = _EnumerateLoadedModules(aProcess, callbackEspecial, (PVOID)aAddr); - if(FALSE != enumRes) + enumRes = _EnumerateLoadedModules(aProcess, callbackEspecial, (PVOID)&aAddr); + if (FALSE != enumRes) { /* * One final go. @@ -217,131 +289,396 @@ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aMo * 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); + DWORD displacement = 0; + BOOL lineRes = FALSE; + lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo); } return retval; } +BOOL SymGetModuleInfoEspecial64(HANDLE aProcess, DWORD64 aAddr, PIMAGEHLP_MODULE64 aModuleInfo, PIMAGEHLP_LINE64 aLineInfo) +{ + BOOL retval = FALSE; + + /* + * Init the vars if we have em. + */ + aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + if (nsnull != aLineInfo) { + aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE64); + } + + /* + * Give it a go. + * It may already be loaded. + */ + retval = _SymGetModuleInfo64(aProcess, aAddr, aModuleInfo); + + if (FALSE == retval) { + BOOL enumRes = FALSE; + + /* + * Not loaded, here's the magic. + * Go through all the modules. + */ + enumRes = _EnumerateLoadedModules64(aProcess, callbackEspecial64, (PVOID)&aAddr); + if (FALSE != enumRes) + { + /* + * One final go. + * If it fails, then well, we have other problems. + */ + retval = _SymGetModuleInfo64(aProcess, aAddr, aModuleInfo); + } + } + + /* + * 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 != _SymGetLineFromAddr64) { + DWORD displacement = 0; + BOOL lineRes = FALSE; + lineRes = _SymGetLineFromAddr64(aProcess, aAddr, &displacement, aLineInfo); + } + + return retval; +} + +HANDLE +GetCurrentPIDorHandle() +{ + if (_SymGetModuleBase64) + return GetCurrentProcess(); // winxp and friends use process handle + + return (HANDLE) GetCurrentProcessId(); // winme win98 win95 etc use process identifier +} + PRBool EnsureSymInitialized() -{ - static PRBool gInitialized = PR_FALSE; +{ + PRBool retStat; + + if (!EnsureImageHlpInitialized()) + return PR_FALSE; - if (! gInitialized) { - if (! EnsureImageHlpInitialized()) - return PR_FALSE; _SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - gInitialized = _SymInitialize(GetCurrentProcess(), 0, TRUE); - } - return gInitialized; + retStat = _SymInitialize(GetCurrentPIDorHandle(), NULL, TRUE); + if (!retStat) + PrintError("SymInitialize", NULL); + return retStat; } /** * Walk the stack, translating PC's found into strings and recording the - * chain in aBuffer. For this to work properly, the dll's must be rebased + * chain in aBuffer. For this to work properly, the DLLs must be rebased * so that the address in the file agrees with the address in memory. - * Otherwise StackWalk will return FALSE when it hits a frame in a dll's + * Otherwise StackWalk will return FALSE when it hits a frame in a DLLs * whose in memory address doesn't match it's in-file address. */ - void -DumpStackToFile(FILE* aStream) +DumpStackToFile(FILE* aStream) { - HANDLE myProcess = ::GetCurrentProcess(); - HANDLE myThread = ::GetCurrentThread(); - BOOL ok; + HANDLE myProcess = ::GetCurrentProcess(); + HANDLE myThread, walkerThread; + DWORD walkerReturn; + struct DumpStackToFileData data; - ok = EnsureSymInitialized(); - if (! ok) + if (!EnsureSymInitialized()) + return; + + // Have to duplicate handle to get a real handle. + ::DuplicateHandle( + ::GetCurrentProcess(), + ::GetCurrentThread(), + ::GetCurrentProcess(), + &myThread, + THREAD_ALL_ACCESS, FALSE, 0 + ); + + data.stream = aStream; + data.thread = myThread; + data.process = myProcess; + walkerThread = ::CreateThread( NULL, 0, DumpStackToFileThread, (LPVOID) &data, 0, NULL ) ; + walkerReturn = ::WaitForSingleObject(walkerThread, INFINITE); + CloseHandle(myThread) ; + if (walkerReturn != WAIT_OBJECT_0) + PrintError("ThreadWait", aStream); return; - - // Get the context information for this thread. That way we will - // know where our sp, fp, pc, etc. are and can fill in the - // STACKFRAME with the initial values. - CONTEXT context; - context.ContextFlags = CONTEXT_FULL; - ok = GetThreadContext(myThread, &context); - if (! ok) - return; - - // Setup initial stack frame to walk from - STACKFRAME frame; - memset(&frame, 0, sizeof(frame)); - frame.AddrPC.Offset = context.Eip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrStack.Offset = context.Esp; - frame.AddrStack.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context.Ebp; - frame.AddrFrame.Mode = AddrModeFlat; - - // Now walk the stack and map the pc's to symbol names - int skip = 2; - while (1) { - ok = _StackWalk(IMAGE_FILE_MACHINE_I386, - myProcess, - myThread, - &frame, - &context, - 0, // read process memory routine - _SymFunctionTableAccess, // function table access routine - _SymGetModuleBase, // module base routine - 0); // translate address routine - - if (!ok) { - LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); - fprintf(aStream, "### ERROR: WalkStack: %s", lpMsgBuf); - fflush(aStream); - LocalFree( lpMsgBuf ); - } - if (!ok || frame.AddrPC.Offset == 0) - break; - - if (skip-- > 0) - continue; - - // - // Attempt to load module info before we attempt to reolve the symbol. - // This just makes sure we get good info if available. - // - IMAGEHLP_MODULE modInfo; - modInfo.SizeOfStruct = sizeof(modInfo); - BOOL modInfoRes = TRUE; - modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo, nsnull); - - char buf[sizeof(IMAGEHLP_SYMBOL) + 512]; - PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf; - symbol->SizeOfStruct = sizeof(buf); - symbol->MaxNameLength = 512; - - DWORD displacement; - ok = _SymGetSymFromAddr(myProcess, - frame.AddrPC.Offset, - &displacement, - symbol); - - if (ok) { - fprintf(aStream, "%s+0x%08X\n", symbol->Name, displacement); - } - else { - fprintf(aStream, "0x%08X\n", frame.AddrPC.Offset); - } - } +} + +DWORD WINAPI +DumpStackToFileThread(LPVOID lpdata) +{ + struct DumpStackToFileData *data = (DumpStackToFileData *)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); + } + else { + if (_StackWalk64) + DumpStackToFileMain64(data); + else + DumpStackToFileMain(data); + ret = ::ResumeThread( data->thread ); + if (ret == -1) { + PrintError("ThreadResume", data->stream); + } + } + + return 0; +} + +void +DumpStackToFileMain64(struct DumpStackToFileData* 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 + // STACKFRAME64 with the initial values. + CONTEXT context; + HANDLE myProcess = data->process; + HANDLE myThread = data->thread; + FILE* aStream = data->stream; + DWORD64 addr; + STACKFRAME64 frame64; + int skip = 6; // 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); + return; + } + + // Setup initial stack frame to walk from + memset(&frame64, 0, sizeof(frame64)); +#ifdef _M_IX86 + frame64.AddrPC.Offset = context.Eip; + frame64.AddrStack.Offset = context.Esp; + frame64.AddrFrame.Offset = context.Ebp; +#elif defined _M_AMD64 + frame64.AddrPC.Offset = context.Rip; + frame64.AddrStack.Offset = context.Rsp; + frame64.AddrFrame.Offset = context.Rbp; +#elif defined _M_IA64 + frame64.AddrPC.Offset = context.StIIP; + frame64.AddrStack.Offset = context.SP; + frame64.AddrFrame.Offset = context.RsBSP; +#else + fprintf(aStream, "Unknown platform. No stack walking."); + return; +#endif + frame64.AddrPC.Mode = AddrModeFlat; + frame64.AddrStack.Mode = AddrModeFlat; + frame64.AddrFrame.Mode = AddrModeFlat; + frame64.AddrReturn.Mode = AddrModeFlat; + + // Now walk the stack and map the pc's to symbol names + while (1) { + + ok = 0; + + // stackwalk is not threadsafe, so grab the lock. + DWORD dwWaitResult; + dwWaitResult = WaitForSingleObject(hStackWalkMutex, INFINITE); + if (dwWaitResult == WAIT_OBJECT_0) { + + ok = _StackWalk64( +#ifdef _M_AMD64 + IMAGE_FILE_MACHINE_AMD64, +#elif defined _M_IA64 + IMAGE_FILE_MACHINE_IA64, +#elif defined _M_IX86 + IMAGE_FILE_MACHINE_I386, +#else + 0, +#endif + myProcess, + myThread, + &frame64, + &context, + NULL, + _SymFunctionTableAccess64, // function table access routine + _SymGetModuleBase64, // module base routine + 0 + ); + + if (ok) + addr = frame64.AddrPC.Offset; + else + PrintError("WalkStack64", aStream); + + 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(myProcess, addr, &displacement, pSymbol); + + // All done with debug calls so release our lock. + ReleaseMutex(hStackWalkMutex); + + if (ok) + fprintf(aStream, "%s!%s+0x%016X\n", modInfo.ImageName, pSymbol->Name, displacement); + else + fprintf(aStream, "0x%016X\n", addr); + + // Stop walking when we get to kernel32.dll. + if (strcmp(modInfo.ImageName,"kernel32.dll") == 0) + break; + } + else { + PrintError("LockError64", aStream); + } + } + return; +} + + +void +DumpStackToFileMain(struct DumpStackToFileData* 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 + // STACKFRAME with the initial values. + CONTEXT context; + HANDLE myProcess = data->process; + HANDLE myThread = data->thread; + FILE* aStream = data->stream; + DWORD addr; + STACKFRAME frame; + int skip = 2; // 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); + return; + } + + // Setup initial stack frame to walk from +#if defined _M_IX86 + memset(&frame, 0, sizeof(frame)); + frame.AddrPC.Offset = context.Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Esp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Ebp; + frame.AddrFrame.Mode = AddrModeFlat; +#else + fprintf(aStream, "Unknown platform. No stack walking."); + return; +#endif + + // Now walk the stack and map the pc's to symbol names + while (1) { + + ok = 0; + + // debug routines are not threadsafe, so grab the lock. + DWORD dwWaitResult; + dwWaitResult = WaitForSingleObject(hStackWalkMutex, INFINITE); + if (dwWaitResult == WAIT_OBJECT_0) { + + ok = _StackWalk( + IMAGE_FILE_MACHINE_I386, + myProcess, + myThread, + &frame, + &context, + 0, // read process memory routine + _SymFunctionTableAccess, // function table access routine + _SymGetModuleBase, // module base routine + 0 // translate address routine + ); + + if (ok) + addr = frame.AddrPC.Offset; + else + PrintError("WalkStack", aStream); + + 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); + + 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(myProcess, addr, &displacement, pSymbol); + + // All done with debug calls so release our lock. + ReleaseMutex(hStackWalkMutex); + + if (ok) + fprintf(aStream, "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement); + else + fprintf(aStream, "0x%08X\n", (DWORD) addr); + + // Stop walking when we get to kernel32.dll. + if (strcmp(modInfo.ImageName,"kernel32.dll") == 0) + break; + + } + else { + PrintError("LockError", aStream); + } + + } + + return; + } diff --git a/xpcom/base/nsStackFrameWin.h b/xpcom/base/nsStackFrameWin.h index d9b6585c64b6..d7f5da9f7b3f 100644 --- a/xpcom/base/nsStackFrameWin.h +++ b/xpcom/base/nsStackFrameWin.h @@ -41,10 +41,13 @@ #define nsStackFrameWin_h___ -#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64)) +// WIN32 x86 stack walking code #include "nspr.h" #include +#ifdef _M_IX86 #include +#endif // 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 @@ -74,30 +77,63 @@ typedef BOOL (__stdcall *STACKWALKPROC)(DWORD, PTRANSLATE_ADDRESS_ROUTINE); extern STACKWALKPROC _StackWalk; +typedef BOOL (__stdcall *STACKWALKPROC64)(DWORD, + HANDLE, + HANDLE, + LPSTACKFRAME64, + PVOID, + PREAD_PROCESS_MEMORY_ROUTINE64, + PFUNCTION_TABLE_ACCESS_ROUTINE64, + PGET_MODULE_BASE_ROUTINE64, + PTRANSLATE_ADDRESS_ROUTINE64); +extern STACKWALKPROC64 _StackWalk64; + typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)(HANDLE, DWORD); extern SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; +typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC64)(HANDLE, DWORD64); +extern SYMFUNCTIONTABLEACCESSPROC64 _SymFunctionTableAccess64; + typedef DWORD (__stdcall *SYMGETMODULEBASEPROC)(HANDLE, DWORD); extern SYMGETMODULEBASEPROC _SymGetModuleBase; -typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL); -extern SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; +typedef DWORD64 (__stdcall *SYMGETMODULEBASEPROC64)(HANDLE, DWORD64); +extern SYMGETMODULEBASEPROC64 _SymGetModuleBase64; + +typedef BOOL (__stdcall *SYMFROMADDRPROC)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); +extern SYMFROMADDRPROC _SymFromAddr; typedef DWORD ( __stdcall *SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD); extern SYMLOADMODULE _SymLoadModule; +typedef DWORD ( __stdcall *SYMLOADMODULE64)(HANDLE, HANDLE, PCSTR, PCSTR, DWORD64, DWORD); +extern SYMLOADMODULE64 _SymLoadModule64; + typedef DWORD ( __stdcall *SYMUNDNAME)(PIMAGEHLP_SYMBOL, PSTR, DWORD); extern SYMUNDNAME _SymUnDName; typedef DWORD ( __stdcall *SYMGETMODULEINFO)( HANDLE, DWORD, PIMAGEHLP_MODULE); extern SYMGETMODULEINFO _SymGetModuleInfo; +typedef BOOL ( __stdcall *SYMGETMODULEINFO64)( HANDLE, DWORD64, PIMAGEHLP_MODULE64); +extern SYMGETMODULEINFO64 _SymGetModuleInfo64; + typedef BOOL ( __stdcall *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID); extern ENUMLOADEDMODULES _EnumerateLoadedModules; +typedef BOOL ( __stdcall *ENUMLOADEDMODULES64)( HANDLE, PENUMLOADED_MODULES_CALLBACK64, PVOID); +extern ENUMLOADEDMODULES64 _EnumerateLoadedModules64; + typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; +typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); +extern SYMGETLINEFROMADDRPROC64 _SymGetLineFromAddr64; + +extern HANDLE hStackWalkMutex; + +HANDLE GetCurrentPIDorHandle(); + PRBool EnsureSymInitialized(); PRBool EnsureImageHlpInitialized(); @@ -114,11 +150,23 @@ PRBool EnsureImageHlpInitialized(); */ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo); +struct DumpStackToFileData { + FILE *stream; + 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); + PR_END_EXTERN_C +#else +#pragma message( "You probably need to fix this file to handle your target platform" ) #endif //WIN32 #endif //nsStackFrameWin_h___