зеркало из https://github.com/mozilla/gecko-dev.git
315 строки
8.3 KiB
C++
315 строки
8.3 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (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 Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
|
* Netscape Communications Corporation. All Rights Reserved.
|
|
*/
|
|
#include "nsISupports.h"
|
|
#include "prprf.h"
|
|
#include "prlog.h"
|
|
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
static PRLogModuleInfo* gTraceRefcntLog;
|
|
|
|
#if defined(NS_MT_SUPPORTED)
|
|
#include "prlock.h"
|
|
|
|
static PRLock* gTraceLock;
|
|
|
|
#define LOCK_TRACELOG() PR_Lock(gTraceLock)
|
|
#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
|
|
#else /* ! NT_MT_SUPPORTED */
|
|
#define LOCK_TRACELOG()
|
|
#define UNLOCK_TRACELOG()
|
|
#endif /* ! NS_MT_SUPPORTED */
|
|
|
|
static void InitTraceLog(void)
|
|
{
|
|
if (0 == gTraceRefcntLog) {
|
|
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
|
|
|
|
#if defined(NS_MT_SUPPORTED)
|
|
gTraceLock = PR_NewLock();
|
|
#endif /* NS_MT_SUPPORTED */
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
#include "imagehlp.h"
|
|
#include <stdio.h>
|
|
|
|
#if 0
|
|
static BOOL __stdcall
|
|
EnumSymbolsCB(LPSTR aSymbolName,
|
|
ULONG aSymbolAddress,
|
|
ULONG aSymbolSize,
|
|
PVOID aUserContext)
|
|
{
|
|
int* countp = (int*) aUserContext;
|
|
int count = *countp;
|
|
if (count < 3) {
|
|
printf(" %p[%4d]: %s\n", aSymbolAddress, aSymbolSize, aSymbolName);
|
|
count++;
|
|
*countp = count++;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL __stdcall
|
|
EnumModulesCB(LPSTR aModuleName,
|
|
ULONG aBaseOfDll,
|
|
PVOID aUserContext)
|
|
{
|
|
HANDLE myProcess = ::GetCurrentProcess();
|
|
|
|
printf("module=%s dll=%x\n", aModuleName, aBaseOfDll);
|
|
// int count = 0;
|
|
// SymEnumerateSymbols(myProcess, aBaseOfDll, EnumSymbolsCB, (void*) &count);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* 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(char* aBuffer, int aBufLen)
|
|
{
|
|
CONTEXT context;
|
|
STACKFRAME frame;
|
|
char* cp = aBuffer;
|
|
|
|
aBuffer[0] = '\0';
|
|
aBufLen--; // leave room for nul
|
|
|
|
HANDLE myProcess = ::GetCurrentProcess();
|
|
HANDLE myThread = ::GetCurrentThread();
|
|
|
|
// 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.ContextFlags = CONTEXT_FULL;
|
|
GetThreadContext(myThread, &context);
|
|
|
|
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
SymEnumerateModules(myProcess, EnumModulesCB, NULL);
|
|
#endif
|
|
|
|
// Setup initial stack frame to walk from
|
|
memset(&frame, 0, sizeof(frame));
|
|
frame.AddrPC.Mode = AddrModeFlat;
|
|
frame.AddrPC.Offset = context.Eip;
|
|
frame.AddrReturn.Mode = AddrModeFlat;
|
|
frame.AddrReturn.Offset = context.Ebp;
|
|
frame.AddrFrame.Mode = AddrModeFlat;
|
|
frame.AddrFrame.Offset = context.Ebp;
|
|
frame.AddrStack.Mode = AddrModeFlat;
|
|
frame.AddrStack.Offset = context.Esp;
|
|
frame.Params[0] = context.Eax;
|
|
frame.Params[1] = context.Ecx;
|
|
frame.Params[2] = context.Edx;
|
|
frame.Params[3] = context.Ebx;
|
|
|
|
// Now walk the stack and map the pc's to symbol names that we stuff
|
|
// append to *cp.
|
|
|
|
int skip = 2;
|
|
int syms = 0;
|
|
while (aBufLen > 0) {
|
|
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 512];
|
|
PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) symbolBuffer;
|
|
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
|
|
pSymbol->MaxNameLength = 512;
|
|
|
|
DWORD oldAddress = frame.AddrPC.Offset;
|
|
BOOL b = ::StackWalk(IMAGE_FILE_MACHINE_I386, myProcess, myThread,
|
|
&frame, &context, NULL,
|
|
SymFunctionTableAccess,
|
|
SymGetModuleBase,
|
|
NULL);
|
|
if (!b || (0 == frame.AddrPC.Offset)) {
|
|
if (syms <= 1) {
|
|
skip = 7;
|
|
}
|
|
break;
|
|
}
|
|
if (--skip >= 0) {
|
|
continue;
|
|
}
|
|
DWORD disp;
|
|
if (SymGetSymFromAddr(myProcess, frame.AddrPC.Offset, &disp, pSymbol)) {
|
|
int nameLen = strlen(pSymbol->Name);
|
|
if (nameLen + 2 > aBufLen) {
|
|
break;
|
|
}
|
|
memcpy(cp, pSymbol->Name, nameLen);
|
|
cp += nameLen;
|
|
*cp++ = ' ';
|
|
aBufLen -= nameLen + 1;
|
|
syms++;
|
|
}
|
|
else {
|
|
if (11 > aBufLen) {
|
|
break;
|
|
}
|
|
char tmp[30];
|
|
PR_snprintf(tmp, sizeof(tmp), "0x%08x ", frame.AddrPC.Offset);
|
|
memcpy(cp, tmp, 11);
|
|
cp += 11;
|
|
aBufLen -= 11;
|
|
syms++;
|
|
}
|
|
}
|
|
*cp = 0;
|
|
}
|
|
|
|
#else /* _WIN32 */
|
|
void
|
|
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
|
{
|
|
aBuffer[0] = '\0';
|
|
}
|
|
#endif /* _WIN32 */
|
|
|
|
NS_COM void
|
|
nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
|
void* aLibrayHandle)
|
|
{
|
|
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
|
#if defined(_WIN32)
|
|
InitTraceLog();
|
|
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
HANDLE myProcess = ::GetCurrentProcess();
|
|
|
|
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
|
return;
|
|
}
|
|
|
|
BOOL b = ::SymLoadModule(myProcess,
|
|
NULL,
|
|
(char*)aLibraryName,
|
|
(char*)aLibraryName,
|
|
0,
|
|
0);
|
|
// DWORD lastError = 0;
|
|
// if (!b) lastError = ::GetLastError();
|
|
// printf("loading symbols for library %s => %s [%d]\n", aLibraryName,
|
|
// b ? "true" : "false", lastError);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
NS_COM unsigned long
|
|
nsTraceRefcnt::AddRef(void* aPtr,
|
|
unsigned long aNewRefcnt,
|
|
const char* aFile,
|
|
PRIntn aLine)
|
|
{
|
|
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
|
InitTraceLog();
|
|
|
|
LOCK_TRACELOG();
|
|
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
char sb[1000];
|
|
WalkTheStack(sb, sizeof(sb));
|
|
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
|
("AddRef: %p: %d=>%d [%s] in %s (line %d)",
|
|
aPtr, aNewRefcnt-1, aNewRefcnt, sb, aFile, aLine));
|
|
}
|
|
UNLOCK_TRACELOG();
|
|
#endif
|
|
return aNewRefcnt;
|
|
|
|
}
|
|
|
|
NS_COM unsigned long
|
|
nsTraceRefcnt::Release(void* aPtr,
|
|
unsigned long aNewRefcnt,
|
|
const char* aFile,
|
|
PRIntn aLine)
|
|
{
|
|
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
|
InitTraceLog();
|
|
|
|
LOCK_TRACELOG();
|
|
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
char sb[1000];
|
|
WalkTheStack(sb, sizeof(sb));
|
|
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
|
("Release: %p: %d=>%d [%s] in %s (line %d)",
|
|
aPtr, aNewRefcnt+1, aNewRefcnt, sb, aFile, aLine));
|
|
}
|
|
UNLOCK_TRACELOG();
|
|
#endif
|
|
return aNewRefcnt;
|
|
}
|
|
|
|
NS_COM void
|
|
nsTraceRefcnt::Create(void* aPtr,
|
|
const char* aType,
|
|
const char* aFile,
|
|
PRIntn aLine)
|
|
{
|
|
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
|
InitTraceLog();
|
|
|
|
LOCK_TRACELOG();
|
|
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
char sb[1000];
|
|
WalkTheStack(sb, sizeof(sb));
|
|
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
|
("Create: %p[%s]: [%s] in %s (line %d)",
|
|
aPtr, aType, sb, aFile, aLine));
|
|
}
|
|
UNLOCK_TRACELOG();
|
|
#endif
|
|
}
|
|
|
|
NS_COM void
|
|
nsTraceRefcnt::Destroy(void* aPtr,
|
|
const char* aFile,
|
|
PRIntn aLine)
|
|
{
|
|
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
|
InitTraceLog();
|
|
|
|
LOCK_TRACELOG();
|
|
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
|
char sb[1000];
|
|
WalkTheStack(sb, sizeof(sb));
|
|
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
|
("Destroy: %p: [%s] in %s (line %d)",
|
|
aPtr, sb, aFile, aLine));
|
|
}
|
|
UNLOCK_TRACELOG();
|
|
#endif
|
|
}
|