diff --git a/mozilla/xpcom/base/nsStackFrameWin.cpp b/mozilla/xpcom/base/nsStackFrameWin.cpp index 0c759ec185c..7ff36d4e0df 100644 --- a/mozilla/xpcom/base/nsStackFrameWin.cpp +++ b/mozilla/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,112 @@ SYMINITIALIZEPROC _SymInitialize; SYMCLEANUPPROC _SymCleanup; STACKWALKPROC _StackWalk; +#ifdef _IMAGEHLP64 +STACKWALKPROC64 _StackWalk64; +#else +#define _StackWalk64 0 +#endif SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; +#ifdef _IMAGEHLP64 +SYMFUNCTIONTABLEACCESSPROC64 _SymFunctionTableAccess64; +#else +#define _SymFunctionTableAccess64 0 +#endif SYMGETMODULEBASEPROC _SymGetModuleBase; +#ifdef _IMAGEHLP64 +SYMGETMODULEBASEPROC64 _SymGetModuleBase64; +#else +#define _SymGetModuleBase64 0 +#endif SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; +#ifdef _IMAGEHLP64 +SYMFROMADDRPROC _SymFromAddr; +#else +#define _SymFromAddr 0 +#endif SYMLOADMODULE _SymLoadModule; +#ifdef _IMAGEHLP64 +SYMLOADMODULE64 _SymLoadModule64; +#else +#define _SymLoadModule64 0 +#endif SYMUNDNAME _SymUnDName; SYMGETMODULEINFO _SymGetModuleInfo; +#ifdef _IMAGEHLP64 +SYMGETMODULEINFO64 _SymGetModuleInfo64; +#else +#define _SymGetModuleInfo64 0 +#endif ENUMLOADEDMODULES _EnumerateLoadedModules; +#ifdef _IMAGEHLP64 +ENUMLOADEDMODULES64 _EnumerateLoadedModules64; +#else +#define _EnumerateLoadedModules64 0 +#endif SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; +#ifdef _IMAGEHLP64 +SYMGETLINEFROMADDRPROC64 _SymGetLineFromAddr64; +#else +#define _SymGetLineFromAddr64 0 +#endif + +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 +176,69 @@ EnsureImageHlpInitialized() _SymCleanup = (SYMCLEANUPPROC)GetProcAddress(module, "SymCleanup"); if (!_SymCleanup) return PR_FALSE; +#ifdef _IMAGEHLP64 + _StackWalk64 = (STACKWALKPROC64)GetProcAddress(module, "StackWalk64"); +#endif _StackWalk = (STACKWALKPROC)GetProcAddress(module, "StackWalk"); - if (!_StackWalk) return PR_FALSE; + if (!_StackWalk64 && !_StackWalk) return PR_FALSE; +#ifdef _IMAGEHLP64 + _SymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESSPROC64) GetProcAddress(module, "SymFunctionTableAccess64"); +#endif _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(module, "SymFunctionTableAccess"); - if (!_SymFunctionTableAccess) return PR_FALSE; + if (!_SymFunctionTableAccess64 && !_SymFunctionTableAccess) return PR_FALSE; +#ifdef _IMAGEHLP64 + _SymGetModuleBase64 = (SYMGETMODULEBASEPROC64)GetProcAddress(module, "SymGetModuleBase64"); +#endif _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; +#ifdef _IMAGEHLP64 + _SymFromAddr = (SYMFROMADDRPROC)GetProcAddress(module, "SymFromAddr"); +#endif + if (!_SymFromAddr && !_SymGetSymFromAddr) return PR_FALSE; +#ifdef _IMAGEHLP64 + _SymLoadModule64 = (SYMLOADMODULE64)GetProcAddress(module, "SymLoadModule64"); +#endif _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; +#ifdef _IMAGEHLP64 + _SymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress(module, "SymGetModuleInfo64"); +#endif _SymGetModuleInfo = (SYMGETMODULEINFO)GetProcAddress(module, "SymGetModuleInfo"); - if (!_SymGetModuleInfo) return PR_FALSE; + if (!_SymGetModuleInfo64 && !_SymGetModuleInfo) return PR_FALSE; +#ifdef _IMAGEHLP64 + _EnumerateLoadedModules64 = (ENUMLOADEDMODULES64)GetProcAddress(module, "EnumerateLoadedModules64"); +#endif _EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules"); - if (!_EnumerateLoadedModules) return PR_FALSE; + if (!_EnumerateLoadedModules64 && !_EnumerateLoadedModules) return PR_FALSE; +#ifdef _IMAGEHLP64 + _SymGetLineFromAddr64 = (SYMGETLINEFROMADDRPROC64)GetProcAddress(module, "SymGetLineFromAddr64"); +#endif _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,25 +246,53 @@ static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULON * Not sure this is even a realistic consideration. */ const BOOL addressIncreases = TRUE; - + /* - * If it falls in side the known range, load the symbols. + * If it falls inside 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 = _SymLoadModule(GetCurrentProcess(), NULL, aModuleName, NULL, aModuleBase, aModuleSize); } return retval; } +static BOOL CALLBACK callbackEspecial64( + PTSTR aModuleName, + DWORD64 aModuleBase, + ULONG aModuleSize, + PVOID aUserContext) +{ +#ifdef _IMAGEHLP64 + 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 + ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize)) + : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize)) + ) { + retval = _SymLoadModule64(GetCurrentProcess(), NULL, aModuleName, NULL, aModuleBase, aModuleSize); + } + + return retval; +#else + return FALSE; +#endif +} + /* * SymGetModuleInfoEspecial * @@ -201,8 +327,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 +343,420 @@ 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; } +#ifdef _IMAGEHLP64 +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; +} +#endif + +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 - * whose in memory address doesn't match it's in-file address. + * Otherwise StackWalk will return FALSE when it hits a frame in a DLL + * whose in memory address doesn't match its in-file address. */ +void +DumpStackToFile(FILE* aStream) +{ + HANDLE myProcess = ::GetCurrentProcess(); + HANDLE myThread, walkerThread; + DWORD walkerReturn; + struct DumpStackToFileData data; + + 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; +} + +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) +{ +#ifdef _IMAGEHLP64 + // 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; +#endif +} + void -DumpStackToFile(FILE* aStream) +DumpStackToFileMain(struct DumpStackToFileData* data) { - HANDLE myProcess = ::GetCurrentProcess(); - HANDLE myThread = ::GetCurrentThread(); - BOOL ok; + // 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); + +#ifdef _IMAGEHLP64 + 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; +#else + char buf[sizeof(IMAGEHLP_SYMBOL) + 512]; + PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) buf; + pSymbol->SizeOfStruct = sizeof(buf); + pSymbol->MaxNameLength = 512; + + DWORD displacement; +#endif + +#ifdef _IMAGEHLP64 + ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol); +#endif + if (!ok) + { + ok = _SymGetSymFromAddr(myProcess, + frame.AddrPC.Offset, + &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); + } + + } - ok = EnsureSymInitialized(); - if (! ok) 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); - } - } } diff --git a/mozilla/xpcom/base/nsStackFrameWin.h b/mozilla/xpcom/base/nsStackFrameWin.h index d9b6585c64b..f60bb083533 100644 --- a/mozilla/xpcom/base/nsStackFrameWin.h +++ b/mozilla/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,82 @@ typedef BOOL (__stdcall *STACKWALKPROC)(DWORD, PTRANSLATE_ADDRESS_ROUTINE); extern STACKWALKPROC _StackWalk; +#ifdef _IMAGEHLP64 +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; +#endif + typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)(HANDLE, DWORD); extern SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; +#ifdef _IMAGEHLP64 +typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC64)(HANDLE, DWORD64); +extern SYMFUNCTIONTABLEACCESSPROC64 _SymFunctionTableAccess64; +#endif + typedef DWORD (__stdcall *SYMGETMODULEBASEPROC)(HANDLE, DWORD); extern SYMGETMODULEBASEPROC _SymGetModuleBase; +#ifdef _IMAGEHLP64 +typedef DWORD64 (__stdcall *SYMGETMODULEBASEPROC64)(HANDLE, DWORD64); +extern SYMGETMODULEBASEPROC64 _SymGetModuleBase64; +#endif + typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL); extern SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; +#ifdef _IMAGEHLP64 +typedef BOOL (__stdcall *SYMFROMADDRPROC)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); +extern SYMFROMADDRPROC _SymFromAddr; +#endif + typedef DWORD ( __stdcall *SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD); extern SYMLOADMODULE _SymLoadModule; +#ifdef _IMAGEHLP64 +typedef DWORD ( __stdcall *SYMLOADMODULE64)(HANDLE, HANDLE, PCSTR, PCSTR, DWORD64, DWORD); +extern SYMLOADMODULE64 _SymLoadModule64; +#endif + typedef DWORD ( __stdcall *SYMUNDNAME)(PIMAGEHLP_SYMBOL, PSTR, DWORD); extern SYMUNDNAME _SymUnDName; typedef DWORD ( __stdcall *SYMGETMODULEINFO)( HANDLE, DWORD, PIMAGEHLP_MODULE); extern SYMGETMODULEINFO _SymGetModuleInfo; +#ifdef _IMAGEHLP64 +typedef BOOL ( __stdcall *SYMGETMODULEINFO64)( HANDLE, DWORD64, PIMAGEHLP_MODULE64); +extern SYMGETMODULEINFO64 _SymGetModuleInfo64; +#endif + typedef BOOL ( __stdcall *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID); extern ENUMLOADEDMODULES _EnumerateLoadedModules; +#ifdef _IMAGEHLP64 +typedef BOOL ( __stdcall *ENUMLOADEDMODULES64)( HANDLE, PENUMLOADED_MODULES_CALLBACK64, PVOID); +extern ENUMLOADEDMODULES64 _EnumerateLoadedModules64; +#endif + typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; +#ifdef _IMAGEHLP64 +typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); +extern SYMGETLINEFROMADDRPROC64 _SymGetLineFromAddr64; +#endif + +extern HANDLE hStackWalkMutex; + +HANDLE GetCurrentPIDorHandle(); + PRBool EnsureSymInitialized(); PRBool EnsureImageHlpInitialized(); @@ -114,11 +169,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___