• 栈回溯,x86+x64


    如果需要配合PDB符号展示栈信息,可以参考github  stackwalker项目,写的很详细了

    调用的windows api,直接上代码如下:

      1 #include <iostream>
      2 #include <vector>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <windows.h>
      6 
      7 
      8 struct STACK_FRAME_INFO {
      9     PVOID returnAddress;
     10     PVOID functionAddress;
     11     PVOID callAddress;
     12     PVOID callTargetAddress;
     13 };
     14 
     15 struct CALL_STACK_INFO {
     16     PVOID stackBottom;
     17     PVOID stackTop;
     18     DWORD dwFrameCount;
     19     STACK_FRAME_INFO* pFrameList;
     20 };
     21 
     22 typedef ULONG(WINAPI *RTLWALKFRAMECHAIN)(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags);
     23 
     24 void GetCallStackInfo(CALL_STACK_INFO& callStack, DWORD dwMaxFrame)
     25 {
     26     std::vector<STACK_FRAME_INFO> vecFrames;
     27 #ifdef _M_IX86
     28     STACK_FRAME_INFO StackFrame;
     29     std::vector<PVOID> vecRetAddr;
     30     ULONG StackCount = 0;
     31     RTLWALKFRAMECHAIN pRtlWalkFrameChain =
     32         (RTLWALKFRAMECHAIN)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlWalkFrameChain");
     33 
     34     vecRetAddr.resize(50);
     35     StackCount = pRtlWalkFrameChain(&vecRetAddr[0], vecRetAddr.size(), 0);
     36 
     37     for (ULONG i = 0;i < StackCount;i++)
     38     {
     39         RtlZeroMemory(&StackFrame, sizeof(StackFrame));
     40 
     41         if (vecRetAddr[i] == nullptr)
     42         {
     43             break;
     44         }
     45 
     46         StackFrame.returnAddress = vecRetAddr[i];
     47 
     48         vecFrames.push_back(StackFrame);
     49     }
     50 
     51 #elif (_M_X64)
     52     CONTEXT                       Context;
     53     KNONVOLATILE_CONTEXT_POINTERS NvContext;
     54     UNWIND_HISTORY_TABLE          UnwindHistoryTable;
     55     PRUNTIME_FUNCTION             RuntimeFunction;
     56     PVOID                         HandlerData;
     57     ULONG64                       EstablisherFrame;
     58     ULONG64                       ImageBase;
     59     STACK_FRAME_INFO              StackFrame;
     60 
     61     RtlCaptureContext(&Context);
     62 
     63     RtlZeroMemory(&UnwindHistoryTable, sizeof(UNWIND_HISTORY_TABLE));
     64 
     65     for (ULONG Frame = 0; Frame <= dwMaxFrame; Frame++)
     66     {
     67         RuntimeFunction = RtlLookupFunctionEntry(
     68             Context.Rip,
     69             &ImageBase,
     70             &UnwindHistoryTable
     71         );
     72 
     73         RtlZeroMemory(
     74             &NvContext,
     75             sizeof(KNONVOLATILE_CONTEXT_POINTERS));
     76         
     77         PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(ImageBase + RuntimeFunction->UnwindInfoAddress);
     78 
     79         if (!RuntimeFunction)
     80         {
     81             Context.Rip = (ULONG64)(*(PULONG64)Context.Rsp);
     82             Context.Rsp += 8;
     83         }
     84         else
     85         {
     86             RtlVirtualUnwind(
     87                 UNW_FLAG_NHANDLER,
     88                 ImageBase,
     89                 Context.Rip,
     90                 RuntimeFunction,
     91                 &Context,
     92                 &HandlerData,
     93                 &EstablisherFrame,
     94                 &NvContext);
     95         }
     96 
     97         if (!Context.Rip)
     98         {
     99             break;
    100         }
    101             
    102         RtlZeroMemory(&StackFrame, sizeof(StackFrame));
    103 
    104         StackFrame.returnAddress = (PVOID)Context.Rip;
    105         StackFrame.functionAddress = (PVOID)(ImageBase + RuntimeFunction->BeginAddress);
    106 
    107         vecFrames.push_back(StackFrame);
    108     }
    109 #endif
    110     
    111     callStack.pFrameList = (STACK_FRAME_INFO*)malloc(vecFrames.size() * sizeof(STACK_FRAME_INFO));
    112     if (!callStack.pFrameList)
    113     {
    114         callStack.dwFrameCount = 0;
    115         return;
    116     }
    117 
    118     callStack.dwFrameCount = vecFrames.size();
    119     for (DWORD dwFrame = 0; dwFrame < vecFrames.size(); dwFrame++)
    120     {
    121         RtlCopyMemory(&callStack.pFrameList[dwFrame], &vecFrames[dwFrame], sizeof(STACK_FRAME_INFO));
    122     }
    123 }
    124 
    125 void Func1()
    126 {
    127     CALL_STACK_INFO callStack;
    128     GetCallStackInfo(callStack, 100);
    129 
    130     for (DWORD dwFrame = 0; dwFrame < callStack.dwFrameCount; dwFrame++)
    131     {
    132         printf(
    133             "FRAME %02x: FuncAddrss=%p CallAddress=%p 
    ",
    134             dwFrame,
    135             callStack.pFrameList[dwFrame].functionAddress,
    136             callStack.pFrameList[dwFrame].returnAddress);
    137     }
    138 
    139 }
    140 
    141 void DumpCallStack()
    142 {
    143     Func1();
    144 }
    145 
    146 int main()
    147 {
    148     DumpCallStack();
    149 
    150     ::system("pause");
    151 }
  • 相关阅读:
    vue store状态存储管理
    Git分支管理
    oracle事务不能回滚的原因
    vue教程(四)--其他实用用法补充
    vue教程(三)-slotkeep-alive的使用
    vue教程(二)--过滤器和监视改动功能
    vue教程(一)-html使用vue
    Linux后台命令导入MySQL语句
    CentOS6下的ElasticSearch运行步骤
    浅谈JAVA代码优化
  • 原文地址:https://www.cnblogs.com/hanawasakuraki/p/13664214.html
Copyright © 2020-2023  润新知