AVR调试时avr-gdb无法正确识别局部变量tmpx10、rhx10求助
8位AVR调试中局部变量无法正确查看的问题分析
我在8位AVR控制器上使用编译选项-g -ggdb -gstabs -Og编译代码,调试以下函数:
usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *req = (void *)data; if (req->bRequest == CUSTOM_REQ_TMP) { // 温度(℃)乘以10 int16_t tmpx10 = (mVAvgTmp >> EWMA_BS) - 500; // 相对湿度(%)乘以10 uint32_t rhx10 = (mvAvgRh * 100 - (75750 << EWMA_BS)) / (318 << EWMA_BS); static char msg[16]; snprintf(msg, sizeof(msg), "%d|%ld", tmpx10, rhx10); usbMsgPtr = (usbMsgPtr_t)msg; asm("break"); return sizeof(msg); } // 未实现的请求返回空数据 return 0; }
当执行停在手动插入的asm("break");指令处时,avr-gdb能正确打印出msg的值,其中包含tmpx10和rhx10的正确计算结果:
(gdb) p msg $1 = "200|528\000\000\000\000\000\000\000\000"
但直接打印tmpx10会得到错误值,打印rhx10则提示符号不存在:
(gdb) p tmpx10 $2 = 116 (gdb) p rhx10 No symbol "rhx10" in current context.
尽管这两个变量和msg处于同一作用域,问题根源在于**-Og编译选项带来的轻量优化**:
-Og是GCC专为调试设计的优化选项,它会在尽量不影响调试的前提下做代码优化,但依然会对局部变量进行处理:比如将变量直接存放在寄存器中、使用后立即释放寄存器资源,甚至直接把变量的计算结果内联到后续函数调用(如snprintf)中,不再保留独立的变量符号。tmpx10的符号虽然还在,但它的存储位置已经被复用或寄存器被覆盖,所以gdb读取到错误值;rhx10则因为被完全内联到snprintf的参数里,编译器直接删除了该变量的符号表条目,导致gdb无法找到它。- 而
msg是静态数组,存储在全局数据区,不会被优化掉,因此能正常查看。
解决方法
- 全局禁用优化:将编译选项中的
-Og替换为-O0,彻底关闭所有优化,这样所有局部变量的符号和存储都会被完整保留,调试时可正常查看变量值。 - 针对单个变量禁用优化:如果不想全局关闭优化,可以给目标变量添加
volatile修饰符,强制编译器保留变量的内存存储和符号信息:volatile int16_t tmpx10 = (mVAvgTmp >> EWMA_BS) - 500; volatile uint32_t rhx10 = (mvAvgRh * 100 - (75750 << EWMA_BS)) / (318 << EWMA_BS); - 保留调试符号:添加编译选项
-fno-eliminate-unused-debug-symbols,强制编译器保留所有调试符号,即使变量被优化,gdb至少能找到符号(不过变量值可能依然不准确,因为存储已被复用)。
内容的提问来源于stack exchange,提问作者Torsten Römer
相关产品推荐
相关产品推荐

