Linux 中的调试器如何工作?

Linux 中的调试器如何工作?

Linux 中的调试器如何工作?它如何“附加”到已经运行的可执行文件或进程。我知道编译器将代码翻译为机器语言,但是调试器如何“知道”它所附加的内容?

答案1

有一个名为的系统调用跟踪。它需要 4 个参数:操作、目标进程的 PID、目标进程内存中的地址和数据指针。最后 2 个参数的使用方式取决于操作。

例如,您可以将调试器附加/分离到进程:

ptrace(PTRACE_ATTACH, pid, 0, 0);
...
ptrace(PTRACE_DETACH, pid, 0, 0);

单步执行:

ptrace(PTRACE_ATTACH, pid, 0, 0);
int status;
waitpid(pid, &status, WSTOPPED);
while (...) {
    ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
    // give the user a chance to do something
}
ptrace(PTRACE_DETACH, pid, 0, 0);

您还可以使用 PTRACE_PEEKDATA 和 PTRACE_POKEDATA 读/写目标进程的内存。如果您想查看真实示例,请查看数据库

答案2

但是调试器如何“知道”它所附加的是什么?

人追踪

ptrace() 系统调用提供了一种方法,一个进程(“跟踪器”)可以通过该方法观察和控制另一个进程(“被跟踪者”)的执行,并检查和更改被跟踪者的内存和寄存器。主要用于实现断点调试和系统调用跟踪。

调试器如何工作(第 1 部分(共 3 部分))是一个很好的使用参考跟踪,调试系统调用。

非常简单,因为 gdb 是一个复杂的野兽。在今天的 gdb 源代码中,有关 gdb 使用的有趣信息跟踪发现于目标.hinf-ptrace.c并且很容易被野心勃勃的人追赶。你会看到 gdb 正在使用跟踪,通常根本没有太多歧义。请参阅 target_ops 结构的组件并在以下位置找到它们inf-ptrace.c

来自 人追踪

>PTRACE_ATTACH
>       Attach to the process specified in pid, making it a tracee of the calling process.  The
>       tracee is sent a SIGSTOP, but will not necessarily have stopped by  the  completion  of
>       this  call;  use  waitpid(2)  to  wait  for the tracee to stop.  See the "Attaching and
>       detaching" subsection for additional information.  (addr and data are ignored.)

所以使用了 ptrace,但是它如何知道某个东西在哪里呢? GDB如何获取设置断点和读取数据所需的信息?如果没有 DWARF 或一些较小的调试格式,gdb 并不真正知道它在做什么或在哪里可以找到任何东西。你仍然可以通过手动搜索的方式用gdb找到它们,因为这些信息仍然存在于程序的映像中,但gdb没有任何线索。

以下是来自GDB使用手册-Stallman。 GDB 与所有调试器一样,使用调试格式(在合理的操作系统上通常为 DWARF)来获取有关程序的函数和变量的符号信息。

为了有效地调试程序,需要在编译时生成调试信息。该调试信息存储在目标文件中;它描述了每个变量或函数的数据类型以及源代码行号和可执行代码中的地址之间的对应关系。 .... 如果您使用编译器支持的最新版本的 DWARF 调试格式,您将获得最佳的调试体验。

有关 GDB、DWARF 和 PTRACE 的信息都非常容易找到。如果您喜欢符号,也可以轻松找到有关 ELF 文件的信息。

相关内容