mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Convert trace-malloc to using XPCOM stack walking API. b=374829 r+a=brendan
This commit is contained in:
parent
def4dbe999
commit
593cd91cf8
@ -55,17 +55,15 @@ CSRCS = \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsDemangle.cpp \
|
||||
nsTypeInfo.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = nsTraceMalloc.h
|
||||
|
||||
EXTRA_DSO_LDOPTS = $(NSPR_LIBS)
|
||||
EXTRA_DSO_LDOPTS = $(NSPR_LIBS) $(XPCOM_LIBS)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
CPPSRCS += nsDebugHelpWin32.cpp nsWinTraceMalloc.cpp nsStackFrameWin.cpp
|
||||
EXTRA_DSO_LDOPTS += $(XPCOM_LIBS)
|
||||
CPPSRCS += nsDebugHelpWin32.cpp nsWinTraceMalloc.cpp
|
||||
OS_LIBS += shell32.lib ole32.lib uuid.lib imagehlp.lib
|
||||
endif
|
||||
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include "prlock.h"
|
||||
#include "nscore.h"
|
||||
#include "nsDebugHelpWin32.h"
|
||||
#include "nsStackFrameWin.h"
|
||||
#else
|
||||
#error "nsDebugHelpWin32.cpp should only be built in Win32 x86 builds"
|
||||
#endif
|
||||
@ -164,7 +163,6 @@ DHWImportHooker::DHWImportHooker(const char* aModuleName,
|
||||
gLock = PR_NewLock();
|
||||
PR_Lock(gLock);
|
||||
|
||||
EnsureImageHlpInitialized();
|
||||
dhwEnsureImageHlpInitialized(); // for the extra ones we care about.
|
||||
|
||||
if(!gRealGetProcAddress)
|
||||
|
@ -1,49 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** 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 trace-malloc/nsDemangle.cpp.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 ***** */
|
||||
#ifdef MOZ_DEMANGLE_SYMBOLS
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" char *nsDemangle(const char *symbol);
|
||||
|
||||
char *nsDemangle(const char *symbol) {
|
||||
return abi::__cxa_demangle(symbol, 0, 0, 0);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,351 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** 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 nsStackFrameWin.h code, released
|
||||
* December 20, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2000
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Judge, 20-December-2000
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nscore.h"
|
||||
#include "windows.h"
|
||||
#include "imagehlp.h"
|
||||
#include "stdio.h"
|
||||
#include "nsStackFrameWin.h"
|
||||
|
||||
// Define these as static pointers so that we can load the DLL on the
|
||||
// fly (and not introduce a link-time dependency on it). Tip o' the
|
||||
// hat to Matt Pietrick for this idea. See:
|
||||
//
|
||||
// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm
|
||||
//
|
||||
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
SYMSETOPTIONSPROC _SymSetOptions;
|
||||
|
||||
SYMINITIALIZEPROC _SymInitialize;
|
||||
|
||||
SYMCLEANUPPROC _SymCleanup;
|
||||
|
||||
STACKWALKPROC _StackWalk;
|
||||
|
||||
SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess;
|
||||
|
||||
SYMGETMODULEBASEPROC _SymGetModuleBase;
|
||||
|
||||
SYMGETSYMFROMADDRPROC _SymGetSymFromAddr;
|
||||
|
||||
SYMLOADMODULE _SymLoadModule;
|
||||
|
||||
SYMUNDNAME _SymUnDName;
|
||||
|
||||
SYMGETMODULEINFO _SymGetModuleInfo;
|
||||
|
||||
ENUMLOADEDMODULES _EnumerateLoadedModules;
|
||||
|
||||
SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
|
||||
|
||||
|
||||
PRBool
|
||||
EnsureImageHlpInitialized()
|
||||
{
|
||||
static PRBool gInitialized = PR_FALSE;
|
||||
|
||||
if (! gInitialized) {
|
||||
HMODULE module = ::LoadLibrary("IMAGEHLP.DLL");
|
||||
if (!module) return PR_FALSE;
|
||||
|
||||
_SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions");
|
||||
if (!_SymSetOptions) return PR_FALSE;
|
||||
|
||||
_SymInitialize = (SYMINITIALIZEPROC) ::GetProcAddress(module, "SymInitialize");
|
||||
if (!_SymInitialize) return PR_FALSE;
|
||||
|
||||
_SymCleanup = (SYMCLEANUPPROC)GetProcAddress(module, "SymCleanup");
|
||||
if (!_SymCleanup) return PR_FALSE;
|
||||
|
||||
_StackWalk = (STACKWALKPROC)GetProcAddress(module, "StackWalk");
|
||||
if (!_StackWalk) return PR_FALSE;
|
||||
|
||||
_SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(module, "SymFunctionTableAccess");
|
||||
if (!_SymFunctionTableAccess) return PR_FALSE;
|
||||
|
||||
_SymGetModuleBase = (SYMGETMODULEBASEPROC)GetProcAddress(module, "SymGetModuleBase");
|
||||
if (!_SymGetModuleBase) return PR_FALSE;
|
||||
|
||||
_SymGetSymFromAddr = (SYMGETSYMFROMADDRPROC)GetProcAddress(module, "SymGetSymFromAddr");
|
||||
if (!_SymGetSymFromAddr) return PR_FALSE;
|
||||
|
||||
_SymLoadModule = (SYMLOADMODULE)GetProcAddress(module, "SymLoadModule");
|
||||
if (!_SymLoadModule) return PR_FALSE;
|
||||
|
||||
_SymUnDName = (SYMUNDNAME)GetProcAddress(module, "SymUnDName");
|
||||
if (!_SymUnDName) return PR_FALSE;
|
||||
|
||||
_SymGetModuleInfo = (SYMGETMODULEINFO)GetProcAddress(module, "SymGetModuleInfo");
|
||||
if (!_SymGetModuleInfo) return PR_FALSE;
|
||||
|
||||
_EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules");
|
||||
if (!_EnumerateLoadedModules) return PR_FALSE;
|
||||
|
||||
_SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr");
|
||||
if (!_SymGetLineFromAddr) return PR_FALSE;
|
||||
|
||||
gInitialized = PR_TRUE;
|
||||
}
|
||||
|
||||
return gInitialized;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback used by SymGetModuleInfoEspecial
|
||||
*/
|
||||
static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULONG aModuleSize, PVOID aUserContext)
|
||||
{
|
||||
BOOL retval = TRUE;
|
||||
DWORD addr = (DWORD)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))
|
||||
)
|
||||
{
|
||||
BOOL loadRes = FALSE;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
|
||||
loadRes = _SymLoadModule(process, NULL, aModuleName, NULL, aModuleBase, aModuleSize);
|
||||
PR_ASSERT(FALSE != loadRes);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* SymGetModuleInfoEspecial
|
||||
*
|
||||
* Attempt to determine the module information.
|
||||
* Bug 112196 says this DLL may not have been loaded at the time
|
||||
* SymInitialize was called, and thus the module information
|
||||
* and symbol information is not available.
|
||||
* This code rectifies that problem.
|
||||
*/
|
||||
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo)
|
||||
{
|
||||
BOOL retval = FALSE;
|
||||
|
||||
/*
|
||||
* Init the vars if we have em.
|
||||
*/
|
||||
aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE);
|
||||
if (nsnull != aLineInfo) {
|
||||
aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Give it a go.
|
||||
* It may already be loaded.
|
||||
*/
|
||||
retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo);
|
||||
|
||||
if (FALSE == retval) {
|
||||
BOOL enumRes = FALSE;
|
||||
|
||||
/*
|
||||
* Not loaded, here's the magic.
|
||||
* Go through all the modules.
|
||||
*/
|
||||
enumRes = _EnumerateLoadedModules(aProcess, callbackEspecial, (PVOID)aAddr);
|
||||
if(FALSE != enumRes)
|
||||
{
|
||||
/*
|
||||
* One final go.
|
||||
* If it fails, then well, we have other problems.
|
||||
*/
|
||||
retval = _SymGetModuleInfo(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 != _SymGetLineFromAddr) {
|
||||
DWORD displacement = 0;
|
||||
BOOL lineRes = FALSE;
|
||||
|
||||
lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
PRBool
|
||||
EnsureSymInitialized()
|
||||
{
|
||||
static PRBool gInitialized = PR_FALSE;
|
||||
|
||||
if (! gInitialized) {
|
||||
if (! EnsureImageHlpInitialized())
|
||||
return PR_FALSE;
|
||||
_SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
|
||||
gInitialized = _SymInitialize(GetCurrentProcess(), 0, TRUE);
|
||||
}
|
||||
return gInitialized;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* Fortunately, there is a handy dandy routine in IMAGEHLP.DLL that does
|
||||
* the rebasing and accordingly I've made a tool to use it to rebase the
|
||||
* DLL's in one fell swoop (see xpcom/tools/windows/rebasedlls.cpp).
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
DumpStackToFile(FILE* aStream)
|
||||
{
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
HANDLE myThread = ::GetCurrentThread();
|
||||
BOOL ok;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,126 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** 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 nsStackFrameWin.h code, released
|
||||
* December 20, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2000
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Judge, 20-December-2000
|
||||
*
|
||||
* 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 ***** */
|
||||
#ifndef nsStackFrameWin_h___
|
||||
#define nsStackFrameWin_h___
|
||||
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code
|
||||
#include "nspr.h"
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
// Define these as static pointers so that we can load the DLL on the
|
||||
// fly (and not introduce a link-time dependency on it). Tip o' the
|
||||
// hat to Matt Pietrick for this idea. See:
|
||||
//
|
||||
// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm
|
||||
//
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
typedef DWORD (__stdcall *SYMSETOPTIONSPROC)(DWORD);
|
||||
extern SYMSETOPTIONSPROC _SymSetOptions;
|
||||
|
||||
typedef BOOL (__stdcall *SYMINITIALIZEPROC)(HANDLE, LPSTR, BOOL);
|
||||
extern SYMINITIALIZEPROC _SymInitialize;
|
||||
|
||||
typedef BOOL (__stdcall *SYMCLEANUPPROC)(HANDLE);
|
||||
extern SYMCLEANUPPROC _SymCleanup;
|
||||
|
||||
typedef BOOL (__stdcall *STACKWALKPROC)(DWORD,
|
||||
HANDLE,
|
||||
HANDLE,
|
||||
LPSTACKFRAME,
|
||||
LPVOID,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE,
|
||||
PGET_MODULE_BASE_ROUTINE,
|
||||
PTRANSLATE_ADDRESS_ROUTINE);
|
||||
extern STACKWALKPROC _StackWalk;
|
||||
|
||||
typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)(HANDLE, DWORD);
|
||||
extern SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess;
|
||||
|
||||
typedef DWORD (__stdcall *SYMGETMODULEBASEPROC)(HANDLE, DWORD);
|
||||
extern SYMGETMODULEBASEPROC _SymGetModuleBase;
|
||||
|
||||
typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL);
|
||||
extern SYMGETSYMFROMADDRPROC _SymGetSymFromAddr;
|
||||
|
||||
typedef DWORD ( __stdcall *SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD);
|
||||
extern SYMLOADMODULE _SymLoadModule;
|
||||
|
||||
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 *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID);
|
||||
extern ENUMLOADEDMODULES _EnumerateLoadedModules;
|
||||
|
||||
typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);
|
||||
extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
|
||||
|
||||
PRBool EnsureSymInitialized();
|
||||
|
||||
PRBool EnsureImageHlpInitialized();
|
||||
|
||||
/*
|
||||
* SymGetModuleInfoEspecial
|
||||
*
|
||||
* Attempt to determine the module information.
|
||||
* Bug 112196 says this DLL may not have been loaded at the time
|
||||
* SymInitialize was called, and thus the module information
|
||||
* and symbol information is not available.
|
||||
* This code rectifies that problem.
|
||||
* Line information is optional.
|
||||
*/
|
||||
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo);
|
||||
|
||||
|
||||
void DumpStackToFile(FILE* out);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif //WIN32
|
||||
|
||||
#endif //nsStackFrameWin_h___
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,122 +7,9 @@
|
||||
#include "nscore.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
#include "nsStackFrameWin.h"
|
||||
#include "nsDebugHelpWin32.h"
|
||||
#include "nsTraceMallocCallbacks.h"
|
||||
|
||||
// XXX These are *very* quick hacks and need improvement!
|
||||
|
||||
static PRBool GetSymbolFromAddress(uint32 addr, char* outBuf)
|
||||
{
|
||||
PRBool ok;
|
||||
ok = EnsureSymInitialized();
|
||||
if(!ok)
|
||||
return ok;
|
||||
|
||||
char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
|
||||
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf;
|
||||
symbol->SizeOfStruct = sizeof(buf);
|
||||
symbol->MaxNameLength = 512;
|
||||
|
||||
DWORD displacement;
|
||||
|
||||
ok = SymGetSymFromAddr(::GetCurrentProcess(),
|
||||
addr,
|
||||
&displacement,
|
||||
symbol);
|
||||
|
||||
if(ok)
|
||||
{
|
||||
char buf2[512];
|
||||
sprintf(buf2, "%s+0x%08X", symbol->Name, displacement);
|
||||
strcat(outBuf, buf2);
|
||||
}
|
||||
else
|
||||
strcat(outBuf, "dunno");
|
||||
return ok;
|
||||
}
|
||||
|
||||
static PRBool GetModuleFromAddress(uint32 addr, char* outBuf)
|
||||
{
|
||||
PRBool ok;
|
||||
ok = EnsureSymInitialized();
|
||||
if(!ok)
|
||||
return ok;
|
||||
|
||||
|
||||
IMAGEHLP_MODULE module;
|
||||
module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
|
||||
|
||||
ok = SymGetModuleInfo(::GetCurrentProcess(),
|
||||
addr,
|
||||
&module);
|
||||
|
||||
if(ok)
|
||||
strcat(outBuf, module.ModuleName);
|
||||
else
|
||||
strcat(outBuf, "dunno");
|
||||
return ok;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
#ifdef VERBOSE
|
||||
#define SHOW(x_, buf_) \
|
||||
printf(#x_" = %#x... %s\n", x_, \
|
||||
(buf_[0] = 0, \
|
||||
GetModuleFromAddress((uint32)x_, buf_), \
|
||||
strcat(buf," :: "), \
|
||||
GetSymbolFromAddress((uint32)x_, buf_), \
|
||||
buf_));
|
||||
#else
|
||||
#define SHOW(x_, buf_)
|
||||
#endif //VERBOSE
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
#ifdef VERBOSE
|
||||
// XXX This is a quick hack to show that x86 Win32 stack walking can be done
|
||||
// with this sort of loop following the bp.
|
||||
|
||||
void dumpStack()
|
||||
{
|
||||
uint32* bp_;
|
||||
uint32* bpdown;
|
||||
uint32 pc;
|
||||
|
||||
char buf[512];
|
||||
|
||||
_asm { mov bp_ , ebp }
|
||||
|
||||
/* Stack walking code adapted from Kipp's "leaky". */
|
||||
while (1) {
|
||||
bpdown = (uint32*) *bp_++;
|
||||
pc = *bp_;
|
||||
// These addresses are iffy...
|
||||
if (pc < 0x00400000 || pc > 0x7fffffff || bpdown < bp_)
|
||||
break;
|
||||
SHOW(pc, buf);
|
||||
bp_ = bpdown;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
char* _stdcall call2(void* v)
|
||||
{
|
||||
// dumpStack();
|
||||
// return 0;
|
||||
|
||||
return (char *)malloc(123);
|
||||
}
|
||||
|
||||
int call1(char c, int i, double d, ... )
|
||||
{
|
||||
free(call2(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
// shows how to use the dhw stuff to hook imported functions
|
||||
|
||||
@ -239,93 +126,10 @@ void __cdecl dhw_delete(void* p)
|
||||
FreeCallback(p, start, end);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
// A demonstration of using the _CrtSetAllocHook based hooking.
|
||||
// This system sucks because you don't get to see the allocated pointer.
|
||||
#if 0
|
||||
class myAllocationSizePrinter : public DHWAllocationSizeDebugHook
|
||||
{
|
||||
public:
|
||||
PRBool AllocHook(size_t size)
|
||||
{
|
||||
alloc_calls++ ;
|
||||
total_mem += size;
|
||||
if(verbosity)
|
||||
{
|
||||
printf("alloc called to get %d bytes.\n", size);
|
||||
dumpStack();
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool ReallocHook(size_t size, size_t sizeOld)
|
||||
{
|
||||
realloc_calls++ ;
|
||||
total_mem += size;
|
||||
total_mem -= sizeOld;
|
||||
if(verbosity)
|
||||
{
|
||||
printf("realloc called to size to %d bytes. Old size: %d.\n",
|
||||
size, sizeOld);
|
||||
dumpStack();
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool FreeHook(size_t size)
|
||||
{
|
||||
free_calls++ ;
|
||||
total_mem -= size;
|
||||
if(verbosity)
|
||||
{
|
||||
printf("free called to release %d bytes.\n", size);
|
||||
dumpStack();
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
myAllocationSizePrinter(int v)
|
||||
: verbosity(v),
|
||||
alloc_calls(0),
|
||||
realloc_calls(0),
|
||||
free_calls(0),
|
||||
total_mem(0) {}
|
||||
virtual ~myAllocationSizePrinter(){}
|
||||
|
||||
void report()
|
||||
{
|
||||
printf("%d allocs, %d reallocs, %d frees, %d bytes leaked\n",
|
||||
alloc_calls, realloc_calls, free_calls, total_mem);
|
||||
}
|
||||
|
||||
private:
|
||||
void dumpStack()
|
||||
{
|
||||
if(verbosity == 2)
|
||||
::dumpStack();
|
||||
}
|
||||
|
||||
int verbosity;
|
||||
int alloc_calls;
|
||||
int realloc_calls;
|
||||
int free_calls;
|
||||
size_t total_mem;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*C Callbacks*/
|
||||
PR_IMPLEMENT(void)
|
||||
StartupHooker()
|
||||
{
|
||||
if (!EnsureSymInitialized())
|
||||
return;
|
||||
|
||||
//run through get all hookers
|
||||
DHWImportHooker &loadlibraryW = DHWImportHooker::getLoadLibraryWHooker();
|
||||
DHWImportHooker &loadlibraryExW = DHWImportHooker::getLoadLibraryExWHooker();
|
||||
@ -344,50 +148,3 @@ PR_IMPLEMENT(void)
|
||||
ShutdownHooker()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
int main()
|
||||
{
|
||||
// A demonstration of using the (sucky) _CrtSetAllocHook based hooking.
|
||||
myAllocationSizePrinter ap(0);
|
||||
dhwSetAllocationSizeDebugHook(&ap);
|
||||
|
||||
// show that the ImportHooker is hooking calls from loaded dll
|
||||
DHW_DECLARE_FUN_TYPE(void, __stdcall, SOMECALL_, (void));
|
||||
HMODULE module = ::LoadLibrary("Other.dll");
|
||||
if(module) {
|
||||
SOMECALL_ _SomeCall = (SOMECALL_) GetProcAddress(module, "SomeCall");
|
||||
if(_SomeCall)
|
||||
_SomeCall();
|
||||
}
|
||||
|
||||
// show that the ImportHooker is hooking sneaky calls made from this dll.
|
||||
HMODULE module2 = ::LoadLibrary(NS_DEBUG_CRT);
|
||||
if(module2) {
|
||||
MALLOC_ _sneakyMalloc = (MALLOC_) GetProcAddress(module2, "malloc");
|
||||
if(_sneakyMalloc)
|
||||
{
|
||||
void* p = _sneakyMalloc(987);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
call1('x', 1, 1.0, "hi there", 2);
|
||||
|
||||
char* p = new char[10];
|
||||
delete p;
|
||||
|
||||
void* v = malloc(10);
|
||||
v = realloc(v, 15);
|
||||
v = realloc(v, 5);
|
||||
free(v);`
|
||||
|
||||
ap.report();
|
||||
dhwClearAllocationSizeDebugHook();
|
||||
return 0;
|
||||
}
|
||||
#endif //0
|
||||
|
||||
|
@ -137,9 +137,8 @@ void PrintError(char *prefix)
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
char buf[512];
|
||||
_snprintf(buf, sizeof(buf), "### ERROR: %s: %s", prefix, lpMsgBuf);
|
||||
fputs(buf, stderr);
|
||||
fprintf(stderr, "### ERROR: %s: %s", prefix, lpMsgBuf);
|
||||
fflush(stderr);
|
||||
LocalFree( lpMsgBuf );
|
||||
}
|
||||
|
||||
@ -448,8 +447,7 @@ EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
void *aClosure)
|
||||
{
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
HANDLE myThread, walkerThread;
|
||||
HANDLE myProcess, myThread, walkerThread;
|
||||
DWORD walkerReturn;
|
||||
struct WalkStackData data;
|
||||
|
||||
@ -457,13 +455,23 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Have to duplicate handle to get a real handle.
|
||||
::DuplicateHandle(
|
||||
::GetCurrentProcess(),
|
||||
::GetCurrentThread(),
|
||||
::GetCurrentProcess(),
|
||||
&myThread,
|
||||
THREAD_ALL_ACCESS, FALSE, 0
|
||||
);
|
||||
if (!::DuplicateHandle(::GetCurrentProcess(),
|
||||
::GetCurrentProcess(),
|
||||
::GetCurrentProcess(),
|
||||
&myProcess,
|
||||
THREAD_ALL_ACCESS, FALSE, 0)) {
|
||||
PrintError("DuplicateHandle (process)");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!::DuplicateHandle(::GetCurrentProcess(),
|
||||
::GetCurrentThread(),
|
||||
::GetCurrentProcess(),
|
||||
&myThread,
|
||||
THREAD_ALL_ACCESS, FALSE, 0)) {
|
||||
PrintError("DuplicateHandle (thread)");
|
||||
::CloseHandle(myProcess);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
data.callback = aCallback;
|
||||
data.skipFrames = aSkipFrames;
|
||||
@ -476,11 +484,13 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
if (walkerReturn != WAIT_OBJECT_0) {
|
||||
PrintError("ThreadWait");
|
||||
}
|
||||
CloseHandle(myThread);
|
||||
::CloseHandle(walkerThread);
|
||||
}
|
||||
else {
|
||||
PrintError("ThreadCreate");
|
||||
}
|
||||
::CloseHandle(myThread);
|
||||
::CloseHandle(myProcess);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "nsStackWalk.h"
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code
|
||||
|
||||
#include "nsStackFrameWin.cpp"
|
||||
|
||||
// WIN32 x86 stack walking code
|
||||
|
Loading…
Reference in New Issue
Block a user