Hexagon GDB Debugger介绍(14)

2023-10-27

Hexagon GDB Debugger介绍 (14)

2.9.2 连续和单步调试

连续意味着恢复程序执行,直到程序正常完成。 相比之下,单步调试意味着只执行程序的一个"step",其中“step”可能意味着一行源代码或一条机器指令(取决于您使用的特定命令)。 在连续和单步执行时,程序可能会因断点而更快停止。

命令 描述
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
在程序上次停止的地址继续执行程序; 在该地址设置的任何断点都将被绕过。 可选参数 ignore-count 允许指定更多次数以忽略此位置的断点; 它的效果类似于忽略(参见第 2.9.1.6 节)。
参数 ignore-count 仅在程序因断点而停止时才有意义。 在其他时候,参数 continue 被忽略。
同义词 c 和 fg(对于前台,因为被调试的程序被认为是前台程序)纯粹是为了方便而提供的,并且具有与 continue 完全相同的行为。

要在不同的地方恢复执行,您可以使用 return(参见第 2.17.3 节)返回调用函数; 或跳转(参见第 2.17.2 节)以转到程序中的任意位置。
使用单步调试的典型方法是在函数的开头或程序中认为存在问题的部分设置断点(参见第 2.9.1 节),运行程序直到它在该断点处停止,然后逐步通过可疑区域,检查感兴趣的变量,直到看到问题发生。

step
继续运行程序,直到控制权到达不同的源代码行,然后停止它并将控制权返回给调试器。 该命令缩写为s.

注意
    如果在控制位于没有调试信息的情况下编译的函数内时使用 step 命令,则执行将继续进行,直到控制到达具有调试信息的函数。  同样,它不会进入没有调试信息编译的函数。  要在没有调试信息的情况下单步执行函数,请使用 stepi 命令,如下所述。

step 命令仅在源代码行的第一条指令处停止。 这可以防止可能在 switch 语句、for 循环等中发生的多次停止。如果在该行中调用具有调试信息的函数,则 step 继续停止。 换句话说,在该行内调用的任何函数都会因断点而停止。

此外,如果有该函数的行号信息,则 step 命令仅进入该函数。 否则它就像下一个命令一样。

step count
继续按步骤运行,但要计算次数。 如果到达断点,则步进立即停止。

next [count]
继续到当前(最里面)堆栈帧中的下一个源代码行。 这与 step 类似,但在代码行中出现的函数调用不会停止执行。 当控制到达在您发出下一个命令时正在执行的原始堆栈级别的不同代码行时,执行将停止。 该命令缩写为 n。
参数计数是重复计数,对于step。
下一个命令仅在源代码行的第一条指令处停止。 这可以防止可能在 switch 语句、for 循环等中发生的多次停止。

set step-mode
set step-mode on

set step-mode on 命令导致 step 命令在不包含调试行信息的函数的第一条指令处停止,而不是跳过它。
这在你可能有兴趣检查没有符号信息的函数的机器指令并且不希望调试器自动跳过此函数的情况下很有用。

set step-mode off
使 step 命令跳过任何不包含调试信息的函数。 这是默认设置。

finish
继续运行,直到所选堆栈帧中的函数返回之后。 打印返回值(如果有)。
将此与返回命令进行对比(参见第 2.17.3 节)。

until
u

继续运行,直到到达当前堆栈帧中超过当前行的源行。 此命令用于避免多次单步执行循环。 和next命令一样,只不过until遇到跳转时,会自动继续执行,直到程序计数器大于跳转的地址。
这意味着在单步执行循环后到达循环末尾时,until 使程序继续执行,直到它退出循环。 相比之下,循环末尾的下一个命令只是返回到循环的开头,这会迫使你逐步执行下一次迭代。
如果程序试图退出当前堆栈帧,则它始终会停止。
如果机器代码的顺序与源代码行的顺序不匹配,直到会产生一些违反直觉的结果。 例如,在以下调试会话的摘录中,f(frame)命令显示执行在第 206 行停止; 但是当我们使用until时,我们到达了第195行:

(hexagon-gdb) f
#0  main (argc=4, argv=0xf7fffae8) at m4.c:206

206                 expand_input();
(hexagon-gdb) until
195             for ( ; argc > 0; NEXTARG) {

这种情况是因为,为了执行效率,编译器在循环结束而不是开始时生成了用于循环闭合测试的代码,即使 C for 循环中的测试是在循环体之前编写的。 当它前进到这个表达式时,until 命令似乎退回到循环的开头。 然而,它并没有真正进入更早的语句,而不是在实际的机器代码方面。
没有参数的until通过单指令单步调试,因此比有参数的until慢。

until location
u location

继续运行程序,直到到达指定位置或当前堆栈帧返回。 location 是任何可以接受的参数形式的中断(参见第 2.9.1.1 节)。 这种形式的命令使用断点,因此比不带参数的 until 更快。 只有在当前帧中才实际到达指定位置。 这意味着直到可以用来跳过递归函数调用。 例如,在下面的代码中,如果当前位置是第 96 行,则发出直到 99 将在相同的阶乘调用中(即,在内部调用返回之后)执行到第 99 行的程序。

94 int factorial (int value)
95 {
96     if (value > 1) {
97            value *= factorial (value - 1);
98     }
99     return (value);
100 }

advance location
继续运行程序到给定的位置。 至少一个参数,任何形式与 break 命令的参数相同。 从当前堆栈帧退出时,执行也将停止。 该命令类似于until,但advance 不会跳过递归函数调用,并且目标位置不必与当前位置在同一帧中。

stepi
stepi arg
si

执行一条机器指令,然后停止并返回调试器。
在按机器指令步进时执行 display/i $pc 通常很有用。 这使得调试器在每次程序停止时自动显示下一条要执行的指令。 见第 2.12.6 节。
参数是重复计数,如step所示。

nexti
nexti arg
ni

执行一条机器指令,但如果是函数调用,则继续执行,直到函数返回。
参数是重复计数,如next所示。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hexagon GDB Debugger介绍(14) 的相关文章

随机推荐