我正在使用源代码级调试器。 elf中提供的调试信息 格式。怎么可能'跨越'实施? 问题出在'Point1',无论如何我可以等待 下一个源代码行(从.debug_line表中读取)。
由于
if (a == 1)
x = 1; //Point1
else if (a == 2)
x = 1;
z = 1;
答案 0 :(得分:4)
我不确定我是否完全理解这个问题,但我可以告诉你GDB如何实现其step
命令。
一旦控制进入特定的编译单元,GDB就会读取CU的调试信息;特别是,它读取.debug_line部分的CU部分,并构建一个将指令地址映射到源代码位置的表。
当step
开始时,GDB会查找当前PC的源位置。然后按机器指令逐步执行,每次查找新PC的源位置,直到源位置发生变化。当源位置更改时,step
已完成。
它还计算帧ID - 堆栈帧的基地址,以及每个步骤之后的函数的起始地址,并检查它是否已更改。如果有,这意味着我们已经进入递归调用或从递归调用返回,step
已完成。
要了解为什么需要检查帧ID和源位置,请考虑逐步调用以下函数:
int fact(n) { if (n > 0) { return n * fact(n-1); } else return 1; }
由于此函数完全在同一源代码行上定义,因此逐步执行直到源代码行更改将逐步完成所有递归调用,而不会停止。但是,当我们输入一个新的事实调用时,堆栈帧基址将发生变化,表明我们应该停止。这给了我们以下行为:
fact (n=10) at recurse.c:4
(gdb) step
fact (n=9) at recurse.c:4
(gdb) step
fact (n=8) at recurse.c:4
GDB的next
命令将这种一般行为与用于识别函数调用并让它们返回完成的适当逻辑相结合。和以前一样,必须使用帧ID来决定呼叫何时真正返回到原始帧;还有其他并发症。
值得思考一下如何处理内联函数实例(DWARF描述的内容)。但这对于这个问题来说有点多了。
不要劝阻实验,但如果我开始调试项目,我想看一下Apple的正在进行的调试器lldb,它是开源的。