首页 > 其他分享 >利用DbgHelp获取线程的栈回溯信息

利用DbgHelp获取线程的栈回溯信息

时间:2022-09-25 16:59:30浏览次数:33  
标签:回溯 SYMBOL DbgHelp stackFrame 线程 Mode context Offset AddrModeFlat

 

#include <iostream>
#include <Windows.h>
#include <process.h>
#include <DbgHelp.h>

#pragma comment(lib, "Dbghelp.lib")

using std::cout;
using std::endl;

HANDLE g_hThread = INVALID_HANDLE_VALUE;

void StackTrack()
{
    HANDLE hCurProcess = GetCurrentProcess();
    if(FALSE == SymInitialize(hCurProcess, NULL, TRUE))
    {
        cout << "SymInitialize fail. LastError: 0x" << std::hex << GetLastError();
        return;
    }

    if (0xFFFFFFFF == SuspendThread(g_hThread))
    {
        cout << "SuspendThread fail. LastError: 0x" << std::hex << GetLastError();
        return;
    }

    CONTEXT context;
    context.ContextFlags = CONTEXT_FULL;
    if (FALSE == GetThreadContext(g_hThread, &context))
    {
        cout << "GetThreadContext fail. LastError: 0x" << std::hex << GetLastError();
        return;
    }

    DWORD machineType = IMAGE_FILE_MACHINE_I386;    // 机器Cpu类型

    STACKFRAME stackFrame = { 0 };
#ifdef _M_IX86
    machineType = IMAGE_FILE_MACHINE_I386;
    stackFrame.AddrPC.Offset = context.Eip;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context.Esp;
    stackFrame.AddrStack.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context.Ebp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
#elif _M_X64
    machineType = IMAGE_FILE_MACHINE_AMD64;
    stackFrame.AddrPC.Offset = context->Rip;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context->Rsp;
    stackFrame.AddrStack.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context->Rsp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
#elif _M_IA64
    machineType = IMAGE_FILE_MACHINE_IA64;
    stackFrame.AddrPC.Offset = context->StIIP;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context->IntSp;
    stackFrame.AddrStack.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context->IntSp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    stackFrame.AddrBStore.Offset = context->RsBSP;
    stackFrame.AddrBStore.Mode = AddrModeFlat;
#else
#error "platform not supported!"
#endif

    typedef struct tag_SYMBOL_INFO
    {
        IMAGEHLP_SYMBOL symInfo;
        TCHAR szBuffer[MAX_PATH];
    } SYMBOL_INFO, * LPSYMBOL_INFO;

    decltype(stackFrame.AddrPC.Offset) dwDisplament = 0;
    DWORD dwDis32 = 0;
    SYMBOL_INFO stack_info = { 0 };
    PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&stack_info;
    pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
    pSym->MaxNameLength = sizeof(SYMBOL_INFO) - offsetof(SYMBOL_INFO, symInfo.Name);
    IMAGEHLP_LINE ImageLine = { 0 };
    ImageLine.SizeOfStruct = sizeof(IMAGEHLP_LINE);

    while (TRUE == StackWalk(
        machineType,
        hCurProcess,
        g_hThread,
        &stackFrame,
        &context,
        NULL,
        SymFunctionTableAccess,
        SymGetModuleBase,
        NULL)
        )
    {
        if (FALSE == SymGetSymFromAddr(hCurProcess, stackFrame.AddrPC.Offset, &dwDisplament, pSym))
        {
            cout << "SymGetSymFromAddr fail. LastError: 0x" << std::hex << GetLastError();
            //continue;
        }
        if (FALSE == SymGetLineFromAddr(hCurProcess, stackFrame.AddrPC.Offset, &dwDis32, &ImageLine))
        {
            cout << "SymGetLineFromAddr fail. LastError: 0x" << std::hex << GetLastError();
            //continue;
        }

        printf("当前调用函数 :(FILE[%s]LINE[%d]) %08x + %s \n",
            ImageLine.FileName, ImageLine.LineNumber, pSym->Address, pSym->Name);
    }

    if (0xFFFFFFFF == ResumeThread(g_hThread))
    {
        cout << "ResumeThread fail. LastError: 0x" << std::hex << GetLastError();
        return;
    }

    if (FALSE == SymCleanup(hCurProcess))
    {
        cout << "SymCleanup fail. LastError: 0x" << std::hex << GetLastError();
    }

    return;
}


void func1()
{
    Sleep(10 * 1000);
}

void func2()
{
    func1();
}

void func3()
{
    func2();
}

unsigned _stdcall ThreadTestStack(void* lpArgList)
{
    func3();
    return 0;
}

int main(int argc, char* argv[])
{
    unsigned uThreadID = 0;
    g_hThread = (HANDLE)_beginthreadex(NULL, 0, &ThreadTestStack, NULL, 0, &uThreadID);
    if (INVALID_HANDLE_VALUE == g_hThread)
    {
        cout << "_beginthreadex fail." << endl;
        return 0;
    }

    Sleep(1 * 1000);

    StackTrack();

    return 0;
}
View Code

 

标签:回溯,SYMBOL,DbgHelp,stackFrame,线程,Mode,context,Offset,AddrModeFlat
From: https://www.cnblogs.com/Arthurian/p/15722991.html

相关文章

  • 线程安全问题的产生条件、解决方式
    1、线程安全的产生条件■线程安全问题概念:多个线程在并发下执行,对共享数据进行访问,造成执行结果不一致的情况。线程安全产生前提:存在多个线程、并发执行(线程之间......
  • MySQL维护之连接数、线程等
    实际生产维护中可能还会查看如下内容:1、如何在MySQL中查询OS线程id(LWP轻量级线程)?OS系统提供ps-Lfpid命令查看LWP;在performance_schema.threads中有......
  • 线程同步(线程锁)
    多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)但是当线程需要共享数据时,可能存在数据不同步的问题。为了避免这种情况,引入了锁的概念。1lock=threading.Lo......
  • 线程和进程的关系?js为什么是单线程的?
    一、线程是包含在进程中的,线程其实就是一个指令序列,如果加上计算机分配给它的资源(如内存等)之后就是一个进程。二、可以设想一个场景,js适用于多线程,如果几个线程同时对一个......
  • Python使用事件循环创建线程池和进程池
    1、来源参考参考官方文档示例:https://docs.python.org/3.9/library/asyncio-eventloop.html#asyncio.loop.run_in_executor2、代码示例1#-*-coding:utf-8-*-2......
  • Ubuntu 进程 线程 查看 设置(top taskset)
    目录toptop详解及使用top常用的命令tasksettaskset的基本使用1.显示某个进程(线程)运行所在的核2.设置某个进程(线程)运行的核top主要用于查看Linux系统中的所有......
  • 如何优雅转换且避免线程不安全的问题
    一、常见时间格式化方式publicstaticvoidmain(String[]args){Datenow=newDate();//创建一个Date对象,获取当前时间StringstrDateFormat="yyyy-MM......
  • UEC++ 多线程(一) FRunnable
    虚幻官方文档:https://docs.unrealengine.com/5.0/en-US/API/Runtime/Core/HAL/FRunnable/FRunnable“runnable”对象的接口。可运行对象是在任意线程上“运行”的对象......
  • 线程池
    Java内置线程池线程池有几个核心参数:1、核心线程数2、最大线程数3、阻塞队列1、线程池创建时,不会创建线程。2、当有任务到来时,如果当前执行线程数少于核心线程数,会......
  • 进程与线程
     程序的概念:程序是指令和数据的有序集合,其本身没有任何运行的含义,程序是静态的。什么是进程?进程是程序在处理器上的一次执行过程,它是一个动态的概念。进程是......