天天看点

Hexagon GDB Debugger介绍(5)

Hexagon GDB Debugger介绍(5)

      • 2.5.4 shell 命令
      • 2.5.5 Tcl 脚本
      • 2.5.6 记录输出
      • 2.5.7 获得帮助
      • 2.5.8 示例调试会话

2.5.4 shell 命令

如果你需要在调试会话期间偶尔执行 shell 命令,则无需离开或暂停调试器; 相反,你可以使用 shell 命令。

shell 命令字符串

调用标准 shell 来执行 command_string。 如果存在,环境变量 SHELL 决定运行哪个 shell。 否则,调试器将使用默认 shell(例如,UNIX 系统上的 /bin/sh)。

在开发环境中经常需要实用程序 make。 为此,你不必使用 shell 命令。 例如:

make make_args

… 使用指定的参数执行 make 程序。 这相当于“shell make make_args”。

2.5.5 Tcl 脚本

调试器可选择支持使用 Tcl 脚本语言。 可以使用 set 命令启用 Tcl 脚本。

set tclfe on
启用 Tcl 脚本(第 4.4 节)。
注意
    启用脚本会影响 GDB 命令缩写(第 2.5.1 节)
           

2.5.6 记录输出

你可能希望将调试器命令的输出保存到文件中。 有几个命令可以控制日志记录。

命令 描述
set logging on 启用日志记录。
set logging off 禁用日志记录。
set logging file file 更改当前日志文件的名称。 默认日志文件是 gdb.txt。
set logging overwrite [on|off] 默认情况下,调试器会将新的日志信息附加到日志文件中。 如果你希望将登录设置为覆盖日志文件,请设置覆盖。
set logging redirect [on|off] 默认情况下,调试器输出同时写入终端和日志文件。 如果你只想输出到日志文件,请设置重定向。
show logging 显示日志设置的当前值。

2.5.7 获得帮助

你始终可以使用命令帮助向调试器询问有关其命令的信息。

命令 描述
help / h 可以使用不带参数的帮助(缩写为 h)来显示命名命令类的简短列表。
help class 使用通用帮助类之一作为参数,可以获得该类中各个命令的列表。 例如,这里是class状态的帮助显示:
(hexagon-gdb) help status
 状态查询。
 命令列表:
 info -- 用于显示有关正在调试的程序的信息的通用命令

 show -- 用于显示有关调试器的内容的通用命令
 键入“help”后跟命令名称以获取完整文档。

 如果没有歧义,则允许使用命令名称缩写。
           
命令 描述
help command 使用命令名称作为帮助参数,显示关于如何使用该命令的简短段落。
apropos command_expr apropos 命令在所有调试器命令及其相应文档中搜索 command_expr 中指定的正则表达式。 它打印出找到的所有匹配项。 例如:
apropos reload
 ... 结果是: 
 set symbol-reloading -- 在一次运行中设置动态符号表重新加载多次

 show symbol-reloading -- 在一次运行中显示多次重新加载的动态符号表
           
命令 描述
complete command_string complete 命令列出了命令开头的所有可能的补全。 使用 command_string 指定要完成的命令的开头。 例如:
complete i
... results in: 
if
ignore
info

inspec
NOTE complete 旨在供 GNU Emacs 使用。

           

除了帮助之外,还可以使用命令 info 和 show 来查询程序的状态或调试器本身的状态。 每个命令支持多个查询主题; 本手册在适当的上下文中介绍了它们中的每一个。

命令 描述
info 此命令(缩写为 i)用于描述程序的状态。 例如,可以使用 info args 列出给你的程序的参数,使用 info registers 列出当前正在使用的寄存器,或者列出你使用 info breakpoints 设置的断点。 你可以通过帮助信息获取信息子命令的完整列表。
set 你可以使用 set 将表达式的结果分配给环境变量。 例如,你可以使用 set prompt $ 将调试器提示设置为 $-sign。
show 与 info 不同,show 用于描述调试器本身的状态。 通过使用相关的命令集,你可以更改你可以显示的大部分内容; 例如,你可以使用 set radix 控制显示使用的数字系统,或者只需使用 show radix 查询当前正在使用的数字系统。 要显示所有可设置的参数及其当前值,你可以使用不带参数的 show; 你也可以使用信息集。 这两个命令产生相同的显示。

以下是三个杂项 show 子命令,所有这些子命令都缺少相应的 set 命令:

命令 描述
show version 显示正在运行的调试器版本。
show copying 显示有关复制调试器的权限的信息。
show warranty 显示 GNU “NO WARRANTY”声明或保证(如果你的调试器版本附带有)。

2.5.8 示例调试会话

本节提供了一个示例调试会话,它演示了基本的调试器命令。

gnu m4(一种通用宏处理器)的一个初步版本显示出以下错误:有时,当我们从默认值更改其引号字符串时,用于捕获另一个宏定义中的命令的命令会停止工作。 在以下简短的 m4 会话中,我们定义了一个宏 foo,它扩展为 0000; 然后我们使用 m4 内置的 defn 将 bar 定义为相同的东西。 但是,当我们将左引号字符串更改为 并将关闭引号字符串更改为 时,相同的过程无法定义新的同义词 baz:

$ cd gnu/m4
$ ./m4
define(foo,0000)
foo
0000

define(bar,defn(’foo’))
bar
0000
changequote(<QUOTE>,<UNQUOTE>)
define(baz,defn(<QUOTE>foo<UNQUOTE>))
baz

Ctrl-d

m4: End of input: 0: fatal error: EOF in string
           

要查找 m4 中的错误,请启动调试器:

$ hexagon-gdb
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
(hexagon-gdb)
           

调试器只读取足够的符号数据,以便在需要时知道在哪里可以找到其余的; 结果,第一个提示出现得非常快。 我们现在告诉它使用比平时更窄的显示宽度,以便示例适合本手册。

(hexagon-gdb) set width 70
           

我们需要看看 m4 内置的 changequote 是如何工作的。 查看源代码后,我们知道相关子程序是 m4_changequote,因此我们使用 break 命令在那里设置了一个断点。

(hexagon-gdb) break m4_changequote
Breakpoint 1 at 0x62f4: file builtin.c, line 879.
           

使用 run 命令,我们启动 m4 在调试器的控制下运行; 只要控制没有到达 m4_changequote 子程序,程序就照常运行:

(hexagon-gdb) run
Starting program: /work/Editorial/gdb/gnu/m4/m4

define(foo,0000)
foo
0000
           

为了触发断点,我们调用changequote。 调试器暂停 m4 的执行,显示有关它停止的上下文的信息。

changequote(<QUOTE>,<UNQUOTE>)
Breakpoint 1, m4_changequote (argc=3, argv=0x33c70)
  at builtin.c:879
879         if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))
           

现在我们使用命令 n (next) 将执行推进到当前函数的下一行。

(hexagon-gdb) n
882    set_quotes((argc >= 2) ? TOKEN_DATA_TEXT(argv[1])\
 : nil,
           

set_quotes 看起来像是一个很有前途的子程序。 我们可以使用命令 s (step) 而不是 next 来进入它。 step 转到要在任何子例程中执行的下一行,因此它步入 set_quotes。

(hexagon-gdb) s
set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")

at input.c:530

530         if (lquote != def_lquote)
           

显示 m4 现在挂起的子程序(及其参数)的显示称为堆栈帧显示。 它显示了堆栈的摘要。 我们可以使用 backtrace 命令(也可以拼写为 bt)来查看我们在整个堆栈中的位置:backtrace 命令显示每个活动子程序的堆栈帧。

(hexagon-gdb) bt
#0  set_quotes (lq=0x34c78 "<QUOTE>", rq=0x34c88 "<UNQUOTE>")

at input.c:530
#1  0x6344 in m4_changequote (argc=3, argv=0x33c70)
at builtin.c:882
#2  0x8174 in expand_macro (sym=0x33320) at macro.c:242
#3  0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30)
at macro.c:71
#4  0x79dc in expand_input () at macro.c:40
#5  0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195
           

我们再多走几行看看会发生什么。 前两次,我们可以使用s; 接下来的两次我们使用 n 来避免陷入 xstrdup 子例程。

(hexagon-gdb) s
0x3b5c  532         if (rquote != def_rquote)

(hexagon-gdb) s
0x3b80  535         lquote = (lq == nil || *lq == ’\0’) ?  \

def_lquote : xstrdup(lq);

(hexagon-gdb) n
536         rquote = (rq == nil || *rq == ’\0’) ? def_rquote\
 : xstrdup(rq);

(hexagon-gdb) n
538         len_lquote = strlen(rquote);
           

显示的最后一行看起来有点奇怪; 我们可以检查变量 lquote 和 rquote 以查看它们是否实际上是我们指定的新左引号和右引号。 我们使用命令 p(打印)来查看它们的值。

(hexagon-gdb) p lquote
$1 = 0x35d40 "<QUOTE>"
(hexagon-gdb) p rquote
$2 = 0x35d50 "<UNQUOTE>"
           

lquote 和 rquote 确实是新的左右引号。 为了查看一些上下文,我们可以使用 l (list) 命令显示围绕当前行的十行源代码。

(hexagon-gdb)  l
533        xfree(rquote);
534
535         lquote = (lq == nil || *lq == ’\0’) ? def_lquote\
 : xstrdup (lq);
536         rquote = (rq == nil || *rq == ’\0’) ? def_rquote\

 : xstrdup (rq);
537
538         len_lquote = strlen(rquote);
539         len_rquote = strlen(lquote);
540     }
541
542     void
           

让我们跳过设置 len_lquote 和 len_rquote 的两行,并检查这些变量的值。

(hexagon-gdb) n
539         len_rquote = strlen(lquote);

(hexagon-gdb) n
540     }

(hexagon-gdb) p len_lquote
$3 = 9
(hexagon-gdb) p len_rquote
$4 = 7
           

这看起来肯定是错误的,假设 len_lquote 和 len_rquote 分别是 lquote 和 rquote 的长度。 我们可以使用 p 命令将变量设置为更好的值,因为它可以打印任何表达式的值,并且该表达式可以包括子例程调用和赋值。

(hexagon-gdb)  p len_lquote=strlen(lquote)
$5 = 7

(hexagon-gdb)  p len_rquote=strlen(rquote)
$6 = 9
           

这足以解决在 m4 内置 defn 中使用新引号的问题吗? 我们可以让 m4 继续执行 c (continue) 命令,然后尝试最初出现问题的示例:

(hexagon-gdb) c
Continuing.
define(baz,defn(<QUOTE>foo<UNQUOTE>))

baz
0000
           

成功! 新报价现在与默认报价一样有效。 问题似乎只是定义错误长度的两个拼写错误。 我们通过给它一个 EOF 作为输入来允许 m4 退出:

Ctrl-d
Program exited normally.
           

调试器生成的消息“程序正常退出”。 表示 m4 已经执行完毕。 我们可以使用 quit 命令结束我们的调试会话。

(hexagon-gdb) quit
           

继续阅读