Stack Trace для бедных :)
От: Tom Россия http://www.RSDN.ru
Дата: 23.08.05 10:44
Оценка: 14 (3)
Понадобилось самое простое решение данной задачи.
class StackTraceEngine
{
public:
    HMODULE m_hDbhHelp;
    HANDLE m_hProcess;

    // SymGetLineFromAddr64()
    typedef BOOL (__stdcall *tfnSymGetLineFromAddr64)( IN HANDLE hProcess, IN DWORD64 dwAddr,
        OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
    tfnSymGetLineFromAddr64 pfnSymGetLineFromAddr64;

    // SymGetSymFromAddr64()
    typedef BOOL (__stdcall *tfnSymGetSymFromAddr64)( IN HANDLE hProcess, IN DWORD64 dwAddr,
        OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
    tfnSymGetSymFromAddr64 pfnSymGetSymFromAddr64;

    // SymInitialize()
    typedef BOOL (__stdcall *tfnSymInitialize)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
    tfnSymInitialize pfnSymInitialize;

    // SymSetOptions()
    typedef DWORD (__stdcall *tfnSymSetOptions)( IN DWORD SymOptions );
    tfnSymSetOptions pfnSymSetOptions;

    // StackWalk64()
    typedef BOOL (__stdcall *tfnStackWalk64)( 
        DWORD MachineType, 
        HANDLE hProcess,
        HANDLE hThread, 
        LPSTACKFRAME64 StackFrame, 
        PVOID ContextRecord,
        PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
        PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
        PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
        PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
    tfnStackWalk64 pfnStackWalk64;

    // UnDecorateSymbolName()
    typedef DWORD (__stdcall WINAPI *tfnUnDecorateSymbolName)( PCSTR DecoratedName, PSTR UnDecoratedName,
        DWORD UndecoratedLength, DWORD Flags );
    tfnUnDecorateSymbolName pfnUnDecorateSymbolName;
    
    // SymFunctionTableAccess64()
    typedef PVOID (__stdcall *tfnSymFunctionTableAccess64)( HANDLE hProcess, DWORD64 AddrBase );
    tfnSymFunctionTableAccess64 pfnSymFunctionTableAccess64;

    // SymGetModuleBase64()
    typedef DWORD64 (__stdcall *tfnSymGetModuleBase64)( IN HANDLE hProcess, IN DWORD64 dwAddr );
    tfnSymGetModuleBase64 pfnSymGetModuleBase64;

    StackTraceEngine(HANDLE hProcess) :
        m_hDbhHelp(0),
        m_hProcess(hProcess),
        pfnSymGetLineFromAddr64(0),
        pfnSymGetSymFromAddr64(0),
        pfnSymInitialize(0),
        pfnSymSetOptions(0),
        pfnStackWalk64(0),
        pfnUnDecorateSymbolName(0),
        pfnSymFunctionTableAccess64(0),
        pfnSymGetModuleBase64(0)
    {
    }

    HRESULT Init()
    {
        BOOL Ret;

        //
        // Load dbghelp.dll dynamically.
        //
        if ((m_hDbhHelp = LoadLibrary(L"dbghelp.dll")) == 0)
        {
            return HRESULT_FROM_WIN32(GetLastError());
        }

        //
        // Load procedures.
        //
        pfnSymInitialize = (tfnSymInitialize) GetProcAddress(m_hDbhHelp, "SymInitialize" );
        pfnStackWalk64 = (tfnStackWalk64) GetProcAddress(m_hDbhHelp, "StackWalk64" );
        pfnSymGetLineFromAddr64 = (tfnSymGetLineFromAddr64) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );
        pfnSymGetSymFromAddr64 = (tfnSymGetSymFromAddr64) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );
        pfnUnDecorateSymbolName = (tfnUnDecorateSymbolName) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );
        pfnSymFunctionTableAccess64 = (tfnSymFunctionTableAccess64) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );
        pfnSymGetModuleBase64 = (tfnSymGetModuleBase64) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );
        pfnSymSetOptions = (tfnSymSetOptions) GetProcAddress(m_hDbhHelp, "SymSetOptions" );

        if ((pfnSymInitialize == 0) ||
            (pfnStackWalk64 == 0) ||
            (pfnSymGetLineFromAddr64 == 0) ||
            (pfnSymGetSymFromAddr64 == 0) ||
            (pfnUnDecorateSymbolName == 0) ||
            (pfnSymFunctionTableAccess64 == 0) ||
            (pfnSymGetModuleBase64 == 0) ||
            (pfnSymSetOptions == 0))
        {
            FreeLibrary(m_hDbhHelp);
            m_hDbhHelp = 0;
            return E_UNEXPECTED;
        }

        //
        // Initialize symbols engine.
        //
        if ((Ret = pfnSymSetOptions(SYMOPT_LOAD_LINES)) == FALSE)
        {
            return HRESULT_FROM_WIN32(GetLastError());
        }

        if ((Ret = pfnSymInitialize(
            m_hProcess,
            0,
            TRUE)) == FALSE)
        {
            return HRESULT_FROM_WIN32(GetLastError());
        }

        return S_OK;
    }

    HRESULT WalkStack(
        char* StackTrace,
        DWORD StackTraceSize)
    {
        if ((StackTrace == 0) ||
            (IsBadWritePtr(StackTrace, StackTraceSize)))
        {
            return E_INVALIDARG;
        }

        //
        // Init out parameters.
        //
        StackTrace[0] = '\0';

        //
        // The following should be enough for walking the call stack...
        //
        CONTEXT ctx = {0};

        __asm    call x;
        __asm x: pop eax;
        __asm    mov ctx.Eip, eax;
        __asm    mov ctx.Ebp, ebp;
        __asm    mov ctx.Esp, esp;

        //
        // Init STACKFRAME for the first call
        //
        STACKFRAME64 stfrm = {0}; // in/out stackframe
        stfrm.AddrPC.Offset = ctx.Eip;
        stfrm.AddrPC.Mode = AddrModeFlat;

        stfrm.AddrFrame.Offset = ctx.Ebp;
        stfrm.AddrFrame.Mode = AddrModeFlat;

        stfrm.AddrStack.Offset = ctx.Esp;
        stfrm.AddrStack.Mode = AddrModeFlat;

        //
        // Symbol info memory buffer.
        //
        char SymbolBuffer[65535] = {0};
        IMAGEHLP_SYMBOL64 *pSymbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&SymbolBuffer);
        pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);

        DWORD SymbolNameSize = (DWORD)sizeof(SymbolBuffer) - offsetof(IMAGEHLP_SYMBOL64, Name);
        pSymbol->MaxNameLength = SymbolNameSize;

        HANDLE hCurrentThread = GetCurrentThread();

        //
        // Line info.
        //
        IMAGEHLP_LINE64 Line = {0};
        Line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

        while(true)
        {
            //
            // IMAGE_FILE_MACHINE_I386 is only supported now.
            // I have no other platforms to check this code :(
            //
            pfnStackWalk64(
                IMAGE_FILE_MACHINE_I386,
                m_hProcess,
                hCurrentThread,
                &stfrm,
                &ctx,
                0,
                pfnSymFunctionTableAccess64,
                pfnSymGetModuleBase64,
                0);

            if (stfrm.AddrPC.Offset == 0)
                break;

            //
            // Get procedure info.
            //
            DWORD64 SymbolDisplacement = 0;
            pfnSymGetSymFromAddr64(
                m_hProcess,
                stfrm.AddrPC.Offset,
                &SymbolDisplacement,
                pSymbol);

            //
            // Get line info.
            //
            DWORD LineDisplacement = 0;
            pfnSymGetLineFromAddr64(
                m_hProcess,
                stfrm.AddrPC.Offset,
                &LineDisplacement,
                &Line);

            //
            // Format and store current frame.
            //
            size_t SymbolNameRealSize = 0;
            StringCchLengthA(
                pSymbol->Name,
                SymbolNameSize,
                &SymbolNameRealSize);

            //
            // Append symbol name.
            //
            if (SymbolNameRealSize == 0)
            {
                StringCchCatA(
                    StackTrace,
                    StackTraceSize,
                    "Procedure: <unknown>");
            }
            else
            {
                char buff[16384];
                StringCchPrintfA(
                    buff,
                    sizeof(buff),
                    "Procedure: %s",
                    pSymbol->Name);

                StringCchCatA(
                    StackTrace,
                    StackTraceSize,
                    buff);
            }

            //
            // Append symbol location
            //
            if (Line.FileName[0] == 0)
            {
                StringCchCatA(
                    StackTrace,
                    StackTraceSize,
                    ", File: <unknown>, Line: <unknown>\n");
            }
            else
            {
                char buff[16384];
                StringCchPrintfA(
                    buff,
                    sizeof(buff),
                    " , File: %s, Line: %d\n",
                    Line.FileName,
                    Line.LineNumber);

                StringCchCatA(
                    StackTrace,
                    StackTraceSize,
                    buff);
            }
        }

        return S_OK;
    }
};


Применять примерно так:
void DoStackTrace(void)
{
    HANDLE hProcess = OpenProcess(
        PROCESS_ALL_ACCESS,
        FALSE,
        GetCurrentProcessId());

    StackTraceEngine se(hProcess);
    se.Init();

    char buff[65535];
    se.WalkStack(
        buff,
        sizeof(buff));
    printf("%s", buff);
}


как альтернативу смотреть:
http://www.codeproject.com/threads/StackWalker.asp

Мне он не подошёл обьёмом. ~1200 строк.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.