我想知道调试器如何能够一步一步地遍历源代码。
一旦编译了源代码并运行了程序,调试器将如何知道机器级指令和更高级别的语句之间的对应关系?
例如,如果我在源文件的一行上设置了一个断点,它如何知道要在哪条机器级指令处停止?
答案 0 :(得分:3)
看看gcc -g -S
的asm输出,您会看到.line
的debug-info指令,依此类推,对应于C源代码行的asm块。
(启用优化功能后,同一行可以映射到多个非连续指令,因此棘手得多,但是编译器仍然会尝试将大多数指令映射到某个源代码行,即使它们“实际上是优化并执行了源代码中没有出现的操作的结果...)。
https://godbolt.org/使用与调试器相同的调试信息,但是将其用于颜色突出显示以将源行与asm匹配。
当汇编器汇编这些.line
指令时,它将在.o
对象文件中创建调试信息,该文件最终链接到可执行文件或库中。或拆分为单独的调试符号文件。或被剥夺。
调试器读取的是此调试信息。
(调试信息还包括有关哪些命名C变量存储在何处以及它们的类型的信息。对于本地变量,位置相对于包含它们的函数的堆栈框架。)
答案 1 :(得分:2)
编译器和链接器可以产生包含此信息的所谓调试符号。调试信息包含源文件/行到地址的映射,全局变量的地址和所有函数的开始地址以及它们在堆栈上的局部变量偏移量。对于gcc,-g编译器选项可以执行此操作。调试符号信息可以像gcc通常那样嵌入到可执行程序中,也可以嵌入单独的符号文件(带有msvc的.pdb文件)中。