From 927c29d1d6192d987e96cc14a80d3a923c1186ba Mon Sep 17 00:00:00 2001 From: "dougt%netscape.com" Date: Wed, 15 Jan 2003 20:40:06 +0000 Subject: [PATCH] move nsTraceMalloc out of XPCOM. Factory out stackwalking code into new files. 189221 r=chak, 186585 r=blythe sr=dbaron. Most of this patch was contributed by seawood. --- Makefile.in | 8 +- allmakefiles.sh | 2 +- dom/src/base/Makefile.in | 7 +- dom/src/build/Makefile.in | 5 + embedding/browser/gtk/tests/Makefile.in | 9 + embedding/tests/mfcembed/Makefile.in | 8 + js/src/Makefile.in | 4 - tools/trace-malloc/Makefile.in | 4 + tools/trace-malloc/lib/Makefile.in | 59 ++ tools/trace-malloc/lib/nsDebugHelpWin32.cpp | 139 +---- tools/trace-malloc/lib/nsDebugHelpWin32.h | 8 +- tools/trace-malloc/lib/nsStackFrameWin.cpp | 346 +++++++++++ tools/trace-malloc/lib/nsStackFrameWin.h | 121 ++++ tools/trace-malloc/lib/nsWinTraceMalloc.cpp | 21 +- webshell/tests/viewer/Makefile.in | 18 +- webshell/tests/viewer/unix/gtk/Makefile.in | 4 + webshell/tests/viewer/unix/gtk2/Makefile.in | 4 + widget/src/gtk/Makefile.in | 12 +- xpcom/base/Makefile.in | 14 +- xpcom/base/nsDebugHelpWin32.h | 250 -------- xpcom/base/nsStackFrameUnix.cpp | 372 +++++++++++ xpcom/base/nsStackFrameUnix.h | 41 ++ xpcom/base/nsStackFrameWin.cpp | 346 +++++++++++ xpcom/base/nsStackFrameWin.h | 6 + xpcom/base/nsTraceRefcnt.cpp | 588 +----------------- xpcom/base/nsTraceRefcntImpl.cpp | 588 +----------------- xpcom/build/dlldeps.cpp | 15 - .../standalone/nsGREDirServiceProvider.cpp | 10 +- xpfe/bootstrap/Makefile.in | 14 +- 29 files changed, 1423 insertions(+), 1600 deletions(-) create mode 100644 tools/trace-malloc/lib/Makefile.in create mode 100644 tools/trace-malloc/lib/nsStackFrameWin.cpp create mode 100644 tools/trace-malloc/lib/nsStackFrameWin.h create mode 100644 xpcom/base/nsStackFrameUnix.cpp create mode 100644 xpcom/base/nsStackFrameUnix.h create mode 100644 xpcom/base/nsStackFrameWin.cpp diff --git a/Makefile.in b/Makefile.in index 3b5e67f5d7c..c1b51b6e391 100644 --- a/Makefile.in +++ b/Makefile.in @@ -130,6 +130,10 @@ tier_2_dirs += \ xpcom \ $(NULL) +ifdef NS_TRACE_MALLOC +tier_2_dirs += tools/trace-malloc/lib tools/trace-malloc +endif + # # tier 9 - core components (necko,gecko) # @@ -208,10 +212,6 @@ ifdef MOZ_LEAKY tier_9_dirs += tools/leaky endif -ifdef NS_TRACE_MALLOC -tier_9_dirs += tools/trace-malloc -endif - ifdef MOZ_MAPINFO tier_9_dirs += tools/codesighs endif diff --git a/allmakefiles.sh b/allmakefiles.sh index 2e3edaf5237..5491888bc9c 100755 --- a/allmakefiles.sh +++ b/allmakefiles.sh @@ -996,7 +996,7 @@ fi # tools/trace-malloc if [ "$NS_TRACE_MALLOC" ]; then - MAKEFILES_tracemalloc="tools/trace-malloc/Makefile" + MAKEFILES_tracemalloc="tools/trace-malloc/Makefile tools/trace-malloc/lib/Makefile" fi # tools/codesighs diff --git a/dom/src/base/Makefile.in b/dom/src/base/Makefile.in index 780b103e935..4b78d021927 100644 --- a/dom/src/base/Makefile.in +++ b/dom/src/base/Makefile.in @@ -60,6 +60,10 @@ REQUIRES = xpcom \ intl \ $(NULL) +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif + CPPSRCS = \ nsBarProps.cpp \ nsDOMException.cpp \ @@ -84,7 +88,4 @@ include $(topsrcdir)/config/rules.mk CXXFLAGS += -I$(srcdir) -I$(srcdir)/../build -ifdef NS_TRACE_MALLOC -DEFINES += -DNS_TRACE_MALLOC -endif diff --git a/dom/src/build/Makefile.in b/dom/src/build/Makefile.in index 7adbdeef798..e5fd76f92aa 100644 --- a/dom/src/build/Makefile.in +++ b/dom/src/build/Makefile.in @@ -52,6 +52,10 @@ ifeq ($(OS_ARCH),WINNT) EXTRA_DSO_LIBS = gkgfx endif +ifdef NS_TRACE_MALLOC +EXTRA_DSO_LIBS += tracemalloc +endif + CPPSRCS = \ nsDOMFactory.cpp \ nsScriptNameSpaceManager.cpp \ @@ -63,6 +67,7 @@ SHARED_LIBRARY_LIBS = \ $(NULL) EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ $(EXTRA_DSO_LIBS) \ $(MOZ_COMPONENT_LIBS) \ $(MOZ_JS_LIBS) \ diff --git a/embedding/browser/gtk/tests/Makefile.in b/embedding/browser/gtk/tests/Makefile.in index d1ce874fadf..84072e0b75a 100644 --- a/embedding/browser/gtk/tests/Makefile.in +++ b/embedding/browser/gtk/tests/Makefile.in @@ -31,6 +31,10 @@ REQUIRES = xpcom \ dom \ $(NULL) +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif + CPPSRCS = \ TestGtkEmbed.cpp \ TestGtkEmbedNotebook.cpp \ @@ -77,6 +81,11 @@ EXTRA_LIBS += $(EXTRA_DSO_LIBS) $(STATIC_EXTRA_LIBS) endif +ifdef NS_TRACE_MALLOC +EXTRA_LIBS += -ltracemalloc +endif + + EXTRA_LIBS += $(MOZ_JS_LIBS) EXTRA_LIBS += $(MOZ_COMPONENT_LIBS) diff --git a/embedding/tests/mfcembed/Makefile.in b/embedding/tests/mfcembed/Makefile.in index 2fcb1d7ec10..280237e86ff 100644 --- a/embedding/tests/mfcembed/Makefile.in +++ b/embedding/tests/mfcembed/Makefile.in @@ -63,6 +63,10 @@ REQUIRES = \ webbrwsr \ $(NULL) +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif + CPPSRCS = \ CCustomPromptDialog.cpp \ CMarginHeaderFooter.cpp \ @@ -87,6 +91,10 @@ CPPSRCS = \ EXTRA_DSO_LIBS = embed_base_s gkgfx mfcEmbedComponents +ifdef NS_TRACE_MALLOC +EXTRA_DSO_LIBS += tracemalloc +endif + LIBS = \ $(EXTRA_DSO_LIBS) \ $(XPCOM_LIBS) \ diff --git a/js/src/Makefile.in b/js/src/Makefile.in index df30c3806da..0126a78b288 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -55,10 +55,6 @@ endif # and then the static data cells used for locking no longer work. FORCE_SHARED_LIB = 1 -ifdef NS_TRACE_MALLOC -REQUIRES = xpcom -endif - CSRCS = \ jsapi.c \ jsarena.c \ diff --git a/tools/trace-malloc/Makefile.in b/tools/trace-malloc/Makefile.in index 64bbb699621..0a85d33ca79 100644 --- a/tools/trace-malloc/Makefile.in +++ b/tools/trace-malloc/Makefile.in @@ -27,6 +27,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk REQUIRES = xpcom \ + tracemalloc \ $(NULL) SIMPLECSRCS += \ @@ -51,9 +52,12 @@ endif include $(topsrcdir)/config/config.mk +EXTRA_DSO_LIBS = tracemalloc + LIBS += \ $(LIBS_DIR) \ tmreader.$(OBJ_SUFFIX) \ + $(EXTRA_DSO_LIBS) \ $(XPCOM_LIBS) \ $(NSPR_LIBS) \ $(NULL) diff --git a/tools/trace-malloc/lib/Makefile.in b/tools/trace-malloc/lib/Makefile.in new file mode 100644 index 00000000000..b38c53755ef --- /dev/null +++ b/tools/trace-malloc/lib/Makefile.in @@ -0,0 +1,59 @@ +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 2003 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = tracemalloc +LIBRARY_NAME = tracemalloc +EXPORT_LIBRARY = 1 +DEFFILE = $(srcdir)/tm.def + +REQUIRES = xpcom + +CSRCS = \ + nsTraceMalloc.c \ + $(NULL) + +CPPSRCS = \ + nsTypeInfo.cpp \ + $(NULL) + +EXPORTS = nsTraceMalloc.h + +EXTRA_DSO_LDOPTS = $(NSPR_LIBS) + +ifdef MOZ_DEMANGLE_SYMBOLS +EXTRA_DSO_LDOPTS += -liberty +endif + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += nsDebugHelpWin32.cpp nsWinTraceMalloc.cpp nsStackFrameWin.cpp +EXTRA_DSO_LDOPTS += $(XPCOM_LIBS) +OS_LIBS += shell32.lib ole32.lib uuid.lib imagehlp.lib +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/tools/trace-malloc/lib/nsDebugHelpWin32.cpp b/tools/trace-malloc/lib/nsDebugHelpWin32.cpp index 4de14637b71..31456c27675 100644 --- a/tools/trace-malloc/lib/nsDebugHelpWin32.cpp +++ b/tools/trace-malloc/lib/nsDebugHelpWin32.cpp @@ -36,7 +36,6 @@ * * ***** END LICENSE BLOCK ***** */ -/* 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 @@ -48,19 +47,23 @@ #include "plstr.h" #include "prlock.h" #include "nscore.h" -#include "nsAutoLock.h" #include "nsDebugHelpWin32.h" +#include "nsStackFrameWin.h" #else #error "nsDebugHelpWin32.cpp should only be built in Win32 x86 builds" #endif +/***************************************************************************/ +PRLock* DHWImportHooker::gLock = nsnull; +DHWImportHooker* DHWImportHooker::gHooks = nsnull; +GETPROCADDRESS DHWImportHooker::gRealGetProcAddress = nsnull; -PRBool +static PRBool dhwEnsureImageHlpInitialized() { static PRBool gInitialized = PR_FALSE; @@ -82,24 +85,9 @@ dhwEnsureImageHlpInitialized() 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; @@ -108,33 +96,6 @@ dhwEnsureImageHlpInitialized() return gInitialized; } -PRBool -dhwEnsureSymInitialized() -{ - static PRBool gInitialized = PR_FALSE; - - if (! gInitialized) { - if (! dhwEnsureImageHlpInitialized()) - return PR_FALSE; - dhwSymSetOptions( -#if defined(NS_TRACE_MALLOC) - SYMOPT_LOAD_LINES | -#endif - 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() @@ -201,9 +162,10 @@ DHWImportHooker::DHWImportHooker(const char* aModuleName, if(!gLock) gLock = PR_NewLock(); - nsAutoLock lock(gLock); + PR_Lock(gLock); - dhwEnsureImageHlpInitialized(); + EnsureImageHlpInitialized(); + dhwEnsureImageHlpInitialized(); // for the extra ones we care about. if(!gRealGetProcAddress) gRealGetProcAddress = ::GetProcAddress; @@ -215,11 +177,13 @@ DHWImportHooker::DHWImportHooker(const char* aModuleName, gHooks = this; PatchAllModules(); + + PR_Unlock(gLock); } DHWImportHooker::~DHWImportHooker() { - nsAutoLock lock(gLock); + PR_Lock(gLock); mHooking = PR_FALSE; PatchAllModules(); @@ -236,16 +200,18 @@ DHWImportHooker::~DHWImportHooker() break; } } - NS_ASSERTION(cur, "we were not in the list!"); + PR_ASSERT(cur); //we were not in the list! } if(!gHooks) { PRLock* theLock = gLock; gLock = nsnull; - lock.unlock(); + PR_Unlock(theLock); PR_DestroyLock(theLock); } + if (gLock) + PR_Unlock(gLock); } static BOOL CALLBACK ModuleEnumCallback(LPSTR ModuleName, @@ -351,11 +317,12 @@ DHWImportHooker::ModuleLoaded(HMODULE aModule, DWORD flags) //printf("ModuleLoaded\n"); if(aModule && !(flags & LOAD_LIBRARY_AS_DATAFILE)) { - nsAutoLock lock(gLock); + PR_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(); + PR_Unlock(gLock); } return PR_TRUE; } @@ -413,7 +380,7 @@ DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName) if(pfn) { - nsAutoLock lock(gLock); + PR_Lock(gLock); for(DHWImportHooker* cur = gHooks; cur; cur = cur->mNext) { if(pfn == cur->mOriginal) @@ -422,75 +389,9 @@ DHWImportHooker::GetProcAddress(HMODULE aModule, PCSTR aFunctionName) break; } } + PR_Unlock(gLock); } 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/tools/trace-malloc/lib/nsDebugHelpWin32.h b/tools/trace-malloc/lib/nsDebugHelpWin32.h index 5cb7d512496..e272407aa10 100644 --- a/tools/trace-malloc/lib/nsDebugHelpWin32.h +++ b/tools/trace-malloc/lib/nsDebugHelpWin32.h @@ -104,7 +104,7 @@ /***************************************************************************/ // Global declarations of entry points into ImgHelp functions - +#if 0 DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMINITIALIZEPROC, SymInitialize, \ BOOL, __stdcall, (HANDLE, LPSTR, BOOL)); @@ -120,13 +120,14 @@ DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETMODULEINFO, SymGetModuleInfo, \ DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETSYMFROMADDRPROC, SymGetSymFromAddr, \ BOOL, __stdcall, (HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL)); +#endif + 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... /* @@ -167,9 +168,6 @@ DHW_DECLARE_FUN_TYPE_AND_GLOBAL(SYMGETLINEFROMADDR, SymGetLineFromAddr, \ extern PRBool dhwEnsureImageHlpInitialized(); -extern PRBool -dhwEnsureSymInitialized(); - /***************************************************************************/ DHW_DECLARE_FUN_TYPE(FARPROC, __stdcall, GETPROCADDRESS, (HMODULE, PCSTR)); diff --git a/tools/trace-malloc/lib/nsStackFrameWin.cpp b/tools/trace-malloc/lib/nsStackFrameWin.cpp new file mode 100644 index 00000000000..dfa33365e78 --- /dev/null +++ b/tools/trace-malloc/lib/nsStackFrameWin.cpp @@ -0,0 +1,346 @@ +/* -*- 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 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 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. + */ + +#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); + } + } +} + diff --git a/tools/trace-malloc/lib/nsStackFrameWin.h b/tools/trace-malloc/lib/nsStackFrameWin.h new file mode 100644 index 00000000000..6d197310bb3 --- /dev/null +++ b/tools/trace-malloc/lib/nsStackFrameWin.h @@ -0,0 +1,121 @@ +/* -*- 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 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 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 "nspr.h" +#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 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___ + + diff --git a/tools/trace-malloc/lib/nsWinTraceMalloc.cpp b/tools/trace-malloc/lib/nsWinTraceMalloc.cpp index e5d24bc3d1a..b27b4da357d 100644 --- a/tools/trace-malloc/lib/nsWinTraceMalloc.cpp +++ b/tools/trace-malloc/lib/nsWinTraceMalloc.cpp @@ -7,6 +7,7 @@ #include "nscore.h" #include "nsAutoLock.h" +#include "nsStackFrameWin.h" #include "nsDebugHelpWin32.h" #include "nsTraceMallocCallbacks.h" @@ -15,7 +16,7 @@ static PRBool GetSymbolFromAddress(uint32 addr, char* outBuf) { PRBool ok; - ok = dhwEnsureSymInitialized(); + ok = EnsureSymInitialized(); if(!ok) return ok; @@ -26,10 +27,10 @@ static PRBool GetSymbolFromAddress(uint32 addr, char* outBuf) DWORD displacement; - ok = dhwSymGetSymFromAddr(::GetCurrentProcess(), - addr, - &displacement, - symbol); + ok = SymGetSymFromAddr(::GetCurrentProcess(), + addr, + &displacement, + symbol); if(ok) { @@ -45,7 +46,7 @@ static PRBool GetSymbolFromAddress(uint32 addr, char* outBuf) static PRBool GetModuleFromAddress(uint32 addr, char* outBuf) { PRBool ok; - ok = dhwEnsureSymInitialized(); + ok = EnsureSymInitialized(); if(!ok) return ok; @@ -53,9 +54,9 @@ static PRBool GetModuleFromAddress(uint32 addr, char* outBuf) IMAGEHLP_MODULE module; module.SizeOfStruct = sizeof(IMAGEHLP_MODULE); - ok = dhwSymGetModuleInfo(::GetCurrentProcess(), - addr, - &module); + ok = SymGetModuleInfo(::GetCurrentProcess(), + addr, + &module); if(ok) strcat(outBuf, module.ModuleName); @@ -368,7 +369,7 @@ private: PR_IMPLEMENT(void) StartupHooker() { - if (!dhwEnsureSymInitialized()) + if (!EnsureSymInitialized()) return; //run through get all hookers diff --git a/webshell/tests/viewer/Makefile.in b/webshell/tests/viewer/Makefile.in index aeed188fb78..cc50dbfd291 100644 --- a/webshell/tests/viewer/Makefile.in +++ b/webshell/tests/viewer/Makefile.in @@ -104,30 +104,32 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk) GTK_GLUE = -lgtksuperwin endif -XP_DIST_LIBS = \ - -lgkgfx \ - $(NULL) +EXTRA_DSO_LIBS = gkgfx + +ifdef NS_TRACE_MALLOC +EXTRA_DSO_LIBS += tracemalloc +endif ifeq ($(OS_ARCH),WINNT) RESFILE = viewer.res -XP_DIST_LIBS += -lxpwidgets_s -ldbgrobot -lwidget_windows +EXTRA_DSO_LIBS += xpwidgets_s dbgrobot widget_windows endif ifeq ($(OS_ARCH),OS2) RESFILE = vieweros2.res DEFINES += -DUSE_LOCAL_WIDGETS -XP_DIST_LIBS += $(DIST)/lib/components/wdgtos2.lib +EXTRA_DSO_LIBS += $(DIST)/lib/components/wdgtos2.lib endif ifdef MOZ_OJI ifeq ($(OS_ARCH),WINNT) -XP_DIST_LIBS += -ljsj$(MOZ_BITS)$(VERSION_NUMBER) +EXTRA_DSO_LIBS += jsj$(MOZ_BITS)$(VERSION_NUMBER) else -XP_DIST_LIBS += -ljsj +EXTRA_DSO_LIBS += jsj endif endif ifdef MOZ_PERF_METRICS -XP_DIST_LIBS += -lmozutil_s +EXTRA_DSO_LIBS += mozutil_s endif XP_DIST_LIBS += \ diff --git a/webshell/tests/viewer/unix/gtk/Makefile.in b/webshell/tests/viewer/unix/gtk/Makefile.in index 441501312de..5ef7bfe4265 100644 --- a/webshell/tests/viewer/unix/gtk/Makefile.in +++ b/webshell/tests/viewer/unix/gtk/Makefile.in @@ -41,6 +41,10 @@ REQUIRES = xpcom \ util \ $(NULL) +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif + CPPSRCS = \ nsGtkMain.cpp \ nsGtkMenu.cpp \ diff --git a/webshell/tests/viewer/unix/gtk2/Makefile.in b/webshell/tests/viewer/unix/gtk2/Makefile.in index 2e6fe7e3ef1..cd52716ade6 100644 --- a/webshell/tests/viewer/unix/gtk2/Makefile.in +++ b/webshell/tests/viewer/unix/gtk2/Makefile.in @@ -41,6 +41,10 @@ REQUIRES = xpcom \ util \ $(NULL) +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif + CPPSRCS = \ nsGtkMain.cpp \ nsGtkMenu.cpp \ diff --git a/widget/src/gtk/Makefile.in b/widget/src/gtk/Makefile.in index c4e9b0257e8..54ca063e6fe 100644 --- a/widget/src/gtk/Makefile.in +++ b/widget/src/gtk/Makefile.in @@ -42,6 +42,9 @@ REQUIRES = xpcom \ util \ unicharutil \ $(NULL) +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif CSRCS = \ keysym2ucs.c @@ -72,9 +75,16 @@ CPPSRCS = \ SHARED_LIBRARY_LIBS = $(DIST)/lib/libxpwidgets_s.a +EXTRA_DSO_LIBS = gkgfx + +ifdef NS_TRACE_MALLOC +EXTRA_DSO_LIBS += tracemalloc +endif + EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(EXTRA_DSO_LIBS) \ $(MOZ_COMPONENT_LIBS) \ - -lgkgfx \ $(MOZ_JS_LIBS) \ $(NULL) diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index 15e397a3481..f3b0f0e91b4 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -64,23 +64,17 @@ EXPORTS = \ nsWeakPtr.h \ $(NULL) -ifdef NS_TRACE_MALLOC -CSRCS += nsTraceMalloc.c -CPPSRCS += nsTypeInfo.cpp -ifeq ($(OS_ARCH),WINNT) -CPPSRCS += nsDebugHelpWin32.cpp nsWinTraceMalloc.cpp -endif -EXPORTS += nsTraceMalloc.h -DEFINES += -DNS_TRACE_MALLOC -endif - ifeq ($(OS_ARCH),WINNT) ifdef MOZ_DEBUG CSRCS += pure_api.c EXPORTS += pure.h endif +CPPSRCS += nsStackFrameWin.cpp endif +ifneq ($(OS_ARCH),WINNT) +CPPSRCS += nsStackFrameUnix.cpp +endif SDK_XPIDLSRCS = \ nsIInterfaceRequestor.idl \ diff --git a/xpcom/base/nsDebugHelpWin32.h b/xpcom/base/nsDebugHelpWin32.h index 5cb7d512496..e69de29bb2d 100644 --- a/xpcom/base/nsDebugHelpWin32.h +++ b/xpcom/base/nsDebugHelpWin32.h @@ -1,250 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * 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 the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * John Bandhauer - * - * 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 NPL, 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 NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* 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/xpcom/base/nsStackFrameUnix.cpp b/xpcom/base/nsStackFrameUnix.cpp new file mode 100644 index 00000000000..87bce457db0 --- /dev/null +++ b/xpcom/base/nsStackFrameUnix.cpp @@ -0,0 +1,372 @@ +/* -*- 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 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 Netscape are + * Copyright (C) 2003 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * 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. + */ + +#include "nsStackFrameUnix.h" +#include +#include +#include +#include "nscore.h" + +#if defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code + +#include +// +// On glibc 2.1, the Dl_info api defined in is only exposed +// if __USE_GNU is defined. I suppose its some kind of standards +// adherence thing. +// +#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU) +#define __USE_GNU +#endif + +#include + +#ifdef HAVE_LIBDL +#include +#endif + +// This thing is exported by libiberty.a (-liberty) +// Yes, this is a gcc only hack +#if defined(MOZ_DEMANGLE_SYMBOLS) +extern "C" char * cplus_demangle(const char *,int); +#include // for free() +#endif // MOZ_DEMANGLE_SYMBOLS + +void DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen) +{ + aBuffer[0] = '\0'; + +#if defined(MOZ_DEMANGLE_SYMBOLS) + /* See demangle.h in the gcc source for the voodoo */ + char * demangled = cplus_demangle(aSymbol,3); + + if (demangled) + { + strncpy(aBuffer,demangled,aBufLen); + free(demangled); + } +#endif // MOZ_DEMANGLE_SYMBOLS +} + +void DumpStackToFile(FILE* aStream) +{ + jmp_buf jb; + setjmp(jb); + + // Stack walking code courtesy Kipp's "leaky". + + // Get the frame pointer out of the jmp_buf +#if defined(__i386) + unsigned long* bp = (unsigned long*) (jb[0].__jmpbuf[JB_BP]); +#elif defined(PPC) + unsigned long* bp = (unsigned long*) (jb[0].__jmpbuf[JB_GPR1]); +#endif + + int skip = 2; + for (unsigned long *nextbp = (unsigned long*) *bp++, pc = *bp; + pc >= 0x08000000 && pc < 0x7fffffff && nextbp > bp; + bp = nextbp, nextbp = (unsigned long*) *bp++, pc = *bp) { + if (--skip <= 0) { + Dl_info info; + int ok = dladdr((void*) pc, &info); + if (!ok) { + fprintf(aStream, "UNKNOWN %p\n", (void *)pc); + continue; + } + + PRUint32 foff = (char*)pc - (char*)info.dli_fbase; + + const char * symbol = info.dli_sname; + int len; + if (!symbol || !(len = strlen(symbol))) { + fprintf(aStream, "UNKNOWN [%s +0x%08X]\n", + info.dli_fname, foff); + continue; + } + + char demangled[4096] = "\0"; + + DemangleSymbol(symbol, demangled, sizeof(demangled)); + + if (strlen(demangled)) { + symbol = demangled; + len = strlen(symbol); + } + + PRUint32 off = (char*)pc - (char*)info.dli_saddr; + fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n", + symbol, off, info.dli_fname, foff); + } + } +} + +#elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) + +/* + * Stack walking code for Solaris courtesy of Bart Smaalder's "memtrak". + */ + +#include +#include +#include +#include +#include + +static int load_address ( void * pc, void * arg, FILE * aStream ); +static int write_address_file ( void * pc ); +static struct bucket * newbucket ( void * pc ); +static struct frame * cs_getmyframeptr ( void ); +static void cs_walk_stack ( void * (*read_func)(char * address), + struct frame * fp, + int (*operate_func)(void *, void *), + void * usrarg, FILE * aStream ); +static void cs_operate ( void (*operate_func)(void *, void *), + void * usrarg, FILE * aStream ); + +#ifndef STACK_BIAS +#define STACK_BIAS 0 +#endif /*STACK_BIAS*/ + +#define LOGSIZE 4096 + +/* type of demangling function */ +typedef int demf_t(const char *, char *, size_t); + +static demf_t *demf; + +static int initialized = 0; + +#if defined(sparc) || defined(__sparc) +#define FRAME_PTR_REGISTER REG_SP +#endif + +#if defined(i386) || defined(__i386) +#define FRAME_PTR_REGISTER EBP +#endif + +struct bucket { + void * pc; + int index; + struct bucket * next; +}; + +struct mybuf { + char * buffer; + int chars_left; +}; + + +static void myinit(); + +#pragma init (myinit) + +static void +myinit() +{ + + if (! initialized) { +#ifndef __GNUC__ + void *handle; + const char *libdem = "libdemangle.so.1"; + + /* load libdemangle if we can and need to (only try this once) */ + if ((handle = dlopen(libdem, RTLD_LAZY)) != NULL) { + demf = (demf_t *)dlsym(handle, + "cplus_demangle"); /*lint !e611 */ + /* + * lint override above is to prevent lint from + * complaining about "suspicious cast". + */ + } +#endif /*__GNUC__*/ + } + initialized = 1; +} + + +static int +write_address_file(void * pc, FILE* aStream) +{ + static struct bucket table[2048]; + static mutex_t lock; + struct bucket * ptr; + + unsigned int val = NS_PTR_TO_INT32(pc); + + ptr = table + ((val >> 2)&2047); + + mutex_lock(&lock); + while (ptr->next) { + if (ptr->next->pc == pc) + break; + ptr = ptr->next; + } + + if (ptr->next) { + mutex_unlock(&lock); + return (ptr->next->index); + } else { + char buffer[4096], dembuff[4096]; + Dl_info info; + char *func, *lib; + + ptr->next = newbucket(pc); + mutex_unlock(&lock); + + if (dladdr(pc, & info) == 0) { + func = "??"; + lib = "??"; + } else { + lib = (char *) info.dli_fname; + func = (char *) info.dli_sname; + } + +#ifdef __GNUC__ + nsTraceRefcnt::DemangleSymbol(func, dembuff, sizeof(dembuff)); + if (strlen(dembuff)) { + func = dembuff; + } +#else + if (demf) { + if (demf(func, dembuff, sizeof (dembuff)) == 0) + func = dembuff; + } +#endif /*__GNUC__*/ + + fprintf(aStream, "%u %s:%s+0x%x\n", + ptr->next->index, + lib, + func, + (char *)pc - (char*)info.dli_saddr); + + return (ptr->next->index); + } +} + + +static int +load_address(void * pc, void * arg, FILE * aStream) +{ + struct mybuf * buf = (struct mybuf *) arg; + + char name[80]; + int len; + + sprintf(name, " %u", write_address_file(pc, aStream)); + + len = strlen(name); + + if (len >= buf->chars_left) + return (1); + + strcat(buf->buffer, name); + + buf->chars_left -= len; + + return (0); +} + + +static struct bucket * +newbucket(void * pc) +{ + struct bucket * ptr = (struct bucket *) malloc(sizeof (*ptr)); + static int index; /* protected by lock in caller */ + + ptr->index = index++; + ptr->next = NULL; + ptr->pc = pc; + return (ptr); +} + + +static struct frame * +csgetframeptr() +{ + ucontext_t u; + struct frame *fp; + + (void) getcontext(&u); + + fp = (struct frame *) + ((char *)u.uc_mcontext.gregs[FRAME_PTR_REGISTER] + + STACK_BIAS); + + /* make sure to return parents frame pointer.... */ + + return ((struct frame *)((ulong_t)fp->fr_savfp + STACK_BIAS)); +} + + +static void +cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), + void *usrarg, FILE * aStream) +{ + + while (fp != 0 && fp->fr_savpc != 0) { + + if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0) + break; + /* + * watch out - libthread stacks look funny at the top + * so they may not have their STACK_BIAS set + */ + + fp = (struct frame *)((ulong_t)fp->fr_savfp + + (fp->fr_savfp?(ulong_t)STACK_BIAS:0)); + } +} + + +static void +cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream) +{ + cswalkstack(csgetframeptr(), operate_func, usrarg, aStream); +} + +void DumpStackToFile(FILE* aStream) +{ + char buffer[LOGSIZE]; + struct mybuf mybuf; + + if (!initialized) + myinit(); + + mybuf.chars_left = LOGSIZE - strlen(buffer)-1; + mybuf.buffer = buffer; + cs_operate(load_address, &mybuf, aStream); +} +#endif diff --git a/xpcom/base/nsStackFrameUnix.h b/xpcom/base/nsStackFrameUnix.h new file mode 100644 index 00000000000..268a998fe08 --- /dev/null +++ b/xpcom/base/nsStackFrameUnix.h @@ -0,0 +1,41 @@ +/* -*- 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 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 Netscape are + * Copyright (C) 2003 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * 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 nsStackFrameUnix_h___ +#define nsStackFrameUnix_h___ + +#include "stdio.h" + +void DumpStackToFile(FILE* out); + +#endif diff --git a/xpcom/base/nsStackFrameWin.cpp b/xpcom/base/nsStackFrameWin.cpp new file mode 100644 index 00000000000..33028eadbac --- /dev/null +++ b/xpcom/base/nsStackFrameWin.cpp @@ -0,0 +1,346 @@ +/* -*- 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 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, 2003. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2003 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. + */ + +#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); + } + } +} + diff --git a/xpcom/base/nsStackFrameWin.h b/xpcom/base/nsStackFrameWin.h index 539866d1599..6d197310bb3 100644 --- a/xpcom/base/nsStackFrameWin.h +++ b/xpcom/base/nsStackFrameWin.h @@ -37,6 +37,7 @@ #if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#include "nspr.h" #include #include @@ -94,6 +95,8 @@ extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; PRBool EnsureSymInitialized(); +PRBool EnsureImageHlpInitialized(); + /* * SymGetModuleInfoEspecial * @@ -106,6 +109,9 @@ PRBool EnsureSymInitialized(); */ BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo); + +void DumpStackToFile(FILE* out); + PR_END_EXTERN_C #endif //WIN32 diff --git a/xpcom/base/nsTraceRefcnt.cpp b/xpcom/base/nsTraceRefcnt.cpp index 489ee3dfaa5..ebb7fe171f0 100644 --- a/xpcom/base/nsTraceRefcnt.cpp +++ b/xpcom/base/nsTraceRefcnt.cpp @@ -852,599 +852,23 @@ static void InitTraceLog(void) #endif #if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code -#include "imagehlp.h" -#include #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 - -static 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 nsTraceRefcnt::WalkTheStack(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); - } - } + DumpStackToFile(aStream); } -#elif defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code - +// WIN32 x86 stack walking code +// i386 or PPC Linux stackwalking code or Solaris +#elif (defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))) +#include "nsStackFrameUnix.h" void nsTraceRefcnt::WalkTheStack(FILE* aStream) { - jmp_buf jb; - setjmp(jb); - - // Stack walking code courtesy Kipp's "leaky". - - // Get the frame pointer out of the jmp_buf -#if defined(__i386) - u_long* bp = (u_long*) (jb[0].__jmpbuf[JB_BP]); -#elif defined(PPC) - u_long* bp = (u_long*) (jb[0].__jmpbuf[JB_GPR1]); -#endif - - int skip = 2; - for (u_long *nextbp = (u_long*) *bp++, pc = *bp; - pc >= 0x08000000 && pc < 0x7fffffff && nextbp > bp; - bp = nextbp, nextbp = (u_long*) *bp++, pc = *bp) { - if (--skip <= 0) { - Dl_info info; - int ok = dladdr((void*) pc, &info); - if (!ok) { - fprintf(aStream, "UNKNOWN %p\n", (void *)pc); - continue; - } - - PRUint32 foff = (char*)pc - (char*)info.dli_fbase; - - const char * symbol = info.dli_sname; - int len; - if (!symbol || !(len = strlen(symbol))) { - fprintf(aStream, "UNKNOWN [%s +0x%08X]\n", - info.dli_fname, foff); - continue; - } - - char demangled[4096] = "\0"; - - DemangleSymbol(symbol, demangled, sizeof(demangled)); - - if (strlen(demangled)) { - symbol = demangled; - len = strlen(symbol); - } - - PRUint32 off = (char*)pc - (char*)info.dli_saddr; - fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n", - symbol, off, info.dli_fname, foff); - } - } -} -#elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) - -/* - * Stack walking code for Solaris courtesy of Bart Smaalder's "memtrak". - */ - -#include -#include -#include -#include -#include - -static int load_address ( void * pc, void * arg, FILE * aStream ); -static int write_address_file ( void * pc ); -static struct bucket * newbucket ( void * pc ); -static struct frame * cs_getmyframeptr ( void ); -static void cs_walk_stack ( void * (*read_func)(char * address), - struct frame * fp, - int (*operate_func)(void *, void *), - void * usrarg, FILE * aStream ); -static void cs_operate ( void (*operate_func)(void *, void *), - void * usrarg, FILE * aStream ); - -#ifndef STACK_BIAS -#define STACK_BIAS 0 -#endif /*STACK_BIAS*/ - -#define LOGSIZE 4096 - -/* type of demangling function */ -typedef int demf_t(const char *, char *, size_t); - -static demf_t *demf; - -static int initialized = 0; - -#if defined(sparc) || defined(__sparc) -#define FRAME_PTR_REGISTER REG_SP -#endif - -#if defined(i386) || defined(__i386) -#define FRAME_PTR_REGISTER EBP -#endif - -struct bucket { - void * pc; - int index; - struct bucket * next; -}; - -struct mybuf { - char * buffer; - int chars_left; -}; - - -static void myinit(); - -#pragma init (myinit) - -static void -myinit() -{ - - if (! initialized) { -#ifndef __GNUC__ - void *handle; - const char *libdem = "libdemangle.so.1"; - - /* load libdemangle if we can and need to (only try this once) */ - if ((handle = dlopen(libdem, RTLD_LAZY)) != NULL) { - demf = (demf_t *)dlsym(handle, - "cplus_demangle"); /*lint !e611 */ - /* - * lint override above is to prevent lint from - * complaining about "suspicious cast". - */ - } -#endif /*__GNUC__*/ - } - initialized = 1; + DumpStackToFile(aStream); } - -static int -write_address_file(void * pc, FILE* aStream) -{ - static struct bucket table[2048]; - static mutex_t lock; - struct bucket * ptr; - - unsigned int val = NS_PTR_TO_INT32(pc); - - ptr = table + ((val >> 2)&2047); - - mutex_lock(&lock); - while (ptr->next) { - if (ptr->next->pc == pc) - break; - ptr = ptr->next; - } - - if (ptr->next) { - mutex_unlock(&lock); - return (ptr->next->index); - } else { - char buffer[4096], dembuff[4096]; - Dl_info info; - char *func, *lib; - - ptr->next = newbucket(pc); - mutex_unlock(&lock); - - if (dladdr(pc, & info) == 0) { - func = "??"; - lib = "??"; - } else { - lib = (char *) info.dli_fname; - func = (char *) info.dli_sname; - } - -#ifdef __GNUC__ - nsTraceRefcnt::DemangleSymbol(func, dembuff, sizeof(dembuff)); - if (strlen(dembuff)) { - func = dembuff; - } -#else - if (demf) { - if (demf(func, dembuff, sizeof (dembuff)) == 0) - func = dembuff; - } -#endif /*__GNUC__*/ - - fprintf(aStream, "%u %s:%s+0x%x\n", - ptr->next->index, - lib, - func, - (char *)pc - (char*)info.dli_saddr); - - return (ptr->next->index); - } -} - - -static int -load_address(void * pc, void * arg, FILE * aStream) -{ - struct mybuf * buf = (struct mybuf *) arg; - - char name[80]; - int len; - - sprintf(name, " %u", write_address_file(pc, aStream)); - - len = strlen(name); - - if (len >= buf->chars_left) - return (1); - - strcat(buf->buffer, name); - - buf->chars_left -= len; - - return (0); -} - - -static struct bucket * -newbucket(void * pc) -{ - struct bucket * ptr = (struct bucket *) malloc(sizeof (*ptr)); - static int index; /* protected by lock in caller */ - - ptr->index = index++; - ptr->next = NULL; - ptr->pc = pc; - return (ptr); -} - - -static struct frame * -csgetframeptr() -{ - ucontext_t u; - struct frame *fp; - - (void) getcontext(&u); - - fp = (struct frame *) - ((char *)u.uc_mcontext.gregs[FRAME_PTR_REGISTER] + - STACK_BIAS); - - /* make sure to return parents frame pointer.... */ - - return ((struct frame *)((ulong_t)fp->fr_savfp + STACK_BIAS)); -} - - -static void -cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), - void *usrarg, FILE * aStream) -{ - - while (fp != 0 && fp->fr_savpc != 0) { - - if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0) - break; - /* - * watch out - libthread stacks look funny at the top - * so they may not have their STACK_BIAS set - */ - - fp = (struct frame *)((ulong_t)fp->fr_savfp + - (fp->fr_savfp?(ulong_t)STACK_BIAS:0)); - } -} - - -static void -cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream) -{ - cswalkstack(csgetframeptr(), operate_func, usrarg, aStream); -} - -void -nsTraceRefcnt::WalkTheStack(FILE* aStream) -{ - char buffer[LOGSIZE]; - struct mybuf mybuf; - - if (!initialized) - myinit(); - - mybuf.chars_left = LOGSIZE - strlen(buffer)-1; - mybuf.buffer = buffer; - cs_operate(load_address, &mybuf, aStream); -} #elif defined(XP_MAC) /** diff --git a/xpcom/base/nsTraceRefcntImpl.cpp b/xpcom/base/nsTraceRefcntImpl.cpp index 489ee3dfaa5..ebb7fe171f0 100644 --- a/xpcom/base/nsTraceRefcntImpl.cpp +++ b/xpcom/base/nsTraceRefcntImpl.cpp @@ -852,599 +852,23 @@ static void InitTraceLog(void) #endif #if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code -#include "imagehlp.h" -#include #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 - -static 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 nsTraceRefcnt::WalkTheStack(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); - } - } + DumpStackToFile(aStream); } -#elif defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code - +// WIN32 x86 stack walking code +// i386 or PPC Linux stackwalking code or Solaris +#elif (defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))) +#include "nsStackFrameUnix.h" void nsTraceRefcnt::WalkTheStack(FILE* aStream) { - jmp_buf jb; - setjmp(jb); - - // Stack walking code courtesy Kipp's "leaky". - - // Get the frame pointer out of the jmp_buf -#if defined(__i386) - u_long* bp = (u_long*) (jb[0].__jmpbuf[JB_BP]); -#elif defined(PPC) - u_long* bp = (u_long*) (jb[0].__jmpbuf[JB_GPR1]); -#endif - - int skip = 2; - for (u_long *nextbp = (u_long*) *bp++, pc = *bp; - pc >= 0x08000000 && pc < 0x7fffffff && nextbp > bp; - bp = nextbp, nextbp = (u_long*) *bp++, pc = *bp) { - if (--skip <= 0) { - Dl_info info; - int ok = dladdr((void*) pc, &info); - if (!ok) { - fprintf(aStream, "UNKNOWN %p\n", (void *)pc); - continue; - } - - PRUint32 foff = (char*)pc - (char*)info.dli_fbase; - - const char * symbol = info.dli_sname; - int len; - if (!symbol || !(len = strlen(symbol))) { - fprintf(aStream, "UNKNOWN [%s +0x%08X]\n", - info.dli_fname, foff); - continue; - } - - char demangled[4096] = "\0"; - - DemangleSymbol(symbol, demangled, sizeof(demangled)); - - if (strlen(demangled)) { - symbol = demangled; - len = strlen(symbol); - } - - PRUint32 off = (char*)pc - (char*)info.dli_saddr; - fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n", - symbol, off, info.dli_fname, foff); - } - } -} -#elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) - -/* - * Stack walking code for Solaris courtesy of Bart Smaalder's "memtrak". - */ - -#include -#include -#include -#include -#include - -static int load_address ( void * pc, void * arg, FILE * aStream ); -static int write_address_file ( void * pc ); -static struct bucket * newbucket ( void * pc ); -static struct frame * cs_getmyframeptr ( void ); -static void cs_walk_stack ( void * (*read_func)(char * address), - struct frame * fp, - int (*operate_func)(void *, void *), - void * usrarg, FILE * aStream ); -static void cs_operate ( void (*operate_func)(void *, void *), - void * usrarg, FILE * aStream ); - -#ifndef STACK_BIAS -#define STACK_BIAS 0 -#endif /*STACK_BIAS*/ - -#define LOGSIZE 4096 - -/* type of demangling function */ -typedef int demf_t(const char *, char *, size_t); - -static demf_t *demf; - -static int initialized = 0; - -#if defined(sparc) || defined(__sparc) -#define FRAME_PTR_REGISTER REG_SP -#endif - -#if defined(i386) || defined(__i386) -#define FRAME_PTR_REGISTER EBP -#endif - -struct bucket { - void * pc; - int index; - struct bucket * next; -}; - -struct mybuf { - char * buffer; - int chars_left; -}; - - -static void myinit(); - -#pragma init (myinit) - -static void -myinit() -{ - - if (! initialized) { -#ifndef __GNUC__ - void *handle; - const char *libdem = "libdemangle.so.1"; - - /* load libdemangle if we can and need to (only try this once) */ - if ((handle = dlopen(libdem, RTLD_LAZY)) != NULL) { - demf = (demf_t *)dlsym(handle, - "cplus_demangle"); /*lint !e611 */ - /* - * lint override above is to prevent lint from - * complaining about "suspicious cast". - */ - } -#endif /*__GNUC__*/ - } - initialized = 1; + DumpStackToFile(aStream); } - -static int -write_address_file(void * pc, FILE* aStream) -{ - static struct bucket table[2048]; - static mutex_t lock; - struct bucket * ptr; - - unsigned int val = NS_PTR_TO_INT32(pc); - - ptr = table + ((val >> 2)&2047); - - mutex_lock(&lock); - while (ptr->next) { - if (ptr->next->pc == pc) - break; - ptr = ptr->next; - } - - if (ptr->next) { - mutex_unlock(&lock); - return (ptr->next->index); - } else { - char buffer[4096], dembuff[4096]; - Dl_info info; - char *func, *lib; - - ptr->next = newbucket(pc); - mutex_unlock(&lock); - - if (dladdr(pc, & info) == 0) { - func = "??"; - lib = "??"; - } else { - lib = (char *) info.dli_fname; - func = (char *) info.dli_sname; - } - -#ifdef __GNUC__ - nsTraceRefcnt::DemangleSymbol(func, dembuff, sizeof(dembuff)); - if (strlen(dembuff)) { - func = dembuff; - } -#else - if (demf) { - if (demf(func, dembuff, sizeof (dembuff)) == 0) - func = dembuff; - } -#endif /*__GNUC__*/ - - fprintf(aStream, "%u %s:%s+0x%x\n", - ptr->next->index, - lib, - func, - (char *)pc - (char*)info.dli_saddr); - - return (ptr->next->index); - } -} - - -static int -load_address(void * pc, void * arg, FILE * aStream) -{ - struct mybuf * buf = (struct mybuf *) arg; - - char name[80]; - int len; - - sprintf(name, " %u", write_address_file(pc, aStream)); - - len = strlen(name); - - if (len >= buf->chars_left) - return (1); - - strcat(buf->buffer, name); - - buf->chars_left -= len; - - return (0); -} - - -static struct bucket * -newbucket(void * pc) -{ - struct bucket * ptr = (struct bucket *) malloc(sizeof (*ptr)); - static int index; /* protected by lock in caller */ - - ptr->index = index++; - ptr->next = NULL; - ptr->pc = pc; - return (ptr); -} - - -static struct frame * -csgetframeptr() -{ - ucontext_t u; - struct frame *fp; - - (void) getcontext(&u); - - fp = (struct frame *) - ((char *)u.uc_mcontext.gregs[FRAME_PTR_REGISTER] + - STACK_BIAS); - - /* make sure to return parents frame pointer.... */ - - return ((struct frame *)((ulong_t)fp->fr_savfp + STACK_BIAS)); -} - - -static void -cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), - void *usrarg, FILE * aStream) -{ - - while (fp != 0 && fp->fr_savpc != 0) { - - if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0) - break; - /* - * watch out - libthread stacks look funny at the top - * so they may not have their STACK_BIAS set - */ - - fp = (struct frame *)((ulong_t)fp->fr_savfp + - (fp->fr_savfp?(ulong_t)STACK_BIAS:0)); - } -} - - -static void -cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream) -{ - cswalkstack(csgetframeptr(), operate_func, usrarg, aStream); -} - -void -nsTraceRefcnt::WalkTheStack(FILE* aStream) -{ - char buffer[LOGSIZE]; - struct mybuf mybuf; - - if (!initialized) - myinit(); - - mybuf.chars_left = LOGSIZE - strlen(buffer)-1; - mybuf.buffer = buffer; - cs_operate(load_address, &mybuf, aStream); -} #elif defined(XP_MAC) /** diff --git a/xpcom/build/dlldeps.cpp b/xpcom/build/dlldeps.cpp index 75500469a01..02919f6430a 100644 --- a/xpcom/build/dlldeps.cpp +++ b/xpcom/build/dlldeps.cpp @@ -90,9 +90,6 @@ #include "pure.h" #endif #include "pldhash.h" -#ifdef NS_TRACE_MALLOC -#include "nsTraceMalloc.h" -#endif #include "nsVariant.h" #ifdef DEBUG @@ -182,17 +179,5 @@ void XXXNeverCalled() nsCOMArray dummyArray; NS_NewArray(nsnull, dummyArray); NS_NewArrayEnumerator(nsnull, dummyArray); -#ifdef NS_TRACE_MALLOC - NS_TraceMallocStartup(0); - NS_TraceMallocStartupArgs(0, NULL); - NS_TraceMallocShutdown(); - NS_TraceMallocDisable(); - NS_TraceMallocEnable(); - NS_TraceMallocChangeLogFD(0); - NS_TraceMallocCloseLogFD(0); - NS_TraceMallocLogTimestamp(NULL); - NS_TraceMallocDumpAllocations(NULL); - NS_TraceMallocFlushLogfiles(); -#endif nsVariant(); } diff --git a/xpcom/glue/standalone/nsGREDirServiceProvider.cpp b/xpcom/glue/standalone/nsGREDirServiceProvider.cpp index a22eaf821c9..4632b559220 100644 --- a/xpcom/glue/standalone/nsGREDirServiceProvider.cpp +++ b/xpcom/glue/standalone/nsGREDirServiceProvider.cpp @@ -121,13 +121,21 @@ nsGREDirServiceProvider::GetGREDirectoryPath() { char *pGreLocation = nsnull; +#ifndef XP_UNIX // If there exists a file named ".gre.conf" in the current working directory, // then we will not use any GRE. The assumption here is that the GRE is in the // same directory as the executable. - + + // we only do this on non-unix platforms per blizzard. struct stat configStat; if (stat(".gre.config", &configStat) != -1) return nsnull; +#endif + + // if USE_LOCAL_GRE is set, we just fall back on using no gre or rather, + // the Gecko bits that sit next to the application or in the LD_LIBRARY_PATH + if (PR_GetEnv("USE_LOCAL_GRE")) + return nsnull; // check in the HOME directory char * path = PR_GetEnv("HOME"); diff --git a/xpfe/bootstrap/Makefile.in b/xpfe/bootstrap/Makefile.in index 4d2c6312154..15ca609b6fa 100644 --- a/xpfe/bootstrap/Makefile.in +++ b/xpfe/bootstrap/Makefile.in @@ -73,6 +73,10 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),windows) REQUIRES += intl profile appcomps endif +ifdef NS_TRACE_MALLOC +REQUIRES += tracemalloc +endif + include $(topsrcdir)/config/config.mk ifeq ($(USE_SHORT_LIBNAME),1) @@ -107,6 +111,10 @@ EXTRA_DSO_LIBS += jsj endif endif +ifdef NS_TRACE_MALLOC +EXTRA_DSO_LIBS += tracemalloc +endif + else include $(topsrcdir)/config/static-config.mk @@ -130,10 +138,6 @@ XP_LIBS += \ $(NSPR_LIBS) \ $(NULL) -ifdef NS_TRACE_MALLOC -DEFINES += -DNS_TRACE_MALLOC -endif - ifdef MOZ_JPROF XP_LIBS += -ljprof endif @@ -327,7 +331,7 @@ $(EXE_DEF_FILE): @echo WinQueryProperty = PMMERGE.5450 >>$(EXE_DEF_FILE) @echo WinRemoveProperty = PMMERGE.5451 >>$(EXE_DEF_FILE) @echo WinSetProperty = PMMERGE.5452 >>$(EXE_DEF_FILE) - + LDFLAGS += /NOE endif endif