调试器GDB的基本使用方式(一)

2023-11-20

GDB的功能及其丰富,我们按照调试的流程进行说明。基本用法很简单。

流程如下所示:

  1. 带着调试选项编译、构建调试对象。
  2. 启动调试器(GDB)
    1. 设置断点。
    2. 显示栈帧。
    3. 显示值。
    4. 继续执行。

一、准备

        通过 gcc 的 -g 选项生成调试信息

        gcc -Wall -O2 -g 源文件

        如果使用Makefile 构建,一般要给CFLAGS中指定 -g 选项。

        CFLAGS = -Wall -O2 -g  

        如果用configure 脚本生成 Makefile,可以这样用。

        ./configure CFLAGS=-Wall -O2 -g  

        构建方法通常会写在 INSTALL、README 等文件中,参考即可。

        编译器含有针对源代码中的各种各样的错误输出信息的功能,称为警告选项(Warning Option)。这些信息并一定是错误,但却指出了容易引发bug的编码方式。

        要用心写出整洁的代码,编译时不要出现警告甚至错误信息。编译错误是bug的最大来源。

        -Werror 选项可以在警告发生时,将其当作错误来处理。

        此外,发生编译器错误时不会生成可执行文件。

        

        编译器GCC加上优化选项后,实际的执行顺序可能由于优化与源代码顺序不同,因此利用调试器跟踪运行时,有时会执行到莫名其妙的地方,从而造成混乱。比如内联(inline)函数优化(去掉函数调用,而将函数代码在调用处展开),该函数名上就无法设置断点。这是因为内联优化从目标文件中去掉了该函数的入口点,符号表中也没有改函数的名称。

        优化还会将局部变量保存到寄存器中,因此无法显示该局部变量的内容,必须直接查看寄存器的值。由于这些副作用,有些人建议在调试时去掉优化选项进行编译和构建,但是我们不推荐这样做。

        为什么呢?

        使用C、C++ 这些过程式编程语言编程,就是利用编译器这个工具把我们期待的行为告诉计算机。尽管无需详细了解编译器优化选项的方方面面,但至少应当知道,优化编译选项可能会让执行顺序和源代码顺序不同。而优化选项就是在理解这一点的基础之上添加的,用来加快只想速度,所以没有必要特意去除。

        如果只是调试时去掉优化选项,那就必须管理有优化编译选项和无优化编译选项两种可执行文件。管理对象增加会导致管理成本增加,并不是好事。这会消耗大量成本,比如花费大量时间对没有优化选项的可执行文件进行调试,但实际上优化后的可执行文件中的bug并不存在;那么怎么管理同一源代码进行编译、构建出不同可执行文件呢?

        而且准备两个可执行文件的话,测试工作量肯定回变成两倍,管理成本也会上升。

二、启动

        gdb 可执行文件名

        通过emacs启动的方法是M-x gdb。

        启动后显示下述信息,出现gdb提示符。

skyesysi@VM-8-95-centos ~/hack_test]$ gdb a.out 
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.tl2
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /data/home/skyesysi/hack_test/a.out...done.
(gdb) 

设置断点

        可以在函数名和行号等上设置断点,程序运行后,到达断点就会自动暂停运行。此时可以查看该时刻的变量值,显示栈帧、重新设置断点或重新运行等。断点命令(break)可以简写为b。

格式:

        break        断点

        (gdb) b main
        Breakpoint 1 at 0x400400: file assemble.c, line 17.

断点可以通过函数名、当前文件内的行号来设置,也可以先制定文件名再指定行号,还可以指定与暂停位置的偏移量,或者用地址来设置。

格式:

        break        函数名

        break        行号

        break        文件名:行号

        break        文件名:函数名

        break        +偏移量

        break        - 偏移量

        break        *地址

【例】

上面例子中,分别对iseq_compile()函数、compile.c的516行、暂停往后3行、地址(0x8116d6)设置断点。

如果不指定断点位置,就在下一行代码上设置断点。

设置好的断点可以通过info break 确认。

运行

        用 run 命令开始运行,不加参数执行run,就会执行到设置断点的位置后暂停执行,可以简写为r。

格式:

        run  参数

 经常遇到的操作是在main() 上设置断点,然后执行到main() 函数,start 命令能达到同样的效果。

格式:

        start 

显示栈帧

        backtrace命令可以在遇到断点而暂停执行时显示栈帧。该命令简写为bt。次啊外,backtrace 的别名还有 where 和 info stack(简写为info s)。

格式:
        backtrace 

        bt

显示所有栈桢

        backtrace N

        bt N

只显示开头N个栈桢

        backtrace -N

        bt -N

只显示最后N个栈桢

        backtrace full 

        bt full

        backtrace full N

        bt full N

        backtrace full -N

        bt full -N

不仅显示backtrace,还要显示局部变量。

【例】

     

【例:只显示前三个栈帧】

【例:从外向内显示3个栈帧,及其局部变量】

        显示栈帧之后,就可以看到程序在何处停止(即断点位置),以及程序的调用路径。

 显示变量

        print 命令可以显示变量。print 可以简写为p。

格式:

        print 变量

        该例显示 argv[]。可以看出,argv[0] 中为可执行文件名(/home/hyoshiok/coreutils/src/uname),argv[1]中为第一个选项(-a)。

显示寄存器

        info registers 可以显示寄存器,简写为info reg。

(gdb)  info reg
rax            0x0                 0
rbx            0x4f3c020           83083296
rcx            0x0                 0
rdx            0x0                 0
rsi            0x305c598           50709912
rdi            0x0                 0
rbp            0x7f012b357870      0x7f012b357870
rsp            0x7f012b357860      0x7f012b357860
r8             0xffffffff          4294967295
r9             0x7f                127
r10            0x1                 1
r11            0x246               582
r12            0x1                 1
r13            0x4f6c068           83279976
r14            0x49d8710           77432592
r15            0x2ac3580           44840320
rip            0x43bdac            0x43bdac <qemu_bh_delete+28>
eflags         0x10246             [ PF ZF IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x2b                43
es             0x2b                43
fs             0x0                 0
gs             0x0                 0

在寄存器名之前添加$,即可显示各个寄存器的内容

(gdb) p $rax
$1 = 0

   显示可以使用以下格式,如表2-3所示。

        格式:

        p / 格式 变量

        表2-3 显示寄存器可使用的格式

 

 

        十进制数的97为ASCII字符的 ‘a’ 。

        程序指针可以写为$pc,也可写为eip,两者都可以显示。这是因为Intel IA-32 架构中的程序指针名为eip。

(gdb) p $pc
$2 = (void (*)()) 0x43bdac <qemu_bh_delete+28>
(gdb) p $rip
$3 = (void (*)()) 0x43bdac <qemu_bh_delete+28>
(gdb) 

 用 x 命令可以显示内存的内容。x 这个名字的由来是 eXaming。

        格式:

        x / 格式 地址

(gdb) x $pc
0x43bdac <qemu_bh_delete+28>:   0x001847c6
(gdb) x/i $pc
=> 0x43bdac <qemu_bh_delete+28>:        movb   $0x0,0x18(%rdi)

此处 x / i 意为显示汇编指令。

一般使用 x 命令时,格式为 x / NFU ADDR。此处ADDR 为希望显示的地址,N为重复次数,F为前面讲过的格式(x、d、u、o、t、a、c、f、s、i),U为表2-4 中所示的单位。

 

下面显示从 pc 所指的地址开始的10条指令。

(gdb) x/10i $pc
=> 0x43bdac <qemu_bh_delete+28>:        movb   $0x0,0x18(%rdi)
   0x43bdb0 <qemu_bh_delete+32>:        movb   $0x1,0x1a(%rdi)
   0x43bdb4 <qemu_bh_delete+36>:        mov    -0x8(%rbp),%rax
   0x43bdb8 <qemu_bh_delete+40>:        xor    %fs:0x28,%rax
   0x43bdc1 <qemu_bh_delete+49>:        jne    0x43bdc5 <qemu_bh_delete+53>
   0x43bdc3 <qemu_bh_delete+51>:        leaveq 
   0x43bdc4 <qemu_bh_delete+52>:        retq   
   0x43bdc5 <qemu_bh_delete+53>:        callq  0x439308 <__stack_chk_fail@plt>
   0x43bdca:    nopw   0x0(%rax,%rax,1)
   0x43bdd0 <qemu_bh_update_timeout>:   push   %rbp

也有反汇编的命令 disassemble,简写为disas

格式:

        disassemble。

        disassemble 程序计数器。

        disassemble 开始地址 结束地址。

格式1 反汇编整个函数,2为反汇编程序计数器所在函数的整个函数,3为反汇编开始到结束的地址

(gdb) 
Dump of assembler code for function qemu_bh_delete:
   0x000000000043bd90 <+0>:     push   %rbp
   0x000000000043bd91 <+1>:     mov    %rsp,%rbp
   0x000000000043bd94 <+4>:     sub    $0x10,%rsp
   0x000000000043bd98 <+8>:     callq  0x529f40 <mcount>
   0x000000000043bd9d <+13>:    mov    %fs:0x28,%rax
   0x000000000043bda6 <+22>:    mov    %rax,-0x8(%rbp)
   0x000000000043bdaa <+26>:    xor    %eax,%eax
=> 0x000000000043bdac <+28>:    movb   $0x0,0x18(%rdi)
   0x000000000043bdb0 <+32>:    movb   $0x1,0x1a(%rdi)
   0x000000000043bdb4 <+36>:    mov    -0x8(%rbp),%rax
   0x000000000043bdb8 <+40>:    xor    %fs:0x28,%rax
   0x000000000043bdc1 <+49>:    jne    0x43bdc5 <qemu_bh_delete+53>
   0x000000000043bdc3 <+51>:    leaveq 
   0x000000000043bdc4 <+52>:    retq   
   0x000000000043bdc5 <+53>:    callq  0x439308 <__stack_chk_fail@plt>
End of assembler dump.

首先在任意位置暂停执行程序,即可像上例哪样自由显示任意变量和地址,通过确认其值与预期是否相同,以确认是否存在bug。

单步执行

        单步执行的意思是根据源代码一行一行的执行。

        执行源代码中的一行命令是next (简写为n)。执行时如果遇到函数调用,可能想执行到函数内部,此时可以用step(简写为s)命令。

        例如,下例中

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

调试器GDB的基本使用方式(一) 的相关文章

  • 电话号码的正则表达式,不允许全零

    需要您的正则表达式帮助 我当前的正则表达式是 d 8 最小长度为 8 不允许包含字母 特殊字符和空格 我还想禁止全零 如 00000000 Thanks 该模式应该可以满足您的需求 0 d 8 The 0 部分是负前瞻 将阻止仅输入零 Ex
  • 如何从RichTextBox中获取显示的文本?

    如何获得显示的RichTextBox 中的文本 我的意思是 如果 RichTextBox 滚动到末尾 我只想接收那些对我来说可见的行 P S 获得第一个显示的字符串就足够了 您想使用 RichTextBox GetCharIndexFrom
  • 如何使用 MVVM 更新 WPF 中编辑的数据? [复制]

    这个问题在这里已经有答案了 我正在为聊天应用程序构建 UI 设计 在尝试更新所选联系人的消息时遇到问题 选择现有联系人 选择编辑选项 然后编辑其属性 例如用户名和图像 后 唯一进行的更改是联系人的用户名和图像 我仍然想更改 MessageM
  • 使用API​​隐藏程序标题栏

    它可以使用 c 和 windows api 删除窗口控制台标题栏 如果是的话如何 请 这个简单的应用程序隐藏并显示其所在控制台的标题栏 它会立即将控制台标题更改为 guid 以查找窗口句柄 然后 它使用 ToggleTitleBar 使用找
  • 使用 OpenGL 着色器进行数学计算 (C++)

    我有一个矩阵 例如 100x100 尺寸 我需要对每个元素进行计算 matrix i j tt 8 5例如 我有一个巨大的矩阵 我想使用 OpenGL 着色器来实现该算法 我想使用着色器 例如 uniform float val unifo
  • C# 中四舍五入到偶数

    我没有看到 Math Round 的预期结果 return Math Round 99 96535789 2 MidpointRounding ToEven returning 99 97 据我了解 MidpointRounding ToE
  • 访问“if”语句之外的变量

    我怎样才能使insuranceCost以外可用if陈述 if this comboBox5 Text Third Party Fire and Theft double insuranceCost 1 在 if 语句之外定义它 double
  • 从 future 中检索值时的 SIGABRT

    我在使用 C 11 future 时遇到问题 当我打电话时wait or get 关于返回的未来std async 程序接收从mutex标头 可能是什么问题呢 如何修复它 我在 Linux 上使用 g 4 6 将以下代码粘贴到 ideone
  • 默认值 C# 类 [重复]

    这个问题在这里已经有答案了 我在控制器中有一个函数 并且我收到表单的信息 我有这个代码 public Actionresult functionOne string a string b string c foo 我尝试将其转换为类似的类
  • 您可以在一个 Windows Azure 实例上部署多个 Web 应用程序吗?

    是否可以在一个 windows azure 小型计算实例中运行一堆 Web 应用程序 我正在考虑使用 Azure 作为放置一堆处于开发和非生产状态的项目 Web 应用程序 的地方 有些实际上已经被封存了 但我想在某个地方有一个活跃的实例 我
  • 格式化货币

    在下面的示例中 逗号是小数点分隔符 我有这个 125456 89 我想要这个 125 456 89 其他示例 23456789 89 gt 23 456 789 89 Thanks 看看这个例子 double value 12345 678
  • 以编程方式更新 ClickOnce 应用程序的部署清单会导致缺少 4.0 中所需的 <兼容框架> 元素

    我正在致力于自动化 NET 4 0 ClickOnce WPF 应用程序的安装程序 该应用程序需要在应用程序配置文件 我经历了寻找必须遵循的具体步骤的棘手过程Mage exe http msdn microsoft com en us li
  • 在VisualStudio DTE中,如何获取ActiveDocument的内容?

    我正在 VisualStudio 中编写脚本 并尝试获取当前 ActiveDocument 的内容 这是我当前的解决方案 var visualStudio new API VisualStudio 2010 var vsDTE visual
  • 错误左值需要作为赋值C++的左操作数

    整个程序基本上只允许用户移动光标 如果用户位于给定的坐标范围 2 2 内 则允许用户键入输入 我刚刚提供了一些我认为足以解决问题的代码 我不知道是什么导致了这个问题 你能解释一下为什么会发生吗 void goToXY int int 创建一
  • 使用 foreach 循环和 XmlNodeList C# 将新节点附加到节点列表

    目前我处理的是这样的XML类型 XML FILE http 20drive google com open id 0By5BxgNi9eGcRldxcEZNU0FDTzQ 参考XML文件 我想检查一个节点 如果找不到该节点 我必须将该节点附
  • TPL 数据流块下游如何获取源生成的数据?

    我正在使用 TPL Dataflow 处理图像 我收到处理请求 从流中读取图像 应用多次转换 然后将生成的图像写入另一个流 Request gt Stream gt Image gt Image gt Stream 为此 我使用块 Buff
  • 如何将对象转换为传递给函数的类型?

    这不会编译 但我想做的只是将对象转换为传递给函数的 t public void My Func Object input Type t t object ab TypeDescriptor GetConverter t ConvertFro
  • 在 C++ 和 Windows 中使用 XmlRpc

    我需要在 Windows 平台上使用 C 中的 XmlRpc 尽管我的朋友向我保证 XmlRpc 是一种 广泛可用的标准技术 但可用的库并不多 事实上 我只找到一个库可以在 Windows 上执行此操作 另外一个库声称 您必须做很多工作才能
  • 如何设置 CMake 与 clang 交叉编译 Windows 上的 ARM 嵌入式系统?

    我正在尝试生成 Ninja makefile 以使用 Clang 为 ARM Cortex A5 CPU 交叉编译 C 项目 我为 CMake 创建了一个工具链文件 但似乎存在错误或缺少一些我无法找到的东西 当使用下面的工具链文件调用 CM
  • 新的 .NET 6 控制台模板中的 C# 函数重载不起作用

    我在尝试重载该函数时遇到错误Print object in the 新的 NET 6 C 控制台应用程序模板 https learn microsoft com en us dotnet core tutorials top level t

随机推荐

  • 蟒蛇集

    In this tutorial we are going to learn Python Set In our previous article we learnt about Python String You can learn it
  • 如何在 Ubuntu 12.10 上使用 Python 创建 Nagios 插件

    介绍 Python 是 Linux 上默认提供的流行命令处理器 我们之前已经介绍过如何在Ubuntu 12 10 x64上安装Nagios监控服务器 这次 我们将扩展这个想法并使用 Python 创建 Nagios 插件 这些插件将在客户端
  • 如何编辑 Sudoers 文件

    介绍 权限分离是 Linux 和类 Unix 操作系统中实现的基本安全范例之一 普通用户以有限的权限进行操作 以减少对自己环境 而不是更广泛的操作系统 的影响范围 一个特殊的用户 称为root has 超级用户特权 这是一个管理帐户 没有普
  • JSTL 教程、JSTL 标签示例

    JSTL 代表JSP 标准标签库 JSTL 是标准标记库 它提供标记来控制 JSP 页面行为 JSTL 标签可用于迭代和控制语句 国际化 SQL 等 我们将在本 JSTL 教程中详细研究 JSTL 标签 之前我们看到了如何使用JSP EL
  • 了解 Python 3 中的类继承

    介绍 面向对象编程创建可重用的代码模式 以减少开发项目中的冗余 面向对象编程实现可回收代码的一种方法是通过继承 此时一个子类可以利用另一个基类的代码 本教程将介绍 Python 中继承的一些主要方面 包括父类和子类如何工作 如何重写方法和属
  • 电商java 面试题_JAVA电商项目面试题(一)

    需要按照功能点把系统拆分 拆分成独立的功能 单独为某一个节点添加服务器 需要系统之间配合才能完成整个业务逻辑 叫做分布式 集群 同一个工程部署到多台服务器上 优点 1 把模块拆分 使用接口通信 降低模块之间的耦合度 2 把项目拆分成若干个子
  • Rabbitmq消息的有序性、消息不丢失、不被重复消费

    如何保证消息的顺序性 如图所示 RabbitMQ保证消息的顺序性 就是拆分多个 queue 每个 queue 对应一个 consumer 消费者 就是多一些 queue 而已 确实是麻烦点 或者就一个 queue 但是对应一个 consum
  • 查经 民数记3章 利未人

    3章 利未人 1 4节 亚伦的儿子们 5 13节 利未人的职责 14 39 利未人男丁的统计 40 51节 利未人代替长子的地位 本章记载了利未人被神呼召 代替以色列各家长子成为事奉神的人 利未人的宗族 人数 及各族负责的事务 这件事灵意上
  • 程序的调试技巧。

    什么是调试 调试又叫Debug 又称除错 是发现和减少计算机程序或电子仪器设备中程序错误的一个过程 生活中所有发生的事情都一定有迹可循 如果问心无愧 就不需要掩盖也就没有迹象了 如果问心有愧疚 必然需要掩盖 那就一定会有迹象 迹象越多就容易
  • 如何控制asp.net控件TextBox输入内容的长度--(多种方法)

    2009 10 22 17 36 件代码如下
  • 在 CentOS 上安装 Docker Engine

    文章目录 在 CentOS 上安装 Docker Engine 先决条件 操作系统要求 卸载旧版本 安装方法 使用 rpm 存储库安装 设置存储库 安装 Docker Engine 安装最新版本 安装指定版本 以非 root 用户身份管理
  • js获取时间戳的四种方法

  • vscode使用手册

    VS Code Visual Studio Code 是一款轻量级 跨平台的源代码编辑器 支持语法高亮 自动补全 调试 Git 版本控制等功能 下面是一些使用 VS Code 的基本操作 安装和启动 在官网上下载并安装 VS Code 打开
  • react里面的接口调用方法

    react接口调用 我们通过npm create react app my app创建react项目 在项目里都是要进行接口调用来获取数据 进行增删改查各种操作的 所以掌握接口调用方式是非常必要的 话不多说进入正题 想要掌握接口调用的内里逻
  • 何恺明组《Designing Network Design Spaces》的整体解读(一篇更比六篇强)

    本文原载自知乎 已获原作者授权转载 请勿二次转载 https zhuanlan zhihu com p 122557226 statistics 大法好 DL不是statistics 因为DL不如statistics 基本全文从统计学的角度
  • 编程猫python讲师面试_【编程猫教师面试】笔试:试题+打字测速-看准网

    985师范本加硕 想要从事k12教育 坚挺到最后一轮但是未通过的小姐姐掩面飘过 来谈谈我的面试感受吧 个人觉得猫厂管培生的面试整体流程安排挺合理的 有感觉确实是在用心的挑选人才 然后所有的面试官都很nice 我是直接在boss直聘上投的简历
  • ffmpeg最简单的解码保存YUV数据

    文章转载自 http blog chinaunix net xmlrpc php r blog article id 4584541 uid 24922718 video的raw data一般都是YUV420p的格式 简单的记录下这个格式的
  • 技术英雄会【新闻】CSDN最有价值博客TOP10颁奖【图】【我在左边数第四个】

    2007年04月06日 10 04 新浪科技夹带些私货 呵呵 社区英雄会 一 问周鸿祎一个问题 社区英雄会 二 问CSDN一个信息过滤器的问题 技术英雄会 三 社区英雄们的与会感言大赏 技术英雄会 四 也谈如何发掘到需要的内容和英雄 图为
  • linux_compress

    tar 解包 tar xvf FileName tar 打包 tar cvf FileName tar DirName 注 tar是打包 不是压缩 gz 解压1 gunzip FileName gz 解压2 gzip d FileName
  • 调试器GDB的基本使用方式(一)

    GDB的功能及其丰富 我们按照调试的流程进行说明 基本用法很简单 流程如下所示 带着调试选项编译 构建调试对象 启动调试器 GDB 设置断点 显示栈帧 显示值 继续执行 一 准备 通过 gcc 的 g 选项生成调试信息 gcc Wall O