• 【WIN32】C++在打印Windows中调用堆栈信息


    C++在打印Windows中调用堆栈信息

    关键函数

    GetCurrentProcess

    返回当前进程的伪句柄
    伪句柄是一个特殊常量,当前 (HANDLE) -1,被解释为当前进程句柄。 为了与将来的操作系统兼容,最好调用 GetCurrentProcess ,而不是硬编码此常量值。 每当需要进程句柄时,调用进程都可以使用伪句柄来指定自己的进程。 伪句柄不由子进程继承

    SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)

    初始化进程的符号处理
    hProcess标识调用方的句柄
    UserSearchPath用于搜索符号文件的路径或用分号分隔的路径系列。 如果此参数为 NULL,则库将尝试从以下源形成符号路径:

    • 应用程序的当前工作目录
    • _NT_SYMBOL_PATH 环境变量
    • _NT_ALTERNATE_SYMBOL_PATH 环境变量

    fInvadeProcess如果为 TRUE,则枚举进程的加载模块,并有效地为每个模块调用 SymLoadModule64 函数

    如果函数成功,则返回值为 TRUE。
    如果函数失败,则返回值为 FALSE。

    CaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash)

    通过向上浏览堆栈并记录每个帧的信息来捕获堆栈回跟踪。
    FramesToSkip 标识要从回溯开始跳过的帧数
    FramesToCapture要捕获的帧数。 最多可以捕获 MAXUSHORT 帧
    Windows Server 2003 和 Windows XP:FramesToSkip 和 FramesToCapture 参数的总和必须小于 63。
    BackTrace标识从当前堆栈跟踪捕获的指针数组。
    BackTraceHash标识可用于组织哈希表的值。 如果此参数为 NULL,则不计算哈希值。
    此值是根据 BackTrace 数组中返回的指针的值计算的。 两个相同的堆栈跟踪将生成相同的哈希值。

    返回
    捕获的帧数。

    SymFromAddr(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol)

    检索指定地址的符号信息
    hProcess进程的句柄。此句柄必须以前传递给 SymInitialize 函数。
    Address符号应位于的地址。地址不必位于符号边界上。如果地址位于符号的开头之后和符号的末尾之前,则会找到该符号。
    Displacement符号开头的位移,或零。
    Symbol指向 SYMBOL_INFO 结构的指针,该结构提供有关符号的信息。 符号名称的长度可变;因此,此缓冲区必须足够大,才能保存存储在 SYMBOL_INFO 结构末尾的名称。 请务必将 MaxNameLen 成员设置为为名称保留的字节数。

    #include 
    #include 
    #include 
    
    #if _MSC_VER
    #define snprintf _snprintf
    #endif
    
    #define STACK_INFO_LEN  1024
    
    void ShowTraceStack(char* szBriefInfo)
    {
        static const int MAX_STACK_FRAMES = 12;
        void *pStack[MAX_STACK_FRAMES];
        static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES];
        static char szFrameInfo[STACK_INFO_LEN];
    
        HANDLE process = GetCurrentProcess();
        SymInitialize(process, NULL, TRUE);
        WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, NULL);
        strcpy(szStackInfo, szBriefInfo == NULL ? "stack traceback:\n" : szBriefInfo);
    
        for (WORD i = 0; i < frames; ++i) {
            DWORD64 address = (DWORD64)(pStack[i]);
    
            DWORD64 displacementSym = 0;
            char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME * sizeof(TCHAR)];
            PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
            pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
            pSymbol->MaxNameLen = MAX_SYM_NAME;
    
            DWORD displacementLine = 0;
            IMAGEHLP_LINE64 line;
            line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
    
            if (SymFromAddr(process, address, &displacementSym, pSymbol) && 
            	SymGetLineFromAddr64(process, address, &displacementLine, &line))
            {
                snprintf(szFrameInfo, sizeof(szFrameInfo), "\t%s() at %s:%d(0x%x)\n", 
                	pSymbol->Name, line.FileName, line.LineNumber, pSymbol->Address);
            }
            else
            {
                snprintf(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError());
            }
            strcat(szStackInfo, szFrameInfo);
        }
    
        printf("%s", szStackInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    HTML 语义化:构建优质网页的关键
    选择屏幕2
    期货交易如何定义趋势?
    【MySQL】操作日期类型字段的函数方法
    视频怎么加水印?这里有你想要的答案
    R语言ggplot2可视化:ggcharts包的bar_chart函数可视化条形图、bar_chart函数自动排序条形图并水平显示
    Vue中的过滤器 Filters
    HDLbits:Dff16e
    12.验证码以及付费代理
    Elesticsearch使用总结
  • 原文地址:https://blog.csdn.net/weixin_38734534/article/details/133302014