当我使用GDB调试问题时,遇到了这种奇怪的行为。为此,我无法用任何合乎逻辑的答案说服自己。
下面是由于函数开始处的断点而获得的调用堆栈的快照(为简单起见,我将堆栈帧限制为3级)。
(gdb)
#0 hashset_get (hashset=<value optimized out>, item_key=0x7fffd7e4f5b8)
at /xxx/yyy/zzz/hashset.c:123
#1 0x00007fffed855d00 in hashmap_get (hashmap=<value optimized out>, key=0x7fffd7e4f648)
at /xxx/yyy/zzz/hashmap.c:789
#2 0x00007ffa589d8eeb in hashmap_get_value (hashmap=0x7ff9d82d1b78, key=0x7fffd7e4f648)
at /xxx/yyy/zzz/hashmap.c:456
此后,将执行一个单步执行。稍后的堆栈框架如下所示-
(gdb) bt
#0 hashset_get (hashset=0xf8f8f8f8f8f8f8f8, item_key=0x7fffd7e4f5b8)
at /xxx/yyy/zzz/hashset.c:125
#1 0x00007fffed855d00 in hashmap_get (hashmap=<value optimized out>, key=0x7fffd7e4f648)
at /xxx/yyy/zzz/hashmap.c:789
#2 0x00007ffa589d8eeb in hashmap_get_value (hashmap=0x7ff9d82d1b78, key=0x7fffd7e4f648)
at /xxx/yyy/zzz/hashmap.c:456
我知道,当GDB将任何变量显示为“ 值优化输出”时,它表明其值存储在寄存器中,而不是存储在堆栈帧中。
但是,在这种情况下,最初显示为“ 值优化输出”的参数hashset
后来更改为某个地址位置-0xf8f8f8f8f8f8f8f8
。那是否意味着它最初已将hashset
存储在寄存器中,然后在堆栈帧上创建了一个空间?
此地址看起来与其他任何内存位置地址都不一样。您可以在地址中看到一些模式(例如f8f8 ...)
为了使事实更加混乱,如果我尝试在该位置打印数据,GDB的输出如下-
(gdb) p *hashset
Cannot access memory at address 0xf8f8f8f8f8f8f8f8
我尝试了更多尝试,希望它有助于理解这种行为。
我为0x7fffd7e4f5b8
分配了一个有效地址item_key
(由参数hashset
持有)
(gdb) s hashset=0x7fffd7e4f5b8
(gdb) p *hashset
Cannot access memory at address 0xb8b8b8b8b8b8b8b8
(gdb) p hashset
$6 = (hashset) 0xb8b8b8b8b8b8b8b8
但是令我惊讶的是,当我打印hashset
的值时,它显示的地址为0xb8b8b8b8b8b8b8b8
而不是0x7fffd7e4f5b8
!
有人可以解释一下这里发生了什么吗?
[编辑:没有崩溃/挂起。系统正常运行]
答案 0 :(得分:2)
我知道,当GDB将任何变量显示为“值优化输出”时,它表明其值存储在寄存器中,而不是存储在堆栈帧中。
这不是“优化价值”的意思。
这意味着:编译器未在当前程序计数器处提供此变量的位置信息。
从理论上讲,DWARF
标准足够丰富,可以描述诸如“可以通过将constant
添加到register
的值来定位此变量”或“通过添加{{ 1}}和register A
,然后将结果与register B
”进行“或”运算。实际上,很少有编译器会花这么长的时间,而只是省略了信息。
但是,在这种情况下,最初显示为“值优化输出”的arg哈希集后来被更改为某个地址位置
当您推进程序计数器时,GDB在新PC上找到了位置信息。但是解释该位置信息会产生值contents of location pointed by register C
,该值不能是0xf8f8f8f8f8f8f8f8
上指针的真实值。
由此您可以得出结论,或者位置信息不正确(很可能是编译器错误),或者GDB没有正确解释x86_64
描述(并非闻所未闻)
不幸的是,当调试优化的代码时,这样的调试工件已经成为现实。它们还依赖于GCC和GDB的确切版本-新版本通常(但并非总是如此)更好。 Clang / LLVM目前非常差,并且比应有的方式频繁产生“优化的价值”。