GDB 在调用堆栈上显示函数地址的当前编译二进制文件

GDB show current compiled binary file for function address on call stack

在visual studio中您可以看到函数所在的位置,即在哪个编译的二进制文件中。例如:

有GDB命令吗?


一个符号的多个版本可以被加载两次以防你加载一个dll。 必须 知道代码是在 .exe 中执行还是在加载的 .dll 库中执行。 Visual Studio 调试器会像提供的屏幕截图一样显示此信息(虽然它是针对 C# 的,但我只是从网站上复制了它)。

当我使用 Visual Studio 时,我能够发现一些情况,即预期在 .dll 中执行的代码在 .exe 中执行。当然这是由于链接命令的错误。但是这种错误可能很难发现,查看当前执行的二进制文件有很大帮助。

存储在可执行文件中的调试信息提供了当前代码是从哪个源文件和源代码的哪一行生成的信息。像目标文件这样的中间文件不是此类信息的一部分,也并不总是可用。如果您一步编译代码 ( compile & link ),您将在某处只有一些临时生成的文件。特别是在这种情况下,引用目标文件是没有意义的。

你在VS中显示的信息也是源代码位置!

您还应该注意到,像 C 和 C++ 这样的编译语言与像 C# 这样的语言是完全不同的,即使也有某种“字节代码生成”或其他东西。

可能是我理解错了,需要查看当前代码在编译和[=之间generated/placed的中间目标文件的名称是什么? 27=]正在?二进制文件本身是完整的 linked 程序,因此二进制文件的名称将始终是您已启动且当前正在调试的可执行文件的名称。

如果您真的需要知道哪个目标文件包含您要查找的代码,您可以使用objdump -t获取所有符号的列表以获得完整的二进制以及所有目标文件。在 C++ 的情况下,你应该将它与 demangling 结合使用,也许手头有 c++filt

免责声明:这是针对 GNU/Linux 上的 GDB,使用 ELF 文件。 GDB 手册没有说我在这里显示的命令是 Linux 特定的,但我不知道它们是否会在 Windows.

上产生类似的结果

GDB 的 info symbol 命令,给定一个地址,将输出与该地址对应的最接近的符号(和偏移量)、文件名和目标文件的部分。

这是一个示例,其中主程序从两个不同的共享库访问 foo 函数。 foo 只是调用 lseek,这将是一个放置断点的方便点,因为它不会在程序的其他任何地方使用,包括 dl 函数。

$ nl -ba a.c
     1  #include <sys/types.h>
     2  #include <unistd.h>
     3  void foo() {
     4          lseek(0, 0, SEEK_CUR);
     5  }
$ cc -fpic -shared -g a.c -o a.so

$ nl -ba b.c
     1  #include <sys/types.h>
     2  #include <unistd.h>
     3  void foo() {
     4          lseek(0, 0, SEEK_CUR);
     5  }
$ cc -fpic -shared -g b.c -o b.so
$ nl -ba main.c
     1  #include <dlfcn.h>
     2  #include <unistd.h>
     3  #include <stdio.h>
     4  int main() {
     5          void *a = dlopen("./a.so", RTLD_LAZY|RTLD_LOCAL);
     6          void *b = dlopen("./b.so", RTLD_LAZY|RTLD_LOCAL);
     7
     8          void (*afoo)() = (void (*)()) dlsym(a, "foo");
     9          void (*bfoo)() = (void (*)()) dlsym(b, "foo");
    10
    11          (*afoo)();
    12          (*bfoo)();
    13  }
$ cc main.c -g -ldl -o main

这是 GDB 会话。 bt 命令将显示每个帧的 PC 地址,以及源文件的名称,因为所有内容都是使用 GCC 的 -g 选项编译的。 info sym 命令将显示可执行文件或目标文件的名称。

$ gdb -q ./main
(gdb) start
Temporary breakpoint 1, main () at main.c:5
5               void *a = dlopen("./a.so", RTLD_LAZY|RTLD_LOCAL);
(gdb) b lseek
Breakpoint 2 at 0x7ffffef38d30: file ../sysdeps/unix/syscall-template.S, line 84.
(gdb) c
Continuing.

Breakpoint 2, lseek64 () at ../sysdeps/unix/syscall-template.S:84
84      T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) bt
#0  lseek64 () at ../sysdeps/unix/syscall-template.S:84
#1  0x00007ffffec40688 in foo () at a.c:4
#2  0x000000000800078b in main () at main.c:11
(gdb) info sym 0x00007ffffec40688
foo + 24 in section .text of ./a.so
(gdb) c
Continuing.

Breakpoint 2, lseek64 () at ../sysdeps/unix/syscall-template.S:84
84      T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) bt
#0  lseek64 () at ../sysdeps/unix/syscall-template.S:84
#1  0x00007ffffea30688 in foo () at b.c:4
#2  0x0000000008000796 in main () at main.c:12
(gdb) info sym 0x00007ffffea30688
foo + 24 in section .text of ./b.so