Esempio n. 1
0
DWORD resolveFunction(SIZE_T programCounter, IMAGEHLP_LINE* sourceInfo, DWORD displacement,
	LPCSTR functionName, LPSTR stack_line, DWORD stackLineSize)
{
	char callingModuleName[260];
	HMODULE hCallingModule = GetCallingModule(programCounter);
	LPSTR moduleName = "(Module name unavailable)";
	if (hCallingModule &&
		GetModuleFileNameA(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0)
	{

		moduleName = strrchr(callingModuleName, '\\');
		if (moduleName == NULL)
			moduleName = strrchr(callingModuleName, '/');
		if (moduleName != NULL)
			moduleName++;
		else
			moduleName = callingModuleName;
	}
	ZeroMemory(stack_line, stackLineSize * sizeof(char));
	// Display the current stack frame's information.
	if (sourceInfo)
	{
		if (displacement == 0)
		{
			sprintf_s(stack_line, stackLineSize, "    %s (%d): %s!%s()\n",
				sourceInfo->FileName, sourceInfo->LineNumber, moduleName,
				functionName);
		}
		else
		{
			sprintf_s(stack_line, stackLineSize, "    %s (%d): %s!%s() + 0x%x bytes\n",
				sourceInfo->FileName, sourceInfo->LineNumber, moduleName,
				functionName, displacement);
		}
	}
	else
	{
		if (displacement == 0)
		{
			sprintf_s(stack_line, stackLineSize, "    %s!%s()\n",
				moduleName, functionName);
		}
		else
		{
			sprintf_s(stack_line, stackLineSize, "    %s!%s() + 0x%x bytes\n",
				moduleName, functionName, displacement);
		}
	}

	LPSTR end = find(stack_line, stack_line + stackLineSize, '\0');
	DWORD NumChars = (DWORD)(end - stack_line);
	stack_line[NumChars] = '\0';
	return NumChars;
}
Esempio n. 2
0
DWORD CallStack::resolveFunction(SIZE_T programCounter, IMAGEHLP_LINEW64* sourceInfo, DWORD displacement,
    LPCWSTR functionName, LPWSTR stack_line, DWORD stackLineSize) const
{
    WCHAR callingModuleName[260];
    HMODULE hCallingModule = GetCallingModule(programCounter);
    LPWSTR moduleName = L"(Module name unavailable)";
    if (hCallingModule &&
        GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0)
    {
        moduleName = wcsrchr(callingModuleName, L'\\');
        if (moduleName == NULL)
            moduleName = wcsrchr(callingModuleName, L'/');
        if (moduleName != NULL)
            moduleName++;
        else
            moduleName = callingModuleName;
    }

    fmt::WArrayWriter w(stack_line, stackLineSize);
    // Display the current stack frame's information.
    if (sourceInfo)
    {
        if (displacement == 0)
        {
            w.write(L"    {} ({}): {}!{}()\n",
                sourceInfo->FileName, sourceInfo->LineNumber, moduleName,
                functionName);
        }
        else
        {
            w.write(L"    {} ({}): {}!{}() + 0x{:X} bytes\n",
                sourceInfo->FileName, sourceInfo->LineNumber, moduleName,
                functionName, displacement);
        }
    }
    else
    {
        if (displacement == 0)
        {
            w.write(L"    {}!{}()\n",
                moduleName, functionName);
        }
        else
        {
            w.write(L"    {}!{}() + 0x{:X} bytes\n",
                moduleName, functionName, displacement);
        }
    }
    DWORD NumChars = (DWORD)w.size();
    stack_line[NumChars] = '\0';
    return NumChars;
}
// 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.
//
void 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;
    }
    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);

    BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 };
    
    WCHAR callingModuleName [MAX_PATH] = L"";
    WCHAR lowerCaseName [MAX_PATH];

    const size_t max_line_length = MAXREPORTLENGTH + 1;
    m_resolvedCapacity = m_size * max_line_length;
    m_resolved = new WCHAR[m_resolvedCapacity];
    const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR);
    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];
        g_symbolLock.Enter();
        BOOL             foundline = FALSE;
        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());
        foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo);
        assert(m_resolved != NULL);

        if (foundline && !showInternalFrames) {
            wcscpy_s(lowerCaseName, sourceInfo.FileName);
            _wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1);
            if (isInternalModule(lowerCaseName)) {
                // Don't show frames in files internal to the heap.
                g_symbolLock.Leave();
                continue;
            }
        }

        // Initialize structures passed to the symbol handler.
        SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer;
        functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
        functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH;

        // Try to get the name of the function containing this program
        // counter address.
        DWORD64          displacement64 = 0;
        LPWSTR           functionName;
        DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId());
        if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) {
            functionName = functionInfo->Name;
        }
        else {
            // GetFormattedMessage( GetLastError() );
            functionName = L"(Function name unavailable)";
            displacement64 = 0;
        }
        g_symbolLock.Leave();

        HMODULE hCallingModule = GetCallingModule(programCounter);
        LPWSTR moduleName = L"(Module name unavailable)";
        if (hCallingModule && 
            GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0)
        {
            moduleName = wcsrchr(callingModuleName, L'\\');
            if (moduleName == NULL)
                moduleName = wcsrchr(callingModuleName, L'/');
            if (moduleName != NULL)
                moduleName++;
            else
                moduleName = callingModuleName;
        }

        // Use static here to increase performance, and avoid heap allocs. Hopefully this won't
        // prove to be an issue in thread safety. If it does, it will have to be simply non-static.
        static WCHAR stack_line[max_line_length] = L"";
        int NumChars = -1;
        // Display the current stack frame's information.
        if (foundline) {
            // Just truncate anything that is too long.
            if (displacement == 0)
                NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L"    %s (%d): %s!%s\n", 
                sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName);
            else
                NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L"    %s (%d): %s!%s + 0x%X bytes\n", 
                sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement);
        }
        else {
            if (displacement64 == 0)
                NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L"    " ADDRESSFORMAT L" (File and line number not available): %s!%s\n", 
                programCounter, moduleName, functionName);
            else
                NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L"    " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n", 
                programCounter, moduleName, functionName, (DWORD)displacement64);
        }

        if (NumChars >= 0) {
            assert(m_resolved != NULL);
            m_resolvedLength += NumChars;
            wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars);
        }
    } // end for loop
}
// 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);

    BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 };

    WCHAR lowerCaseName [MAX_PATH];
    WCHAR callingModuleName [MAX_PATH];

    const size_t max_size = MAXREPORTLENGTH + 1;

    // 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];
        g_symbolLock.Enter();
        BOOL             foundline = FALSE;
        DWORD            displacement = 0;
        DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId());
        foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo);
        if (foundline && !showInternalFrames) {
            wcscpy_s(lowerCaseName, sourceInfo.FileName);
            _wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1);
            if (isInternalModule(lowerCaseName)) {
                // Don't show frames in files internal to the heap.
                g_symbolLock.Leave();
                continue;
            }
        }

        // Initialize structures passed to the symbol handler.
        SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer;
        functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
        functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH;

        // Try to get the name of the function containing this program
        // counter address.
        DWORD64          displacement64 = 0;
        LPWSTR           functionName;
        DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId());
        if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) {
            functionName = functionInfo->Name;
        }
        else {
            // GetFormattedMessage( GetLastError() );
            functionName = L"(Function name unavailable)";
            displacement64 = 0;
        }
        g_symbolLock.Leave();

        HMODULE hCallingModule = GetCallingModule(programCounter);
        LPWSTR moduleName = L"(Module name unavailable)";
        if (hCallingModule && 
            GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0)
        {
            moduleName = wcsrchr(callingModuleName, L'\\');
            if (moduleName == NULL)
                moduleName = wcsrchr(callingModuleName, L'/');
            if (moduleName != NULL)
                moduleName++;
            else
                moduleName = callingModuleName;
        }

        // Use static here to increase performance, and avoid heap allocs. Hopefully this won't
        // prove to be an issue in thread safety. If it does, it will have to be simply non-static.
        static WCHAR stack_line[MAXREPORTLENGTH + 1] = L"";
        int NumChars = -1;
        // Display the current stack frame's information.
        if (foundline) {
            if (displacement == 0)
                NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L"    %s (%d): %s!%s\n", 
                sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName);
            else
                NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L"    %s (%d): %s!%s + 0x%X bytes\n", 
                sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement);
        }
        else {
            if (displacement64 == 0)
                NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L"    " ADDRESSFORMAT L" (File and line number not available): %s!%s\n", 
                programCounter, moduleName, functionName);
            else
                NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L"    " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n", 
                programCounter, moduleName, functionName, (DWORD)displacement64);	
        }

        Print(stack_line);
    }
}
Esempio n. 5
0
// 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.
//
//   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;
    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];
        if (GetCallingModule(programCounter) == g_vld.m_vldBase)
            continue;

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

        if (skipStartupLeaks) {
            if (!(m_status & (CALLSTACK_STATUS_STARTUPCRT | CALLSTACK_STATUS_NOTSTARTUPCRT))) {
                m_status |= isCrtStartupFunction(functionName);
            }
            if (m_status & CALLSTACK_STATUS_STARTUPCRT) {
                delete[] m_resolved;
                m_resolved = NULL;
                m_resolvedCapacity = 0;
                m_resolvedLength = 0;
                return 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.
        DWORD            displacement = 0;
        DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId());
        BOOL 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 (NumChars > 0 && !isFrameInternal && isPrevFrameInternal) {
            m_resolvedLength += NumChars;
            if (m_resolved) {
                wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars);
            }
        }
        isPrevFrameInternal = isFrameInternal;

        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;
}