调试器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的基本使用方式(一) 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 用于检查类是否具有运算符/成员的 C++ 类型特征[重复]

    这个问题在这里已经有答案了 可能的重复 是否可以编写一个 C 模板来检查函数是否存在 https stackoverflow com questions 257288 is it possible to write a c template
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co

随机推荐

  • 蟒蛇集

    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