检索指定地址的符号信息
hProcess
进程的句柄。此句柄必须以前传递给 SymInitialize 函数。
Address
符号应位于的地址。地址不必位于符号边界上。如果地址位于符号的开头之后和符号的末尾之前,则会找到该符号。
Displacement
符号开头的位移,或零。
Symbol
指向 SYMBOL_INFO 结构的指针,该结构提供有关符号的信息。 符号名称的长度可变;因此,此缓冲区必须足够大,才能保存存储在 SYMBOL_INFO 结构末尾的名称。 请务必将 MaxNameLen 成员设置为为名称保留的字节数。
#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
#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);
snprintf(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError());
strcat(szStackInfo, szFrameInfo);
printf("%s", szStackInfo);
伪句柄是一个特殊常量,当前 (HANDLE) -1,被解释为当前进程句柄。每当需要进程句柄时,调用进程都可以使用伪句柄来指定自己的进程。指向 SYMBOL_INFO 结构的指针,该结构提供有关符号的信息。用于搜索符号文件的路径或用分号分隔的路径系列。如果地址位于符号的开头之后和符号的末尾之前,则会找到该符号。如果为 TRUE,则枚举进程的加载模块,并有效地为每个模块调用 SymLoadModule64 函数。此值是根据 BackTrace 数组中返回的指针的值计算的。符号开头的位移,或零。
文章目录前言查看函数堆栈的作用实现打印堆栈信息的函数显示堆栈调用信息总结程序源码
程序运行的过程中,函数之间的是会相互调用的,在某一时刻函数之间的调用关系,可以通过函数调用堆栈表现出来,这个调用堆栈所展现的就是函数A调用了函数B,而函数B又调用了函数C,这些调用关系在代码中都是静态的,不需要程序运行就可以知道。
既然函数之间的调用关系可以通过分析代码就可以知道,那么查看函数调用的堆栈是不是...
Win32环境下函数调用的堆栈之研究
由于阅读《Q版缓冲区溢出教程》的需要理解和掌握栈的相关知识,故而使用VC 6.0工具来研究win32环境下函数调用时具体的栈操作。
阅读本文建议先看结论,大概了解相关概念,再看第4节,更易于理解。
日常生活中,我们可以使用一句话表达不同的意思。“哦”既可以表示肯定,也可以表示疑惑。那如果想使用同一个函数名实现不同的功能,在C++中能够实现吗?那我们就得先来了解一下函数重载了。
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似、数据类型不同的问题。1.参数类型不同下面代码中,实现了两个同名的函数PrintNum,但两个函数的参数列表不同,一个参数为整型,一个参数为双精度浮点型。对于这
1.使用std::stacktrace库
在C++17标准中,引入了std::stacktrace库,可以方便地打印堆栈信息。使用该库需要编译器支持,并且需要链接对应的库文件。
示例代码:
```cpp
#include <iostream>
#include <stacktrace>
int main() {
std::cout << std::stacktrace() << std::endl;
return 0;
2.使用libunwind库
libunwind是一个轻量级的C库,用于获取堆栈信息。使用该库需要在编译时链接对应的库文件。
示例代码:
```cpp
#include <iostream>
#include <libunwind.h>
void print_trace() {
unw_cursor_t cursor;
unw_context_t context;
unw_word_t ip, sp;
// 初始化cursor和context
unw_getcontext(&context);
unw_init_local(&cursor, &context);
// 遍历堆栈信息
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
std::cout << "ip = " << ip << ", sp = " << sp << std::endl;
int main() {
print_trace();
return 0;
以上两种方法都可以打印出函数调用的堆栈信息,可以根据需要选择合适的方法。
QueryDet: Cascaded Sparse Query for Accelerating High-Resolution for Small Object Detection