GDB常用调试方法及其底层原理

news2024/11/16 22:43:03

本文分为两个大模块,第一部分记录下本人常用到的GDB的调试方法和技巧,第二部分则尝试分析GDB调试的底层原理。

一、GDB调试

要让程序能被调试,首先得编译成debug版本,当然release版本的也能通过导入符号表来实现调试,目前没试过。

GDB打断点用break命令,一般简写b,断点有多种形式。

1.1 行断点

可以在指定的文件的指定行里打断点,形式是:break 源文件名字 : 行号,比如:

b source.cpp:22
1.2 函数断点

感觉更常用的是函数断点,因为我们在定位问题的时候,往往定位到某个关键函数,该函数可能被多次调用,被调用的位置也很多,那么用行断点就不太方便了,GDB可以给一个函数打上断点,打上断点后,用continue,简写c,程序执行到函数被调用处就会阻塞,而不需要关注它在哪个文件哪一行被调用了。用法如下:

b func1

当进程阻塞在这之后,我们就可以用step命令,简写s,来进入该函数内部,然后进一步用next或step来跟踪函数里面的代码

1.3 条件断点

在调试一些循环语句中,我们有时候需要观察某自增变量达到一个特定值的时候,代码的行为,这个时候就需要条件变量,比如for循环语句里,我们只想在i == 12的时候观察程序的运行,那么就可以在断点位置后面加上一个触发条件,比如:

b source.cpp:22 if i == 12

那么程序只会在i==12的时候阻塞,在i取其它值的时候,程序可以正常运行

1.4 多线程调试

当程序有多个线程的情况时,某个函数可能会被多个线程调用我们可以先用info threads查看线程编号,然后再限定下哪个线程指定到这里需要阻塞,比如我们指定编号为3的线程:

break source.cpp : 22 thread 3break func1 thread 3

或者我们指定仅运行当前线程,如下:

set scheduler-locking on

on就是打开,off关闭后就是运行所有线程。
注意:一般是用step进入到函数里面,只想跟踪该函数内部的执行时才使用该命令,否则其余情况线程不能切换,可能对调试会造成麻烦。

从语句就可以看出,它的意思就是设置(线程)调度关闭/开启。
因为在大型工程里面,一个函数被多个线程调用,而那些线程调用我们这个目标函数具体做什么事情我们并不关心,我们只需要在当前的线程里,(该函数也可能在一个循环里多次调用,服务器进程经常有这种情况),当前面几次函数执行完还没有达到我们想要的结果时,如果发生了线程切换,那将很麻烦,而限定程序不切换线程,那么一直执行当前这个线程,那就更好定位问题了。
比如调试某基于PG内核的数据库的SQL入口函数的时候,该函数会被十多个线程调用,而我的问题出现在主线程上,所以我需要设置线程不切换。

另外,在多进程情况下(有fork()时),GDB默认模式下,只能调试这个父进程不会跟踪子进程,不过可以设置,命令:set follow-fork-child,这样就会跟踪子进程了

1.5 删除断点和忽略断点

用info break查看断点信息,每个断点都有个编号,当某些断点不需要时,我们可以用delete删除它,,比如删除断点3:

delete 3

也可以将某行代码上的所有断点都清除,clear:

clear source.cpp : 22

如果只是暂时忽略某个断点,还可以设置忽略次数,比如忽略断点3一共12次,ignore:

ignore 3 12

2. next和step

next简写成n,当执行到某一行我们想要继续往下一行代码走时就可以用该命令;
step简写成s,它也是单步执行,与next不同的是1,如果当前代码行是调用了某个函数,那么step会进入该被调用的函数里面,一般比较接近我们的问题相关的代码时,就可以用step进入函数内部,再单步调试。

3. 查看栈帧

在多线程环境下,因为每个线程都有一个栈,所以首先得切换线程,info threads查看线程编号,加入要切换到的线程是3号,那么thread 3即可切换到3号线程。如果前面设置了关闭线程切换,那就不用管。
查看栈帧的命令是backtrace,简写bt。它会依次从栈顶往栈底列出当前线程的栈帧,如下所示,#0即是栈顶,也就是说,当前线程正在执行exec_simple_query()函数,而且我们可以看到该函数被传入的参数的值
在这里插入图片描述

4. attach和detach

我们经常需要调试一个已经在运行的进程,一般先用top命令查看其进程号,或者ps -ef | grep 进程名字查看,其中-ef可以把前台、后台的进程都展示出来。
查询到PID之后,就用gdb attach PID调试该进程;注意,调试完该进程后,用detach命令分离被调试进程和gdb,这样该程序将不再受gdb的控制,而gdb也可以继续去attach其它进程。
如果没有detach,那么当我们杀死gdb进程的时候,被调试的进程也会被杀死。
看看GDB的官方文档对detach的描述:

detach
When you have finished debugging the attached process, you can use the detach command to release it from GDB control. Detaching the process continues its execution. After the detach command, that process and GDB become completely independent once more, and you are ready to attach another process or start one with run. detach does not repeat if you press RET again after executing the command.
If you exit GDB or use the run command while you have an attached process, you kill that process. By default, GDB asks for confirmation if you try to do either of these things; you can control whether or not you need to confirm by using the set confirm command (see section Optional warnings and messages).

5. handle信号处理

GDB在调试进程的时候,可能会受到来自进程的各种信号,这个时候我们需要定义下GDB遇到某种信号时,做某种处理,其语法格式为:

handle 信号类型 处理方式

比如我调试PG内核的时候,就会收到SIGUSR2,这是用户自定义信号,某个进程收到该信号时,默认的处理方式是进程终止,因此当没有在gdb调试前设置针对该信号的处理方式时,输入c后,调试并没有正常进行,而是停了下来,并且打印了一些信息,这个时候就需要使用handle来处理SIGUSR2信号,如下:

handle SIGUSR2 nostop noprint

然后再输入c去continue,就能正常进行调试了,具体的可以参考这几篇博客:
https://www.cnblogs.com/kex1n/p/8296332.html
https://blog.csdn.net/artine/article/details/80008529

二、GDB调试原理

GDB能够对程序进行调试,源自于一个系统调用:ptrace

#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

第一个参数request 参数指定了我们要使用 ptrace 的什么功能。

2.1 调试一个可执行程序test

用GDB去运行一个程序,比如gdb ./test,或者是先进入gdb,再执行./test运行程序test,第一个参数就是PTRACE_TRACEME,顾名思义,就是“跟踪我”。
参数 pid 表示的是要跟踪进程的 pid, addr 表示要监控的被跟踪子进程的地址。
这个时候,原理就是开启一个GDB进程,然后GDB进程fork出一个子进程,让子进程执行PTRACE_TRACEME,然后子进程再调用execve(),如下图,来自博客
在这里插入图片描述
此时,GDB进程及其子进程就可以读写test进程的指令空间、数据空间、堆栈和寄存器的值。而且gdb进程接管了test进程的所有信号,也就是说系统向test进程发送的所有信号,都被gdb进程接收到。
(其实应该是内核给gdb的子进程发信号,然后该进程给其父进程即GDB进程发信号,父子进程间通信很容易)

2.2 GDB调试一个已经存在的程序即gdb attach原理

我们用gdb attach PID的时候,ptrace第一个参数传入的就是PTRACE_ATTACH,这是父进程调用 attach 到已经运行的子进程中;
这个命令会有权限的检查, 普通用户进程不能 attach 到 root 进程中,但一般调试的都是普通用户进程,所以也没遇到过问题。
这个过程就是:运行一个GDB进程,他调用ptrace()尝试去attach附着目标进程test,此时GDB需要给test进程发送一个信号SIGSTOP,要求test停止,这个信号是不能忽略的,然后test进程就进入TASK_STOPED状态,(用top -u 用户名可以看到被gdb attach的进程如果没有continue的话,其进程状态是t,这个就是暂停或被跟踪),然后之后状态是被跟踪状态TASK_TRACED,这个不重要,反正状态都是t,而不是Run。
这个过程的示意图如下,来自博客:
在这里插入图片描述

2.3 GDB断点原理

在某行代码处打一个断点,其实就是将该行代码的汇编用INT 3中断指令代替,原来的代码被保存到“断点链表”中。
这个是软中断,硬中断是外设给CPU中断,让CPU停下,这个是内核在CPU待执行指令中插入的中断指令,所以是软中断。(都是让CPU收到中断指令,只是看是硬件发的还是软件发的)
INT n这种中断指令,CPU执行到这里时,内核调用相应的中断处理程序,对于INT 3,那就是当前进程test停止运行,将CPU交给GDB进程用。

INT 3 是x86系列处理器提供的专门用来支持调试的指令。简单地说,这条指令的目的就是使CPU中断(break)到调试器,以供调试者对执行现场进行各种分析

这里还有个细节,就是运行到中断指令的话,这句指令不是执行完了吗,那我们到断点处,是怎么继续运行该断点处的代码的?
实际上,CPU轮到GDB进程后,GDB会去断点链表里找到原先的汇编指令(源代码也一样),将断点那一行的INT 3又替换回原先的代码,而且让PC指针回退回该行。
所以我们想执行断点处的代码的话,输入指令n,就行了,而不是直接执行断点的下一行。

PC:Program Counter,是通用寄存器,但是有特殊用途,用来指向当前运行指令的下一条指令

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/689813.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos7下tensorflow 2.12无法找到NVIDIA Tesla T4 GPU终极解决方法

目录 背景 系统信息 GPU信息 关键软件信息 问题现象 原因分析

解决element-ui消息提示$message重叠问题

在进行表单校验的时候&#xff0c;当触发两个提示消息的时候会出现上面的叠加情况&#xff0c;没有将提示消息分开显示&#xff0c;这样就给用户造成不好的视觉效果 我们的预期效果是达到上面的显示效果&#xff0c;就是在进行提示的时候&#xff0c;如果叠加就需分开显示&…

Centos8同步时间(阿里云NTP服务为例)

一、安装chrony sudo dnf install chrony二、使用 sed 命令一键完成配置 #pool 2.centos.pool.ntp.org iburst给这一行加注释 sudo sed -i s/^pool 2.centos.pool.ntp.org iburst/#&/ /etc/chrony.conf #添加3个阿里云NTP服务器 echo -e "server ntp1.aliyun.com ib…

withContext CoroutineScope协程切换,kotlin

withContext CoroutineScope协程切换&#xff0c;kotlin <dependency><groupId>org.jetbrains.kotlinx</groupId><artifactId>kotlinx-coroutines-core</artifactId><version>1.4.2</version></dependency> import kotlinx.co…

python 上传包到pypi

参考 https://www.jianshu.com/p/81fe5a5cd27a 1.打包 在pypi注册账号&#xff0c;并新建token 需要在用户下创建一个.pypirc文件。username__ token __ 是固定的&#xff0c;password 填入刚刚的token。 使用下面两个命令把dist中文件推送到pypi python setup.py sdist…

AI读心重磅突破登Nature!AI破译大脑信号

近日&#xff0c;洛桑联邦理工学院团队在Nature上提出了一种名为CEBRA的可实现AI读脑的最新算法&#xff0c;以高精度捕捉到了动物大脑的动态。 利用AI&#xff0c;一个研究团队「看见」了老鼠眼中的电影世界。更神奇的是&#xff0c;这种机器学习算法&#xff0c;还能揭示大脑…

【以太坊】本地搭建以太坊测试网络,部署合约

文章目录 工具建议参考测试 工具 Ganache 建议 推荐使用 Ganache 搭建&#xff0c;简单易上手 参考 https://www.npmjs.com/package/ganache 测试 npm install ganache --global && ganache --help ganache

[230609] 阅读TPO57汇总|9:30-10:50

TPO57 01 Pests and Pesticides [3]修辞目的题 修辞目的题做题技巧&#xff1a;找观点&#xff01;不能推理&#xff01;一般找例子前后的观点&#xff01; P3段 段意即观点&#xff0c;观点在段首或段尾&#xff01; 考察比较的作用 主要理解In other words后面的话&#…

新老版本AndroidStudio删除无用资源方法总结

今年AndroidStudio版本更新比较快&#xff0c;一些常用的功能都在变化&#xff0c;其中删除项目中无用资源变化的有点大&#xff0c;特在此记录总结下。这里所说的新老版本的Android Studio其实就是看Android Studio最上面有没有&#xff1a;Anaylze 老版本是有的 新版本这个…

SeaTunnel 发布成为 Apache 顶级项目后首个版本 2.3.2,进一步提高 Zeta 引擎稳定性和易用性

近日&#xff0c;Apache SeaTunnel 正式发布 2.3.2 版本。此时距离上一版本 2.3.1 发布已有两个多月&#xff0c;期间我们收集并根据用户和开发者的反馈&#xff0c;在 2.3.2 版本中对 SeaTunnel Zeta Engine 进行了 Bug 修复&#xff0c;提高了引擎的稳定性和使用效率。 此外&…

【Java】Java核心 74:XML (下)

文章目录 **7** **Schema约束(能够看懂即可)****1** **书写schema约束****2** **在xml文件中引入schema约束** 7 Schema约束(能够看懂即可) 与dtd约束一样&#xff0c;schema它也是用来约束xml文件的。schema约束书写的时候&#xff0c;它遵守xml的语法规则。在书写schema的时…

vb.net 正则表达式解析一些奇奇怪怪的文件名为时间类型

Public Function 正则表达式A(f As String) As Date2023-02-06 1653830If New Regex("\d{4}.\d{2}.\d{2}.\d{6}").IsMatch(f) ThenDim nian Strings.Mid(f, 1, 4)Dim yue Strings.Mid(f, 6, 2)Dim ri Strings.Mid(f, 9, 2)Dim shi Strings.Mid(f, 12, 2)Dim feng…

什么是编程语言?||与编程相关的计算机硬件介绍

什么是编程语言&#xff1f; 学习编程语言之前&#xff0c;首先要搞清楚“编程语言”这个概念。 很小的时候&#xff0c;父母就教我们开口说话&#xff0c;也教我们如何理解别人讲话的意思。经过长时间的熏陶和自我学习&#xff0c;我们竟然在不知不觉中学会了说话&#xff0c…

【从零开始学习JAVA | 第二十二篇】BigInteger

目录 前言&#xff1a; BigInterger&#xff1a; BigInteger常见的方法&#xff1a; 总结&#xff1a; 前言&#xff1a; 本篇我们将介绍BigInteger这个比较实用一点的API&#xff0c;这个API在我们实际写项目中都是很实用的API&#xff0c;因此大家应该对这个API有更加熟练的…

sublime text 打开 txt 文档乱码问题

对于 windows 系统使用系统自带的 txt 编辑工具&#xff0c;默认打开和保存文件的文件的格式是 GBK 或者 GB2312&#xff0c;而 sublime 默认仅支持 utf-8&#xff0c;所以当从 windows 系统拷贝文件在 mac 上浏览有时候会出现乱码的问题&#xff0c;这时候就需要安装插件使 su…

RDBMS 与 非RDBMS

RDBMS vs 非RDBMS 前言一、关系型数据库(RDBMS)1、实质2、优势 二、非关系型数据库(非RDBMS)1、介绍2、有哪些非关系型数据库3、NoSQL的演变4、小结 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注博主&#xff01;…

基于uni-app+vue3跨端「h5+小程序+App」仿制chatGPT模板实例

uni-chatgpt 一款uniappvite4uview-plus多端ChatGPT模板实例。 全新首发的一款多端仿制chatgpt智能对话实战项目&#xff0c;基于uniAppVue3PiniauViewUIMarkdownIt等技术开发搭建项目。支持编译到h5小程序APP端&#xff0c;支持markdown语法解析及代码高亮。 功能特点 全屏沉…

LinkedList的底层实现原理(JDK8)

目录 一、知识点回顾二、LinkedList 的 add() 和 remove() 的实现2.1 list.add(e) 实现原理2.2 list.remove(e) 实现原理 一、知识点回顾 双向链表特点&#xff1a; 区间离散&#xff0c;占用内存宽松&#xff0c;空间复杂度小&#xff0c;时间复杂度 O(n)。优点&#xff1a;…

Android Jetpack Compose —— FloatingActionButton

FloatingActionButton 通常用于呈现应用程序的主要操作或常用操作&#xff0c;并具有显著的圆形形状和浮动的定位。FloatingActionButton 提供了一种简单而优雅的方式来引导用户进行主要的应用程序交互&#xff0c;例如开始一个新的任务、分享内容、启动一个动作等。它在应用程…

Java——《面试题——Zookeeper篇》

前文 java——《面试题——基础篇》 Java——《面试题——JVM篇》 Java——《面试题——多线程&并发篇》 Java——《面试题——Spring篇》 Java——《面试题——SpringBoot篇》 Java——《面试题——MySQL篇》​​​​​​ Java——《面试题——SpringCloud》 Java…