|
1. 调试器是如何实现栈回溯的?
因为函数调用指令会将函数的返回地址记录在栈上,因此可以通过从栈顶向下遍历每个栈帧来追溯函数调用的过程。
知识背景
1.源代码级调试、栈回溯、按名称显示变量等功能的实现,都离不开调试符号。
2.调试符号是在编译器在将源文件编译为可执行程序的过程中,为支持调试而摘录的调试信息。调试信息包括变量,类型,函数名,源代码行等。
3.PDB,ProgramDataBase, 微软用于描述源程序的数据库。
4.可以通过DbgHelp函数库或者DIASDK两种方式来访问调试符号文件中的符号。
5.栈帧就是利用寄存器访问栈内局部变量、参数、函数返回地址等的手段。指向每个栈帧的指针被称为帧指针。遍历整个栈中的所有栈帧,便可以得到函数调用序列。
在通过DbgHelp函数库返回地址对应的符号,便可以得到栈回溯信息。
以下是我在文件夹中找到的dbghelp.dll的身影。
X64dbg
OllyDbg
接下来是我在其它地方学习来的的代码
[C++] 纯文本查看 复制代码#include #include #include #include#include#pragma comment(lib, "dbghelp.lib")bool PrintCallStackBackTrace() { DWORD options = SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES; SymSetOptions(options); CONTEXT context = { 0 }; RtlCaptureContext(&context); STACKFRAME64 stack = { 0 }; stack.AddrPC.Offset = context.Eip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Esp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Ebp; stack.AddrFrame.Mode = AddrModeFlat; std::vector backtrace; std::string path = R"(SRV*D:\symbols*https://msdl.microsoft.com/download/symbols)"; BOOL result = SymInitialize(GetCurrentProcess(), path.c_str(), TRUE); if (!result) { DWORD error = GetLastError(); std::cout |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|