如何修复GDB 9.2函数序言参数异常问题 或在GCC 9.3中禁用该逻辑
GCC 9.3 + GDB 9.2 函数入参调试异常解决方案
问题原因
GCC 9.x版本开始默认开启CET(控制流强制技术)安全特性,编译时默认添加-fcf-protection参数,函数起始位置会插入endbr64指令,同时生成的DWARF调试信息将函数定义行的映射位置指向了整个函数序言的最开头,而非序言执行完成、参数已入栈的位置。GDB在函数行号下断点时会直接停在序言未执行的位置,此时入参还未从寄存器写入栈帧,读取到的是栈上垃圾值,依赖入参的条件断点也会因值非法触发内存访问错误。
你遇到的现象完全符合该问题的特征:
函数入口读取参数为垃圾值,执行完首条语句后参数恢复正常:
Thread 3 "lexe.inc.exe" hit Breakpoint 1, bitGenNode (T=0x0, Gen=0x0, Node=0x0) at ../bitGen/bitGen.c:433 433 fct void bitGenNode(void* T, bitGen* Gen, bitNode* Node) { (gdb) p Node $2 = (bitNode *) 0x0 (gdb) n 434 mySubProc(T, Gen, Node); (gdb) p Node $3 = (bitNode *) 0x7ffff5958d50条件断点触发时会报内存访问错误:
Error in testing breakpoint condition: Cannot access memory at address 0x8
解决方案
方案1:GDB端配置(无需重新编译程序)
打开GDB的函数断点自动跳过序言配置,所有函数断点都会自动停在序言执行完成、参数可用的位置,条件断点也会在此位置才进行校验:
- 单次调试生效:进入GDB后执行命令
set breakpoint function-end-prologue on - 永久生效:将上述命令写入
~/.gdbinit配置文件,所有GDB调试会话自动生效。
如果需要临时给单个函数设置带条件的断点,也可以使用断点自动执行命令实现:
# 先打函数断点 break bitGenNode # 给刚才打的断点(假设是1号断点)设置自动执行逻辑 commands 1 # 自动执行完序言,跳转到第一行C语句位置 next # 在此处校验你的条件 if Node == 0x7ffff5958d50 # 条件满足则停留,不做额外操作 else # 条件不满足自动继续运行 continue end end
方案2:GCC编译参数调整(永久修复调试信息映射)
编译时添加额外参数关闭CET特性,生成传统结构的函数序言:
在原有-g -O0编译参数基础上,新增-fcf-protection=none参数,示例编译命令:gcc -g -O0 -fcf-protection=none your_code.c -o your_output
如果仍有异常,可以额外添加-fno-omit-frame-pointer显式保留帧指针,确保调试信息映射正确。调整参数重新编译后,函数断点默认停在参数可用的位置,无需额外GDB配置即可正常读取参数、使用条件断点。
内容的提问来源于stack exchange,提问作者Bernd Elkemann
相关产品推荐
相关产品推荐

