
2.1.5 《Debugging With GDB》
文章平均质量分 83
2.1.5 《Debugging With GDB》
hyh-hz
书是越读越薄的
展开
-
32 Using History Interactively
历史扩展分为两个部分。从历史中选择的行称为事件,而对该行进行操作的部分称为单词。该行按照Bash的方式拆分成单词,因此被引号包围的多个单词被视为一个单词。如果单词指定符以‘^’,‘$’,‘*’,‘-’或‘%’开头,则可以省略该符号。历史扩展将历史列表中的单词引入输入流,使得重复命令、将先前命令的参数插入到当前输入行中或快速修正先前命令中的错误变得容易。历史库提供了一种历史扩展功能,类似于csh提供的历史扩展。在可选的单词指定符之后,您可以添加一个或多个以下修饰符的序列,每个修饰符前面都带有一个‘:’。翻译 2025-02-04 11:28:26 · 13 阅读 · 0 评论 -
31 Command Line Editing
作为特殊情况,如果此命令紧接其后是一个既不是数字也不是负号的字符,则下一个命令的参数计数将乘以四。例如,要给C-d命令提供一个参数1 0,你可以输入‘M-1 0C-d’,这将删除输入行上的接下来十个字符。按下ESC会切换到“命令”模式,在这里你可以使用标准的vi移动键来编辑该行的文本,用“k”跳转到前一条历史行,用“j”跳转到后一条历史行,等等。为了在emacs和vi编辑模式之间进行交互式切换,可使用命令M-C-j (在vi模式下绑定到emacs编辑模式,在emacs模式下绑定到vi编辑模式)。翻译 2025-02-03 23:16:56 · 29 阅读 · 0 评论 -
30 Reporting Bugs in gdb
假设发生了奇怪的事情,比如你的gdb副本不同步了,或者你在系统中遇到了C库中的错误。如果你告诉我们预期会出现崩溃,那么当我们的副本没有崩溃时,我们就知道错误并没有发生在我们身上。这通常会花费大量时间,而且不太有用,因为我们要找到错误的方法是通过在调试器下运行带有断点的单个示例,而不是从一系列示例中纯粹推断出错误所在。可能之前已经有人报告过这个错误了,但是除非你的错误报告是完整的、自成一体的,否则你和我们都不知道这一点。但是,你应该注意到,你对“无效输入”的理解可能是我们对“扩展”或“支持传统做法”的理解。翻译 2025-02-03 23:08:06 · 54 阅读 · 0 评论 -
29 JIT Compilation Interface
使用JIT编译的程序通常难以调试,因为它们的部分代码是在运行时生成的,而不是从目标文件中加载的,而gdb通常在这些目标文件中找到程序的符号和调试信息。为了调试使用JIT编译的程序,gdb提供了一个接口,允许程序在运行时将内存中的符号文件注册到gdb。当gdb附加时,它从全局变量中读取符号文件的链表,以查找现有代码,并在该函数中设置断点,以便它可以了解额外的代码。如果JIT在未注销代码的情况下释放或重新编译代码,则gdb和JIT将会泄漏与相关符号文件使用的内存。1.从链表中移除与该代码对应的代码条目。翻译 2025-02-03 23:04:46 · 21 阅读 · 0 评论 -
28 gdb Annotations
级别0表示不进行任何注释,级别1表示在gdb作为gnu Emacs的子进程运行时使用,级别3是适合控制gdb的程序的最大注释级别,而级别2注释已被废弃(参见gdb中“注释界面的局限性”部分)。其中,name是信号名称,例如SIGILL或SIGSEGV,strin g是信号的解释,例如Ille gal Instruction或Segmentation fault.intro-text,middle-text和end-text是为了用户方便而设置的,并没有特定的格式。普通注释,表示提示的结束;翻译 2025-02-03 22:59:30 · 42 阅读 · 0 评论 -
27 The gdb/mi Interface
27.1 功能和目的 基于gdb和miisaline的面向企业的文本界面通过使用‘--interpreter’命令行选项激活(参见第2.1.2节[模式选项],第13页)。该界面特别旨在支持将调试器作为更大系统中一个小组件的开发。 本章是thegdb/mi接口的规范,以参考手册的形式编写。 请注意,gdb/mi仍在建设中,因此下面描述的一些功能是不完整的,可能会发生变化(请参见第27.6节[gdb/mi开发和前端结束],第2翻译 2025-02-03 22:54:49 · 48 阅读 · 0 评论 -
26 Using gdb under gnu Emacs
在文本命令模式下,如果您输入M-x speedbar,Emacs会显示一个单独的窗口,当GUD缓冲区处于当前状态时,它会显示一个回溯。在这种情况下,gdb可能通过搜索环境的PATH变量找到您的程序,但在某些操作系统上,它可能找不到源代码。如果您需要用不同的名称调用gdb(例如,如果您保留多个配置,名称不同),您可以自定义Emacs变量gud-gdb-command-name以运行您想要的版本。我们称之为文本命令模式。gdb的初始工作目录打印在GUD缓冲区的第一行,这作为指定gdb操作文件的命令的默认值。翻译 2025-02-03 22:39:53 · 28 阅读 · 0 评论 -
25 gdb Text User Interface
因为在TUI模式下箭头键滚动的是活动窗口,所以除非命令窗口有焦点,否则readline无法正常使用箭头键。当另一个窗口处于活动状态时,必须使用其他readline键绑定,如C-p、C-n、C-b和C-f来控制命令窗口。gdb文本用户界面(TUI)是一个终端界面,它使用c urses库在单独的文本窗口中显示源文件、汇编输出、程序寄存器和gdb命令。您还可以在gdb运行期间通过各种TUI命令和键绑定,如C-xC-a,在TUI模式中切换进出。当gdb处于标准模式时,大多数这些命令会自动切换到TUI模式。翻译 2025-02-03 22:35:43 · 39 阅读 · 0 评论 -
24 Command Interpreters
gdb所使用的解释器在运行时可能无法动态切换。虽然您在启动时只能选择一个解释器,但您可以通过当前解释器使用适当的命令在任何解释器中执行命令。默认情况下,gdb将使用控制台解释器启动。目前,gdb支持两种命令解释器,即控制台解释器(有时称为命令行解释器或CLI)和机器接口解释器(或gdb/mi)。gdb支持多种命令解释器,并提供了一些命令基础设施,以便用户或用户界面开发者可以在解释器之间切换或在其他解释器中运行命令。gdb/mi也有类似的命令,但它仅在支持gdb/mi版本2(或更高版本)的gdb中可用。翻译 2025-02-03 22:31:17 · 11 阅读 · 0 评论 -
23 Extending gdb
最后,如果此文件不存在,则gdb将查找名为“data-directory/Python/auto-load/real-name”的文件,其中data- directory是gdb的数据目录(可通过show data- directory查看,见第18.4节[数据文件],第198页),而real-name是对象文件的真实名称,如上所述。每个函数都会传递一个值;由于存储在命令文件中的命令通常比交互式输入的命令更为通用,因此它们经常需要处理复杂的情况,例如变量和符号的不同或意外值、被调试程序构建方式的变化等。翻译 2025-02-03 22:28:22 · 45 阅读 · 0 评论 -
22 Controlling gdb
如果您的程序包含使用多个C++ ABI的代码,或者gdb无法正确识别您程序的ABI,则可以告诉gdb使用哪个ABI。目前支持的ABI包括“gnu-v2”,用于3.0之前的g++版本,“gnu-v3”,用于3.0及更高版本的g++,以及“hpaCC”,用于HP ANSI C++编译器。另一方面,‘设置输入-基数10’保持输入基数不变,无论其原本是什么,因为‘10’没有任何前导或尾随的基数符号,在当前基数下被解释。因此,如果当前基数是16,‘10’将在十六进制中解释,即为十进制的16,这不会改变基数。翻译 2025-02-03 19:53:47 · 46 阅读 · 0 评论 -
21 Configuration-Specific Information
否则,最简单的方法是将两个系统的工件目录设置为对象文件所在的目录,然后通过其名称引用该文件,而不使用任何路径。如果gdb配置为具有此功能的操作系统,则命令info proc可用于报告运行您程序的进程的信息,或报告系统上运行的任何进程的信息。请注意,必须将变量地址转换为char*,否则djgpp_ base_ address的值,即adjgpp程序中所有变量和函数的基地址,将按照C指针运算规则相加:如果i被声明为int,gdb将将djgpp_ base_ address的值乘以4加到i的地址上。翻译 2025-02-03 19:42:32 · 32 阅读 · 0 评论 -
20 Debugging Remote Programs
你需要这样做是因为子程序无法知道目标系统上的异常处理表是什么样的(例如,处理器的表可能位于rom中,包含指向ram中的表的条目)。此外,gdb还提供了一种通用的串行协议(专属于gdb,但不特定于任何特定的目标系统),如果您编写远程子程序——即在远程系统上运行以与gdb通信的代码——可以使用该协议。但是,在调用set_ debug_ traps之前,如果将它设置为指向程序中的一个函数,则在gdb在陷阱(例如,总线错误)上停止后继续运行时,将调用该函数。您需要一个要调试的程序的副本,包括它需要的所有库。翻译 2025-02-03 19:14:35 · 16 阅读 · 0 评论 -
19 Specifying a Debugging Target
如果您还指定了一个核心文件——通常是来自先前崩溃并生成核心转储的运行——那么 gdb 就有了两个活动目标,并会同时使用它们,首先在核心文件目标中查找,然后在可执行文件中查找,以满足对内存地址的请求。当您需要更多的灵活性时——例如,在物理上分离的主机上运行 gdb,或通过串行端口控制独立系统,或者通过 TCP/IP 连接控制实时系统——您可以使用 `target` 命令来指定为 gdb 配置的目标类型之一(参见第 19.2 节 [管理目标的命令],第 200 页)。可以为多个不同的目标架构构建 gdb。翻译 2025-02-03 19:03:52 · 18 阅读 · 0 评论 -
18 gdb Files
该调试文件的名称通常为 `executable.debug`,其中 `executable` 是相应可执行文件的名称,去掉前导目录(例如,`/usr/bin/ls` 对应的调试文件名为 `ls.debug`)。- 对于“构建 ID”方法,GDB 会在全局调试目录的 `.build-id` 子目录中查找名为 `nn/nnnnnnnn.debug` 的文件,其中 `nn` 是构建 ID 位串的前两个十六进制字符,`nnnnnnnn` 是其余位串。在这些情况下,指定新文件的 `gdb` 命令是很有用的。翻译 2025-02-03 12:03:12 · 48 阅读 · 0 评论 -
17 Altering Execution
如果 `set` 命令的参数字符串的开头与某个 `set` 子命令完全相同,应该使用 `set variable` 命令,而不是单纯使用 `set`。例如,如果你的程序有一个名为 `width` 的变量,尝试仅使用 `set width=13` 来设置新值时会报错,因为 gdb 会认为这是 `set width` 命令。如果你想执行程序中的一个不返回任何值的函数(即 `void` 函数),可以使用这种变体的 `print` 命令,这样就不会因为 `gdb` 会打印 `void` 返回值而导致输出变得混乱。翻译 2025-02-03 11:53:32 · 31 阅读 · 0 评论 -
16 Examining the Symbol Table
如果 `arg` 是一个类型名,它可以是类型名或 `typedef`,对于 C 代码,它的形式可能是 `class class-name`、`struct struct-tag`、`union union-tag` 或 `enum enum-tag`。因此,`i type value` 会给出程序中所有名称包含字符串 `value` 的类型的信息,而 `i type ^value$` 仅会提供完整名称为 `value` 的类型的信息。打印 `arg` 的数据类型,`arg` 可以是一个表达式或数据类型。翻译 2025-02-02 22:34:53 · 36 阅读 · 0 评论 -
15 Using gdb with Different Languages
如果某个帧的语言未知(即对应的函数或代码块是在一个没有被识别扩展名的源文件中定义的),当前的工作语言不会改变,gdb 会发出警告。除了工作语言之外,gdb 知道的每个源文件都有其自己的工作语言。如果您尝试调试一个程序,而工作语言与源语言不同,这可能会导致混淆,特别是当一个表达式对于两种语言都是可接受的,但意义不同的情况下。如果你允许 gdb 自动设置语言,它会识别以 `.c`、`.C` 或 `.cc` 等为后缀的源文件,当 gdb 进入从这些文件编译的代码时,它会将工作语言设置为 C 或 C++。翻译 2025-02-02 22:28:59 · 16 阅读 · 0 评论 -
14 Debugging Programs That Use Overlays
你加载到系统上的可执行文件必须包含每个覆盖模块的指令,这些指令应出现在覆盖模块的加载地址,而不是映射地址。如果覆盖管理器在每次更改覆盖表时调用此函数,这将使 gdb 能够准确跟踪哪些覆盖位于程序内存中,并更新可能已在覆盖中设置的断点。为了决定一个特定的覆盖是否已映射,gdb 会查找 _ovly_table 中的一个条目,其 vma 和 lma 成员分别等于覆盖在可执行文件中对应部分的 VMA 和 LMA。当启用覆盖调试时,gdb 可以找到覆盖中的函数和变量的正确地址,无论该覆盖是否已映射。翻译 2025-02-02 20:28:08 · 17 阅读 · 0 评论 -
13 Tracepoints
(不过需要注意,目标的 `tfile` 命令只能读取主机可访问的文件。通过使用 gdb 的 `trace` 和 `collect` 命令,你可以在程序中指定位置,称为跟踪点,并且可以指定在这些跟踪点达到时评估的任意表达式。例如,与断点一样,跟踪点的编号是从1开始的连续整数,许多与跟踪点相关的命令会使用跟踪点编号作为其参数,以识别要操作的跟踪点。每个追踪点都会单独解析这些表达式,例如,一个名为 `xyz` 的变量,可能在某个追踪点被解释为全局变量,而在另一个追踪点则被解释为局部变量,具体取决于追踪点的位置。翻译 2025-02-02 20:14:05 · 38 阅读 · 0 评论 -
12 C Preprocessor Macros
此定义将覆盖正在调试的程序中所有现有的 `macro` 定义,以及任何先前用户提供的定义。在上面的例子中,请注意,`macro expand-once` 只会扩展原始文本中明确调用的宏——即 `ADD` 的调用——而不会扩展由 `ADD` 引入的宏 `M` 的调用。GDB可以评估包含宏调用的表达式,显示宏展开的结果,并显示宏的定义,包括其定义的位置。显示扩展表达式中所有预处理器宏调用的结果。当我们逐步执行那些移除 `N` 的定义并为其重新定义的指令时,GDB 会在每个点找到当前有效的定义(或者没有定义)。翻译 2025-01-28 16:42:56 · 21 阅读 · 0 评论 -
11 Debugging Optimized Code
为了让GDB支持内联函数,编译器必须在调试信息中记录有关内联的信息——使用DWARF 2格式的GCC做到了这一点,其他一些编译器也能做到。相反,它将内联函数的参数和局部变量显示为调用者中的局部变量。你可以查看它们的参数和局部变量,使用`step`进入内联函数,使用`next`跳过内联函数,使用`finish`跳出内联函数。某些功能在使用 `-g -O` 时表现不如仅使用 `-g` 时好,尤其是在具有指令调度的机器上。在编译器生成的调试信息的帮助下,gdb 可以将运行中的程序映射回原始源代码中的构造。翻译 2025-01-28 13:56:16 · 32 阅读 · 0 评论 -
10 Examining Data
而在基于 x86 的机器上,`$ps` 是 `eflags` 寄存器的别名。事实上,`display` 会根据你的格式指定来决定使用 `print` 还是 `x` —— 如果你指定了 `i` 或 `s` 格式,或指定了单位大小,它会使用 `x`,否则使用 `print`。`$` 仅指代历史中最新的值,`$$` 指代紧接着的上一个值,`$$n` 指代从末尾数起的第 n 个值;例如,`$$2` 是紧接着 `$$` 之前的值,`$$1` 等同于 `$$`,而 `$$0` 等同于 `$`。翻译 2025-01-28 13:54:47 · 20 阅读 · 0 评论 -
9 Examining Source Files
以之前的例子为例,假设 `foo-1.0` 目录从 `/usr/src` 移动到了 `/mnt/cross`,你可以告诉 gdb 在所有源路径名中将 `/usr/src` 替换为 `/mnt/cross`。例如,如果源路径是 `/mnt/cross`,并且源文件记录为 `../lib/foo.c`,gdb 会首先尝试 `../lib/foo.c`,然后尝试 `/mnt/cross/../lib/foo.c`,最后再尝试 `/mnt/cross/foo.c`。将目录 `dirname` 添加到源路径的前面。翻译 2025-01-26 18:13:48 · 17 阅读 · 0 评论 -
8 Examining the Stack
当程序启动时,栈中只有一个栈帧,即主函数(main)的栈帧。它显示每个栈帧的一行信息,从当前正在执行的栈帧(栈帧零)开始,接着是调用它的栈帧(栈帧一),然后依次向上显示栈帧。gdb 会为所有存在的栈帧分配编号,从最内层栈帧开始编号为零,接着是调用它的栈帧编号为一,依此类推。请记住,栈帧零是最内层的(当前正在执行的)栈帧,栈帧一是调用最内层栈帧的栈帧,依此类推。当程序停止时,gdb 会自动选择当前正在执行的栈帧并简要描述它,类似于 frame 命令(请参见第 8.4 节 [关于栈帧的信息],第 81 页)。翻译 2025-01-26 13:39:08 · 22 阅读 · 0 评论 -
7 Recording Inferior’s Execution and Replaying It
默认值为200000。当在记录模式下停止进程记录和回放目标(即在执行日志的末尾时),被调试程序将停留在下一个本应被记录的指令位置。如果被调试程序处于非停止模式(参见第5.4.2节 [非停止模式],第67页)或异步执行模式(参见第5.4.3节 [后台执行],第68页),则无法启动进程记录和回放目标,因为它不支持这两种模式。另一方面,如果在回放模式下停止进程记录和回放目标(即不是在执行日志的末尾,而是在某个较早的时刻),被调试进程将在该较早的状态下“变为活动状态”,然后可以从该状态继续进行常规的“实时”调试。翻译 2025-01-26 12:09:06 · 16 阅读 · 0 评论 -
6 Running programs backward(reverse)
当程序逆向执行时,最近执行的指令会按逆序“未执行”。像 `nexti` 命令一样,`reverse-nexti` 会向后执行单条指令,唯一的区别是被调用的函数会被“未执行”原子化处理。也就是说,如果之前执行的指令是从另一个函数返回的,`reverse-nexti` 会继续向后执行,直到到达当前堆栈帧中对该函数的调用。从函数的第一行开始,`reverse-next` 会将你带回到该函数的调用者,也就是在函数被调用之前,就像正常的 `next` 命令将你从函数的最后一行带回到返回点一样。翻译 2025-01-25 21:23:48 · 24 阅读 · 0 评论 -
5 Stopping and Continuing
使用调试器的主要目的是在程序终止之前暂停程序的执行;或者在程序遇到问题时,能够进行调查并找出原因。在 GDB 中,程序可能会因为多种原因而停止,例如接收到信号、触发断点,或者在执行 GDB 命令(如 `step`)后进入新的代码行。你可以检查和修改变量,设置新的断点或删除旧的断点,然后继续执行程序。通常,GDB 显示的消息会充分解释程序的状态,但你也可以随时显式地请求这些信息。5.1 Breakpoints, Watchpoints, and Catchpoints断点使得程序在达到某个特定点时暂停。对翻译 2025-01-25 19:29:51 · 51 阅读 · 0 评论 -
4 Running Programs Under gdb
你可以通过使用 `info inferiors` 命令列出所有由 gdb 控制的派生进程,并使用 `inferior` 命令在不同的派生进程之间切换(参见第 4.9 节 [调试多个 inferior 和程序],第 32 页)。分离进程后,进程会继续执行。你必须首先通过向 gdb 提供程序名称(在 VxWorks 上除外)作为参数(参见第 2 章 [进入和退出 gdb],第 11 页),或者使用 `file` 或 `exec-file` 命令(参见第 18.1 节 [指定文件的命令],第 187 页)。翻译 2025-01-25 11:02:04 · 32 阅读 · 0 评论 -
3 gdb Commands
例如,你可以使用 `info args` 显示传递给函数的参数,使用 `info registers` 列出当前使用的寄存器,或者使用 `info breakpoints` 列出你设置的断点。例如,`s` 被特别定义为与 `step` 等效,尽管还有其他命令的名称以 `s` 开头。除了 `help`,你还可以使用 gdb 命令 `info` 和 `show` 来查询程序的状态或 gdb 本身的状态。当你用回车键重复 `list` 和 `x` 命令时,它们会构造新的参数,而不是完全重复之前输入的内容。翻译 2025-01-24 18:56:34 · 26 阅读 · 0 评论 -
2 Getting In and Out of gdb
--interpreter=mi`(或 `--interpreter=mi2`)使 gdb 使用 gdb/mi 接口(参见第27章[gdb/mi 接口],第289页),该接口自 gdb 版本 6.0 起包含。因此,你可以有多个初始化文件,一个是主目录中的通用文件,另一个是与你正在调试的程序相关的文件,位于你调用 gdb 的目录中。在处理完所有通过 `-x` 指定的命令文件(以及所有来自初始化文件的命令,如果没有使用 `-n` 禁用的话)后,以状态 0 退出。否则,它将使用表达式的结果作为错误代码退出。翻译 2025-01-19 17:52:30 · 23 阅读 · 0 评论 -
1 A Sample gdb Session
GNU m4(一个通用宏处理器)的一个早期版本出现了如下错误:有时,当我们改变其默认的引用字符串时,用于在一个宏定义中捕获另一个宏定义的命令会停止工作。我们可以使用 backtrace 命令(也可以简写为 bt)来查看我们在整个栈中的位置:backtrace 命令会显示每个活动子程序的栈帧。在查看了源代码之后,我们知道相关的子程序是 m4_changequote,因此我们使用 gdb 的 break 命令在该位置设置了一个断点。我们可以使用 gdb 的 quit 命令结束我们的 gdb 会话。翻译 2025-01-18 18:25:38 · 17 阅读 · 0 评论