// 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);
    }
}
Exemple #2
0
// 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);
    }
}