gdb调试optimized out变量
生产环境下的程序发生crash,一般都是开了编译期优化的,当查看调用栈中某个变量时,很可能遇到变量被优化的情况,这时没法简单看到变量的值。
假设函数代码为,
MDLMessagePtr GetPackage(FileBufferPtr file) {
const char *package_head = file->ReadHead(sizeof(MDLMessageHead));
if (!package_head) {
return MDLMessagePtr();
}
auto msg_Len = reinterpret_cast<MDLMessageHead*>((void *)package_head)->MessageSize;
DynBufferPtr readbuf(new DynBuffer);
const char *pkg = file->ReadPkg(msg_Len);
if (!pkg) {
return MDLMessagePtr();
}
readbuf->append(pkg, msg_Len);
MDLBinaryMessagePtr bm(new MDLBinaryMessage(reinterpret_cast<MDLMessageHead*>(readbuf->address())));
return bm->Duplicate();
}gdb调试中,
(gdb) i locals
msg_Len = <optimized out>
readbuf = {m_RefObj = 0x7ee65280e040}
package_head = <optimized out>
pkg = <optimized out>
bm = <optimized out>
(gdb) p msg_Len
$19 = <optimized out>
(gdb) disas
Dump of assembler code for function datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>):
0x00000000004ea620 <+0>: push %r13
0x00000000004ea622 <+2>: push %r12
0x00000000004ea624 <+4>: mov %rdi,%r12
0x00000000004ea627 <+7>: push %rbp
0x00000000004ea628 <+8>: mov %rsi,%rbp
0x00000000004ea62b <+11>: mov $0x17,%esi
0x00000000004ea630 <+16>: push %rbx
0x00000000004ea631 <+17>: sub $0x8,%rsp
0x00000000004ea635 <+21>: mov 0x0(%rbp),%rdi
0x00000000004ea639 <+25>: callq 0x46c1a0 <_ZN7datayes10FileBuffer8ReadHeadEj@plt>
0x00000000004ea63e <+30>: test %rax,%rax
0x00000000004ea641 <+33>: je 0x4ea720 <datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>)+256>
0x00000000004ea647 <+39>: mov $0x28,%edi
0x00000000004ea64c <+44>: mov 0x1(%rax),%r13d
0x00000000004ea650 <+48>: callq 0x46b840 <je_malloc@plt>
0x00000000004ea655 <+53>: mov %rax,%rbx
0x00000000004ea658 <+56>: movl $0x0,0x8(%rax)
0x00000000004ea65f <+63>: mov 0xac5742(%rip),%rax # 0xfafda8
0x00000000004ea666 <+70>: lea 0x8(%rbx),%rdi
0x00000000004ea66a <+74>: movq $0x0,0x10(%rbx)
0x00000000004ea672 <+82>: movq $0x0,0x18(%rbx)
0x00000000004ea67a <+90>: movq $0x0,0x20(%rbx)
0x00000000004ea682 <+98>: add $0x10,%rax
0x00000000004ea686 <+102>: mov %rax,(%rbx)
0x00000000004ea689 <+105>: callq 0x46b340 <DllInterlockedIncrement@plt>
0x00000000004ea68e <+110>: mov 0x0(%rbp),%rdi
0x00000000004ea692 <+114>: mov %r13d,%esi
0x00000000004ea695 <+117>: callq 0x46d280 <_ZN7datayes10FileBuffer7ReadPkgEj@plt>
0x00000000004ea69a <+122>: test %rax,%rax
0x00000000004ea69d <+125>: mov %rax,%rbp
0x00000000004ea6a0 <+128>: je 0x4ea710 <datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>)+240>
0x00000000004ea6a2 <+130>: test %r13,%r13
0x00000000004ea6a5 <+133>: jne 0x4ea740 <datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>)+288>
0x00000000004ea6ab <+139>: mov $0x38,%edi
0x00000000004ea6b0 <+144>: mov 0x20(%rbx),%r13
0x00000000004ea6b4 <+148>: callq 0x46b840 <je_malloc@plt>
0x00000000004ea6b9 <+153>: mov %r13,%rsi
0x00000000004ea6bc <+156>: mov %rax,%rdi
0x00000000004ea6bf <+159>: mov %rax,%rbp
0x00000000004ea6c2 <+162>: callq 0x46d830 <_ZN7datayes3mdl16MDLBinaryMessageC1EPKNS0_14MDLMessageHeadE@plt>
=> 0x00000000004ea6c7 <+167>: test %rbp,%rbp
0x00000000004ea6ca <+170>: je 0x4ea6d5 <datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>)+181>
0x00000000004ea6cc <+172>: mov 0x0(%rbp),%rax
0x00000000004ea6d0 <+176>: mov %rbp,%rdi
0x00000000004ea6d3 <+179>: callq *(%rax)
0x00000000004ea6d5 <+181>: mov %rbp,%rsi
0x00000000004ea6d8 <+184>: mov %r12,%rdi
...这时想要获得msg_Len的值,就需要找到对应的位置。可以看到调用ReadPackge时,需要这个参数。因此重点看下,
0x00000000004ea68e <+110>: mov 0x0(%rbp),%rdi
0x00000000004ea692 <+114>: mov %r13d,%esi
0x00000000004ea695 <+117>: callq 0x46d280 <_ZN7datayes10FileBuffer7ReadPkgEj@plt>可以看到%esi寄存器中就是存的这个变量,直接打印可得,
(gdb) p $esi
$20 = 0
(gdb) p $r13d
$21 = 0备注
(gdb) disas
Dump of assembler code for function datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>):
0x00000000004ea620 <+0>: push %r13
0x00000000004ea622 <+2>: push %r12
0x00000000004ea624 <+4>: mov %rdi,%r12
0x00000000004ea627 <+7>: push %rbp
0x00000000004ea628 <+8>: mov %rsi,%rbp
0x00000000004ea62b <+11>: mov $0x17,%esi
0x00000000004ea630 <+16>: push %rbx
0x00000000004ea631 <+17>: sub $0x8,%rsp
0x00000000004ea635 <+21>: mov 0x0(%rbp),%rdi
0x00000000004ea639 <+25>: callq 0x46c1a0 <_ZN7datayes10FileBuffer8ReadHeadEj@plt>
0x00000000004ea63e <+30>: test %rax,%rax
0x00000000004ea641 <+33>: je 0x4ea720 <datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>)+256>
...
0x00000000004ea720 <+256>: movq $0x0,(%r12)
0x00000000004ea728 <+264>: add $0x8,%rsp
0x00000000004ea72c <+268>: mov %r12,%rax
0x00000000004ea72f <+271>: pop %rbx
0x00000000004ea730 <+272>: pop %rbp
0x00000000004ea731 <+273>: pop %r12
0x00000000004ea733 <+275>: pop %r13
0x00000000004ea735 <+277>: retq 在这个输出中,第一列是这个函数汇编码的地址,第二列<+offset>表示汇编指令相对于函数入口的偏移。
je 0x4ea720 <datayes::mdl::utils::GetPackage(datayes::RefCountedPtrT<datayes::FileBuffer>)+256>
表示跳转到0x4ea720亦即GetPackage(...)+256处的指令(0x00000000004ea720 <+256>: movq $0x0,(%r12))。