GDB调试下的多进程与多线程

2023-05-16

主要方法


1、attach方法

2、follow-fork-mode方法


背景知识


首先要进行调试,我们就不得不先搞清楚调试的一些基本操作。


gdb(Linux调试器)使用


(1)产生调试信息:要进行代码的调试,就需要有调试信息,要产生调试信息,就需要在源代码生成时添加-g选项;

(2)调试的开始和退出


开始调试:gdb file(file表示要进行调试的源文件)

退出调试:ctrl+d或quit


(3)调试的一些基本操作




attach调试方法


attach是GDB中中有附着到正在运行的进程中的功能实现,通过attach(pid),就可直接该进程进行调试


在介绍这种调试方法时,我们需要先对守护进程做一个简单的学习,因为attach方法对于守护进程的调试有很大的作用


守护进程


定义:守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。


简介:守护进程是一个在后台运行并且不受任何终端控制的进程,如果你了解过信号方面的知识,你就会明白信号在捕捉的时候为什么会单独留下一个‘9号’进程不能被捕获,两者其实都是从保护系统的角度所设计出来的。


守护进程创建步骤:


(1)创建子进程,终结父进程;

(2)在子进程中创建新会话;

(3)改变工作目录;

(4)重建子网掩码;


简单测试(在这段代码中我们很明显会发现父进程中调用的Div函数中有一个除0错误):


//Makefile(Makefile中的注释并不是“//”这里这是为了表示文件的信息,后面将不再做解释)
gdb:gdb.c
        gcc -o $@ $^ -g -lpthread
.PHONY:clean
clean:
        rm -f gdb

代码编译结果:


#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>

int Div(int num1, int num2)
{
        pit_t id=getpid();
        printf("my pid is %d\n",id);
        int result, diff;
        diff = num1 - num2;
        result = num1 / diff;
        return result;
}

int main()
{
        pid_t   pid;

        pid = fork();
        if (pid <0) {
                printf("fork err\n");
                exit(-1);
        } else if (pid == 0) {//child
                int val1 = 5;
                int val2 = 1;
                int ret = 0;
                int i=5;
                while(i--) {//parent
                        ret = Div(val1, val2);
                        val2++;
                        val1--;
                        printf("cur result is %d\n",ret);
                }

        } else {//child
                sleep(4);
                wait(-1);
                exit(0);
        }
}

运行结果:




先让程序运行到后台:执行gdb &




调试演示:




follow-fork-mode调试方法


使用方法:


set follow-fork-mode [parent|child]

(1)parent:fork之后继续调试父进程,子进程不受影响

(2)child::fork之后继续调试子进程,父进程不受影响


子进程调试方法:


启动gdb之后:


(gdb) set follow-fork-mode child

(1)在子进程相应可能会出错的地方设置断点

(2)设置detach-on-fork参数(用于指示gdb在fork之后,gdb的进程)

设置方法设置方法:set follow-fork-mode [parent|child]   set detach-on-fork [on|off]

具体设置和功能如图所示:(GDB 6.6或以上版本



常用的一些其他方法:


查询正在调试的进程:info inferiors
切换调试的进程: inferior <infer number>
添加新的调试进程: add-inferior [-copies n] [-exec executable] ,可以用file executable来分配给inferior可执行文件。
其他:remove-inferiors infno, detach inferior


简单演示(这个我们只是走一下调试的过程本身并没有错误):


//Makefile
Gdb:Gdb.c
        gcc -o $@ $^ -g -lpthread
.PHONY:clean
clean:
        rm -f Gdb

#include<stdio.h>
#include<pthread.h>

void* Thread(void* arg){
        pid_t id=getpid();
        printf("I am a thread, my pid is %d\n",id);
}

void childfunc()
{
        pid_t id=getpid();
        printf("I am a child , my pid is %d\n",id);
}

void parentfunc()
{
        pid_t id=getpid();
        int stat;
        pthread_t pt;
        printf("I am a parent , my pid is %d\n",id);
        stat=pthread_create(&pt,NULL,Thread,NULL);
        if(stat!=0){
                printf("parent process can not create thread");
        }
        Thread(NULL);
        sleep(2);
}

int main()
{
        int id=fork();
        if(id<0){
                perror("fork");
                return -1;
        }
        else if(id==0){//child
                childfunc();
                sleep(2);
        }
        else{//parent
                parentfunc();
                sleep(2);
        }
        return 0;
}


运行结果:




调试演示:


(1)调试主进程,block子进程




(2)切换到子进程




(3)调试主进程中产生的两个线程




两种调试方法比较


attach子进程方法灵活强大,但需要添加额外代码,适合于各种复杂情况,特别是守护进程;

follow-fork-mode方法:方便易用,对系统内核和GDB版本有限制,适合于较为简单的多进程系


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

GDB调试下的多进程与多线程 的相关文章

  • Code::blocks 中的调试器命令行参数

    在 Code blocks 中调试程序时 如何指定要发送到正在调试的程序的命令行参数 我一生都找不到在哪里设置它 谷歌搜索会显示用于调试编译器本身的设置 而不是编译器中编写的程序 如果把它排除在外 那就太奇怪了 Thanks Tim 啊 正
  • 在剥离的 ELF 可执行文件中设置断点

    我有一个 ELF 32 位动态链接 剥离文件 我希望对其进行调试 尝试在某个地址设置断点时 出现一条消息 提示符号表未加载 我的问题是 当你说 ELF 文件是stripped究竟发生了什么 如何剥离 ELF 文件 是否可以以某种方式重建符号
  • 是否可以使用 vscode 连接到远程 gdb 目标?

    我正在尝试设置配置以附加到使用 Visual Studio 代码运行 gdbserver 的远程 C C gdb 目标 目前支持吗 如果是这样 我该如何克服这些限制 地址和端口选项表明它们不支持 C C 我可以强制代码使用 gdb 的特殊远
  • 如何在 gdb 中使用 python 访问寄存器

    如何访问当前调试实例的cpu寄存器 例如 您可以从 gdb 调用printf 0x x eax and set eax b eax还有一种方法可以通过 gdb 提供的 python 支持来做到这一点吗 或者我应该创建一个可以像这样调用的 p
  • 编译器的“-O0”选项和“-Og”选项有什么区别?

    当我想要调试 C 或 C 程序时 我被教导使用 O0关闭优化 以及 ggdb将符号插入到为使用 GNU 而优化的可执行文件中gdb调试器 我使用它 或者 你可以使用 glldb对于 LLVM clang 来说lldb调试器 或者只是 g对于
  • 如何判断共享库加载到进程地址空间中的位置?

    我正在尝试调试一个共享库 其中有使用 gdb 的源代码和调试符号 我没有实际使用此共享库的进程的调试符号或代码 我自己编译它 所以我可以拥有一切 但生成的二进制文件被剥离 以模拟我没有代码的情况 该进程打印我正在尝试调试的目标函数 foo
  • 如何使用gdb来探索堆栈/堆?

    谁能给我一个快速概述 给我指出一种检查 C 程序堆栈 和堆 的方法的文档 我认为这应该用 GDB 来完成 但如果有其他更直接的替代方案 那么也应该没问题 Thanks 您可以使用 x 命令转储原始内存 因此 如果您想查看堆栈或堆的位 请尝试
  • 为什么 GNU binutils 和 GDB 合并为一个包?

    https sourceware org git gitweb cgi p binutils gdb git https sourceware org git gitweb cgi p binutils gdb git 尤其是请参阅tags
  • 将大核心文件转换为“minicore”文件

    如何将核心文件减少到仅线程堆栈 我希望能够运行 gdbthread apply all bt在迷你核心上 仅此而已 我正在处理大型 gt 4GB 多线程 Linux ELF 核心文件 这些文件太大而无法返回进行分析 我见过谷歌断点器 htt
  • Go:使用 gdb 打印变量

    在此程序中 如何使用调试器中断执行并打印 i 的值 package main import fmt func main x abc i 3 fmt Println i fmt Println x 我无法打印我 不过我可以打印 x go bu
  • 在运行时从应用程序读取调试信息

    除了调试之外 我还有一些关于调试符号以及可以用它们做什么的问题 我最感兴趣的是有关 GCC 的答案 但我也很高兴知道它在其他编译器 包括 MSVC 下的样子 首先 调试符号的常见格式 类型有哪些 它们与编译器和平台有何关系 GCC 和 Mi
  • 使用 gdb 调试时彻底退出 valgrind

    我正在使用 valgrind 和 gdb 调试程序 然而 我以一种野蛮的方式终止了这些调试会话 这真的是它应该做的吗 设置调试会话 按照来自的指示valgrind 官方网站 http valgrind org docs manual man
  • 如何在GDB中运行记录指令历史记录和函数调用历史记录?

    编辑 根据下面的第一个答案 当前的 技巧 似乎正在使用 Atom 处理器 但我希望一些 gdb 专家可以回答这是否是一个基本限制 或者路线图上是否添加了对其他处理器的支持 反向执行似乎在我的环境中起作用 我可以反向继续 查看合理的记录日志
  • 有没有办法在 gdb 中设置一个以调用堆栈为条件的断点?

    我正在 Linux 上的 gdb 7 1 中调试 C 我有一个函数a 代码中很多地方都会调用它 我想在其中设置一个断点 但前提是它是从b 有什么办法可以做到吗 有没有办法做到这一点 只有当b 被叫自c 等等无穷无尽 Update 现在有一个
  • 有什么方法可以判断我的 iPhone 应用程序在运行时是否在调试器下运行?

    如果我的错误处理代码在调试器下运行 我希望它的行为有所不同 具体来说 如果我在手机上运行 未连接到调试器并且断言失败 我想将错误发送到我的服务器 当我在gdb下时 我想闯入调试器 虽然我可以想象苹果将如何编写代码 但我找不到任何关于测试调试
  • 专门逐行调试

    我有一个用 Pascal 编写的脚本 我会以这种方式调试它 在每一行停止 转储内存中所有变量的值 然后转到下一行 是否可以使用 gdb 或其他 Linux 开源工具来完成此操作 使用选项编译文件 g fpc gpc g file pas R
  • 在 GDB 中显示结构体值

    在 GDB 中 给定一个指向结构体的变量 print将显示原始指针值并x将显示指向的原始字节 有什么方法可以显示指向该结构的数据 即字段及其值的列表 print variable 如果这样做 它将在 GDB 中显示该变量的值 您还可以选择显
  • 使用 gdb 调试反汇编库

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

    我正在开发一个使用 GNU 自动工具的项目 因此为了使用 gdb 调试代码 我从 libtool 中运行 gdb libtool mode execute gdbtui foobar 是否可以重新加载项目的修改版本 而不必退出 gdb li
  • 哪个信号被传递到信号处理程序中死锁的进程

    我有一个来自调用信号处理程序后死锁的进程的核心转储 如何确定传送了哪个信号以及是谁发送的 GDB 为接收信号的线程生成的回溯如下 信号处理程序在第 15 帧中被调用 gdb bt 0 0x00007fa9c204654b in sys fu

随机推荐

  • 深入理解C++强制类型转换

    C 43 43 四种强制转换类型 static cast reinterpret cast const cast dynamic cast static cast 静态转换 xff0c 用于非多态类型 xff0c 任何标准的转换都可以用它
  • Linux背景设置

    桌面背景设置 对于Linux的CentOs系统 刚进入时系统默认的生成的背景如下 显然对于一些比较有艺术欣赏的人来说 xff0c 这个背景显然是很让人感到很不好受 xff0c 所以下面就来看一下如何更换桌面背景 1 单击鼠标右键 2 双击鼠
  • Linux常用工具安装和vim设置的命令实现

    声明 xff1a 本文是针对centos6 0的版本进行安装和设置的 xff0c 在现在下载的Centos版本上基本上会自带一些基本的工具 xff0c 因此在安装之前需要先进行检查 xff0c 如果不存在 xff0c 在进行下载安装 gcc
  • C实现当前机器模式是大端还是小端

    声明 xff1a 本文是在32位机器 xff0c vs2013下运行无误 大小端背景 xff1a 大小端这一词最早是来自 格列夫游记 xff0c 书中记录有一个村子 xff0c 村子里的人有一个强烈的争议 xff0c 关于吃鸡蛋的时候应该从
  • C模拟实现点分十进制IP转换

    声明 xff1a 本文在32位机器上测试无误 点分十进制 点分十进制是计算机网络中的一个名词 xff0c 是一种网络地址的表示方法 xff0c 每一组数字都是在0 255之间 xff0c 每个组之间都是通过 34 34 来进行分割的 xff
  • C面试常考知识点详解

    小结清单 xff1a 指针与引用区别与联系 指针与数组的区别与联系 结构体内存对齐 指针与引用区别与联系 联系 xff1a 底层实现方式相同 xff0c 都是按照指针的方式实现 区别 xff1a 1 引用必须初始化 xff0c 指针可以不用
  • 【通信方式一】管道

    管道引入原因 xff1a 由于各个进程之间是相互独立的 xff0c 这样虽然有助于程序内部自己的处理 xff0c 同时也避免各个进程之间相互影响 xff0c 但是有时候程序之间就是需要进行一些信息传递 xff0c 这时就需要相办法来实现这些
  • Linux下的管道组织管理与容量测试

    管道通信方式实现 xff1a http blog csdn net double happiness article details 71685414 在学习完管道的通信方式之后 xff0c 我们知道管道是用来实现进程之间的相互通信的机制
  • 九大排序之——冒泡排序

    冒泡排序 原意是说鱼从水底下吐泡泡 xff0c 然后一直漂浮到水面上的过程 xff0c 冒泡排序就是不断的将一个元素不断的与后面的元素进行比较 xff0c 如果大于 xff08 升序 xff09 就叫交换两个元素的位置 xff0c 直到比较
  • Python解决opencv,cv2.xfeatures2d的办法

    本来要调一下surf特征检测的包但是报错了 xff0c 在查询以后发现cv2 xfeatures2d在opencv3 4 2 16之后的版本不能使用了 那么只好装一下之前的版本 经过多重尝试 xff0c 最后还是通过whl文件的方法去安装p
  • 九大排序之——堆排序

    堆排序 xff1a 思想 xff1a 首先清楚一点堆的低层存储是一个静态数组 xff0c 可以将它看成是一棵完全二树 先建立初始堆 xff0c 然后进行堆调整 xff0c 在进行交换和pop操作 xff0c 直至完成堆排序为止 堆的分类 x
  • 九大排序之——选择排序

    选择排序 xff1a 思想 xff1a 首先将给定的序列看成是一个有序序列和一个无序序列 xff0c 选择排序也就是从给定 的 序列中选取一个最大的 xff08 最小的 xff09 元素放到有序序列的对应位置 xff0c 再从剩余的无序 序
  • 九大排序之——插入排序

    直接插入排序 xff1a 思想 xff1a 将要排序的序列看成两个序列 xff0c 一个是有序序列 xff0c 另一个是无序序列 xff0c 每次取无序序列中的元素往有序序列中的合适位置插入 xff0c 直到无序序列为空 xff0c 排序完
  • 九大排序之——快速排序

    快速排序 算法思想 xff1a 快速排序从名字上就可以看出就是为了排序的效率 xff0c 每次先选择一个关键字key xff0c 一般是选择序列的第一个元素或者序列的最后一个元素 xff0c 将比key值小的元素全部放在左边 xff0c 将
  • 九大排序之——归并排序

    归并排序 算法思想 xff1a 归并操作整体上来看是分治法的应用 xff0c 不断的划分缩小区间 xff1b 图示 xff1a 算法执行步骤 xff1a 1 先申请一个和原序列一样大的空间 xff0c 用来存放合并之后的序列 xff1b 2
  • 九大排序之——计数排序

    计数排序 计数排序步骤 xff1a 1 找出待排序的数组中最大和最小的元素 xff1b 2 统计数组中每个值为i的元素的出现的次数 xff0c 存入数组C的第i项 xff1b 3 对所有的计数累加 xff1b 4 反向填充目标数组 xff1
  • 九大常见排序总结

    九种常基本排序 希尔排序 xff1a http blog csdn net double happiness article details 70157030 冒泡排序 xff1a http blog csdn net double hap
  • 简单的贪吃蛇游戏实现

    贪吃蛇功能实现 xff1a 1 定义贪吃蛇游戏棋盘图 2 初始化棋盘 3 输出棋盘所在信息 3 选择游戏难度 4 随机产生食物 5 更新游戏动态 6 设置游戏相应的操作 7 打印游戏结果 代码实现 span style font famil
  • 深入理解死锁

    死锁定义 死锁是指两个或两个以上的进程在执行过程中 xff0c 由于资源竞争或者由于彼此通信而造成的一种阻塞现象 xff0c 若无外力作用 xff0c 他们都将无法推进下去 xff0c 此时称系统处于死锁状态 xff0c 这些永远在互相等待
  • GDB调试下的多进程与多线程

    主要方法 1 attach方法 2 follow fork mode方法 背景知识 首先要进行调试 xff0c 我们就不得不先搞清楚调试的一些基本操作 gdb Linux调试器 使用 1 产生调试信息 xff1a 要进行代码的调试 xff0