如果 gdb 调试发现 optimized out,这个表示被编译器优化了,这个优化跟编译选项有关,gcc 有个 -O0 -O1 -O2 等编译选项,越高等级能看到的信息越少
一些发现
根据我的实验,这个编译器优化是一个动态优化,就是我同样的代码,但是我输入的参数不一样,优化就不一样(注意堆栈的 main 函数参数)
#0 0x00007ffff70255f7 in raise () from /lib64/libc.so.6
#1 0x00007ffff7026ce8 in abort () from /lib64/libc.so.6
#2 0x00007ffff7928a55 in __gnu_cxx::__verbose_terminate_handler ()
at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x00007ffff7926bf6 in __cxxabiv1::__terminate (handler=<optimized out>)
at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/eh_terminate.cc:38
#4 0x00007ffff7926c23 in std::terminate () at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/eh_terminate.cc:48
#5 0x00007ffff7926e42 in __cxxabiv1::__cxa_throw (obj=0x6030c0, tinfo=0x601de0 <_ZTIPKc@@CXXABI_1.3>, dest=0x0)
at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/eh_throw.cc:87
#6 0x0000000000400eaf in test2 (i=-1) at a.cpp:9
#7 test1 (i=0) at a.cpp:26
#8 test (i=1) at a.cpp:29
#9 0x0000000000400aa9 in main (arg=<optimized out>, args=<optimized out>) at a.cpp:37
对照(代码里有给 arg 重新赋值,没有传 999 个参数)
#0 0x00007ffff70255f7 in raise () from /lib64/libc.so.6
#1 0x00007ffff7026ce8 in abort () from /lib64/libc.so.6
#2 0x00007ffff7928a55 in __gnu_cxx::__verbose_terminate_handler ()
at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x00007ffff7926bf6 in __cxxabiv1::__terminate (handler=<optimized out>)
at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/eh_terminate.cc:38
#4 0x00007ffff7926c23 in std::terminate () at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/eh_terminate.cc:48
#5 0x00007ffff7926e42 in __cxxabiv1::__cxa_throw (obj=0x6030c0, tinfo=0x601de0 <_ZTIPKc@@CXXABI_1.3>, dest=0x0)
at ../../../../gcc-4.8.5/libstdc++-v3/libsupc++/eh_throw.cc:87
#6 0x0000000000400ad8 in main (arg=999, args=<optimized out>) at a.cpp:41
<optimized out> 解决办法
1、如果有条件,或者能复现,可以换 gcc 编译选项为 -O0
2、如果我们知道 optimized out 对应的地址,在 gdb 中,我们可以强制转换打印该参数
比如我们知道某个变量的地址是 0x12345678,类型是 classA,就可以使用 p (classA*)0x12345678,打印该参数
我们如果有代码的上下文,如果能根据我们自己的推断,找到对应的地址,举个例子
#13 0x0000000000efe233 in abc() (last_msg=<optimized out>) at b.cpp:142
#14 0x0000000000efe7ab in test() (m=0x7f940ae69640) at c.cpp:184
比如我想打印 #13 的 last_msg,我根据代码推断,last_msg 传入的是 m 的成员变量 msg,那我就能直接 p (classA*)(m->msg)
3、另外一个获取信息的渠道,还是上图,就是比如我切到 #13 使用 info locals 打印当前 abc 函数里面的所有局部变量,有时候 info locals 打印不全,就需要手动 print 每个变量,看看有没有可用信息,获取信息越多对于调试越有帮助
比如
(gdb) f 8
#8 test (i=1) at a.cpp:30
30 test1(i-1);
(gdb) info locals
a = <optimized out>
(gdb) p b
$1 = 1
在 test 函数我定义了两个局部变量 a 和 b, b 定义在 core 发生位置的前面,a 定义在 core 发生位置的后面(可能未执行定义),这个时候 a 也显示 <optimized out>,而 b 其实应该要在 info locals 里打印,很奇怪就没打印,所以手动 print 还是靠谱的,未来得及赋值的变量也会显示成 <optimized out>
一些其他的 gdb 调试技巧
1、有时候我 core 到一些标准库里了,比如 vector 的 clear,可以想想是不是线程读写冲突所致,一般我们认为标准库是可靠的
2、有时候会每次 core 到一些随机的位置(非导致 core 根因的第一现场),可能是其他地方代码错误把内存写坏了,这样可能 core 在奇奇怪怪的位置,这种就没办法,从概率学角度来说,它总有一天会第一次就写入到一个非法位置,我们看到的 core 文件就是第一现场
3、有时候 core 文件大小生成被截断了,这种情况下,运气好也能 gdb 调试