示例#1
0
const std::wstring SymbolInfo::getProcForAddr(PROFILER_ADDR addr, 
											  std::wstring& procfilepath_out, int& proclinenum_out)
{
	procfilepath_out = L"";
	proclinenum_out = 0;

	Module *mod = getModuleForAddr(addr);
	DbgHelp *dbgHelp = mod ? mod->dbghelp : &dbgHelpMs;

	unsigned char buffer[1024];

	//blame MS for this abomination of a coding technique
	SYMBOL_INFOW* symbol_info = (SYMBOL_INFOW*)buffer;
	symbol_info->SizeOfStruct = sizeof(SYMBOL_INFOW);
	symbol_info->MaxNameLen = ((sizeof(buffer) - sizeof(SYMBOL_INFOW)) / sizeof(WCHAR)) - 1;

	DWORD64 displacement = 0;
	BOOL result = dbgHelp->SymFromAddrW(process_handle, (DWORD64)addr, &displacement, symbol_info);

	if(!result)
	{
		DWORD err = GetLastError();
		wchar_t buf[256];
#if defined(_WIN64)
		if(is64BitProcess)
			swprintf(buf, 256, L"[%016llX]", addr);
		else 
			swprintf(buf, 256, L"[%08X]", unsigned __int32(addr));
#else
		swprintf(buf, 256, L"[%08X]", addr);
#endif
		return buf;
	}
示例#2
0
SymbolInfo::~SymbolInfo()
{
	//------------------------------------------------------------------------
	//clean up
	//------------------------------------------------------------------------
	if ( process_handle )
	{
		DbgHelp *gcc = &dbgHelpGcc;
#ifdef _WIN64
		if (is64BitProcess)
			gcc = &dbgHelpGccWow64;
#endif

		if (!gcc->SymCleanup(process_handle))
		{
			//error
		}

		if (!dbgHelpMs.SymCleanup(process_handle))
		{
			//error
		}

		process_handle = NULL;
	}
}
示例#3
0
            std::string format_address_win32(const void* addr) const
            {
                if (!dbghelp.initialized())
                    return format_address_fallback(addr);

                DWORD64 symbol_info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
                const auto symbol_info = reinterpret_cast<SYMBOL_INFO*>(symbol_info_buf);
                symbol_info->SizeOfStruct = sizeof(SYMBOL_INFO);
                symbol_info->MaxNameLen = MAX_SYM_NAME;

                IMAGEHLP_MODULE64 module_info;
                module_info.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);

                DWORD64 symbol_offset;

                const auto symbol_resolved = SymFromAddr(
                    GetCurrentProcess(),
                    reinterpret_cast<DWORD64>(addr),
                    &symbol_offset,
                    symbol_info);

                if (symbol_resolved)
                {
                    const auto module_resolved = SymGetModuleInfo64(
                        GetCurrentProcess(),
                        symbol_info->ModBase,
                        &module_info);

                    if (module_resolved)
                    {
                        return format_symbol(
                            module_info.ModuleName,
                            symbol_info->Name,
                            reinterpret_cast<const void*>(symbol_offset));
                    }
                    else
                    {
                        return format_symbol(symbol_info->Name, addr);
                    }
                }
                else
                {
                    const auto module_resolved = SymGetModuleInfo64(
                        GetCurrentProcess(),
                        reinterpret_cast<DWORD64>(addr),
                        &module_info);

                    if (module_resolved)
                    {
                        const auto module_offset = reinterpret_cast<const char*>(addr) - module_info.BaseOfImage;
                        return format_module(module_info.ModuleName, module_offset);
                    }
                    else
                    {
                        return format_address_fallback(addr);
                    }
                }
            }
示例#4
0
// getStackTrace - Traces the stack as far back as possible, or until 'maxdepth'
//   frames have been traced. Populates the CallStack with one entry for each
//   stack frame traced.
//
//   Note: This function uses a documented Windows API to walk the stack. This
//     API is supposed to be the most reliable way to walk the stack. It claims
//     to be able to walk stack frames that do not follow the conventional stack
//     frame layout. However, this robustness comes at a cost: it is *extremely*
//     slow compared to walking frames by following frame (base) pointers.
//
//  - maxdepth (IN): Maximum number of frames to trace back.
//
//  - framepointer (IN): Frame (base) pointer at which to begin the stack trace.
//      If NULL, then the stack trace will begin at this function.
//
//  Return Value:
//
//    None.
//
VOID SafeCallStack::getStackTrace (UINT32 maxdepth, const context_t& context)
{
    UINT32 count = 0;
    UINT_PTR function = context.func;
    if (function != NULL)
    {
        count++;
        push_back(function);
    }

    DWORD   architecture   = X86X64ARCHITECTURE;

    // Get the required values for initialization of the STACKFRAME64 structure
    // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.
    CONTEXT currentContext;
    memset(&currentContext, 0, sizeof(currentContext));
    currentContext.SPREG = context.SPREG;
    currentContext.BPREG = context.BPREG;
    currentContext.IPREG = context.IPREG;

    // Initialize the STACKFRAME64 structure.
    STACKFRAME64 frame;
    memset(&frame, 0x0, sizeof(frame));
    frame.AddrPC.Offset       = currentContext.IPREG;
    frame.AddrPC.Mode         = AddrModeFlat;
    frame.AddrStack.Offset    = currentContext.SPREG;
    frame.AddrStack.Mode      = AddrModeFlat;
    frame.AddrFrame.Offset    = currentContext.BPREG;
    frame.AddrFrame.Mode      = AddrModeFlat;
    frame.Virtual             = TRUE;

    CriticalSectionLocker<> cs(g_heapMapLock);
    CriticalSectionLocker<DbgHelp> locker(g_DbgHelp);

    // Walk the stack.
    while (count < maxdepth) {
        count++;
        DbgTrace(L"dbghelp32.dll %i: StackWalk64\n", GetCurrentThreadId());
        if (!g_DbgHelp.StackWalk64(architecture, g_currentProcess, g_currentThread, &frame, &currentContext, NULL,
            SymFunctionTableAccess64, SymGetModuleBase64, NULL, locker)) {
                // Couldn't trace back through any more frames.
                break;
        }
        if (frame.AddrFrame.Offset == 0) {
            // End of stack.
            break;
        }

        // Push this frame's program counter onto the CallStack.
        push_back((UINT_PTR)frame.AddrPC.Offset);
    }
}
示例#5
0
// for kernel32.dll
LPVOID VisualLeakDetector::_HeapReAlloc (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size)
{
    PRINT_HOOKED_FUNCTION();

    // Reallocate the block.
    LPVOID newmem = HeapReAlloc(heap, flags, mem, size);
    if ((newmem == NULL) || !g_vld.enabled())
        return newmem;

    if (!g_DbgHelp.IsLockedByCurrentThread()) { // skip dbghelp.dll calls
        CAPTURE_CONTEXT();
        CaptureContext cc(HeapReAlloc, size, context_);
        cc.Set(heap, mem, newmem, size);
    }

    return newmem;
}
示例#6
0
// HeapAlloc (kernel32.dll) call RtlAllocateHeap (ntdll.dll)
LPVOID VisualLeakDetector::_HeapAlloc (HANDLE heap, DWORD flags, SIZE_T size)
{
    PRINT_HOOKED_FUNCTION2();
    // Allocate the block.
    LPVOID block = HeapAlloc(heap, flags, size);

    if ((block == NULL) || !g_vld.enabled())
        return block;

    if (!g_DbgHelp.IsLockedByCurrentThread()) { // skip dbghelp.dll calls
        CAPTURE_CONTEXT();
        CaptureContext cc(HeapAlloc, size, context_);
        cc.Set(heap, block, NULL, size);
    }

    return block;
}
示例#7
0
// HeapFree (kernel32.dll) call RtlFreeHeap (ntdll.dll)
BOOL VisualLeakDetector::_HeapFree (HANDLE heap, DWORD flags, LPVOID mem)
{
    PRINT_HOOKED_FUNCTION2();
    BOOL status;

    if (!g_DbgHelp.IsLockedByCurrentThread()) // skip dbghelp.dll calls
    {
        // Record the current frame pointer.
        CAPTURE_CONTEXT();
        context_.func = reinterpret_cast<UINT_PTR>(m_HeapFree);

        // Unmap the block from the specified heap.
        g_vld.unmapBlock(heap, mem, context_);
    }

    status = m_HeapFree(heap, flags, mem);

    return status;
}
示例#8
0
文件: callstack.cpp 项目: viknash/vld
// isCrtStartupAlloc - Determines whether the memory leak was generated from crt startup code.
// This is not an actual memory leaks as it is freed by crt after the VLD object has been destroyed.
//
//  Return Value:
//
//    true if isCrtStartupModule for any callstack frame returns true.
//
bool CallStack::isCrtStartupAlloc()
{
    if (m_status & CALLSTACK_STATUS_STARTUPCRT) {
        return true;
    } else if (m_status & CALLSTACK_STATUS_NOTSTARTUPCRT) {
        return false;
    }

    IMAGEHLP_LINE64  sourceInfo = { 0 };
    sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

    BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 };
    CriticalSectionLocker<DbgHelp> locker(g_DbgHelp);

    // Iterate through each frame in the call stack.
    for (UINT32 frame = 0; frame < m_size; frame++) {
        // Try to get the source file and line number associated with
        // this program counter address.
        SIZE_T programCounter = (*this)[frame];
        BOOL             foundline = FALSE;
        DWORD            displacement = 0;
        DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId());
        foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo);

        if (foundline) {
            DWORD64 displacement64;
            LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker);
            if (beginWith(functionName, wcslen(functionName), L"`dynamic initializer for '")) {
                break;
            }

            if (isCrtStartupModule(sourceInfo.FileName)) {
                m_status |= CALLSTACK_STATUS_STARTUPCRT;
                return true;
            }
        }
    }

    m_status |= CALLSTACK_STATUS_NOTSTARTUPCRT;
    return false;
}
示例#9
0
文件: callstack.cpp 项目: viknash/vld
LPCWSTR CallStack::getFunctionName(SIZE_T programCounter, DWORD64& displacement64,
    SYMBOL_INFO* functionInfo, CriticalSectionLocker<DbgHelp>& locker) const
{
    // Initialize structures passed to the symbol handler.
    functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
    functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH;

    // Try to get the name of the function containing this program
    // counter address.
    displacement64 = 0;
    LPCWSTR functionName;
    DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId());
    if (g_DbgHelp.SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo, locker)) {
        functionName = functionInfo->Name;
    }
    else {
        // GetFormattedMessage( GetLastError() );
        fmt::WArrayWriter wf(functionInfo->Name, MAX_SYMBOL_NAME_LENGTH);
        wf.write(L"" ADDRESSCPPFORMAT, programCounter);
        functionName = wf.c_str();
        displacement64 = 0;
    }
    return functionName;
}
示例#10
0
void SymbolInfo::loadSymbols(HANDLE process_handle_, bool download)
{
	process_handle = process_handle_;

	wxBusyCursor busy;

	is64BitProcess = Is64BitProcess(process_handle);

	DWORD options = dbgHelpMs.SymGetOptions(); 

#ifdef _WIN64
	if(!is64BitProcess) {
		options |= SYMOPT_INCLUDE_32BIT_MODULES; 
	}
#endif

	options |= SYMOPT_LOAD_LINES | SYMOPT_DEBUG;

	dbgHelpMs.SymSetOptions(options); 
	dbgHelpGcc.SymSetOptions(options); 
#ifdef _WIN64
	dbgHelpGccWow64.SymSetOptions(options);
#endif

	std::wstring sympath;

	// Add the program's own directory to the search path.
	// Useful if someone's copied the EXE and PDB to a different machine or location.
	wchar_t szExePath[MAX_PATH] = L"";
	DWORD pathsize = MAX_PATH;
	BOOL gotImageName = FALSE;
#ifdef _WIN64
	// GetModuleFileNameEx doesn't always work across 64->32 bit boundaries.
	// Use QueryFullProcessImageName if we have it.
	{
		typedef BOOL WINAPI QueryFullProcessImageNameFn(HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize);

		QueryFullProcessImageNameFn *fn = (QueryFullProcessImageNameFn *)GetProcAddress(GetModuleHandle(L"kernel32"),"QueryFullProcessImageNameW");
		if (fn)
			gotImageName = fn(process_handle, 0, szExePath, &pathsize);
	}
#endif

	if (!gotImageName)
		gotImageName = GetModuleFileNameEx(process_handle, NULL, szExePath, pathsize);

	if (gotImageName)
	{
		// Convert the EXE path to its containing folder and append the
		// resulting folder to the symbol search path.
		wchar_t *p = wcsrchr(szExePath, '\\');

		if (p != NULL)
		{
			*p = '\0';
			sympath += std::wstring(L";") + szExePath;
		}
	}

	prefs.AdjustSymbolPath(sympath, download);

	for( int n=0;n<4;n++ )
	{
		wenforce(dbgHelpMs.SymInitializeW(process_handle, L"", FALSE), "SymInitialize");

		// Hook the debug output, so we actually can provide a clue as to
		// what's happening.
		dbgHelpMs.SymRegisterCallbackW64(process_handle, symCallback, NULL);

		// Add our PDB search paths.
		wenforce(dbgHelpMs.SymSetSearchPathW(process_handle, sympath.c_str()), "SymSetSearchPathW");

		// Load symbol information for all modules.
		// Normally SymInitialize would do this, but we instead do it ourselves afterwards
		// so that we can hook the debug output for it.
		wenforce(dbgHelpMs.SymRefreshModuleList(process_handle), "SymRefreshModuleList");

		wenforce(dbgHelpMs.SymEnumerateModulesW64(process_handle, EnumModules, this), "SymEnumerateModules64");

		if (!modules.empty())
			break;

		// Sometimes the module enumeration will fail (no error code, but no modules
		// will be returned). If we try again a little later it seems to work.
		// I suspect this may be if we try and enum modules too early on, before the process
		// has really had a chance to 'get going'.
		// Perhaps a better solution generally would be to manually load module symbols on demand,
		// as each sample comes in? That'd also solve the problem of modules getting loaded/unloaded
		// mid-profile. Yes, I'll probably do that some day.
		Sleep(100);
		dbgHelpMs.SymCleanup(process_handle);
	}

	DbgHelp *gcc = &dbgHelpGcc;
#ifdef _WIN64
	// We can't use the regular dbghelpw to profile 32-bit applications,
	// as it's got compiled-in things that assume 64-bit. So we instead have
	// a special Wow64 build, which is compiled as 64-bit code but using 32-bit
	// definitions. We load that instead.
	if (!is64BitProcess)
		gcc = &dbgHelpGccWow64;
#endif

	// Now that we've loaded all the modules and debug info for the regular stuff,
	// we initialize the GCC dbghelp and let it have a go at the ones we couldn't do.
	wenforce(gcc->SymInitializeW(process_handle, NULL, FALSE), "SymInitialize");

	gcc->SymSetDbgPrint(&symWineCallback);

	for (size_t n=0;n<modules.size();n++)
	{
		Module &mod = modules[n];

		IMAGEHLP_MODULEW64 info;
		info.SizeOfStruct = sizeof(info);
		if (!dbgHelpMs.SymGetModuleInfoW64(process_handle, mod.base_addr, &info))
			continue;
		
		// If we have a module with no symbol information from the MS dbghelp,
		// let the gcc one handle it instead.
		if (info.SymType == SymNone)
		{
			gcc->SymLoadModuleExW(process_handle, NULL, 
				info.ImageName, info.ModuleName, info.BaseOfImage, info.ImageSize,
				NULL, 0);
			mod.dbghelp = gcc;
		}
	}

	if (g_symLog)
		g_symLog(L"\nFinished.\n");
	sortModules();
}
示例#11
0
bool Profiler::sampleTarget(SAMPLE_TYPE timeSpent, SymbolInfo *syminfo)
{
	// DE: 20090325: Moved declaration of stack variables to reduce size of code inside Suspend/Resume thread

	CallStack stack;
	stack.depth = 0;

	STACKFRAME64 frame;
	PROFILER_ADDR ip, sp, bp;
	void *context;
	DWORD machine;

#if defined(_WIN64)
	CONTEXT64 threadcontext64;
	CONTEXT32 threadcontext32;
	if (is64BitProcess)
	{
		context = &threadcontext64;
		threadcontext64.ContextFlags = CONTEXT64_FLAGS;
		machine = IMAGE_FILE_MACHINE_AMD64;

		// Can fail occasionally, for example if you have a debugger attached to the process.
		HRESULT result = SuspendThread(target_thread);
		if(result == 0xffffffff)
			return false;

		int prev_priority = GetThreadPriority(target_thread);
		SetThreadPriority(target_thread, THREAD_PRIORITY_TIME_CRITICAL);
		result = GetThreadContext(target_thread, &threadcontext64);
		SetThreadPriority(target_thread, prev_priority);

		if(!result){
			// DE: 20090325: If GetThreadContext fails we must be sure to resume thread again
			ResumeThread(target_thread);
			return false;
		}

		ip = threadcontext64.Rip;
		sp = threadcontext64.Rsp;
		bp = threadcontext64.Rbp;
	} else {
		context = &threadcontext32;
		threadcontext32.ContextFlags = CONTEXT32_FLAGS;
		machine = IMAGE_FILE_MACHINE_I386;

		// Can fail occasionally, for example if you have a debugger attached to the process.
		HRESULT result = fn_Wow64SuspendThread(target_thread);
		if(result == 0xffffffff)
			return false;

		int prev_priority = GetThreadPriority(target_thread);
		SetThreadPriority(target_thread, THREAD_PRIORITY_TIME_CRITICAL);
		result = fn_Wow64GetThreadContext(target_thread, &threadcontext32);
		SetThreadPriority(target_thread, prev_priority);

		if(!result){
			// DE: 20090325: If GetThreadContext fails we must be sure to resume thread again
			ResumeThread(target_thread);
			return false;
		}

		ip = threadcontext32.Eip;
		sp = threadcontext32.Esp;
		bp = threadcontext32.Ebp;
	}
#else
	CONTEXT32 threadcontext32;
	context = &threadcontext32;
	threadcontext32.ContextFlags = CONTEXT32_FLAGS;
	machine = IMAGE_FILE_MACHINE_I386;

	// Can fail occasionally, for example if you have a debugger attached to the process.
	HRESULT result = SuspendThread(target_thread);
	if(result == 0xffffffff)
		return false;

	int prev_priority = GetThreadPriority(target_thread);
	SetThreadPriority(target_thread, THREAD_PRIORITY_TIME_CRITICAL);
	result = GetThreadContext(target_thread, &threadcontext32);
	SetThreadPriority(target_thread, prev_priority);

	if(!result){
		// DE: 20090325: If GetThreadContext fails we must be sure to resume thread again
		ResumeThread(target_thread);
		return false;
	}

	applyHacks(target_process, threadcontext32);

	ip = threadcontext32.Eip;
	sp = threadcontext32.Esp;
	bp = threadcontext32.Ebp;
#endif

	DbgHelp *prevDbgHelp = NULL;
	bool first = true;

	while(true)
	{
		// See which module this IP is in.
		Module *mod = syminfo->getModuleForAddr(ip);
		DbgHelp *dbgHelp = mod ? mod->dbghelp : &dbgHelpMs;

		// Use whichever dbghelp stack walker is best for this module type.
		// If we're switching between types, restart the stack walk from 
		// the current place.
		if (dbgHelp != prevDbgHelp)
		{
			prevDbgHelp = dbgHelp;
			memset(&frame, 0, sizeof(frame));
			frame.AddrStack.Offset = sp;
			frame.AddrPC.Offset = ip;
			frame.AddrFrame.Offset = bp;
			frame.AddrStack.Mode = frame.AddrPC.Mode = frame.AddrFrame.Mode = AddrModeFlat;
			frame.AddrReturn.Offset = ip;
			first = true;
		}

		// Add this IP to the stack trace.
		// We skip the first one, as the first call to StackWalk64
		// simply fills in more registers for the current frame,
		// rather than walking down to the next one.
		if (!first)
			stack.addr[stack.depth++] = ip;
		first = false;

		BOOL result = dbgHelp->StackWalk64(
			machine,
			target_process,
			target_thread,
			&frame,
			context,
			NULL,
			dbgHelp->SymFunctionTableAccess64,
			dbgHelp->SymGetModuleBase64,
			NULL
		);

		if (!result || stack.depth >= MAX_CALLSTACK_LEVELS)
			break;

		ip = (PROFILER_ADDR)frame.AddrPC.Offset;
		sp = (PROFILER_ADDR)frame.AddrStack.Offset;
		bp = (PROFILER_ADDR)frame.AddrFrame.Offset;

		// Stop once we hit the end of the stack.
		if (frame.AddrReturn.Offset == 0)
		{
			stack.addr[stack.depth++] = ip;
			break;
		}
	}

	if (!ResumeThread(target_thread))
		throw ProfilerExcep(L"ResumeThread failed.");

	//NOTE: this has to go after ResumeThread.  Otherwise mem allocation needed by std::map
	//may hit a lock held by the suspended thread.
	if (stack.depth > 0)
	{
		flatcounts[stack.addr[0]]+=timeSpent;
		callstacks[stack]+=timeSpent;
	}
	return true;
}
示例#12
0
文件: callstack.cpp 项目: viknash/vld
// Resolve - Creates a nicely formatted rendition of the CallStack, including
//   symbolic information (function names and line numbers) if available. and
//   saves it for later retrieval. This is almost identical to Callstack::dump above.
//
//   Note: The symbol handler must be initialized prior to calling this
//     function.
//
//  - showInternalFrames (IN): If true, then all frames in the CallStack will be
//      dumped. Otherwise, frames internal to the heap will not be dumped.
//
//  Return Value:
//
//    None.
//
int CallStack::resolve(BOOL showInternalFrames)
{
    if (m_resolved)
    {
        // already resolved, no need to do it again
        // resolving twice may report an incorrect module for the stack frames
        // if the memory was leaked in a dynamic library that was already unloaded.
        return 0;
    }

    if (m_status & CALLSTACK_STATUS_STARTUPCRT) {
        // there is no need to resolve a leak that will not be reported
        return 0;
    }

    if (m_status & CALLSTACK_STATUS_INCOMPLETE) {
        // This call stack appears to be incomplete. Using StackWalk64 may be
        // more reliable.
        Report(L"    HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n"
            L"      in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n"
            L"      complete stack trace.\n");
    }

    int unresolvedFunctionsCount = 0;
    IMAGEHLP_LINE64  sourceInfo = { 0 };
    sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

    bool skipStartupLeaks = !!(g_vld.GetOptions() & VLD_OPT_SKIP_CRTSTARTUP_LEAKS);

    // Use static here to increase performance, and avoid heap allocs.
    // It's thread safe because of g_heapMapLock lock.
    static WCHAR stack_line[MAXREPORTLENGTH + 1] = L"";
    bool isPrevFrameInternal = false;
    bool isDynamicInitializer = false;
    DWORD NumChars = 0;
    CriticalSectionLocker<DbgHelp> locker(g_DbgHelp);

    const size_t max_line_length = MAXREPORTLENGTH + 1;
    m_resolvedCapacity = m_size * max_line_length;
    const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR);
    m_resolved = new WCHAR[m_resolvedCapacity];
    if (m_resolved) {
        ZeroMemory(m_resolved, allocedBytes);
    }

    // Iterate through each frame in the call stack.
    for (UINT32 frame = 0; frame < m_size; frame++)
    {
        // Try to get the source file and line number associated with
        // this program counter address.
        SIZE_T programCounter = (*this)[frame];
        DWORD            displacement = 0;

        // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here
        // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns.
        // When that happens there is nothing we can do except crash.
        DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId());
        BOOL foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker);

        if (skipStartupLeaks && foundline && !isDynamicInitializer &&
            !(m_status & CALLSTACK_STATUS_NOTSTARTUPCRT) && isCrtStartupModule(sourceInfo.FileName)) {
            m_status |= CALLSTACK_STATUS_STARTUPCRT;
            delete[] m_resolved;
            m_resolved = NULL;
            m_resolvedCapacity = 0;
            m_resolvedLength = 0;
            return 0;
        }

        bool isFrameInternal = false;
        if (foundline && !showInternalFrames) {
            if (isInternalModule(sourceInfo.FileName)) {
                // Don't show frames in files internal to the heap.
                isFrameInternal = true;
            }
        }

        // show one allocation function for context
        if (NumChars > 0 && !isFrameInternal && isPrevFrameInternal) {
            m_resolvedLength += NumChars;
            if (m_resolved) {
                wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars);
            }
        }
        isPrevFrameInternal = isFrameInternal;

        DWORD64 displacement64;
        BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE];
        LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker);

        if (skipStartupLeaks && foundline && beginWith(functionName, wcslen(functionName), L"`dynamic initializer for '")) {
            isDynamicInitializer = true;
        }

        if (!foundline)
            displacement = (DWORD)displacement64;
        NumChars = resolveFunction( programCounter, foundline ? &sourceInfo : NULL,
            displacement, functionName, stack_line, _countof( stack_line ));

        if (NumChars > 0 && !isFrameInternal) {
            m_resolvedLength += NumChars;
            if (m_resolved) {
                wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars);
            }
        }
    } // end for loop

    m_status |= CALLSTACK_STATUS_NOTSTARTUPCRT;
    return unresolvedFunctionsCount;
}
示例#13
0
文件: callstack.cpp 项目: viknash/vld
// dump - Dumps a nicely formatted rendition of the CallStack, including
//   symbolic information (function names and line numbers) if available.
//
//   Note: The symbol handler must be initialized prior to calling this
//     function.
//
//  - showinternalframes (IN): If true, then all frames in the CallStack will be
//      dumped. Otherwise, frames internal to the heap will not be dumped.
//
//  Return Value:
//
//    None.
//
void CallStack::dump(BOOL showInternalFrames, UINT start_frame) const
{
    // The stack was dumped already
    if (m_resolved)
    {
        dumpResolved();
        return;
    }

    if (m_status & CALLSTACK_STATUS_INCOMPLETE) {
        // This call stack appears to be incomplete. Using StackWalk64 may be
        // more reliable.
        Report(L"    HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n"
            L"      in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n"
            L"      complete stack trace.\n");
    }

    IMAGEHLP_LINE64  sourceInfo = { 0 };
    sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

    // Use static here to increase performance, and avoid heap allocs.
    // It's thread safe because of g_heapMapLock lock.
    static WCHAR stack_line[MAXREPORTLENGTH + 1] = L"";
    bool isPrevFrameInternal = false;
    CriticalSectionLocker<DbgHelp> locker(g_DbgHelp);

    // Iterate through each frame in the call stack.
    for (UINT32 frame = start_frame; frame < m_size; frame++)
    {
        // Try to get the source file and line number associated with
        // this program counter address.
        SIZE_T programCounter = (*this)[frame];
        BOOL             foundline = FALSE;
        DWORD            displacement = 0;
        DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId());
        foundline = g_DbgHelp.SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo, locker);

        bool isFrameInternal = false;
        if (foundline && !showInternalFrames) {
            if (isInternalModule(sourceInfo.FileName))
            {
                // Don't show frames in files internal to the heap.
                isFrameInternal = true;
            }
        }

        // show one allocation function for context
        if (!isFrameInternal && isPrevFrameInternal)
            Print(stack_line);
        isPrevFrameInternal = isFrameInternal;

        DWORD64 displacement64;
        BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE];
        LPCWSTR functionName = getFunctionName(programCounter, displacement64, (SYMBOL_INFO*)&symbolBuffer, locker);

        if (!foundline)
            displacement = (DWORD)displacement64;
        DWORD NumChars = resolveFunction(programCounter, foundline ? &sourceInfo : NULL,
            displacement, functionName, stack_line, _countof(stack_line));
        UNREFERENCED_PARAMETER(NumChars);

        if (!isFrameInternal)
            Print(stack_line);
    }
}