Hexagon GDB Debugger介绍(16)

简介 同时被 2 个专栏收录
127 篇文章 0 订阅
140 篇文章 1 订阅

2.10 检查堆栈

当您的程序停止时,您需要知道的第一件事是它在哪里停止以及它是如何到达那里的。

每次程序执行函数调用时,都会生成有关调用的信息。 该信息包括调用在程序中的位置、调用的参数以及被调用函数的局部变量。 该信息保存在称为堆栈帧的数据块中。 堆栈帧分配在称为调用堆栈的内存区域中。

当您的程序停止时,用于检查堆栈的调试器命令允许您查看所有这些信息。

调试器选择堆栈帧之一,并且许多调试器命令隐式地引用所选帧。 特别是,每当您向调试器询问程序中变量的值时,都会在所选帧中找到该值。 有一些特殊的命令可以选择您感兴趣的帧。请参阅第 2.10.3 节。

当您的程序停止时,调试器会自动选择当前正在执行的帧并对其进行简要描述,类似于帧命令(参见第 2.10.4 节)。

2.10.1 栈帧

调用堆栈被分成连续的部分,称为堆栈帧,或简称帧;每一帧都是与对一个函数的一次调用相关联的数据。框架包含提供给函数的参数、函数的局部变量以及函数执行的地址。

当您的程序启动时,堆栈只有一个框架,即函数 main 的框架。这称为初始框架或最外层框架。每次调用函数时,都会生成一个新帧。每次函数返回时,都会消除该函数调用的框架。如果一个函数是递归的,那么同一个函数可以有很多帧。实际发生执行的函数的框架称为最内层框架。这是所有仍然存在的堆栈帧中最近创建的。

在您的程序中,堆栈帧由它们的地址标识。一个堆栈帧由许多字节组成,每个字节都有自己的地址;每种计算机都有选择一个字节作为帧地址的约定。通常这个地址保存在一个称为帧指针寄存器的寄存器中,同时在该帧中执行。

调试器为所有现有的堆栈帧分配编号,从最里面的帧开始,从 0 开始,从调用它的帧开始,从 1 开始,以此类推。 这些数字实际上并不存在于您的程序中; 它们由调试器分配,为您提供一种在调试器命令中指定堆栈帧的方法。

一些编译器提供了一种编译函数的方法,以便它们在没有堆栈帧的情况下运行。 (例如,六边形gcc 选项-fomit-frame-pointer 生成没有框架的函数。)这偶尔会通过大量使用的库函数来完成,以节省框架设置时间。 调试器处理这些函数调用的功能有限。 如果最里面的函数调用没有堆栈帧,调试器仍然认为它有一个单独的帧,像往常一样编号为 0,允许正确跟踪函数调用链。 但是,调试器在堆栈中的其他地方没有提供无框架函数。

frame args
frame 命令允许您从一个堆栈帧移动到另一个堆栈帧,并打印您选择的堆栈帧。 args 可以是帧的地址或堆栈帧号。 在没有参数的情况下,frame 打印当前堆栈帧。

select-frame
select-frame 命令允许您在不打印帧的情况下从一个堆栈帧移动到另一个堆栈帧。 这是 frame 的无声版本。

2.10.2 回溯

回溯是您的程序如何到达当前位置的摘要。 它显示每帧一行,对于许多帧,从当前执行的帧(帧 0)开始,然后是它的调用者(帧 1),并在堆栈上。

backtrace
bt

显示整个堆栈的回溯:堆栈中所有帧的每帧一行。 您可以随时通过键入系统中断字符(通常是 Ctrl-c )来停止回溯。

backtrace n
bt n
类似,但只打印最里面的 n 帧。

backtrace -n
bt -n
类似,但只打印最外面的 n 帧。

where 和 info stack(缩写为 info s )的名称是 backtrace 的附加别名。

回溯中的每一行都显示了帧编号和函数名称。 程序计数器值也会显示,除非您使用 set print address off 。 回溯还显示源文件名和行号,以及函数的参数。 如果程序计数器值位于该行号的代码开头,则程序计数器值将被省略。

这是一个回溯的例子。 它是用命令 bt 3 制作的,所以它显示了最里面的三个帧。

#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8)
at builtin.c:993
#1 0x6e38 in expand_macro (sym=0x2b600) at macro.c:242
#2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08)
at macro.c:71
(More stack frames follow...)

第 0 帧的显示不以程序计数器值开始,表明您的程序已停止在 builtin.c 的第 993 行代码的开头。

大多数程序都有一个标准的用户入口点:系统库和启动代码转换为用户代码的地方。 对于 C,这是 main 。 当调试器在回溯中找到入口函数时,它将终止回溯,以避免跟踪到高度特定于系统(并且通常无趣)的代码。

如果您需要检查启动代码,或限制回溯中的级别数,您可以更改此行为:
set backtrace past-main
set backtrace past-main on

回溯将继续经过用户入口点。

set backtrace past-main off
当遇到用户入口点时,回溯将停止。 这是默认设置。

show backtrace past-main
显示当前用户入口点回溯策略。

set backtrace limit n
set backtrace limit 0

将回溯限制为 n 级。 值 0 表示无限制。

show backtrace limit
显示回溯级别的当前限制。

2.10.3 选择框架

大多数用于检查程序中堆栈和其他数据的命令都适用于当前选择的任何堆栈帧。 以下是选择堆栈帧的命令; 所有这些都通过打印刚刚选择的堆栈帧的简要描述来完成。

frame n
f n
选择帧号 n。 回想一下,第 0 帧是最内层(当前正在执行)的帧,第 1 帧是调用最内层的帧,依此类推。 编号最高的帧是 main 的帧。

frame addr
f addr
选择地址 addr 处的帧。 这主要在堆栈帧的链接被错误损坏时很有用,使调试器无法为所有帧正确分配编号。 此外,当您的程序有多个堆栈并在它们之间切换时,这会很有用。

up n
将 n 帧向上移动堆栈。 对于正数 n,这会朝着最外层的帧、更高的帧编号、存在时间更长的帧前进。 n 默认为 1。

down n
在堆栈中向下移动 n 帧。 对于正数 n,这将向最里面的帧前进,向较低的帧编号,向最近创建的帧前进。 n 默认为 1。您可以像 do 一样缩写。

所有这些命令都以打印两行描述帧的输出结束。 第一行显示帧编号、函数名称、参数以及该帧中的源文件和执行行号。 第二行显示该源代码行的文本。

例如:

(hexagon-gdb) up
#1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
at env.c:10
10
read_input_file (argv[i]);

在这样的打印输出之后,不带参数的 list 命令以帧中的执行点为中心打印十行。 您还可以在执行时使用您喜欢的编辑程序通过键入 edit 来编辑程序。 有关详细信息,请参阅第 2.11.3 节。

up-silently n
down-silently n
这两个命令分别是 up 和 down 的变体; 它们的不同之处在于它们默默地工作,而不会导致新框架的显示。 它们主要用于调试器命令文件(第 4.3 节),其中的输出可能是不必要的和分散注意力的。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

weixin_38498942

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值