当前位置: 首页 > news >正文

关于gdb调试: 你的问题可能会在这里找到答案


1. 如何保留调试符号信息

如果我们想在调试时能够清晰的看到每一行代码、调用的堆栈信息、变量名以及函数名称等,那么我们在使用 gcc 进行程序编译的时候,可以加上 -g 选项。


示例:带调试信息 gcc -g hello.c -o hello1
执行gdb ./hello1后,信息输出如下,最后一行表示gdb加载成功。
在这里插入图片描述



反例:不带调试信息 gcc hello.c -o hello2
执行gdb ./hello2,信息输出如下,最后一行表示gdb加载失败。
在这里插入图片描述


2. 如何去除调试符号信息

有两种方式:一种是上面第1节中提到的,在编译时不添加 -g 选项;另一种是,使用 strip 命令。比如 已知可执行程序 hello1带有调试符号信息,使用strip指令执行后,再进入gdb调试,打印信息如下:
在这里插入图片描述


3. 启动gdb调试的方式有哪些

调试目标程序
直接启动程序并进入调试模式:gdb filename,如 gdb ./hello


调试附加进程
如果想调试一个正在运行的程序,但又不想重启它,那么可以使用 sudo gdb attach pid
sudo 表示使用root权限,pid为目标程序的进程PID(可通过 ps -ef | grep filename得到)。

当用gdb attach上目标程序后,调试器会暂停下来,此时可以使用过continue命令让程序继续运行,或加上响应的断点再继续运行程序。

当调试完程序后要结束此次调试时,并且不影响该当前进程继续正常工作,可以在gdb的命令行界面输入detach命令,让程序与gdb调试器分开。


调试core文件
服务器程序运行一段时间后突然崩溃,可以通过调试崩溃程序生成的core文件定位原因:gdb filename corefile

示例:testcore.c
在这里插入图片描述


执行程序,崩溃后有看到core文件生成:
在这里插入图片描述


使用gdb testcore core命令调试崩溃原因:
在这里插入图片描述



4. 程序崩溃时如何能够生成core文件

1)查看系统是否开启程序崩溃产生core文件机制,指令:ulimit -a
在这里插入图片描述
上图 core file size 参数的值为 0,说明系统并未开启core文件生成。



2)开启程序崩溃产生core文件机制,指令:ulimit -c unlimited,unlimited表示不限定大小,操作步骤:

ulimit -c unlimited 添加到 /etc/profile;
执行 source /etc/profile
执行 ulimit -a 看是否生效。



5. 指定core文件的生成目录

一般情况下,按照系统默认配置,程序崩溃后core一般是生成在程序的执行目录下;如果项目上有需求,指定core文件的生成目录,我们可以通过修改 /etc/sysctl.conf 文件实现。步骤:

1)首先,在/etc/sysctl.conf 添加 core文件的生成目录:kernel.core_pattern=/home/myubuntu/myfile/core_dump/core-%e-%p-%t
在这里插入图片描述
参数说明:

%%:相当于%
%p:相当于
%u:相当于
%g:相当于
%s:相当于导致 dump 的信号的数字
%t:相当于 dump 的时间
%e:相当于执行文件的名称
%h:相当于 hostname


2)然后,执行sudo sysctl -p /etc/sysctl.conf命令生效
在这里插入图片描述

3)查看是否已经生效:cat /proc/sys/kernel/core_pattern
在这里插入图片描述


4)生成core文件,确认是否已经生成到指定目录
在这里插入图片描述



6. 常用指令说明

在这里插入图片描述



7. 常用指令实操

以 hello.c 为例

#include <stdio.h>
int main()
{
	int i = 1;
	int j = 2;
	int m = i+j;
	for(int k = 0; k < 100; k++)
	{
		printf("number:%d\n");
	}
	printf("hello world!\n");
	return 0;
}

7.1 run命令

默认情况下,执行 gdb filename后,程序并未真正的开始运行,需要使用 run 命令启动它。
在这里插入图片描述

7.2 暂停和continue继续命令

ctrl+c指令可令程序暂停运行:
在这里插入图片描述


通过 continue 指令可让程序继续运行:
在这里插入图片描述

7.3 break添加断点命令

添加的断点的方式有以下几种:
1)break functionname:表示在函数名的入口处添加一个断点;
2)break LineNo:在当前文件行号为LineNo处添加一个断点;
3)break filename:LineNo:在filename文件行号为LineNo处添加一个断点。
在这里插入图片描述


7.4 info break, enable, disable, delete 断点操作命令

1) info break 查询断点信息
在这里插入图片描述


2)disable num 禁用断点
在这里插入图片描述

3)enable num 启用断点
在这里插入图片描述

4)delete num 删除断点
在这里插入图片描述

7.4 backtrace , frame 堆栈操作

1) backtrace 查看当前调用堆栈
在这里插入图片描述

2) frame 切换到指定的堆栈
在这里插入图片描述


7.5 print 打印变量值

1)打印当前位置的变量值
在这里插入图片描述

2)切换到其他堆栈,并打印该堆栈的变量值
在这里插入图片描述

3)print 命令不仅可以显示变量值,也可以显示进行一定运算的表达式计算结果值,甚至可以显示一些函数的执行结果值。

举个栗子,输入:p &i 可以输出变量 i 的地址值
在这里插入图片描述

也可以通过 p i+j+m 打印i+j+m的和
在这里插入图片描述


7.6 list 显示代码

1) list 显示正在执行代码的附近代码
在这里插入图片描述


2) list - 显示正在你执行代码前面的代码
在这里插入图片描述


3) list location 显示指定位置代码的附近代码

  • list lineno,如 list 11,显示行号11附近的源码
    在这里插入图片描述
  • list filename:lineno,如 list kafkaconsumer.c:101 显示 kafkaconsumer.c 文件中第 101 行附近代码
  • list funtionname ,如 list main 列出当前代码文件中 main 函数附近代码
  • list filename:funtionname,如list kafkaconsumer.c:dealdata 显示 kafkaconsumer.c 文件中dealdata函数附近代码
  • list first,last,指定显示代码的具体范围。


4) set listsize count 设置显示代码行数

list 默认显示10行代码,可以使用 set listsize count 命令设置。
在这里插入图片描述

5) show listsize 查看显示代码行数
在这里插入图片描述


7.7 info functions 显示所有函数的名字

info functions 命令会显示程序中所有函数的名词,参数格式,返回值类型以及函数处于哪个代码
文件中。
在这里插入图片描述

7.8 ptype 输出一个变量的类型

1)输出一个变量的类型
在这里插入图片描述

2)如果是变量是结构体类型,ptype不仅可以列出这个变量的类型,还可以详细列出每个成员变量的字段名
在这里插入图片描述


7.9 thread 命令可用于调试多线程

1)info thread 查看当前进程的所有线程运行情况

在这里插入图片描述


2) thread num 切换到其他线程
比如切换到线程2,切换到线程2前面就被加上了星号标志(切换到哪个线程,哪个线程就会有星号标志)

在这里插入图片描述

在这里插入图片描述


7.10 next执行下一条指令

next 命令用调试的术语叫 “单步步过”(step over),即遇到函数调用直接跳过,不进入函数体内部。在 GDB 命令行界面如果直接按下回车键,默认是将最近一条命令重新执行一遍,因此,当使用 next 命令单步调试时,不必反复输入 n 命令,直接 回车 就可以。

在这里插入图片描述


7.11 step执行下一条指令

step 命令(简写为 s)就是 “单步步入”(step into),顾名思义,就是遇到函数调用,进入函数内部。

在这里插入图片描述


7.12 return 和 finish 执行完当前函数

在这里插入图片描述


1) return 命令的作用是结束执行当前函数
在这里插入图片描述


2) finish 命令会执行函数到正常退出该函数。如果当前函数还有剩余的代码未执行
完毕,也不会执行。

在这里插入图片描述


7.13 until 运行到指定的某一行

下图使用 until 指令使得程序从18行断点直接运行到指定的23行。
在这里插入图片描述

7.14 jump 跳转到指定位置

基本语法: jump < location >

jump lineno,跳转到执行的行号-绝对位置,如 jump 29

在这里插入图片描述


7.15 disassemble 查看汇编代码

disassemble 当进行一些高级调试时,可能需要查看某段代码的汇编指令去排查问题,或者
是在调试一些没有调试信息的发布版程序时,可以通过反汇编代码去定位问题。

在这里插入图片描述


7.16 set args 和 show args 命令

1) set args设置程序输入参数

在这里插入图片描述

2) show args查看程序输入参数

在这里插入图片描述

7.17 watch监视

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

使用方式:watch变量名或内存地址

1)整形变量:int i; watch i


2)指针类型:char*p; watch p 或 watch *p
注意:watch p 与 watch *p 是有区别的,前者是查看 *(&p),是 p 变量本身;后者是 p 所指内存的内容。我们需要查看地址,因为目的是要看某内存地址上的数据是怎样变化的


3)一个数组或内存: char buf[128]; watch buf
这里是对 buf 的 128 个数据进行了监视,此时不是采用硬件断点,而是用软中断实现的。用软中断方式去检查内存变量是比较耗费 CPU 资源的,精确地指明地址是硬件中断.

注意:当设置的观察点是一个局部变量时,局部变量无效后,观察点也会失效。


7.18 display 监视

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

在这里插入图片描述



8. 调试技巧

8.1 如何将print打印结果显示完整

print 命令打印一个字符串或者字符数组时,如果该字符串太长,print 命令默认显示不全的;
可以通过 set print element 0 命令进行设置,可以完整地显示变量的所有字符串。


8.2 多线程下禁止线程切换

多个线程都调用同一个函数,当我们进入函数后进行逐行调试时,原本期望执行完第10行后往下11行执行,而此时系统有可能会切换到另外一个线程,而跳转到函数的第5行源码,造成混淆。

为了避免其他线程干扰,可以通过 set scheduler-locking on 命令将执行流锁定在当前线程;也可以通过 set scheduler-locking off 命令解除锁定。


8.3 条件断点

在实际调试中,我们一般会用到三种断点:普通断点、条件断点和硬件断点。

1) 硬件断点又叫数据断点,这样的断点其实就是前面课程中介绍的用 watch 命令添加的部分断点(watch 添加的断点有部分是通过软中断实现的,不属于硬件断点)。硬件断点的触发时机是监视的内存地址或者变量值发生变化。

2)普通断点就是除去条件断点和硬件断点以外的断点。

3)条件断点,就是满足某个条件才会触发的断点
在这里插入图片描述
在这里插入图片描述


8.4 使用gdb调试多进程程序

多进程程序指的是类似 Nginx 的架构的程序,主进程通过 fork() 函数产生子进程。

1) 方法1:用 gdb 调试父进程,等子进程 fork() 出来后,使用 gdb attach 到子进程上。同时,需要重新开启一个session 窗口用于调试。


2)方法2:使用 show follow-fork mode 查看当前值,也可以通过 set follow-fork mode 来设置是当一个进程 fork 出新的子进程时,GDB 是继续调试父进程还是子进程(取值是 child),默认是父进程( 取值是 parent)。

相关文章:

  • J9数字论:什么是Web3.0概念?
  • MediaCodec_Analyze-1-create
  • vue3中<script setup> 和 setup函数的区别
  • c语言进阶 数据的存储(上)
  • A8.2022年全国数学建模竞赛 B题-赛题分析与讨论
  • Vue指令总结
  • 离开二线城市石家庄(勉强算二线吧)去北漂,入职外包测试岗一个月想辞职了~
  • 瑞康医药与亚马逊云科技达成战略合作,全国上百家子公司业务上云
  • 内存取证工具Volatility学习
  • MySQL 中的排序在底层是怎样实现的呢?
  • HID 异步访问和同步访问
  • 吊打面试官系列之:我这样回答 “如何更高效的进行接口测试“,面试官果然跪了。
  • 云资源管理
  • 【机器学习】树模型预剪枝和后剪枝
  • 性能提升 25 倍:Rust 有望取代 C 和 C++,成为机器学习首选 Python 后端
  • chrome扩展demo1-小时钟
  • github从入门到放弃(1)
  • JavaScript设计模式与开发实践系列之策略模式
  • nodejs调试方法
  • Puppeteer:浏览器控制器
  • Ruby 2.x 源代码分析:扩展 概述
  • Solarized Scheme
  • Spring声明式事务管理之一:五大属性分析
  • 阿里云Kubernetes容器服务上体验Knative
  • 动态规划入门(以爬楼梯为例)
  • 多线程 start 和 run 方法到底有什么区别?
  • 分布式任务队列Celery
  • 复习Javascript专题(四):js中的深浅拷贝
  • 关于 Cirru Editor 存储格式
  • 聊聊flink的TableFactory
  • 思考 CSS 架构
  • 线性表及其算法(java实现)
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (1)(1.9) MSP (version 4.2)
  • (39)STM32——FLASH闪存
  • (Ruby)Ubuntu12.04安装Rails环境
  • (八十八)VFL语言初步 - 实现布局
  • (动态规划)5. 最长回文子串 java解决
  • (二)构建dubbo分布式平台-平台功能导图
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • (转)ABI是什么
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • .bat批处理(六):替换字符串中匹配的子串
  • .net framework profiles /.net framework 配置
  • .Net Remoting常用部署结构
  • .net 流——流的类型体系简单介绍
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)