时间:2018-09-11 16:13:05

标签: c debugging gdb

当我使用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

有人可以解释一下这里发生了什么吗?

[编辑:没有崩溃/挂起。系统正常运行]

1 个答案:

答案 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目前非常差,并且比应有的方式频繁产生“优化的价值”。