棧回溯,x86+x64
阿新 • • 發佈:2020-09-14
如果需要配合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 \n", 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 }