实施一步,矮人

Use*_*r01 3 debugging gcc dwarf

我在源代码级调试器上工作。调试信息以elf格式提供。如何执行“跨步”?问题出在'Point1',无论如何我都可以等待下一个源代码行(从.debug_line表中读取它)。

谢谢

if (a == 1)
 x = 1; //Point1
else if (a == 2)
 x = 1;

z = 1;
Run Code Online (Sandbox Code Playgroud)

Jim*_*ndy 5

我不确定我是否完全理解该问题,但是我可以告诉您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; }
Run Code Online (Sandbox Code Playgroud)

由于此函数完全在同一源代码行上定义,因此逐步执行指令直到源代码行更改,将使您逐步完成所有递归调用,而不会停止。但是,当我们输入一个新的事实调用时,堆栈帧的基地址将已更改,表明我们应该停止。这给我们以下行为:

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
Run Code Online (Sandbox Code Playgroud)

GDB的next命令将这种一般行为与适当的逻辑相结合,以识别函数调用并使它们返回完成状态。和以前一样,必须使用帧ID来确定何时呼叫真正返回到原始帧。还有其他并发症。

值得思考一下如何处理内联的函数实例(DWARF确实描述了)。但这对于这个问题来说有点太多了。

并不是为了阻止实验,而是如果我正在开始一个调试器项目,我想看看苹果公司正在进行的调试器lldb,它是开源的。