SymGetSymFromAddr64仅显示DLL符号,自有代码符号无法获取求助
解决MinGW编译下SymGetSymFromAddr64/SymGetLineFromAddr64无法获取自有代码符号的问题
问题描述
在X64架构机器上调用SymGetSymFromAddr64和SymGetLineFromAddr64打印调用栈,输出如下:
调用栈(MAIN线程): #0 at (null):0 #1 at (null):0 #2 at (null):0 #3 at (null):0 #4 BaseThreadInitThunk at (null):0 #5 RtlUserThreadStart at (null):0
仅能获取系统DLL的符号,自有代码符号无法返回,SymGetLineFromAddr64完全失效,调用失败时返回“Attempt to access invalid address”错误。代码通过MinGW环境下gcc -g编译。
相关代码:
HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); SymInitialize (process, NULL, true); SymSetOptions (SymGetOptions() | SYMOPT_LOAD_LINES); DWORD image_file = IMAGE_FILE_MACHINE_AMD64; STACKFRAME64 sf = { .AddrPC = { .Mode = AddrModeFlat, .Offset = thread_ctx.Rip }, .AddrStack = { .Mode = AddrModeFlat, .Offset = thread_ctx.Rsp }, .AddrFrame = { .Mode = AddrModeFlat, .Offset = thread_ctx.Rbp } }; int frame=0; while (StackWalk64 (image_file, process, thread, &sf, &thread_ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL) && sf.AddrPC.Offset) { union symbol { IMAGEHLP_SYMBOL64; char data[sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME]; } symbol = { { .SizeOfStruct = sizeof (union symbol), .MaxNameLength = MAX_SYM_NAME } }; DWORD64 displacement = 0; SymGetSymFromAddr64 (process, sf.AddrPC.Offset, &displacement, (PIMAGEHLP_SYMBOL64)&symbol); IMAGEHLP_LINE64 line = { .SizeOfStruct = sizeof (IMAGEHLP_LINE64) }; DWORD displacement2 = 0; SymGetLineFromAddr64 (process, sf.AddrPC.Offset, &displacement2, &line); fprintf (stderr, "#%u %s at %s:%u\n", frame++, symbol.Name, line.FileName, (uint32_t)line.LineNumber); } CloseHandle (thread); SymCleanup (process);
解决思路
修正符号生成格式与路径
MinGW默认用DWARF格式符号,但Windows DbgHelp API优先支持COFF或PDB格式。编译时添加-gcoff生成COFF符号,或用cv2pdb工具将DWARF符号转换为PDB格式;确保符号文件与可执行文件同目录,或在SymInitialize第二个参数指定符号搜索路径。调整符号初始化顺序
当前先初始化符号库再设置行加载选项,导致选项未生效。正确顺序是先设置选项再初始化:SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_DEBUG); // SYMOPT_DEBUG可排查加载问题 BOOL init_ok = SymInitialize(process, NULL, TRUE); if (!init_ok) { // 用GetLastError()获取初始化失败原因 }验证栈遍历返回的地址有效性
错误提示“无效地址”可能是StackWalk64返回的地址不属于当前进程模块。循环中可先检查地址所属模块:DWORD64 module_base = SymGetModuleBase64(process, sf.AddrPC.Offset); if (module_base == 0) { fprintf(stderr, "#%u 无效地址: 0x%llX\n", frame++, sf.AddrPC.Offset); continue; }添加错误调试输出
调用符号函数后,通过GetLastError()获取具体错误码,定位问题根源:if (!SymGetSymFromAddr64(process, sf.AddrPC.Offset, &displacement, (PIMAGEHLP_SYMBOL64)&symbol)) { DWORD err = GetLastError(); fprintf(stderr, "SymGetSymFromAddr64失败,错误码: %lu\n", err); }
内容的提问来源于stack exchange,提问作者Divon
相关产品推荐
相关产品推荐

