diff --git a/mozilla/tools/trace-malloc/lib/nsDebugHelpWin32.cpp b/mozilla/tools/trace-malloc/lib/nsDebugHelpWin32.cpp new file mode 100644 index 00000000000..dcc577fe1be --- /dev/null +++ b/mozilla/tools/trace-malloc/lib/nsDebugHelpWin32.cpp @@ -0,0 +1,475 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * John Bandhauer + */ + +/* Win32 x86 code for stack walking, symbol resolution, and function hooking */ + +#if defined(_WIN32) && defined(_M_IX86) +// This is the .cpp file where the globals live +#define DHW_IMPLEMENT_GLOBALS +#include +#include "prtypes.h" +#include "prprf.h" +#include "prlog.h" +#include "plstr.h" +#include "prlock.h" +#include "nscore.h" +#include "nsAutoLock.h" +#include "nsDebugHelpWin32.h" +#else +#error "nsDebugHelpWin32.cpp should only be built in Win32 x86 builds" +#endif + + + + + + + +PRBool +dhwEnsureImageHlpInitialized() +{ + static PRBool gInitialized = PR_FALSE; + static PRBool gTried = PR_FALSE; + + if (!gInitialized && !gTried) { + gTried = PR_TRUE; + HMODULE module = ::LoadLibrary("DBGHELP.DLL"); + if (!module) { + DWORD dw = GetLastError(); + printf("DumpStack Error: DBGHELP.DLL wasn't found. " + "GetLastError() returned 0x%8.8X\n", dw); + return PR_FALSE; + } + +#define INIT_PROC(typename_, name_) \ + dhw##name_ = (typename_) ::GetProcAddress(module, #name_); \ + if(!dhw##name_) return PR_FALSE; + + INIT_PROC(SYMINITIALIZEPROC, SymInitialize); + INIT_PROC(SYMSETOPTIONS, SymSetOptions); + INIT_PROC(SYMGETOPTIONS, SymGetOptions); + INIT_PROC(SYMGETMODULEINFO, SymGetModuleInfo); + INIT_PROC(SYMGETSYMFROMADDRPROC, SymGetSymFromAddr); + INIT_PROC(ENUMERATELOADEDMODULES, EnumerateLoadedModules); + INIT_PROC(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData); + +// INIT_PROC(SYMGETLINEFROMADDR, SymGetLineFromAddr); +// INIT_PROC(SYMCLEANUPPROC, SymCleanup); +// INIT_PROC(STACKWALKPROC, StackWalk); +// INIT_PROC(SYMFUNCTIONTABLEACCESSPROC, SymFunctionTableAccess); +// INIT_PROC(SYMGETMODULEBASEPROC, SymGetModuleBase); +// INIT_PROC(SYMLOADMODULE, SymLoadModule); +// INIT_PROC(UNDECORATESYMBOLNAME, UnDecorateSymbolName); +// INIT_PROC(SYMUNDNAME, SymUnDName); + + +#undef INIT_PROC + + gInitialized = PR_TRUE; + } + + return gInitialized; +} + +PRBool +dhwEnsureSymInitialized() +{ + static PRBool gInitialized = PR_FALSE; + + if (! gInitialized) { + if (! dhwEnsureImageHlpInitialized()) + return PR_FALSE; + // dhwSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + dhwSymSetOptions(SYMOPT_UNDNAME); + if (! dhwSymInitialize(::GetCurrentProcess(), NULL, TRUE)) + return PR_FALSE; + gInitialized = PR_TRUE; + } + return gInitialized; +} + +/***************************************************************************/ + + +PRLock* DHWImportHooker::gLock = nsnull; +DHWImportHooker* DHWImportHooker::gHooks = nsnull; +GETPROCADDRESS DHWImportHooker::gRealGetProcAddress = nsnull; + +DHWImportHooker& +DHWImportHooker::getGetProcAddressHooker() +{ + static DHWImportHooker gGetProcAddress("Kernel32.dll", "GetProcAddress", + (PROC)DHWImportHooker::GetProcAddress); + return gGetProcAddress; +} + + +DHWImportHooker& +DHWImportHooker::getLoadLibraryWHooker() +{ + static DHWImportHooker gLoadLibraryW("Kernel32.dll", "LoadLibraryW", + (PROC)DHWImportHooker::LoadLibraryW); + return gLoadLibraryW; +} + +DHWImportHooker& +DHWImportHooker::getLoadLibraryExWHooker() +{ + static DHWImportHooker gLoadLibraryExW("Kernel32.dll", "LoadLibraryExW", + (PROC)DHWImportHooker::LoadLibraryExW); + return gLoadLibraryExW; +} + +DHWImportHooker& +DHWImportHooker::getLoadLibraryAHooker() +{ + static DHWImportHooker gLoadLibraryA("Kernel32.dll", "LoadLibraryA", + (PROC)DHWImportHooker::LoadLibraryA); + return gLoadLibraryA; +} + +DHWImportHooker& +DHWImportHooker::getLoadLibraryExAHooker() +{ + static DHWImportHooker gLoadLibraryExA("Kernel32.dll", "LoadLibraryExA", + (PROC)DHWImportHooker::LoadLibraryExA); + return gLoadLibraryExA; +} + + +static HMODULE ThisModule() +{ + MEMORY_BASIC_INFORMATION info; + return VirtualQuery(ThisModule, &info, sizeof(info)) ? + (HMODULE) info.AllocationBase : nsnull; +} + +DHWImportHooker::DHWImportHooker(const char* aModuleName, + const char* aFunctionName, + PROC aHook, + PRBool aExcludeOurModule /* = PR_FALSE */) + : mNext(nsnull), + mModuleName(aModuleName), + mFunctionName(aFunctionName), + mOriginal(nsnull), + mHook(aHook), + mIgnoreModule(aExcludeOurModule ? ThisModule() : nsnull), + mHooking(PR_TRUE) +{ + printf("DHWImportHooker hooking %s, function %s\n",aModuleName, aFunctionName); + + if(!gLock) + gLock = PR_NewLock(); + nsAutoLock lock(gLock); + + dhwEnsureImageHlpInitialized(); + + if(!gRealGetProcAddress) + gRealGetProcAddress = ::GetProcAddress; + + mOriginal = gRealGetProcAddress(::GetModuleHandleA(aModuleName), + aFunctionName), + + mNext = gHooks; + gHooks = this; + + PatchAllModules(); +} + +DHWImportHooker::~DHWImportHooker() +{ + nsAutoLock lock(gLock); + + mHooking = PR_FALSE; + PatchAllModules(); + + if(gHooks = this) + gHooks = mNext; + else + { + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) + { + if(cur->mNext == this) + { + cur->mNext = mNext; + break; + } + } + NS_ASSERTION(cur, "we were not in the list!"); + } + + if(!gHooks) + { + PRLock* theLock = gLock; + gLock = nsnull; + lock.unlock(); + PR_DestroyLock(theLock); + } +} + +static BOOL CALLBACK ModuleEnumCallback(LPSTR ModuleName, + ULONG ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +{ + //printf("Module Name %s\n",ModuleName); + DHWImportHooker* self = (DHWImportHooker*) UserContext; + HMODULE aModule = (HMODULE) ModuleBase; + return self->PatchOneModule(aModule, ModuleName); +} + +PRBool +DHWImportHooker::PatchAllModules() +{ + return dhwEnumerateLoadedModules(::GetCurrentProcess(), + ModuleEnumCallback, this); +} + +PRBool +DHWImportHooker::PatchOneModule(HMODULE aModule, const char* name) +{ + if(aModule == mIgnoreModule) + { + return PR_TRUE; + } + + // do the fun stuff... + + PIMAGE_IMPORT_DESCRIPTOR desc; + uint32 size; + + desc = (PIMAGE_IMPORT_DESCRIPTOR) + dhwImageDirectoryEntryToData(aModule, PR_TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, &size); + + if(!desc) + { + return PR_TRUE; + } + + for(; desc->Name; desc++) + { + const char* entryModuleName = (const char*) + ((char*)aModule + desc->Name); + if(!lstrcmpi(entryModuleName, mModuleName)) + break; + } + + if(!desc->Name) + { + return PR_TRUE; + } + + PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA) + ((char*) aModule + desc->FirstThunk); + + for(; thunk->u1.Function; thunk++) + { + PROC original; + PROC replacement; + + if(mHooking) + { + original = mOriginal; + replacement = mHook; + } + else + { + original = mHook; + replacement = mOriginal; + } + + PROC* ppfn = (PROC*) &thunk->u1.Function; + if(*ppfn == original) + { + DWORD dwDummy; + VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy); + BOOL result = WriteProcessMemory(GetCurrentProcess(), + ppfn, &replacement, sizeof(replacement), nsnull); + if (!result) //failure + { + printf("failure name %s func %x\n",name,*ppfn); + DWORD error = GetLastError(); + return PR_TRUE; + } + else + { + printf("success name %s func %x\n",name,*ppfn); + DWORD filler = result+1; + return result; + } + } + + } + return PR_TRUE; +} + +PRBool +DHWImportHooker::ModuleLoaded(HMODULE aModule, DWORD flags) +{ + printf("ModuleLoaded\n"); + if(aModule && !(flags & LOAD_LIBRARY_AS_DATAFILE)) + { + nsAutoLock lock(gLock); + // We don't know that the newly loaded module didn't drag in implicitly + // linked modules, so we patch everything in sight. + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) + cur->PatchAllModules(); + } + return PR_TRUE; +} + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryW(PCWSTR path) +{ + wprintf(L"LoadLibraryW %s\n",path); + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYW_, (PCWSTR)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYW_, getLoadLibraryWHooker())(path); + ModuleLoaded(hmod, 0); + return hmod; +} + + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags) +{ + wprintf(L"LoadLibraryExW %s\n",path); + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYEXW_, (PCWSTR, HANDLE, DWORD)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYEXW_, getLoadLibraryExWHooker())(path, file, flags); + ModuleLoaded(hmod, flags); + return hmod; +} + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryA(PCSTR path) +{ + printf("LoadLibraryA %s\n",path); + + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYA_, (PCSTR)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYA_, getLoadLibraryAHooker())(path); + ModuleLoaded(hmod, 0); + return hmod; +} + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags) +{ + printf("LoadLibraryExA %s\n",path); + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYEXA_, (PCSTR, HANDLE, DWORD)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYEXA_, getLoadLibraryExAHooker())(path, file, flags); + ModuleLoaded(hmod, flags); + return hmod; +} +// static +FARPROC WINAPI +DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName) +{ + FARPROC pfn = gRealGetProcAddress(aModule, aFunctionName); + + if(pfn) + { + nsAutoLock lock(gLock); + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) + { + if(pfn == cur->mOriginal) + { + pfn = cur->mHook; + break; + } + } + } + return pfn; +} + +/***************************************************************************/ +#if 0 + +static _CRT_ALLOC_HOOK defaultDbgAllocHook = nsnull; +static DHWAllocationSizeDebugHook* gAllocationSizeHook = nsnull; + +int __cdecl dhw_DbgAllocHook(int nAllocType, void *pvData, + size_t nSize, int nBlockUse, long lRequest, + const unsigned char * szFileName, int nLine ) +{ + DHWAllocationSizeDebugHook* hook = gAllocationSizeHook; + + if(hook) + { + PRBool res; + _CrtSetAllocHook(defaultDbgAllocHook); + + switch(nAllocType) + { + case _HOOK_ALLOC: + res = hook->AllocHook(nSize); + break; + case _HOOK_REALLOC: + res = hook->ReallocHook(nSize, pvData ? + _msize_dbg(pvData, nBlockUse) : 0); + break; + case _HOOK_FREE: + res = hook->FreeHook(pvData ? + _msize_dbg(pvData, nBlockUse) : 0); + break; + default: + NS_ASSERTION(0,"huh?"); + res = PR_TRUE; + break; + } + + _CrtSetAllocHook(dhw_DbgAllocHook); + return (int) res; + } + return 1; +} + +PRBool +dhwSetAllocationSizeDebugHook(DHWAllocationSizeDebugHook* hook) +{ + if(!hook || gAllocationSizeHook) + return PR_FALSE; + + gAllocationSizeHook = hook; + + if(!defaultDbgAllocHook) + defaultDbgAllocHook = _CrtSetAllocHook(dhw_DbgAllocHook); + else + _CrtSetAllocHook(dhw_DbgAllocHook); + + return PR_TRUE; +} + +PRBool +dhwClearAllocationSizeDebugHook() +{ + if(!gAllocationSizeHook) + return PR_FALSE; + gAllocationSizeHook = nsnull; + _CrtSetAllocHook(defaultDbgAllocHook); + return PR_TRUE; +} +#endif //0 diff --git a/mozilla/tools/trace-malloc/lib/nsDebugHelpWin32.h b/mozilla/tools/trace-malloc/lib/nsDebugHelpWin32.h new file mode 100644 index 00000000000..dfcfe56e94a --- /dev/null +++ b/mozilla/tools/trace-malloc/lib/nsDebugHelpWin32.h @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * John Bandhauer + */ + +/* Win32 x86 code for stack walking, symbol resolution, and function hooking */ + +#ifndef __nsDebugHelpWin32_h__ +#define __nsDebugHelpWin32_h__ + +#if defined(_WIN32) && defined(_M_IX86) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include + #include + #include +#else + #error "nsDebugHelpWin32.h should only be included in Win32 x86 builds" +#endif + +// XXX temporary hack... +//#include "hacky_defines.h" + + +/***************************************************************************/ +// useful macros... + +#define DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_) \ + typedef retval_ ( conv_ * typename_ ) args_ ; + +#ifdef DHW_IMPLEMENT_GLOBALS +#define DHW_DECLARE_FUN_GLOBAL(typename_, name_) typename_ dhw##name_ +#else +#define DHW_DECLARE_FUN_GLOBAL(typename_, name_) extern typename_ dhw##name_ +#endif + +#define DHW_DECLARE_FUN_PROTO(retval_, conv_, name_, args_) \ + retval_ conv_ name_ args_ + +#define DHW_DECLARE_FUN_STATIC_PROTO(retval_, name_, args_) \ + static retval_ conv_ name_ args_ + +#define DHW_DECLARE_FUN_TYPE_AND_PROTO(name_, retval_, conv_, typename_, args_) \ + DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \ + DHW_DECLARE_FUN_PROTO(retval_, conv_, name_, args_) + +#define DHW_DECLARE_FUN_TYPE_AND_STATIC_PROTO(name_, retval_, conv_, typename_, args_) \ + DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \ + DHW_DECLARE_FUN_STATIC_PROTO(retval_, conv_, name_, args_) + +#define DHW_DECLARE_FUN_TYPE_AND_GLOBAL(typename_, name_, retval_, conv_, args_) \ + DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \ + DHW_DECLARE_FUN_GLOBAL(typename_, name_) + + +/**********************************************************/ +// These are used to get 'original' function addresses from DHWImportHooker. + +#define DHW_DECLARE_ORIGINAL(type_, name_, hooker_) \ + type_ name_ = (type_) hooker_ . GetOriginalFunction() + +#define DHW_DECLARE_ORIGINAL_PTR(type_, name_, hooker_) \ + type_ name_ = (type_) hooker_ -> GetOriginalFunction() + +#define DHW_ORIGINAL(type_, hooker_) \ + ((type_) hooker_ . GetOriginalFunction()) + +#define DHW_ORIGINAL_PTR(type_, hooker_) \ + ((type_) hooker_ -> GetOriginalFunction()) + +/***************************************************************************/ +// Global declarations of entry points into ImgHelp functions + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMINITIALIZEPROC, SymInitialize, \ + BOOL, __stdcall, (HANDLE, LPSTR, BOOL)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMSETOPTIONS, SymSetOptions, \ + DWORD, __stdcall, (DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETOPTIONS, SymGetOptions, \ + DWORD, __stdcall, ()); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEINFO, SymGetModuleInfo, \ + BOOL, __stdcall, (HANDLE, DWORD, PIMAGEHLP_MODULE)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETSYMFROMADDRPROC, SymGetSymFromAddr, \ + BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(ENUMERATELOADEDMODULES, EnumerateLoadedModules, \ + BOOL, __stdcall, (HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData, \ + PVOID, __stdcall, (PVOID, BOOL, USHORT, PULONG)); + + +// We aren't using any of the below yet... + +/* +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMCLEANUPPROC, SymCleanup, \ + BOOL, __stdcall, (HANDLE)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(STACKWALKPROC, StackWalk, \ + BOOL, + __stdcall, + (DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, \ + PREAD_PROCESS_MEMORY_ROUTINE, \ + PFUNCTION_TABLE_ACCESS_ROUTINE, \ + PGET_MODULE_BASE_ROUTINE, \ + PTRANSLATE_ADDRESS_ROUTINE)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMFUNCTIONTABLEACCESSPROC, SymFunctionTableAccess, \ + LPVOID, __stdcall, (HANDLE, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEBASEPROC, SymGetModuleBase, \ + DWORD, __stdcall, (HANDLE, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMLOADMODULE, SymLoadModule, \ + DWORD, __stdcall, (HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(UNDECORATESYMBOLNAME, _UnDecorateSymbolName, \ + DWORD, __stdcall, (LPCSTR, LPSTR, DWORD, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMUNDNAME, SymUnDName, \ + BOOL, __stdcall, (PIMAGEHLP_SYMBOL, LPSTR, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETLINEFROMADDR, SymGetLineFromAddr, \ + BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE)); + +*/ + +/***************************************************************************/ + +extern PRBool +dhwEnsureImageHlpInitialized(); + +extern PRBool +dhwEnsureSymInitialized(); + +/***************************************************************************/ + +DHW_DECLARE_FUN_TYPE(FARPROC, __stdcall, GETPROCADDRESS, (HMODULE, PCSTR)); + +class DHWImportHooker +{ +public: + + DHWImportHooker(const char* aModuleName, + const char* aFunctionName, + PROC aHook, + PRBool aExcludeOurModule = PR_FALSE); + + ~DHWImportHooker(); + + PROC GetOriginalFunction() {return mOriginal;} + + PRBool PatchAllModules(); + PRBool PatchOneModule(HMODULE aModule, const char* name); + static PRBool ModuleLoaded(HMODULE aModule, DWORD flags); + + + // I think that these should be made not static members, but allocated + // things created in an explicit static 'init' method and cleaned up in + // an explicit static 'finish' method. This would allow the application + // to have proper lifetime control over all the hooks. + + static DHWImportHooker &getLoadLibraryWHooker(); + static DHWImportHooker &getLoadLibraryExWHooker(); + static DHWImportHooker &getLoadLibraryAHooker(); + static DHWImportHooker &getLoadLibraryExAHooker(); + static DHWImportHooker &getGetProcAddressHooker(); + + static HMODULE WINAPI LoadLibraryA(PCSTR path); + +private: + DHWImportHooker* mNext; + const char* mModuleName; + const char* mFunctionName; + PROC mOriginal; + PROC mHook; + HMODULE mIgnoreModule; + PRBool mHooking; + +private: + static PRLock* gLock; + static DHWImportHooker* gHooks; + static GETPROCADDRESS gRealGetProcAddress; + + static HMODULE WINAPI LoadLibraryW(PCWSTR path); + static HMODULE WINAPI LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags); + static HMODULE WINAPI LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags); + + static FARPROC WINAPI GetProcAddress(HMODULE aModule, PCSTR aFunctionName); +}; + +/***************************************************************************/ +// This supports the _CrtSetAllocHook based hooking. +// This system sucks because you don't get to see the allocated pointer. I +// don't think it appropriate for nsTraceMalloc, but is useful as a means to make +// malloc fail for testing purposes. +#if 0 //comment out this stuff. not necessary + +class DHWAllocationSizeDebugHook +{ +public: + virtual PRBool AllocHook(size_t size) = 0; + virtual PRBool ReallocHook(size_t size, size_t sizeOld) = 0; + virtual PRBool FreeHook(size_t size) = 0; +}; + +extern PRBool dhwSetAllocationSizeDebugHook(DHWAllocationSizeDebugHook* hook); +extern PRBool dhwClearAllocationSizeDebugHook(); + +/***************************************************************************/ +#endif //0 + +#endif /* __nsDebugHelpWin32_h__ */ diff --git a/mozilla/tools/trace-malloc/lib/nsTraceMallocCallbacks.h b/mozilla/tools/trace-malloc/lib/nsTraceMallocCallbacks.h new file mode 100644 index 00000000000..fc183bcdc88 --- /dev/null +++ b/mozilla/tools/trace-malloc/lib/nsTraceMallocCallbacks.h @@ -0,0 +1,20 @@ +#ifndef NSTRACEMALLOCCALLBACKS_H +#define NSTRACEMALLOCCALLBACKS_H + +PR_BEGIN_EXTERN_C + + +PR_EXTERN(void) StartupHooker();/*implemented in TraceMalloc.cpp*/ +PR_EXTERN(void) ShutdownHooker(); + +PR_EXTERN(void) MallocCallback(void *aPtr, size_t aSize);/*implemented in nsTraceMalloc.c*/ +PR_EXTERN(void) CallocCallback(void *aPtr, size_t aCount, size_t aSize); +PR_EXTERN(void) ReallocCallback(void *aPin, void* aPout, size_t aSize); +PR_EXTERN(void) FreeCallback(void *aPtr); + + +PR_END_EXTERN_C + + +#endif //NSTRACEMALLOCCALLBACKS_H + diff --git a/mozilla/xpcom/base/nsDebugHelpWin32.cpp b/mozilla/xpcom/base/nsDebugHelpWin32.cpp new file mode 100644 index 00000000000..dcc577fe1be --- /dev/null +++ b/mozilla/xpcom/base/nsDebugHelpWin32.cpp @@ -0,0 +1,475 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * John Bandhauer + */ + +/* Win32 x86 code for stack walking, symbol resolution, and function hooking */ + +#if defined(_WIN32) && defined(_M_IX86) +// This is the .cpp file where the globals live +#define DHW_IMPLEMENT_GLOBALS +#include +#include "prtypes.h" +#include "prprf.h" +#include "prlog.h" +#include "plstr.h" +#include "prlock.h" +#include "nscore.h" +#include "nsAutoLock.h" +#include "nsDebugHelpWin32.h" +#else +#error "nsDebugHelpWin32.cpp should only be built in Win32 x86 builds" +#endif + + + + + + + +PRBool +dhwEnsureImageHlpInitialized() +{ + static PRBool gInitialized = PR_FALSE; + static PRBool gTried = PR_FALSE; + + if (!gInitialized && !gTried) { + gTried = PR_TRUE; + HMODULE module = ::LoadLibrary("DBGHELP.DLL"); + if (!module) { + DWORD dw = GetLastError(); + printf("DumpStack Error: DBGHELP.DLL wasn't found. " + "GetLastError() returned 0x%8.8X\n", dw); + return PR_FALSE; + } + +#define INIT_PROC(typename_, name_) \ + dhw##name_ = (typename_) ::GetProcAddress(module, #name_); \ + if(!dhw##name_) return PR_FALSE; + + INIT_PROC(SYMINITIALIZEPROC, SymInitialize); + INIT_PROC(SYMSETOPTIONS, SymSetOptions); + INIT_PROC(SYMGETOPTIONS, SymGetOptions); + INIT_PROC(SYMGETMODULEINFO, SymGetModuleInfo); + INIT_PROC(SYMGETSYMFROMADDRPROC, SymGetSymFromAddr); + INIT_PROC(ENUMERATELOADEDMODULES, EnumerateLoadedModules); + INIT_PROC(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData); + +// INIT_PROC(SYMGETLINEFROMADDR, SymGetLineFromAddr); +// INIT_PROC(SYMCLEANUPPROC, SymCleanup); +// INIT_PROC(STACKWALKPROC, StackWalk); +// INIT_PROC(SYMFUNCTIONTABLEACCESSPROC, SymFunctionTableAccess); +// INIT_PROC(SYMGETMODULEBASEPROC, SymGetModuleBase); +// INIT_PROC(SYMLOADMODULE, SymLoadModule); +// INIT_PROC(UNDECORATESYMBOLNAME, UnDecorateSymbolName); +// INIT_PROC(SYMUNDNAME, SymUnDName); + + +#undef INIT_PROC + + gInitialized = PR_TRUE; + } + + return gInitialized; +} + +PRBool +dhwEnsureSymInitialized() +{ + static PRBool gInitialized = PR_FALSE; + + if (! gInitialized) { + if (! dhwEnsureImageHlpInitialized()) + return PR_FALSE; + // dhwSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + dhwSymSetOptions(SYMOPT_UNDNAME); + if (! dhwSymInitialize(::GetCurrentProcess(), NULL, TRUE)) + return PR_FALSE; + gInitialized = PR_TRUE; + } + return gInitialized; +} + +/***************************************************************************/ + + +PRLock* DHWImportHooker::gLock = nsnull; +DHWImportHooker* DHWImportHooker::gHooks = nsnull; +GETPROCADDRESS DHWImportHooker::gRealGetProcAddress = nsnull; + +DHWImportHooker& +DHWImportHooker::getGetProcAddressHooker() +{ + static DHWImportHooker gGetProcAddress("Kernel32.dll", "GetProcAddress", + (PROC)DHWImportHooker::GetProcAddress); + return gGetProcAddress; +} + + +DHWImportHooker& +DHWImportHooker::getLoadLibraryWHooker() +{ + static DHWImportHooker gLoadLibraryW("Kernel32.dll", "LoadLibraryW", + (PROC)DHWImportHooker::LoadLibraryW); + return gLoadLibraryW; +} + +DHWImportHooker& +DHWImportHooker::getLoadLibraryExWHooker() +{ + static DHWImportHooker gLoadLibraryExW("Kernel32.dll", "LoadLibraryExW", + (PROC)DHWImportHooker::LoadLibraryExW); + return gLoadLibraryExW; +} + +DHWImportHooker& +DHWImportHooker::getLoadLibraryAHooker() +{ + static DHWImportHooker gLoadLibraryA("Kernel32.dll", "LoadLibraryA", + (PROC)DHWImportHooker::LoadLibraryA); + return gLoadLibraryA; +} + +DHWImportHooker& +DHWImportHooker::getLoadLibraryExAHooker() +{ + static DHWImportHooker gLoadLibraryExA("Kernel32.dll", "LoadLibraryExA", + (PROC)DHWImportHooker::LoadLibraryExA); + return gLoadLibraryExA; +} + + +static HMODULE ThisModule() +{ + MEMORY_BASIC_INFORMATION info; + return VirtualQuery(ThisModule, &info, sizeof(info)) ? + (HMODULE) info.AllocationBase : nsnull; +} + +DHWImportHooker::DHWImportHooker(const char* aModuleName, + const char* aFunctionName, + PROC aHook, + PRBool aExcludeOurModule /* = PR_FALSE */) + : mNext(nsnull), + mModuleName(aModuleName), + mFunctionName(aFunctionName), + mOriginal(nsnull), + mHook(aHook), + mIgnoreModule(aExcludeOurModule ? ThisModule() : nsnull), + mHooking(PR_TRUE) +{ + printf("DHWImportHooker hooking %s, function %s\n",aModuleName, aFunctionName); + + if(!gLock) + gLock = PR_NewLock(); + nsAutoLock lock(gLock); + + dhwEnsureImageHlpInitialized(); + + if(!gRealGetProcAddress) + gRealGetProcAddress = ::GetProcAddress; + + mOriginal = gRealGetProcAddress(::GetModuleHandleA(aModuleName), + aFunctionName), + + mNext = gHooks; + gHooks = this; + + PatchAllModules(); +} + +DHWImportHooker::~DHWImportHooker() +{ + nsAutoLock lock(gLock); + + mHooking = PR_FALSE; + PatchAllModules(); + + if(gHooks = this) + gHooks = mNext; + else + { + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) + { + if(cur->mNext == this) + { + cur->mNext = mNext; + break; + } + } + NS_ASSERTION(cur, "we were not in the list!"); + } + + if(!gHooks) + { + PRLock* theLock = gLock; + gLock = nsnull; + lock.unlock(); + PR_DestroyLock(theLock); + } +} + +static BOOL CALLBACK ModuleEnumCallback(LPSTR ModuleName, + ULONG ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +{ + //printf("Module Name %s\n",ModuleName); + DHWImportHooker* self = (DHWImportHooker*) UserContext; + HMODULE aModule = (HMODULE) ModuleBase; + return self->PatchOneModule(aModule, ModuleName); +} + +PRBool +DHWImportHooker::PatchAllModules() +{ + return dhwEnumerateLoadedModules(::GetCurrentProcess(), + ModuleEnumCallback, this); +} + +PRBool +DHWImportHooker::PatchOneModule(HMODULE aModule, const char* name) +{ + if(aModule == mIgnoreModule) + { + return PR_TRUE; + } + + // do the fun stuff... + + PIMAGE_IMPORT_DESCRIPTOR desc; + uint32 size; + + desc = (PIMAGE_IMPORT_DESCRIPTOR) + dhwImageDirectoryEntryToData(aModule, PR_TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, &size); + + if(!desc) + { + return PR_TRUE; + } + + for(; desc->Name; desc++) + { + const char* entryModuleName = (const char*) + ((char*)aModule + desc->Name); + if(!lstrcmpi(entryModuleName, mModuleName)) + break; + } + + if(!desc->Name) + { + return PR_TRUE; + } + + PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA) + ((char*) aModule + desc->FirstThunk); + + for(; thunk->u1.Function; thunk++) + { + PROC original; + PROC replacement; + + if(mHooking) + { + original = mOriginal; + replacement = mHook; + } + else + { + original = mHook; + replacement = mOriginal; + } + + PROC* ppfn = (PROC*) &thunk->u1.Function; + if(*ppfn == original) + { + DWORD dwDummy; + VirtualProtect(ppfn, sizeof(ppfn), PAGE_EXECUTE_READWRITE, &dwDummy); + BOOL result = WriteProcessMemory(GetCurrentProcess(), + ppfn, &replacement, sizeof(replacement), nsnull); + if (!result) //failure + { + printf("failure name %s func %x\n",name,*ppfn); + DWORD error = GetLastError(); + return PR_TRUE; + } + else + { + printf("success name %s func %x\n",name,*ppfn); + DWORD filler = result+1; + return result; + } + } + + } + return PR_TRUE; +} + +PRBool +DHWImportHooker::ModuleLoaded(HMODULE aModule, DWORD flags) +{ + printf("ModuleLoaded\n"); + if(aModule && !(flags & LOAD_LIBRARY_AS_DATAFILE)) + { + nsAutoLock lock(gLock); + // We don't know that the newly loaded module didn't drag in implicitly + // linked modules, so we patch everything in sight. + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) + cur->PatchAllModules(); + } + return PR_TRUE; +} + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryW(PCWSTR path) +{ + wprintf(L"LoadLibraryW %s\n",path); + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYW_, (PCWSTR)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYW_, getLoadLibraryWHooker())(path); + ModuleLoaded(hmod, 0); + return hmod; +} + + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags) +{ + wprintf(L"LoadLibraryExW %s\n",path); + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYEXW_, (PCWSTR, HANDLE, DWORD)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYEXW_, getLoadLibraryExWHooker())(path, file, flags); + ModuleLoaded(hmod, flags); + return hmod; +} + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryA(PCSTR path) +{ + printf("LoadLibraryA %s\n",path); + + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYA_, (PCSTR)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYA_, getLoadLibraryAHooker())(path); + ModuleLoaded(hmod, 0); + return hmod; +} + +// static +HMODULE WINAPI +DHWImportHooker::LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags) +{ + printf("LoadLibraryExA %s\n",path); + DHW_DECLARE_FUN_TYPE(HMODULE, __stdcall, LOADLIBRARYEXA_, (PCSTR, HANDLE, DWORD)); + HMODULE hmod = DHW_ORIGINAL(LOADLIBRARYEXA_, getLoadLibraryExAHooker())(path, file, flags); + ModuleLoaded(hmod, flags); + return hmod; +} +// static +FARPROC WINAPI +DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName) +{ + FARPROC pfn = gRealGetProcAddress(aModule, aFunctionName); + + if(pfn) + { + nsAutoLock lock(gLock); + for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) + { + if(pfn == cur->mOriginal) + { + pfn = cur->mHook; + break; + } + } + } + return pfn; +} + +/***************************************************************************/ +#if 0 + +static _CRT_ALLOC_HOOK defaultDbgAllocHook = nsnull; +static DHWAllocationSizeDebugHook* gAllocationSizeHook = nsnull; + +int __cdecl dhw_DbgAllocHook(int nAllocType, void *pvData, + size_t nSize, int nBlockUse, long lRequest, + const unsigned char * szFileName, int nLine ) +{ + DHWAllocationSizeDebugHook* hook = gAllocationSizeHook; + + if(hook) + { + PRBool res; + _CrtSetAllocHook(defaultDbgAllocHook); + + switch(nAllocType) + { + case _HOOK_ALLOC: + res = hook->AllocHook(nSize); + break; + case _HOOK_REALLOC: + res = hook->ReallocHook(nSize, pvData ? + _msize_dbg(pvData, nBlockUse) : 0); + break; + case _HOOK_FREE: + res = hook->FreeHook(pvData ? + _msize_dbg(pvData, nBlockUse) : 0); + break; + default: + NS_ASSERTION(0,"huh?"); + res = PR_TRUE; + break; + } + + _CrtSetAllocHook(dhw_DbgAllocHook); + return (int) res; + } + return 1; +} + +PRBool +dhwSetAllocationSizeDebugHook(DHWAllocationSizeDebugHook* hook) +{ + if(!hook || gAllocationSizeHook) + return PR_FALSE; + + gAllocationSizeHook = hook; + + if(!defaultDbgAllocHook) + defaultDbgAllocHook = _CrtSetAllocHook(dhw_DbgAllocHook); + else + _CrtSetAllocHook(dhw_DbgAllocHook); + + return PR_TRUE; +} + +PRBool +dhwClearAllocationSizeDebugHook() +{ + if(!gAllocationSizeHook) + return PR_FALSE; + gAllocationSizeHook = nsnull; + _CrtSetAllocHook(defaultDbgAllocHook); + return PR_TRUE; +} +#endif //0 diff --git a/mozilla/xpcom/base/nsDebugHelpWin32.h b/mozilla/xpcom/base/nsDebugHelpWin32.h new file mode 100644 index 00000000000..dfcfe56e94a --- /dev/null +++ b/mozilla/xpcom/base/nsDebugHelpWin32.h @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * John Bandhauer + */ + +/* Win32 x86 code for stack walking, symbol resolution, and function hooking */ + +#ifndef __nsDebugHelpWin32_h__ +#define __nsDebugHelpWin32_h__ + +#if defined(_WIN32) && defined(_M_IX86) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include + #include + #include +#else + #error "nsDebugHelpWin32.h should only be included in Win32 x86 builds" +#endif + +// XXX temporary hack... +//#include "hacky_defines.h" + + +/***************************************************************************/ +// useful macros... + +#define DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_) \ + typedef retval_ ( conv_ * typename_ ) args_ ; + +#ifdef DHW_IMPLEMENT_GLOBALS +#define DHW_DECLARE_FUN_GLOBAL(typename_, name_) typename_ dhw##name_ +#else +#define DHW_DECLARE_FUN_GLOBAL(typename_, name_) extern typename_ dhw##name_ +#endif + +#define DHW_DECLARE_FUN_PROTO(retval_, conv_, name_, args_) \ + retval_ conv_ name_ args_ + +#define DHW_DECLARE_FUN_STATIC_PROTO(retval_, name_, args_) \ + static retval_ conv_ name_ args_ + +#define DHW_DECLARE_FUN_TYPE_AND_PROTO(name_, retval_, conv_, typename_, args_) \ + DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \ + DHW_DECLARE_FUN_PROTO(retval_, conv_, name_, args_) + +#define DHW_DECLARE_FUN_TYPE_AND_STATIC_PROTO(name_, retval_, conv_, typename_, args_) \ + DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \ + DHW_DECLARE_FUN_STATIC_PROTO(retval_, conv_, name_, args_) + +#define DHW_DECLARE_FUN_TYPE_AND_GLOBAL(typename_, name_, retval_, conv_, args_) \ + DHW_DECLARE_FUN_TYPE(retval_, conv_, typename_, args_); \ + DHW_DECLARE_FUN_GLOBAL(typename_, name_) + + +/**********************************************************/ +// These are used to get 'original' function addresses from DHWImportHooker. + +#define DHW_DECLARE_ORIGINAL(type_, name_, hooker_) \ + type_ name_ = (type_) hooker_ . GetOriginalFunction() + +#define DHW_DECLARE_ORIGINAL_PTR(type_, name_, hooker_) \ + type_ name_ = (type_) hooker_ -> GetOriginalFunction() + +#define DHW_ORIGINAL(type_, hooker_) \ + ((type_) hooker_ . GetOriginalFunction()) + +#define DHW_ORIGINAL_PTR(type_, hooker_) \ + ((type_) hooker_ -> GetOriginalFunction()) + +/***************************************************************************/ +// Global declarations of entry points into ImgHelp functions + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMINITIALIZEPROC, SymInitialize, \ + BOOL, __stdcall, (HANDLE, LPSTR, BOOL)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMSETOPTIONS, SymSetOptions, \ + DWORD, __stdcall, (DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETOPTIONS, SymGetOptions, \ + DWORD, __stdcall, ()); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEINFO, SymGetModuleInfo, \ + BOOL, __stdcall, (HANDLE, DWORD, PIMAGEHLP_MODULE)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETSYMFROMADDRPROC, SymGetSymFromAddr, \ + BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(ENUMERATELOADEDMODULES, EnumerateLoadedModules, \ + BOOL, __stdcall, (HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(IMAGEDIRECTORYENTRYTODATA, ImageDirectoryEntryToData, \ + PVOID, __stdcall, (PVOID, BOOL, USHORT, PULONG)); + + +// We aren't using any of the below yet... + +/* +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMCLEANUPPROC, SymCleanup, \ + BOOL, __stdcall, (HANDLE)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(STACKWALKPROC, StackWalk, \ + BOOL, + __stdcall, + (DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, \ + PREAD_PROCESS_MEMORY_ROUTINE, \ + PFUNCTION_TABLE_ACCESS_ROUTINE, \ + PGET_MODULE_BASE_ROUTINE, \ + PTRANSLATE_ADDRESS_ROUTINE)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMFUNCTIONTABLEACCESSPROC, SymFunctionTableAccess, \ + LPVOID, __stdcall, (HANDLE, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEBASEPROC, SymGetModuleBase, \ + DWORD, __stdcall, (HANDLE, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMLOADMODULE, SymLoadModule, \ + DWORD, __stdcall, (HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(UNDECORATESYMBOLNAME, _UnDecorateSymbolName, \ + DWORD, __stdcall, (LPCSTR, LPSTR, DWORD, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMUNDNAME, SymUnDName, \ + BOOL, __stdcall, (PIMAGEHLP_SYMBOL, LPSTR, DWORD)); + +DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETLINEFROMADDR, SymGetLineFromAddr, \ + BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE)); + +*/ + +/***************************************************************************/ + +extern PRBool +dhwEnsureImageHlpInitialized(); + +extern PRBool +dhwEnsureSymInitialized(); + +/***************************************************************************/ + +DHW_DECLARE_FUN_TYPE(FARPROC, __stdcall, GETPROCADDRESS, (HMODULE, PCSTR)); + +class DHWImportHooker +{ +public: + + DHWImportHooker(const char* aModuleName, + const char* aFunctionName, + PROC aHook, + PRBool aExcludeOurModule = PR_FALSE); + + ~DHWImportHooker(); + + PROC GetOriginalFunction() {return mOriginal;} + + PRBool PatchAllModules(); + PRBool PatchOneModule(HMODULE aModule, const char* name); + static PRBool ModuleLoaded(HMODULE aModule, DWORD flags); + + + // I think that these should be made not static members, but allocated + // things created in an explicit static 'init' method and cleaned up in + // an explicit static 'finish' method. This would allow the application + // to have proper lifetime control over all the hooks. + + static DHWImportHooker &getLoadLibraryWHooker(); + static DHWImportHooker &getLoadLibraryExWHooker(); + static DHWImportHooker &getLoadLibraryAHooker(); + static DHWImportHooker &getLoadLibraryExAHooker(); + static DHWImportHooker &getGetProcAddressHooker(); + + static HMODULE WINAPI LoadLibraryA(PCSTR path); + +private: + DHWImportHooker* mNext; + const char* mModuleName; + const char* mFunctionName; + PROC mOriginal; + PROC mHook; + HMODULE mIgnoreModule; + PRBool mHooking; + +private: + static PRLock* gLock; + static DHWImportHooker* gHooks; + static GETPROCADDRESS gRealGetProcAddress; + + static HMODULE WINAPI LoadLibraryW(PCWSTR path); + static HMODULE WINAPI LoadLibraryExW(PCWSTR path, HANDLE file, DWORD flags); + static HMODULE WINAPI LoadLibraryExA(PCSTR path, HANDLE file, DWORD flags); + + static FARPROC WINAPI GetProcAddress(HMODULE aModule, PCSTR aFunctionName); +}; + +/***************************************************************************/ +// This supports the _CrtSetAllocHook based hooking. +// This system sucks because you don't get to see the allocated pointer. I +// don't think it appropriate for nsTraceMalloc, but is useful as a means to make +// malloc fail for testing purposes. +#if 0 //comment out this stuff. not necessary + +class DHWAllocationSizeDebugHook +{ +public: + virtual PRBool AllocHook(size_t size) = 0; + virtual PRBool ReallocHook(size_t size, size_t sizeOld) = 0; + virtual PRBool FreeHook(size_t size) = 0; +}; + +extern PRBool dhwSetAllocationSizeDebugHook(DHWAllocationSizeDebugHook* hook); +extern PRBool dhwClearAllocationSizeDebugHook(); + +/***************************************************************************/ +#endif //0 + +#endif /* __nsDebugHelpWin32_h__ */ diff --git a/mozilla/xpcom/base/nsStackFrameWin.h b/mozilla/xpcom/base/nsStackFrameWin.h new file mode 100644 index 00000000000..45961fa83a4 --- /dev/null +++ b/mozilla/xpcom/base/nsStackFrameWin.h @@ -0,0 +1,94 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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 oqr + * 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 Netscape are + * Copyright (C) 2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Michael Judge, 20-December-2000 + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + */ +#ifndef nsStackFrameWin_h___ +#define nsStackFrameWin_h___ + + +#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#include +#include + +// 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 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; + +PRBool EnsureSymInitialized(); + +PR_END_EXTERN_C + +#endif //WIN32 + +#endif //nsStackFrameWin_h___ + + diff --git a/mozilla/xpcom/base/nsTraceMallocCallbacks.h b/mozilla/xpcom/base/nsTraceMallocCallbacks.h new file mode 100644 index 00000000000..fc183bcdc88 --- /dev/null +++ b/mozilla/xpcom/base/nsTraceMallocCallbacks.h @@ -0,0 +1,20 @@ +#ifndef NSTRACEMALLOCCALLBACKS_H +#define NSTRACEMALLOCCALLBACKS_H + +PR_BEGIN_EXTERN_C + + +PR_EXTERN(void) StartupHooker();/*implemented in TraceMalloc.cpp*/ +PR_EXTERN(void) ShutdownHooker(); + +PR_EXTERN(void) MallocCallback(void *aPtr, size_t aSize);/*implemented in nsTraceMalloc.c*/ +PR_EXTERN(void) CallocCallback(void *aPtr, size_t aCount, size_t aSize); +PR_EXTERN(void) ReallocCallback(void *aPin, void* aPout, size_t aSize); +PR_EXTERN(void) FreeCallback(void *aPtr); + + +PR_END_EXTERN_C + + +#endif //NSTRACEMALLOCCALLBACKS_H +