Convert trace-malloc to using XPCOM stack walking API. b=374829 r+a=brendan

This commit is contained in:
dbaron%dbaron.org 2007-08-10 22:20:49 +00:00
Родитель 8276ca56e2
Коммит d834a42cdd
9 изменённых файлов: 194 добавлений и 980 удалений

Просмотреть файл

@ -55,17 +55,15 @@ CSRCS = \
$(NULL) $(NULL)
CPPSRCS = \ CPPSRCS = \
nsDemangle.cpp \
nsTypeInfo.cpp \ nsTypeInfo.cpp \
$(NULL) $(NULL)
EXPORTS = nsTraceMalloc.h EXPORTS = nsTraceMalloc.h
EXTRA_DSO_LDOPTS = $(NSPR_LIBS) EXTRA_DSO_LDOPTS = $(NSPR_LIBS) $(XPCOM_LIBS)
ifeq ($(OS_ARCH),WINNT) ifeq ($(OS_ARCH),WINNT)
CPPSRCS += nsDebugHelpWin32.cpp nsWinTraceMalloc.cpp nsStackFrameWin.cpp CPPSRCS += nsDebugHelpWin32.cpp nsWinTraceMalloc.cpp
EXTRA_DSO_LDOPTS += $(XPCOM_LIBS)
OS_LIBS += shell32.lib ole32.lib uuid.lib imagehlp.lib OS_LIBS += shell32.lib ole32.lib uuid.lib imagehlp.lib
endif endif

Просмотреть файл

@ -48,7 +48,6 @@
#include "prlock.h" #include "prlock.h"
#include "nscore.h" #include "nscore.h"
#include "nsDebugHelpWin32.h" #include "nsDebugHelpWin32.h"
#include "nsStackFrameWin.h"
#else #else
#error "nsDebugHelpWin32.cpp should only be built in Win32 x86 builds" #error "nsDebugHelpWin32.cpp should only be built in Win32 x86 builds"
#endif #endif
@ -164,7 +163,6 @@ DHWImportHooker::DHWImportHooker(const char* aModuleName,
gLock = PR_NewLock(); gLock = PR_NewLock();
PR_Lock(gLock); PR_Lock(gLock);
EnsureImageHlpInitialized();
dhwEnsureImageHlpInitialized(); // for the extra ones we care about. dhwEnsureImageHlpInitialized(); // for the extra ones we care about.
if(!gRealGetProcAddress) if(!gRealGetProcAddress)

Просмотреть файл

Просмотреть файл

Просмотреть файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -7,122 +7,9 @@
#include "nscore.h" #include "nscore.h"
#include "nsAutoLock.h" #include "nsAutoLock.h"
#include "nsStackFrameWin.h"
#include "nsDebugHelpWin32.h" #include "nsDebugHelpWin32.h"
#include "nsTraceMallocCallbacks.h" #include "nsTraceMallocCallbacks.h"
// XXX These are *very* quick hacks and need improvement!
static PRBool GetSymbolFromAddress(uint32 addr, char* outBuf)
{
PRBool ok;
ok = EnsureSymInitialized();
if(!ok)
return ok;
char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf;
symbol->SizeOfStruct = sizeof(buf);
symbol->MaxNameLength = 512;
DWORD displacement;
ok = SymGetSymFromAddr(::GetCurrentProcess(),
addr,
&displacement,
symbol);
if(ok)
{
char buf2[512];
sprintf(buf2, "%s+0x%08X", symbol->Name, displacement);
strcat(outBuf, buf2);
}
else
strcat(outBuf, "dunno");
return ok;
}
static PRBool GetModuleFromAddress(uint32 addr, char* outBuf)
{
PRBool ok;
ok = EnsureSymInitialized();
if(!ok)
return ok;
IMAGEHLP_MODULE module;
module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
ok = SymGetModuleInfo(::GetCurrentProcess(),
addr,
&module);
if(ok)
strcat(outBuf, module.ModuleName);
else
strcat(outBuf, "dunno");
return ok;
}
/***************************************************************************/
#ifdef VERBOSE
#define SHOW(x_, buf_) \
printf(#x_" = %#x... %s\n", x_, \
(buf_[0] = 0, \
GetModuleFromAddress((uint32)x_, buf_), \
strcat(buf," :: "), \
GetSymbolFromAddress((uint32)x_, buf_), \
buf_));
#else
#define SHOW(x_, buf_)
#endif //VERBOSE
/***************************************************************************/
#ifdef VERBOSE
// XXX This is a quick hack to show that x86 Win32 stack walking can be done
// with this sort of loop following the bp.
void dumpStack()
{
uint32* bp_;
uint32* bpdown;
uint32 pc;
char buf[512];
_asm { mov bp_ , ebp }
/* Stack walking code adapted from Kipp's "leaky". */
while (1) {
bpdown = (uint32*) *bp_++;
pc = *bp_;
// These addresses are iffy...
if (pc < 0x00400000 || pc > 0x7fffffff || bpdown < bp_)
break;
SHOW(pc, buf);
bp_ = bpdown;
}
printf("\n");
}
#endif
char* _stdcall call2(void* v)
{
// dumpStack();
// return 0;
return (char *)malloc(123);
}
int call1(char c, int i, double d, ... )
{
free(call2(0));
return 0;
}
/***************************************************************************/ /***************************************************************************/
// shows how to use the dhw stuff to hook imported functions // shows how to use the dhw stuff to hook imported functions
@ -239,93 +126,10 @@ void __cdecl dhw_delete(void* p)
FreeCallback(p, start, end); FreeCallback(p, start, end);
} }
/***************************************************************************/
// A demonstration of using the _CrtSetAllocHook based hooking.
// This system sucks because you don't get to see the allocated pointer.
#if 0
class myAllocationSizePrinter : public DHWAllocationSizeDebugHook
{
public:
PRBool AllocHook(size_t size)
{
alloc_calls++ ;
total_mem += size;
if(verbosity)
{
printf("alloc called to get %d bytes.\n", size);
dumpStack();
}
return PR_TRUE;
}
PRBool ReallocHook(size_t size, size_t sizeOld)
{
realloc_calls++ ;
total_mem += size;
total_mem -= sizeOld;
if(verbosity)
{
printf("realloc called to size to %d bytes. Old size: %d.\n",
size, sizeOld);
dumpStack();
}
return PR_TRUE;
}
PRBool FreeHook(size_t size)
{
free_calls++ ;
total_mem -= size;
if(verbosity)
{
printf("free called to release %d bytes.\n", size);
dumpStack();
}
return PR_TRUE;
}
myAllocationSizePrinter(int v)
: verbosity(v),
alloc_calls(0),
realloc_calls(0),
free_calls(0),
total_mem(0) {}
virtual ~myAllocationSizePrinter(){}
void report()
{
printf("%d allocs, %d reallocs, %d frees, %d bytes leaked\n",
alloc_calls, realloc_calls, free_calls, total_mem);
}
private:
void dumpStack()
{
if(verbosity == 2)
::dumpStack();
}
int verbosity;
int alloc_calls;
int realloc_calls;
int free_calls;
size_t total_mem;
};
#endif
/*C Callbacks*/ /*C Callbacks*/
PR_IMPLEMENT(void) PR_IMPLEMENT(void)
StartupHooker() StartupHooker()
{ {
if (!EnsureSymInitialized())
return;
//run through get all hookers //run through get all hookers
DHWImportHooker &loadlibraryW = DHWImportHooker::getLoadLibraryWHooker(); DHWImportHooker &loadlibraryW = DHWImportHooker::getLoadLibraryWHooker();
DHWImportHooker &loadlibraryExW = DHWImportHooker::getLoadLibraryExWHooker(); DHWImportHooker &loadlibraryExW = DHWImportHooker::getLoadLibraryExWHooker();
@ -344,50 +148,3 @@ PR_IMPLEMENT(void)
ShutdownHooker() ShutdownHooker()
{ {
} }
#if 0
int main()
{
// A demonstration of using the (sucky) _CrtSetAllocHook based hooking.
myAllocationSizePrinter ap(0);
dhwSetAllocationSizeDebugHook(&ap);
// show that the ImportHooker is hooking calls from loaded dll
DHW_DECLARE_FUN_TYPE(void, __stdcall, SOMECALL_, (void));
HMODULE module = ::LoadLibrary("Other.dll");
if(module) {
SOMECALL_ _SomeCall = (SOMECALL_) GetProcAddress(module, "SomeCall");
if(_SomeCall)
_SomeCall();
}
// show that the ImportHooker is hooking sneaky calls made from this dll.
HMODULE module2 = ::LoadLibrary(NS_DEBUG_CRT);
if(module2) {
MALLOC_ _sneakyMalloc = (MALLOC_) GetProcAddress(module2, "malloc");
if(_sneakyMalloc)
{
void* p = _sneakyMalloc(987);
free(p);
}
}
call1('x', 1, 1.0, "hi there", 2);
char* p = new char[10];
delete p;
void* v = malloc(10);
v = realloc(v, 15);
v = realloc(v, 5);
free(v);`
ap.report();
dhwClearAllocationSizeDebugHook();
return 0;
}
#endif //0

Просмотреть файл

@ -137,9 +137,8 @@ void PrintError(char *prefix)
0, 0,
NULL NULL
); );
char buf[512]; fprintf(stderr, "### ERROR: %s: %s", prefix, lpMsgBuf);
_snprintf(buf, sizeof(buf), "### ERROR: %s: %s", prefix, lpMsgBuf); fflush(stderr);
fputs(buf, stderr);
LocalFree( lpMsgBuf ); LocalFree( lpMsgBuf );
} }
@ -448,8 +447,7 @@ EXPORT_XPCOM_API(nsresult)
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
void *aClosure) void *aClosure)
{ {
HANDLE myProcess = ::GetCurrentProcess(); HANDLE myProcess, myThread, walkerThread;
HANDLE myThread, walkerThread;
DWORD walkerReturn; DWORD walkerReturn;
struct WalkStackData data; struct WalkStackData data;
@ -457,13 +455,23 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
// Have to duplicate handle to get a real handle. // Have to duplicate handle to get a real handle.
::DuplicateHandle( if (!::DuplicateHandle(::GetCurrentProcess(),
::GetCurrentProcess(), ::GetCurrentProcess(),
::GetCurrentThread(), ::GetCurrentProcess(),
::GetCurrentProcess(), &myProcess,
&myThread, THREAD_ALL_ACCESS, FALSE, 0)) {
THREAD_ALL_ACCESS, FALSE, 0 PrintError("DuplicateHandle (process)");
); return NS_ERROR_FAILURE;
}
if (!::DuplicateHandle(::GetCurrentProcess(),
::GetCurrentThread(),
::GetCurrentProcess(),
&myThread,
THREAD_ALL_ACCESS, FALSE, 0)) {
PrintError("DuplicateHandle (thread)");
::CloseHandle(myProcess);
return NS_ERROR_FAILURE;
}
data.callback = aCallback; data.callback = aCallback;
data.skipFrames = aSkipFrames; data.skipFrames = aSkipFrames;
@ -476,11 +484,13 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
if (walkerReturn != WAIT_OBJECT_0) { if (walkerReturn != WAIT_OBJECT_0) {
PrintError("ThreadWait"); PrintError("ThreadWait");
} }
CloseHandle(myThread); ::CloseHandle(walkerThread);
} }
else { else {
PrintError("ThreadCreate"); PrintError("ThreadCreate");
} }
::CloseHandle(myThread);
::CloseHandle(myProcess);
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -40,6 +40,7 @@
#include "nsStackWalk.h" #include "nsStackWalk.h"
#if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code #if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code
#include "nsStackFrameWin.cpp" #include "nsStackFrameWin.cpp"
// WIN32 x86 stack walking code // WIN32 x86 stack walking code