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))。