9. C++ GDB调试原理(简洁版)

背景

GDB支持断点、单步执行、打印变量、观察变量、查看寄存器、查看堆栈等调试手段

断点

断点是我们在调试中经常用的一个功能,我们在指定位置设置断点之后,程序运行到该位置将会暂停,这个时候我们就可以对程序进行更多的操作,比如查看变量内容,堆栈情况等等,以帮助我们调试程序。

以设置断点的命令分为以下几类:

  • breakpoint;
  • watchpoint;
  • catchpoint;

breakpoint

可以根据行号、函数、条件生成断点,下面是相关命令以及对应的作用说明:

命令作用
break [file]:function在文件file的function函数入口设置断点
break [file]:line在文件file的第line行设置断点
info breakpoints查看断点列表
clear删除所有断点

watchpoint

watchpoint是一种特殊类型的断点,类似于正常断点,是要求GDB暂停程序执行的命令。

watchpoint分为硬件实现和软件实现两种。前者需要硬件系统的支持;后者的原理就是每步执行后都检查变量的值是否改变。GDB在新建数据断点时会优先尝试硬件方式,如果失败再尝试软件实现。

使用数据断点时,需要注意:

  • 当监控变量为局部变量时,一旦局部变量失效,数据断点也会失效;
  • 如果监控的是指针变量p,则watch *p监控的是p所指内存数据的变化情况,而watch p监控的是p指针本身有没有改变指向;

最常见的数据断点应用场景:「定位堆上的结构体内部成员何时被修改」。由于指针一般为局部变量,为了解决断点失效,一般有两种方法。

命令作用
print &variable查看变量的内存地址
watch *(type *)address通过内存地址间接设置断点
watch -l variable指定location参数
watch variable thread 1仅编号为1的线程修改变量var值时会中断

catchpoint

从字面意思理解,是捕获断点,其主要监测信号的产生。

命令含义
catch fork程序调用fork时中断
tcatch fork设置的断点只触发一次,之后被自动删除
catch syscall ptrace为ptrace系统调用设置断点
命令行
命令作用
run arglist以arglist为参数列表运行程序
set args arglist指定启动命令行参数
程序栈
命令作用
backtrace [n]打印栈帧
frame [n]选择第n个栈帧,如果不存在,则打印当前栈帧
info args当前栈帧的参数列表
info locals当前栈帧的局部变量
多进程

GDB在调试多进程程序(程序含fork调用)时,默认只追踪父进程。可以通过命令设置,实现只追踪父进程或子进程,或者同时调试父进程和子进程。

命令作用
info inferiors查看进程列表
attach pid绑定进程id
inferior num切换到指定进程上进行调试
set follow-fork-mode child追踪子进程
set follow-fork-mode parent追踪父进程
set detach-on-fork onfork调用时只追踪其中一个进程
set detach-on-fork offfork调用时会同时追踪父子进程

在调试多进程程序时候,默认情况下,除了当前调试的进程,其他进程都处于挂起状态,所以,如果需要在调试当前进程的时候,其他进程也能正常执行,那么通过设置set schedule-multiple on即可

多线程

多线程开发在日常开发工作中很常见,所以多线程的调试技巧非常有必要掌握。

默认调试多线程时,一旦程序中断,所有线程都将暂停。如果此时再继续执行当前线程,其他线程也会同时执行。

命令作用
info threads查看线程列表
print $_thread显示当前正在调试的线程编号
set scheduler-locking on调试一个线程时,其他线程暂停执行
set scheduler-locking off调试一个线程时,其他线程同步执行
set scheduler-locking step仅用step调试线程时其他线程不执行,用其他命令如next调试时仍执行

如果只关心当前线程,建议临时设置 scheduler-lockingon,避免其他线程同时运行,导致命中其他断点分散注意力。

打印字符串
命令作用
x/s str打印字符串
打印数组
作用
打印从数组开头连续10个元素的值
打印array数组下标从60开始的10个元素,即第60~69个元素
打印指针
命令作用
print ptr查看该指针指向的类型及指针地址
print *(struct xxx *)ptr查看指向的结构体的内容
调试和保存core文件
命令含义
core core_file加载core-dump文件
gcore core_file生成core-dump文件,记录当前进程的状态
启动方式

使用gdb调试,一般有以下几种启动方式:

  • gdb filename: 调试可执行程序
  • gdb attach pid: 通过”绑定“进程ID来调试正在运行的进程
  • gdb filename -c coredump_file: 调试可执行文件
原理

本节,我们大概讲下GDB调试的原理。

gdb 通过系统调用 ptrace 来接管一个进程的执行。ptrace 系统调用提供了一种方法使得父进程可以观察和控制其它进程的执行,检查和改变其核心映像以及寄存器。它主要用来实现断点调试和系统调用跟踪。

在这里插入图片描述

ptrace系统调用定义如下:

#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data)
  • pid_t pid指示 ptrace 要跟踪的进程

  • void *addr:指示要监控的内存地址。

  • enum __ptrace_request request:决定了系统调用的功能,几个主要的选项:

    • PTRACE_TRACEME:表示此进程将被父进程跟踪。
    • PTRACE_ATTACH:attach 到一个指定的进程,使其成为当前进程跟踪的子进程。
    • PTRACE_CONT:继续运行之前停止的子进程。
调试原理
运行并调试新进程

运行并调试新进程,步骤如下:

  • 运行gdb exe

  • 输入run命令,gdb执行以下操作:

    • 通过fork()系统调用创建一个新进程。
    • 在新创建的子进程中执行ptrace(PTRACE_TRACEME, 0, 0, 0)操作。
    • 在子进程中通过execv()系统调用加载指定的可执行文件。
attach运行的进程

可以通过gdb attach pid来调试一个运行的进程,gdb将对指定进程执行ptrace(PTRACE_ATTACH, pid, 0, 0)操作。

需要注意的是,当我们attach一个进程id时候,可能会报如下错误:

Attaching to process 28849
ptrace: Operation not permitted.

这是因为没有权限进行操作,可以根据启动该进程用户下或者root下进行操作。

断点原理
实现原理

当我们通过b或者break设置断点时候,就是在指定位置插入断点指令,当被调试的程序运行到断点的时候,产生SIGTRAP信号。该信号被gdb捕获并 进行断点命中判断。

设置原理

在程序中设置断点,就是先在该位置保存原指令,然后在该位置写入int 3。当执行到int 3时,发生软中断,内核会向子进程发送SIGTRAP信号。当然,这个信号会转发给父进程。然后用保存的指令替换int 3并等待操作恢复。

命中判断

gdb将所有断点位置存储在一个链表中。命中判定将被调试程序的当前停止位置与链表中的断点位置进行比较,以查看断点产生的信号。

单步原理

这个ptrace函数本身就支持,可以通过ptrace(PTRACE_SINGLESTEP, pid,...)调用来实现单步。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IM即时通讯聊天社交APP源码+h5群聊+红包转账+朋友圈

支持文字、表情、图片、语音、单聊、群聊、已读未读、消息群发、内嵌外链、签到、等完备的 IM 功能。 单聊:快速实现私信单聊,具备图片、语音、动态表情、小视频、红包、通话等各种通信能力,消息历史记录支持漫游。 群聊:快速实现群组聊天,单人禁言、全员禁言、群红包、…

Kali Linux实现UEFI和传统BIOS(Legacy)引导启动

默认Kali linux安装会根据当前启动的引导模式进行安装 例&#xff1a;以UEFI引导启动安装程序&#xff0c;安装后仅能在UEFI引导模式下进入系统 安装Kali系统 这边基于VirtualBox虚拟机镜像实战操作 首先创建一个Kali虚拟机 这里需要注意&#xff0c;把启动 EFI (只针对某些操…

一起玩儿物联网人工智能小车(ESP32)——25. 利用超声波传感器测量距离

摘要&#xff1a;本文介绍如何利用超声波传感器测量障碍物的距离 测量距离是智能小车经常要用到的功能&#xff0c;今天就来介绍一个最常用的测量距离的传感器——超声波传感器。 超声波传感器的测距原理是利用超声波发射器向某个方向发射超声波&#xff0c;与此同时&#xff…

计算机网络(2)

计算机网络&#xff08;2&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 计算机网络和因特网&#xff08;2&#xff09;分组交换网中的时延、丢包和吞吐量时延丢包吞吐量总结 协议层次及其服务模型模型类型OSI模型分析TCP/IP模型分析 追溯历史 小程一言 我…

C++线程池的原理(画图)及简单实现+例子(加深理解)

1.为什么线程池会出现&#xff0c;解决什么问题&#xff1f; C线程池&#xff08;ThreadPool&#xff09;的出现主要是为了解决以下几个问题&#xff1a; 1.性能&#xff1a;创建和销毁线程都是相对昂贵的操作&#xff0c;特别是在高并发场景下&#xff0c;频繁地创建和销毁线…

当hashCode相同时,equals是否也相同?

在Java中&#xff0c;理解对象的这两个基本方法—hashCode和equals对于编码是至关重要的&#xff0c;尤其是在处理集合类如HashMap和HashSet时。然而&#xff0c;一个常见的误解是&#xff0c;如果两个对象有相同的哈希码&#xff08;hashCode&#xff09;&#xff0c;那么它们…

数据分析概述

数据分析概述 在当今数字化的时代&#xff0c;数据已经成为我们周围不可忽视的存在。从商业领域到医疗行业&#xff0c;从科学研究到政府治理&#xff0c;数据的涌现为我们提供了前所未有的信息资源。然而&#xff0c;要从这个庞大的信息海洋中获取有意义的见解并做出明智的决策…

虚幻引擎实时音频采集

Part1前言 虚幻引擎其实对实时音频的采集支持得非常好。不过由于对音频概念的学习&#xff0c;还是花了一些时间进行研究。本文主要介绍如何基于虚幻引擎采集实时麦克风的音频数据。 Part2音频采样率 在虚幻引擎中&#xff0c;我没有找到动态修改音频采样率的方法。下面的方法设…

案例253:基于微信小程序的懂球短视频管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SpringBoot JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder …

iOday4

标准io文件拷贝 文件IO拷贝 stat 对目录操作

【已解决】You have an error in your SQL syntax

报错讯息 java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘desc,target_url,sort,status,create_by,modify_by,created,last_update_time FROM…

Unity3D UGUI图集打包与动态使用(TexturePacker)

制作图集的好处&#xff1a; 众所周知CPU是用来处理游戏的逻辑运算的&#xff0c;而GPU是用来处理游戏中图像的。在GPU中&#xff0c;我们要绘制一个图像需要提交图片&#xff08;纹理&#xff09;到显存&#xff0c;然后再进行绘制&#xff08;在这个过程中会产生一次DrawCall…