为什么 GDB 找不到一些可以按名称反汇编的函数?

Why can't GDB find some functions to disassemble by name?

有时我的二进制文件中有一个函数我确定没有被优化掉,因为它被另一个函数调用:

(gdb) disassemble 'k3::(anonymous namespace)::BM_AwaitLongReadyChain(testing::benchmark::State&)'
Dump of assembler code for function k3::(anonymous namespace)::BM_AwaitLongReadyChain(testing::benchmark::State&):
   [...]
   0x00000000003a416d <+45>:    call   0x3ad0e0 <k3::(anonymous namespace)::RecursivelyAwait<k3::(anonymous namespace)::Immediate17>(unsigned long, k3::(anonymous namespace)::Immediate17&&)>
End of assembler dump.

但是如果我要求 GDB 使用与函数引用完全相同的名称反汇编它,它会声称该函数不存在:

(gdb) disassemble 'k3::(anonymous namespace)::RecursivelyAwait<k3::(anonymous namespace)::Immediate17>(unsigned long, k3::(anonymous namespace)::Immediate17&&)'
No symbol "k3::(anonymous namespace)::RecursivelyAwait<k3::(anonymous namespace)::Immediate17>(unsigned long, k3::(anonymous namespace)::Immediate17&&)" in current context.

然而,如果我使用它的地址反汇编它,它工作正常:

(gdb) disassemble 0x3ad0e0
Dump of assembler code for function k3::(anonymous namespace)::RecursivelyAwait<k3::(anonymous namespace)::Immediate17>(unsigned long, k3::(anonymous namespace)::Immediate17&&):
   0x00000000003ad0e0 <+0>:     push   rbp
  [...]
End of assembler dump.

这非常不方便,因为我不知道先验地址——我必须去反汇编调用者才能找到被调用者的地址。真的很麻烦。

如何让 GDB 通过名称反汇编此函数? 我认为这是名称 mangling/canonicalization 的一些问题,可能围绕右值引用 and/or 匿名命名空间,但我无法弄清楚到底发生了什么。我正在使用 GDB 10.0-gg5.

But if I ask GDB to disassemble it using the very same name that it refers to the function with, it claims the function doesn't exist

  1. 有很多可能的修改方案;损坏名称和未损坏名称之间的关系不是 1:1.
  2. GCC 内置的解析器将 foo::bar(int) 转换为可用于在符号 table 中查找符号的东西可能有错误。

This is terribly inconvenient, because I don't know the address a priori—I have to go disassemble a caller just to find the address of the callee.

如果被调用的函数已经在栈上(即活动调用链的一部分),您可以通过 disas $any_address_in_fn 轻松反汇编它——您不需要给 GDB 起始地址。所以你可以做例如frame 5 后跟 disas $pc -- GDB 将在符号 table 中找到封闭函数并将其整个反汇编。

另一种选择是从 file:line 信息中获取地址:info line foo.cc:123 后跟 disas $addr_given_by_previous_command

如果您知道 foo::bar() 存在于某处,但不知道其源位置,另一种选择是通过例如在其上设置断点rbreak 'foo::bar'。这将告诉您设置断点的地址,您可以 disassemble 该地址。