Terms
在本书中,我们将介绍编译器、链接器、操作系统、调试器和调试信息标准,以及软件开发等方面的知识,使用到的术语会非常多。在此处列出常见重要术语,以便读者方便地查找。
Term | Description |
---|---|
Source | 源代码,如go语言编写的源代码 |
Compiler | 编译器,编译源代码为目标文件 |
Linker | 链接器,将目标文件、共享库、系统启动代码链接到一起构建可执行程序 |
Debugger | 调试器,跟踪正在运行的进程或者装载一个core文件,加载程序或core文件调试符号信息,探查、修改、控制进程运行时状态,如暂停执行并查看内存、寄存器 |
Debugger Frontend | 调试器前端,主要负责与用户进行交互,接收用户输入的调试命令,并将结果以友好的方式展示给用户。前端可以是命令行界面(CLI)、图形界面(GUI)、集成开发环境(IDE)插件等。前端本身不直接与被调试进程交互,而是通过后端完成具体的调试操作。 |
Debugger Backend | 调试器后端,负责与被调试进程(tracee)进行实际的交互,包括进程控制、断点设置、内存和寄存器读写、符号信息加载等。后端通常以服务的形式运行,接收前端发来的调试命令请求,并将执行结果返回给前端。前后端之间可以通过本地调用或远程协议(如RPC)通信,实现分布式或跨平台调试。 |
DWARF | DWARF,是一种调试信息标准,指导编译器将调试信息生成到目标文件中,指导链接器合并存储在多个目标文件中的调试信息,调试器将加载此调试信息。简言之,DWARF用来协调编译器、链接器和调试器之间的工作 |
Debugger types | 通常,调试器可以分为两种类型:指令级调试器和符号级调试器 |
Instruction level debugger | 指令级调试器主要面向指令级别的执行控制,如设置指令地址断点、执行到断点或单步操作等。在查看进程内存和寄存器数据时,它提供相对低级的操作,如查看内存区域数据时需要指定以二进制或十进制格式显示。指令级调试器不依赖调试符号信息,因此不支持以源代码符号进行程序控制和数据操作。 指令级调试器对于逆向工程等安全分析领域也是很常见的。 |
Symbol level debugger | 符号级调试器通常具备指令级调试器的所有功能,同时依靠可执行程序中的调试符号信息,建立内存地址、指令地址与源代码之间的映射关系。它支持在源代码位置设置断点、使用源代码符号查看修改变量、通过源代码表达式设置断点条件,还可以查看当前调用堆栈。符号级调试器具备许多指令级调试器所不具备的高级功能,使得使用高级语言开发时的软件调试变得便利。 |
Tracee | 泛指被调试的进程,准确地讲,tracee指的是被调试器跟踪的线程。一个被调试器调试的进程也可能是多线程程序,因此如果需要对其中的多个线程进行调试跟踪,那么就存在多个tracee |
Tracer | 泛指调试器对应的进程,严格来讲也是线程,以Linux为例tracer指的是通过ptrace_attach系统调用与tracee建立跟踪、被跟踪关系的调试器中的线程。Linux内核要求ptrace attach之后的后续ptrace请求必须来自发起ptrace attach请求的线程,因此Linux下的调试器实现往往会有一个专门线程作为tracer,负责与被调试进程中的多个tracee进行交互 |