зеркало из https://github.com/mozilla/pjs.git
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.
This commit is contained in:
Родитель
e09e5e0cf7
Коммит
927c29d1d6
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
// Define these as static pointers so that we can load the DLL on the
|
||||
// fly (and not introduce a link-time dependency on it). Tip o' the
|
||||
// hat to Matt Pietrick for this idea. See:
|
||||
//
|
||||
// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm
|
||||
//
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
typedef DWORD (__stdcall *SYMSETOPTIONSPROC)(DWORD);
|
||||
extern SYMSETOPTIONSPROC _SymSetOptions;
|
||||
|
||||
typedef BOOL (__stdcall *SYMINITIALIZEPROC)(HANDLE, LPSTR, BOOL);
|
||||
extern SYMINITIALIZEPROC _SymInitialize;
|
||||
|
||||
typedef BOOL (__stdcall *SYMCLEANUPPROC)(HANDLE);
|
||||
extern SYMCLEANUPPROC _SymCleanup;
|
||||
|
||||
typedef BOOL (__stdcall *STACKWALKPROC)(DWORD,
|
||||
HANDLE,
|
||||
HANDLE,
|
||||
LPSTACKFRAME,
|
||||
LPVOID,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE,
|
||||
PGET_MODULE_BASE_ROUTINE,
|
||||
PTRANSLATE_ADDRESS_ROUTINE);
|
||||
extern STACKWALKPROC _StackWalk;
|
||||
|
||||
typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)(HANDLE, DWORD);
|
||||
extern SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess;
|
||||
|
||||
typedef DWORD (__stdcall *SYMGETMODULEBASEPROC)(HANDLE, DWORD);
|
||||
extern SYMGETMODULEBASEPROC _SymGetModuleBase;
|
||||
|
||||
typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL);
|
||||
extern SYMGETSYMFROMADDRPROC _SymGetSymFromAddr;
|
||||
|
||||
typedef DWORD ( __stdcall *SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD);
|
||||
extern SYMLOADMODULE _SymLoadModule;
|
||||
|
||||
typedef DWORD ( __stdcall *SYMUNDNAME)(PIMAGEHLP_SYMBOL, PSTR, DWORD);
|
||||
extern SYMUNDNAME _SymUnDName;
|
||||
|
||||
typedef DWORD ( __stdcall *SYMGETMODULEINFO)( HANDLE, DWORD, PIMAGEHLP_MODULE);
|
||||
extern SYMGETMODULEINFO _SymGetModuleInfo;
|
||||
|
||||
typedef BOOL ( __stdcall *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID);
|
||||
extern ENUMLOADEDMODULES _EnumerateLoadedModules;
|
||||
|
||||
typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);
|
||||
extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
|
||||
|
||||
PRBool EnsureSymInitialized();
|
||||
|
||||
PRBool EnsureImageHlpInitialized();
|
||||
|
||||
/*
|
||||
* SymGetModuleInfoEspecial
|
||||
*
|
||||
* Attempt to determine the module information.
|
||||
* Bug 112196 says this DLL may not have been loaded at the time
|
||||
* SymInitialize was called, and thus the module information
|
||||
* and symbol information is not available.
|
||||
* This code rectifies that problem.
|
||||
* Line information is optional.
|
||||
*/
|
||||
BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo);
|
||||
|
||||
|
||||
void DumpStackToFile(FILE* out);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif //WIN32
|
||||
|
||||
#endif //nsStackFrameWin_h___
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 += \
|
||||
|
|
|
@ -41,6 +41,10 @@ REQUIRES = xpcom \
|
|||
util \
|
||||
$(NULL)
|
||||
|
||||
ifdef NS_TRACE_MALLOC
|
||||
REQUIRES += tracemalloc
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsGtkMain.cpp \
|
||||
nsGtkMenu.cpp \
|
||||
|
|
|
@ -41,6 +41,10 @@ REQUIRES = xpcom \
|
|||
util \
|
||||
$(NULL)
|
||||
|
||||
ifdef NS_TRACE_MALLOC
|
||||
REQUIRES += tracemalloc
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsGtkMain.cpp \
|
||||
nsGtkMenu.cpp \
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 <jband@netscape.com>
|
||||
*
|
||||
* 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 <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include <crtdbg.h>
|
||||
#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__ */
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "nscore.h"
|
||||
|
||||
#if defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code
|
||||
|
||||
#include <setjmp.h>
|
||||
//
|
||||
// On glibc 2.1, the Dl_info api defined in <dlfcn.h> 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 <dlfcn.h>
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
#include <dlfcn.h>
|
||||
#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 <stdlib.h> // 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 <synch.h>
|
||||
#include <ucontext.h>
|
||||
#include <sys/frame.h>
|
||||
#include <sys/regset.h>
|
||||
#include <sys/stack.h>
|
||||
|
||||
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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code
|
||||
#include "nspr.h"
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -852,599 +852,23 @@ static void InitTraceLog(void)
|
|||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code
|
||||
#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
|
||||
|
||||
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 <synch.h>
|
||||
#include <ucontext.h>
|
||||
#include <sys/frame.h>
|
||||
#include <sys/regset.h>
|
||||
#include <sys/stack.h>
|
||||
|
||||
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)
|
||||
|
||||
/**
|
||||
|
|
|
@ -852,599 +852,23 @@ static void InitTraceLog(void)
|
|||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code
|
||||
#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
|
||||
|
||||
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 <synch.h>
|
||||
#include <ucontext.h>
|
||||
#include <sys/frame.h>
|
||||
#include <sys/regset.h>
|
||||
#include <sys/stack.h>
|
||||
|
||||
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)
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<nsISupports> 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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче