GDB调试详解

2023-11-05

调试信息

Linux下的c++程序开发,makefile,cmake等编译工具最终都是调用gcc这一编译工具组。
一般要调试某个程序,为了清晰地看到调试的每一行代码,调用的堆栈信息,变量名和函数名等信息,需要调试程序含有调试符号信息。

  • 1.使用-g可以在编译后的程序中保留调试符号信息

那么判断一个可执行程序是否带有调试信息?
gdb hello_world查看显示结果。
这时候在显示信息的最后一行,如果带有调试信息,则显示
Reading symbols from /root/testclient/hello_server…done.
如果不带调试信息,则显示
Reading symbols from /root/testclient/hello_server2…(no debugging symbols found)…done.

当然,对于一个包含了调试信息的程序,我们也可以通过strip移除调试信息。

#strip hello_wrold

实际上生成调试程序时,同时建议关闭编译器的优化选项。因为不优化,可以让符号文件显示的调试变量等能和源代码完全对应起来。

编译器优化选项:O0-O4 5个级别,O0表示不优化,O1-O4表示优化级别越来越高。

启动调试

gdb调试程序分三种模式:

  1. gdb filename :直接调试目标程序
  2. gdb attach pid : 附加进程
  3. gdb filename corename :调试core文件
调试进程

使用场景:当我们一个程序正在运行,我们如何在不重启这个程序的情况下对这个程序进行调试呢(假如运行一段时间之后发现这个程序不再接受连接了)

gdb attack pid

当我们attach上目标进程后,调试器会暂停下来,这时候我们可以用continue继续运行程序。当然,也可以设置相应的断点。
调试结束后,我们可以用detach命令将进程与调试器分离。最后再quit退出调试器即可。

调试core文件

当我们的程序core dump的时候,我们可以用gdb帮助调试这个问题。我们的linux系统在程序发生core dump的时候,有产生core文件的机制。

  1. 通过ulimit -c 我们可以看到当前系统是否开启了core文件生成功能。
    ulimit -c unlimited // core文件的大小不受限制。
    ulimit -c 100 //设置文件大小最大为100K
  2. 当前设置只在本会话有效。
    永久生效的方法:把ulimit -c unlimited加入/etc/profile

生成的core文件的默认命名方式是core.pid。
gdb filename corename
这时候我们可以看到core dump的位置。我们可以通过bt命令查看奔溃时的调用堆栈,进一步分析找到奔溃的原因。

但是,当程序core dump的时候,我们往往找不到PID,这时候我们就需要自定义core文件的名称了。

自定义core文件的名称

  1. 控制core文件是否添加pid作为扩展
    /proc/sys/kernel/core_uses_pid 文件内容为1开启,0关闭。
  2. 格式化控制core文件的保存位置和文件名。
    /proc/sys/kernel/core_pattern
    eg: /root/testcore/core-%e-%p-%t
    参数说明:
    %p:添加pid
    %e:添加程序名
    %t:添加时间戳
    当然还有其他的参数格式,这里只列举了常用的三个。

GDB调试命令

run

在gdb开始调试之后,并没有直接运行启动这个程序。r启动这个程序。
当然了,假如这个程序已经启动过,则再次输入r命令,则是重启这个程序。

continue

当程序触发断点,或者我们使用ctrl+c让程序中断下来,想让程序继续执行,c继续运行。

break

添加断点,添加断点的方式有三种:
b func-name:在函数入口处添加
b lineNo:在当前文件对应的行号处添加
b filename:lineNo:在对应文件行号处添加

backtrace 与 frame

bt命令用来查看当前程序调用的堆栈。f可以用来切换堆栈的层数

#0 anetListen (err=0x746bb0 <server+560> “”, s=10, sa=0x7e34e0, len=16, backlog=511) at anet.c:452
#1 0x0000000000426e35 in _anetTcpServer (err=err@entry=0x746bb0 <server+560> “”, port=port@entry=6379, bindaddr=bindaddr@entry=0x0, af=af@entry=10, backlog=511)
at anet.c:487
#2 0x000000000042793d in anetTcp6Server (err=err@entry=0x746bb0 <server+560> “”, port=port@entry=6379, bindaddr=bindaddr@entry=0x0, backlog=511)
at anet.c:510
#3 0x000000000042b0bf in listenToPort (port=6379, fds=fds@entry=0x746ae4 <server+356>, count=count@entry=0x746b24 <server+420>) at server.c:1728
#4 0x000000000042fa77 in initServer () at server.c:1852
#5 0x0000000000423803 in main (argc=1, argv=0x7fffffffe648) at server.c:3862

这里可以看到调用顺序是
server.c的main函数在3862调用了initServer
依次类推…

info break ,enable,disable,delete

info break:查看断点信息
enable + 断点编号:重新起用断点
disable + 断点编号:禁用断点
delete + 断点编号:删除某个断点,不加断点编号则直接删除所有断点

list

显示当前断点的前后10行代码,继续输入 list 指令会以递增行号的形式继续显示剩下的代码行。
list 指令还可以往前和往后显示代码,命令分别是“list + (加号)”和“list - (减号)”。

print

查看变量的值,也可以修改当前内存中的变量值。

  • 查看变量
    p this 显示当前对象的地址
    p a + b + c 打印这三个变量的结果值
    p &port 输出 port 的地址值
    p func() 输出该变量的执行结果
    p strerror(errno) 将这个错误码对应的文字信息打印出来
  • 更改变量
    p port=6400
ptype

顾名思义,其含义是“print type”,输出一个变量的类型.

info
  • info thread : 显示当前所有的线程。
    线程列表中,带*的一项表示当前 GDB 作用哪个线程。
    这时候我们就可以使用 thread + 编号来切换作用线程。配合bt命令可以查看当前线程的调用堆栈。

  • info args : 列出当前函数的参数值

流程控制命令:next、step、until、finish、return 和 jump
  • next : 执行一条命令,即遇到函数调用直接跳过
  • step : 遇到函数调用,进入函数内部。当函数调用的参数也是函数调用的时候,step实际上依次进入函数内部。
  • until +行号 :快速执行完中间的代码。
  • finish :直接执行完当前函数并回到上一层调用处
  • return :结束执行当前函数,还可以指定该函数的返回值。

这里的return不同于finish,return不会继续执行下面的内容。而是直接返回。

  • jump:程序执行流跳转到指定位置执行。被jump略过的部分则不执行。执行完跳转处的代码会继续执行
disassemble

查看某段代码的汇编指令去排查问题。

set args 和 show args

gdb启动之后,在run之前,使用“set args 参数内容”来设置命令行参数。

(gdb) set args "999 xx" "hu jj"

如果想清除掉已经设置好的命令行参数,使用 set args 不加任何参数即可

tbreak

临时断点,就是一旦该断点触发一次后就会自动删除

watch

监视一个变量或者一段内存,当这个变量或者该内存处的值发生变化时,GDB 就会中断下来。被监视的某个变量或者某个内存地址会产生一个 watch point(观察点)。

display

命令监视的变量或者内存地址,每次程序中断下来都会自动输出这些变量或内存的值。

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

GDB调试详解 的相关文章

  • 如何在 gdb 中打印长字符串的完整值?

    我想在 GDB 中打印 C 字符串的完整长度 默认情况下它是缩写的 如何强制 GDB 打印整个字符串 set print elements 0 来自GDB手册 https sourceware org gdb onlinedocs gdb
  • Go:使用 gdb 打印变量

    在此程序中 如何使用调试器中断执行并打印 i 的值 package main import fmt func main x abc i 3 fmt Println i fmt Println x 我无法打印我 不过我可以打印 x go bu
  • 如何从 gdb 命令提示符执行外部命令?

    我正在使用 gdb 调试程序 每当我错过断点或决定添加另一个观察点时 我必须终止该进程并重新运行它 为了将现有的 gdb 附加到它 我使用attach
  • GNU gdb 如何显示源文件名和符号行

    当使用 GNU gdb 调试 c 进程时 list 命令将打印行但不告诉我文件名 设置断点可以显示我想要的所有行和文件信息 但我不想设置断点并且必须禁用或删除它 gdb b oyss funtion Breakpoint 13 at 0x8
  • 有没有办法在 gdb 中设置一个以调用堆栈为条件的断点?

    我正在 Linux 上的 gdb 7 1 中调试 C 我有一个函数a 代码中很多地方都会调用它 我想在其中设置一个断点 但前提是它是从b 有什么办法可以做到吗 有没有办法做到这一点 只有当b 被叫自c 等等无穷无尽 Update 现在有一个
  • dprintf 与 break + 命令 + continue 之间有什么区别?

    例如 dprintf main hello n run 生成与以下内容相同的输出 break main commands silent printf hello n continue end run 使用是否有显着的优势dprintf ov
  • 使用 gdb 调试反汇编库

    在Linux和Mac OS X中可以使用strapi和next来调试应用程序而无需调试信息 在 Mac OS X 上 gdb 显示在库内部调用的函数 尽管有时会在每个 stepi 指令中推进多个汇编程序指令 在 Linux 上 当我进入动态
  • 从命令输出中设置 GDB 中的环境变量

    我试图在挑战中利用缓冲区溢出 缓冲区从环境变量中获取其值 在 GDB 中 我知道您可以使用以下命令设置环境变量 set environment username test 但是我需要传递用户名变量特殊字符 所以我需要执行以下操作 set e
  • Eclipse 调试模式下的 GDB 找不到 stdlib/rand.c

    我试图让 gdb 在 ubuntu 上与 eclipse cdt 一起运行 以开始调试一些简单的程序 所以我做了我认为必要的步骤来让它运行 1 创建可执行项目 2 Compile 3 Run 4 创建文件 gdbinit 并将其放在主项目文
  • 防止GDB中的PLT(过程链接表)断点

    在最新版本的 GDB 中 在库函数调用上设置断点会导致多个实际断点 调用过程链接表 PLT 实际的函数调用 这意味着当调用库函数时 我们每次都会经历两次中断 在以前的 GDB 版本中 只会创建 2 因此您只能得到一次中断 那么问题来了 是否
  • gdb 不会从外部架构读取核心文件

    我正在尝试在 Linux 桌面上读取 ARM 核心文件 但似乎无法找出我的核心文件 有什么方法可以指示 gdb 我的核心文件是什么类型吗 file daemon daemon ELF 32 bit LSB executable ARM ve
  • gcc 中 -g 选项的作用是什么

    我看到很多关于 gdb 的教程要求在编译 c 程序时使用 g 选项 我无法理解 g 选项的实际作用 它使编译器将调试信息添加到生成的二进制文件中 此信息允许调试器将代码中的指令与源代码文件和行号相关联 拥有调试符号可以使某些类型的调试 例如
  • 如何模拟ARM处理器运行环境并加载Linux内核模块?

    我尝试加载我的vmlinux into gdb并使用 ARM 内核模拟器 但我不明白为什么我会得到Undefined target command sim 这是外壳输出 arm eabi gdb vmlinux GNU gdb GDB 7
  • 使用valgrind进行GDB远程调试

    如果我使用远程调试gdb我连接到gdbserver using target remote host 2345 如果我使用 valgrind 和 gdb 调试内存错误 以中断无效内存访问 我会使用 target remote vgdb 启动
  • 如何使 gdb 在反汇编模型上显示原始的非修改函数名称?

    void outputString const char str cout lt lt outputString const char str lt lt str lt lt endl 原来是 Dump of assembler code
  • 评估 gdb 中的变量/函数

    我有以下代码 char seg mmap 0 printf seg x n seg 该程序打印seg b7ffd000 而在 gdb 中 对于相同的执行 当使用p x seg 它打印 2 0x0 我在这里很困惑 这不是同一个var吗seg
  • GDB命令了解程序是否正在运行或停止

    我正在尝试自动化 GDB 调试会话 我想知道 GDB 中是否有任何命令或任何其他方式可以帮助我知道程序是否正在运行或停止 Use gdb selected inferior threads 0 is running 来自 GDB Pytho
  • 多线程调试器[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 GDB 在使用多线程 pthreads 进行调试时存在严重问题 nix 上还有其他好的 C C 多线程调
  • 使用 GDB 远程调试 MPI

    我正在尝试从 pi 的远程访问组中调试我使用 MPI 编写的代码 我无法直接访问 Pi 以便能够使用 GUI 来调试代码 我已经尝试过使用屏幕显示的内容question https stackoverflow com questions 3
  • 是否可以根据函数要返回的内容在函数末尾设置条件断点?

    我有以下更复杂的版本 unsigned int foo unsigned int bar unsigned int myFunc return foo bar 就我而言 myFunc从很多地方调用 在其中一种情况下 出现了问题 通过进一步调

随机推荐

  • SQL Server2012使用教程(图文详情)

    SQL Server2012的安装 https blog csdn net jiachang98 article details 82874358 在所有应用中点击SQL Server Management Studio 进入SQL Ser
  • golang 数据类型转换

    数据类型转换 同底层数据类型转换 比如将 int 类型数据转换成 int8 int16 int32 int64 package main import fmt func main 同底层数据类型之间的转换 定义数字类型变量 var num
  • oracle中的rowid和rownum理解

    rownum Oracle分页查询相较于mysql来说要繁琐得多 需要配合rownum实现 而为什么需要先获取小于某个值的数据后 再获取大于某个值的结果 是因为rownum是一个逻辑伪列 并不会真实存在 每次生成都是在先生成列表数据后 新增
  • Jeff Atwood倾情推荐——程序员必读之书

    英文版 Code Complete 2 中文版 代码大全 第二版 作者 Steve McConnell译者 金戈 汤凌 陈硕 张菲出版社 电子工业出版社出版日期 2007 年8月Jeff Atwood的推荐 Steve McConnell的
  • STM32CubeMX之内部Flash读写

    有时候需要对一些数据进行掉电可存储 一般来说可以把这些数据存储到外部EEPROM或FLASH 如AT24CXX SPI FLASH等 对于一些不需要经常写入的少量数据 可以直接存储到单片机内部FLASH 可以节省成本 前期准备 STM32硬
  • Windows下 VS code +MinGW如何添加安装 pthread.h

    Windows下 VS code MinGW如何添加安装 pthread h 本人墨大学生小白一名 因为专业课中需要用到 pthread h 去编写C语言 网上有很多教程 但我按步骤走后 在编译时依然会出现错误 试了很多种方法 最后使用mi
  • mmdetection1.4训练fasterrcnn

    mmdetection1 4训练fasterrcnn 指定参数文件 urllib error URLError
  • 循环结构中辅助控制break,continue,pass,else

    文章目录 break与continue pass for while循环中的else扩展用法 综合实例 break与continue break语句是结束整个循环的过程 不在判断执行循环的条件是否成立 continue语句只结束本次循环 并
  • 找不到msvcp140.dll无法继续执行代码怎么解决

    msvcp140 dll是Microsoft Visual C 文件中中的一个共享DLL文件 用于执行C 程序的相关运行库 如果计算机上的某个程序缺少msvcp140 dll文件 则该程序将无法正常运行 通常会弹出相关错误提示信息 小编今天
  • 【U盘量产工具】热插拔导致U盘进入写保护——安国主控AU6989SN-GT

    2022 1 20 前言 前两天我爸的车的中控CD机坏了 嫌修车店修太贵了 又不需要升级成触控导航的中控 就想在淘宝上买了一个原厂一模一样的换上 到货了觉得修车店装一下又得几百块 就让我帮他一起装回去了 那东西居然是2011年产的 到现在已
  • linux socat_Linux多用途中继Socat命令教程和示例

    linux socat Linux provides different philosophy and use cases from system point of view socat is very interesting comman
  • 精通SuiteSparse应用与架构01 compile and install

    solve problem libcublas so no such file or directory as cuda10 nvidia put has shiftted the cublas to usrlib x86 64linux
  • 时序预测

    文章目录 效果一览 文章概述 源码设计 参考资料 效果一览 文章概述 时序预测 Matlab实现基于GRNN广义回归神经网络的电力负荷预测模型 1 Matlab实现基于GRNN广义回归神经网络的电力负荷预测模型 2 单变量时间序列预测 3
  • PID控制器的输入量和输出量的物理关系解释

    PID控制器的输入量和输出量的物理关系解释 其实 PID基本找不到输入与输出的单位关系 但是有很强的数的关系 给定的值与反馈的值还存在偏差时 就会调整输出以达到输入与反馈的平衡 在这里 给定的电流值 反馈的也是电流值 PWM控制的是实际的输
  • 一分钟看懂IoC 原理

    本人的概念总结 一分钟让你懂得Ioc原理 1 1 IoC是什么 Ioc Inversion of Control 即 控制反转 不是什么技术 而是一种设计思想 在开发中 Ioc意味着将你设计好的对象交给容器控制 而不是传统的在你的对象内部直
  • 蓝桥杯之单词分析

    题目描述 小蓝正在学习一门神奇的语言 这门语言中的单词都是由小写英文字母组成 有些单词很长 远远超过正常英文单词的长度 小蓝学了很长时间也记不住一些单词 他准备不再完全记忆这些单词 而是根据单词中哪个字母出现得最多来分辨单词 现在 请你帮助
  • 延时函数介绍

    文章目录 基本介绍 一 sleep 二 usleep 三 mdelay 四 udelay 五 ndelay 在操作系统中和单片机处理延时方式就完全不一样了 不可能是使用for循环浪费系统资源 而是有专门的接口函数 基本介绍 Linux 中常
  • 简洁而实用的NAS导航页——Homarr

    前言 为了更好管理家庭内网中部署的各个服务 尤其访问NAS docker中的容器 之前看过一些类似的导航面板 其中这个界面看上去十分简洁 这里自己就记录和分享一下搭建过程 官方网站 Home Homarr Docs 个人环境 支持docke
  • violin plot 小提琴图 matlab R语言 Python

    最近用到violin图 在此总结制作此图的步骤 matlab 需先下载函数文件 https ww2 mathworks cn matlabcentral fileexchange 45134 violin plot 函数中有默认添加 中位数
  • GDB调试详解

    文章目录 调试信息 启动调试 调试进程 调试core文件 GDB调试命令 run continue break backtrace 与 frame info break enable disable delete list print pt