- 2.5.4 shell 命令
- 2.5.5 Tcl 脚本
- 2.5.6 记录输出
- 2.5.7 获得帮助
- 2.5.8 示例调试会话
如果你需要在调试会话期间偶尔执行 shell 命令,则无需离开或暂停调试器; 相反,你可以使用 shell 命令。
shell 命令字符串
调用标准 shell 来执行 command_string。 如果存在,环境变量 SHELL 决定运行哪个 shell。 否则,调试器将使用默认 shell(例如,UNIX 系统上的 /bin/sh)。
在开发环境中经常需要实用程序 make。 为此,你不必使用 shell 命令。 例如:
make make_args
… 使用指定的参数执行 make 程序。 这相当于“shell make make_args”。
调试器可选择支持使用 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 | 显示日志设置的当前值。 |
你始终可以使用命令帮助向调试器询问有关其命令的信息。
| 命令 | 描述 |
|---|---|
| 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”声明或保证(如果你的调试器版本附带有)。 |
本节提供了一个示例调试会话,它演示了基本的调试器命令。
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(,) define(baz,defn( foo)) 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(,) 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 "", rq=0x34c88 "") at input.c:530 530 if (lquote != def_lquote)
显示 m4 现在挂起的子程序(及其参数)的显示称为堆栈帧显示。 它显示了堆栈的摘要。 我们可以使用 backtrace 命令(也可以拼写为 bt)来查看我们在整个堆栈中的位置:backtrace 命令显示每个活动子程序的堆栈帧。
(hexagon-gdb) bt #0 set_quotes (lq=0x34c78 "", rq=0x34c88 "") 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 == ’ ’) ? def_lquote : xstrdup(lq); (hexagon-gdb) n 536 rquote = (rq == nil || *rq == ’ ’) ? def_rquote : xstrdup(rq); (hexagon-gdb) n 538 len_lquote = strlen(rquote);
显示的最后一行看起来有点奇怪; 我们可以检查变量 lquote 和 rquote 以查看它们是否实际上是我们指定的新左引号和右引号。 我们使用命令 p(打印)来查看它们的值。
(hexagon-gdb) p lquote $1 = 0x35d40 "" (hexagon-gdb) p rquote $2 = 0x35d50 ""
lquote 和 rquote 确实是新的左右引号。 为了查看一些上下文,我们可以使用 l (list) 命令显示围绕当前行的十行源代码。
(hexagon-gdb) l 533 xfree(rquote); 534 535 lquote = (lq == nil || *lq == ’ ’) ? def_lquote : xstrdup (lq); 536 rquote = (rq == nil || *rq == ’ ’) ? 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(foo)) baz 0000
成功! 新报价现在与默认报价一样有效。 问题似乎只是定义错误长度的两个拼写错误。 我们通过给它一个 EOF 作为输入来允许 m4 退出:
Ctrl-d Program exited normally.
调试器生成的消息“程序正常退出”。 表示 m4 已经执行完毕。 我们可以使用 quit 命令结束我们的调试会话。
(hexagon-gdb) quit



