[Linux]gdb调试多进程多线程例程

gdb相信学linux的同学已经比较熟悉了吧,它是linux下代码调试工具。我们在写c语言,c++的代码时经常会用到,它有一些常用的调试命令:

run(r):运行程序,如果有断点在下一个断点处停止
start:开始执行程序,停在main函数第一条语句前
list(l):列出源码,接着上次的位置向下列,每次列10行
list+行号:列出第几行附近的10行源码
list+函数名:列出某个函数名附近10行源码
print(p):显示变量或表达式值
where:哪里出错
whatis:查看变量的类型
info(i):查看当前栈帧局部变量的值
backtrace(bt):查看各级函数调用及参数
frame(f):帧编号,选择栈帧
break:设置断点
break 行号
break 函数名
break 文件名:行号
break 文件名:函数名
delete 1-3: 删除1到3断点
info break:显示断点信息
set variable var = value: 修改变量的值
continue(c): 从断点后继续执行
finish:运行到当前函数返回为止,然后停下来
return [value]:停止执行当前函数,将value返回给调用者;
step(s):执行下一步,step将进入函数,执行函数内每条语句;
next(n):执行下一个语句,不进入函数;
enter键:重复执行最后一条命令;

在我们学过信号之后,我又遇到一个问题就是关于core dumped的问题。我们举个栗子说明一下吧~
#include<stdio.h>

int main()
{
    int a = 10;
    a/=0;
    return 0;
}
我们看上面的这段代码,在代码编译的角度来看,显然它的除数为0了,会出错。那是一个什么样的错呢。
运行结果:

这里写图片描述

出现了core dumped,这里core dumped称为核心转储。当一个进程由于发生异常终止时,可以选择把用户空间内存储的数据全部保存到磁盘上,文件名通常为core,因此称为core dump。一般情况下,异常终止是因为代码有bug,如非法访问内存导致的段错误,刚刚的错误就属于段错误,浮点数异常。事后可以用调试器检查core文件来查清错误原因,这又被称为事后调试。默认是不允许产生core⽂文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。
比如上述程序,我们也生成了一个core文件。

这里写图片描述

这里需要注意的是,有些同学可能说为什么自己的代码运行后生成不了core文件,原因是:你使用命令ulimit -a检测一下你的core文件允许的大小。

这里写图片描述

上边的core文件显示的是0.说明你不能生成core文件,这里需要改一下core文件的大小,我们改成1024。使用命令ulimit -c 1024

这里写图片描述

这时,就可以生成core文件了。

这里写图片描述

下面我们来使用gdb来调试一下:

这里写图片描述

gdb调试多进程程序
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
    pid_t id = fork();
    int i = 0;
    if(id == 0)
    {
        while(1)
        {
            printf("I am child! i = %d\n",i++);
            sleep(1);
        }
    }
    else
    {
        while(1)
        {
            printf("hello world!I am parent! i = %d\n",i);
            sleep(1);
        }
    }
    return 0;
}
我们介绍一些在多进程中新增的一些调试信息:
show follow-fork-mode:查看当前的fork进程,默认为父进程,如果想设置为子进程,则只需命令:set follow-fork-mode child即可

这里写图片描述

show detach-on-fork:显示当前调试哪个进程。默认为on,只调试父子进程中的一个。如果为off,则表示调试父子两个进程。set detach-on-fork off来设置。

这里写图片描述

info inferiors:显示gdb调试的所有进程。inferior [进程编号]:可以切换到特定的inferiors进行调试。其中*代表正在调试的进程。

这里写图片描述

maint info program-spaces:显示当前gdb管理的地址空间数目。

这里写图片描述

detach inferior [进程编号]:detach掉某一进程的编号,此时进程Description部分为NULL

这里写图片描述

kill inferior [进程编号]:杀死当前的fork。比如当前为父进程,则运行时只剩下子进程,当你下次运行的时候会恢复。当前进程为null,且指向kill的进程。

这里写图片描述

remove-inferior [进程编号]:删除某一个inferior。如果该inferior正在运行,则不能删除,因此删除之前必须先killdetach掉。

这里写图片描述

show schedule-multiple:默认为on。显示所有的执行状态的情况。为on表示所有的inferior都可以执行。为off只是当前的inferior执行

这里写图片描述

set print inferior-event on/off:用来打开和关闭inferior状态的提示信息

这里写图片描述

gdb调试多线程
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>

#define SIZE 64
int ring[SIZE];
sem_t blank_sem,data_sem;
void *consume(void* arg)
{
    int i = 0;
    while(1)
    {
        sem_wait(&data_sem);
        int data = ring[i++];
        sem_post(&blank_sem);
        i %= SIZE;
        printf("consume is %d\n",data);
        sleep(3);
    }
}

void *product(void *arg)
{
    int data = 0;
    int i = 0;
    while(1)
    {
        sem_wait(&blank_sem);
        ring[i++] = data;
        sem_post(&data_sem);
        i %= SIZE;
        printf("product is : %d\n",data++);
    //  sleep(1);
    }
}

int main()
{
    sem_init(&blank_sem,0,SIZE);
    sem_init(&data_sem,0,0);
    pthread_t c,p;
    pthread_create(&c,NULL,consume,NULL);
    pthread_create(&p,NULL,product,NULL);

    pthread_join(c,NULL);
    pthread_join(p,NULL);

    sem_destroy(&blank_sem);
    sem_destroy(&data_sem);

    return 0;
}

这里写图片描述

这里写图片描述

thread apply ID command :让ID线程执行命令command
thread apply all command :让所有线程执行命令command
info threads:显示当前可调试的所有线程,gdb为每一个线程分配一个ID号。*表示正在调试的线程。thread [线程ID]:切换到当前要调试的线程ID。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值