在gdb中,变量显示为<optimized out>,如何找到其值?

Wor*_*eek 6 c optimization gdb dwarf

在gdb中,我如何发现显示为优化输出的变量的值?大概该值存储在一个寄存器中,我如何找出哪个?给出这个简单的程序(从下面的网站复制)。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int foo = rand();
    printf("foo is %d\n", foo++);
    return foo;
}
Run Code Online (Sandbox Code Playgroud)

进行优化编译。

gcc -O3 -g optimized.c
gdb a.out
Run Code Online (Sandbox Code Playgroud)

运行GDB

(gdb) print foo
$1 = <optimized out>
Run Code Online (Sandbox Code Playgroud)

到底是怎么回事?该变量foo必须存在于某处,但如何找到它的值或将其存储在何处?

我找到了一个页面,该页面详细说明了DWARF调试信息如何用于优化代码https://undo.io/resources/gdb-watchpoint/build-for-debug-in-gdb。使用那里的建议,我最终可以找到分配给foo它的寄存器,但是这很痛苦。

如何让gdb告诉我要观看哪个寄存器?

我尝试使用-g3进行编译,但这没有帮助。

我在gdb中尝试了一些命令也没有帮助。

ptype foo
info locals
print &foo
Run Code Online (Sandbox Code Playgroud)

Emp*_*ian 1

变量 foo 必须存在于某处

不必要。如果方便的话,编译器可以存储从变量派生的foo+1一些值(例如或)。foo-23

在这种特殊情况下,由于foo被传递给printf,如果您知道特定平台的调用约定,您可以在寄存器或堆栈中发现它。

但我如何找到它的值或它存储在哪里?

目前,调试优化代码需要大量技能、ABI 知识以及所使用的汇编指令。

问题在于,出于调试目的,编译器很少通过寄存器内和内存中的位置准确跟踪值,因为这样做非常困难。

调试器还必须正确解释编译器生成的调试信息,这也不是一个简单或没有错误的过程。

GCC 最近在该领域取得了很大进步。在 Linux x86_64 上使用gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)Fedora 31,我观察到:

(gdb) start
Temporary breakpoint 1 at 0x401050: file t.c, line 6.
Starting program: /tmp/a.out 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.30-5.fc31.x86_64

Temporary breakpoint 1, main () at t.c:6
6       int foo = rand();
(gdb) n
7       printf("foo is %d\n", foo++);
(gdb) p foo
$1 = 1804289384
(gdb) p &foo
Can't take address of "foo" which isn't an lvalue.
(gdb) c
Continuing.
foo is 1804289383
[Inferior 1 (process 2696) exited with code 0150]
(gdb) q
Run Code Online (Sandbox Code Playgroud)

在这里您可以看到gcc描述了寄存器中的位置foo(或非内存的其他位置),并且GDB能够打印几乎的值foo