GDB调试(二)

news/2025/2/24 4:17:10/文章来源:https://www.cnblogs.com/MLSTGA/p/18718324

GDB调试

运行中程序GDB调试

测试程序

//test2.c
//功能:从0开始每秒打印
#include <stdio.h>
#include <unistd.h>
int aaa();
int bbb(int n);
int main()
{aaa();
}int aaa()
{bbb(0);
}int bbb(int n)
{for(int i = n; i < n+10000; i++){printf("i:%d\n", i);n++;sleep(1);}
}
gcc -g -o test2 test2.c
./test2
//结果
:0
i:1
i:2
i:3
i:4
i:5
i:6
i:7
......

操作步骤

1.运行程序

在终端窗口运行编译好的程序

./test2

2.进程ID

在另一个终端窗口,使用ps命令找到正在运行程序的进程ID,其中进程ID是第二个

ps aux | grep test2
//结果如下,其中正在运行程序的进程ID是15554
username   15554  0.0  0.0   2776  1408 pts/1    S+   22:38   0:00 ./test2
username   15557  0.0  0.0  12192  2432 pts/2    S+   22:39   0:00 grep --color=auto test

3.附加GDB

使用GDB附加到正在运行的程序上

sudo gdb test2 -p 15554

这里的sudo加不加看环境,有些不用加

4.GDB调试

在GDB中,你可以使用常用的调试命令如bt(查看调用堆栈),print(打印变量值),continue(继续执行程序),等等

这里因为sleep延时,直接continue后,test2继续运行,gdb这里卡住了,可以用CTRL-C重新中断

5.结束调试

命令 解析
detach 直接使用detach命令,可以从进程中分离GDB并让程序继续运行
attach PID 重新将GDB附加到某个进程上

GDB调试多进程

测试程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{printf("begin\n");if ( fork() != 0 ){printf("我是父进程:进程pid=%d,父进程ppid=%d\n",getpid(),getppid());int ii;for(ii=0; ii<200; ii++){printf("父进程ii=%d\n",ii);sleep(1);}exit(0);}else{printf("我是子进程:进程pid=%d,父进程ppid=%d\n",getpid(),getppid());int jj;for(jj=0; jj<200; jj++){printf("子进程jj=%d\n",jj);sleep(1);}exit(0);}
}
gcc -g -o test3 test3.c
./test3
//运行结果
我是父进程:进程pid=5003,父进程ppid=4675
父进程ii=0
我是子进程:进程pid=5004,父进程ppid=5003
子进程jj=0
父进程ii=1
子进程jj=1
子进程jj=2
父进程ii=2
子进程jj=3
父进程ii=3
子进程jj=4
父进程ii=4
父进程ii=5
子进程jj=5
子进程jj=6
父进程ii=6
子进程jj=7
父进程ii=7
父进程ii=8
子进程jj=8
......//开始调试
gdb test3

调试命令

命令 解析
set follow-fork-mode child 设置追踪子进程。gdb 默认调试的是父进程,如果想调试子进程,那么在用gdb调试的时候要增加。该命令要在子进程运行前设置
set detach-on-fork on/off 继续其他进程/停止其他进程。当我们调试某个进程的时候,设置别的进程是否运行。默认是on,表示调试当前进程的时候,其他的进程继续运行。off,表示调试当前进程,其他的进程被 gdb 挂起。
info inferior 通过查看可以调试的进程,方便后面切换进程
inferior processNum 可以通过 info inferior 来查看可以调试的进程,当需要切换调试的进程时,根据processNum进行切换。这里的processNum是gdb自己排的进程编号,不是进程ID

以下程序未设置命令,因此默认调试父进程,并且调试的时候子进程是运行的

eading symbols from test3...
(gdb) b 7
Breakpoint 1 at 0x1216: file test3.c, line 7.
(gdb) run
Starting program: /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".Breakpoint 1, main () at test3.c:7
7            printf("begin\n");
(gdb) n
begin
9            if ( fork() != 0 )
(gdb) n
[Detaching after fork from child process 5242]
我是子进程:进程pid=5242,父进程ppid=5239
子进程jj=0
11                    printf("我是父进程:进程pid=%d,父进程ppid=%d\n",getpid(),getppid());
(gdb) 子进程jj=1
子进程jj=2
子进程jj=3
子进程jj=4
子进程jj=5
子进程jj=6

使用set follow-fork-mode child命令调试子进程,并使用set detach-on-fork off命令挂起父进程,随后再切换调试父进程

Reading symbols from test3...
(gdb) b 7
Breakpoint 1 at 0x1216: file test3.c, line 7.
(gdb) set follow-fork-mode child
(gdb) set detach-on-fork off
(gdb) r
Starting program: /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".Breakpoint 1, main () at test3.c:7
7            printf("begin\n");
(gdb) n
begin
9            if ( fork() != 0 )
(gdb) n
[Attaching after Thread 0x7ffff7fa9740 (LWP 5333) fork to child process 5336]
[New inferior 2 (process 5336)]
Reading symbols from /usr/lib/debug/.build-id/49/0fef8403240c91833978d494d39e537409b92e.debug...
Reading symbols from /usr/lib/debug/.build-id/41/86944c50f8a32b47d74931e3f512b811813b64.debug...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Switching to Thread 0x7ffff7fa9740 (LWP 5336)]
main () at test3.c:9
9            if ( fork() != 0 )
(gdb) n
24                    printf("我是子进程:进程pid=%d,父进程ppid=%d\n",getpid(),getppid());
(gdb) n
我是子进程:进程pid=5336,父进程ppid=5333
26                    for(jj=0; jj<200; jj++)
(gdb) n
28                            printf("子进程jj=%d\n",jj);
(gdb) n
子进程jj=0
29                            sleep(1);
(gdb) n
26                    for(jj=0; jj<200; jj++)
(gdb) info inferiorNum  Description       Connection           Executable        1    process 5333      1 (native)           /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3 
* 2    process 5336      1 (native)           /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3 
(gdb) inferior 1
[Switching to inferior 1 [process 5333] (/home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3)]
[Switching to thread 1.1 (Thread 0x7ffff7fa9740 (LWP 5333))]
#0  arch_fork (ctid=0x7ffff7fa9a10) at ../sysdeps/unix/sysv/linux/arch-fork.h:52
52    ../sysdeps/unix/sysv/linux/arch-fork.h: 没有那个文件或目录.
(gdb) info inferiorNum  Description       Connection           Executable        
* 1    process 5333      1 (native)           /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3 2    process 5336      1 (native)           /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test3 
(gdb) n
56    in ../sysdeps/unix/sysv/linux/arch-fork.h
(gdb) n
__GI__Fork () at ../sysdeps/nptl/_Fork.c:29
29    ../sysdeps/nptl/_Fork.c: 没有那个文件或目录.
(gdb) n
50    in ../sysdeps/nptl/_Fork.c
(gdb) n
__libc_fork () at ./posix/fork.c:75
75    ./posix/fork.c: 没有那个文件或目录.
(gdb) n
113    in ./posix/fork.c
(gdb) n
126    in ./posix/fork.c
(gdb) n
128    in ./posix/fork.c
(gdb) n
132    in ./posix/fork.c
(gdb) n
main () at test3.c:9
9            if ( fork() != 0 )
(gdb) n
11                    printf("我是父进程:进程pid=%d,父进程ppid=%d\n",getpid(),getppid());
(gdb) n
我是父进程:进程pid=5333,父进程ppid=5328
14                    for(ii=0; ii<200; ii++)
(gdb) n
16                            printf("父进程ii=%d\n",ii);
(gdb) n
父进程ii=0
17                            sleep(1);
(gdb) n
n14                    for(ii=0; ii<200; ii++)
(gdb) n
16                            printf("父进程ii=%d\n",ii);
(gdb) 

GDB调试多线程

测试程序

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>#define MAX 50
//全局变量
int number;
//创建一把互斥锁
pthread_mutex_t mutex;void* funcA_num(void* arg)
{for(int i=0; i<MAX; ++i){pthread_mutex_lock(&mutex);number++;printf("Thread A, id = %lu, number = %d\n", pthread_self(), number);pthread_mutex_unlock(&mutex);sleep(1);}return NULL;
}void* funcB_num(void* arg)
{for(int i=0; i<MAX; ++i){pthread_mutex_lock(&mutex);number++;printf("Thread B, id = %lu, number = %d\n", pthread_self(), number);pthread_mutex_unlock(&mutex);sleep(1);}return NULL;
}int main(int argc, const char* argv[])
{pthread_t p1, p2;// 初始化互斥锁pthread_mutex_init(&mutex, NULL);// 创建两个子线程pthread_create(&p1, NULL, funcA_num, NULL);pthread_create(&p2, NULL, funcB_num, NULL);for(int k = 0; k < MAX; k++){pthread_mutex_lock(&mutex);number++;printf("Thread Main, id = %lu, number = %d\n", pthread_self(), number);pthread_mutex_unlock(&mutex);sleep(1);}// 阻塞,资源回收pthread_join(p1, NULL);pthread_join(p2, NULL);// 销毁互斥锁// 线程销毁之后, 再去释放互斥锁pthread_mutex_destroy(&mutex);return 0;
}
gcc -g -o test4 test4.c -lphtread
./test4
//运行结果
Thread Main, id = 139380790110016, number = 1
Thread A, id = 139380784105024, number = 2
Thread B, id = 139380773619264, number = 3
Thread A, id = 139380784105024, number = 4
Thread B, id = 139380773619264, number = 5
Thread Main, id = 139380790110016, number = 6
......

线程查看命令

命令 解析
ps -aL | grep xxx 查看轻量级进程。轻量级的进程就是线程:p——process:进程; s——state:状态;a——all:全部;L——light:轻
pstree -p 主线程id 主线程和子线程的关系用树形展开
XX@XX-virtual-machine:~/Desktop/fatenone/project/gcc/gdb2$ ps -aL|grep test44523    4523 pts/0    00:00:00 test44523    4524 pts/0    00:00:00 test44523    4525 pts/0    00:00:00 test4
XX@XX-virtual-machine:~/Desktop/fatenone/project/gcc/gdb2$ pstree -p 4523
test4(4523)─┬─{test4}(4524)└─{test4}(4525)

调试命令

命令 解析
info threads 查看线程
thread 线程号 切换到某个线程,这个线程号可以查看info threads
set scheduler-locking on 可以用来锁定当前线程,只观察这个线程的运行情况。当锁定这个线程时,其他线程就处于了暂停状态,也就是说你在当前线程执行 next、step、until、finish、return 命令时,其他线程是不会运行的。需要注意的是,你在使用 set scheduler-locking on/step 选项时要确认下当前线程是否是你期望锁定的线程,如果不是,可以使用 thread <线程编号> 切换到你需要的线程,然后再进行锁定。
set scheduler-locking step 也是用来锁定当前线程,当且仅当使用 next 或 step 命令做单步调试时会锁定当前线程,如果使用 until、finish、return 等线程内的非单步调试命令,其他线程还是有机会运行的。相比较 on 选项值,step 选项值给为单步调试提供了更加精细化的控制,因为通常我们只希望在单步调试时,不希望其他线程对当前调试的各个变量值造成影响。
set scheduler-locking off 关闭锁定当前线程,所有的线程都会执行。
opyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test4...
(gdb) b 54
Breakpoint 1 at 0x1448: file test4.c, line 54.
(gdb) r
Starting program: /home/lisentao/Desktop/fatenone/project/gcc/gdb2/test4 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7a00640 (LWP 4930)]
Thread A, id = 140737347847744, number = 1
[New Thread 0x7ffff7000640 (LWP 4931)]
Thread B, id = 140737337361984, number = 2
Thread Main, id = 140737353783104, number = 3Thread 1 "test4" hit Breakpoint 1, main (argc=1, argv=0x7fffffffdee8) at test4.c:54
54            sleep(1);
(gdb) info threadsId   Target Id                                Frame 
* 1    Thread 0x7ffff7fa9740 (LWP 4927) "test4" main (argc=1, argv=0x7fffffffdee8) at test4.c:542    Thread 0x7ffff7a00640 (LWP 4930) "test4" 0x00007ffff7ce57f8 in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffff79ffde0, rem=rem@entry=0x7ffff79ffde0)at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:783    Thread 0x7ffff7000640 (LWP 4931) "test4" 0x00007ffff7ce57f8 in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffff6fffde0, rem=rem@entry=0x7ffff6fffde0)at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff7a00640 (LWP 4930))]
#0  0x00007ffff7ce57f8 in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffff79ffde0, rem=rem@entry=0x7ffff79ffde0)at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
78    ../sysdeps/unix/sysv/linux/clock_nanosleep.c: 没有那个文件或目录.
(gdb) info threadsId   Target Id                                Frame 1    Thread 0x7ffff7fa9740 (LWP 4927) "test4" main (argc=1, argv=0x7fffffffdee8) at test4.c:54
* 2    Thread 0x7ffff7a00640 (LWP 4930) "test4" 0x00007ffff7ce57f8 in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffff79ffde0, rem=rem@entry=0x7ffff79ffde0)at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:783    Thread 0x7ffff7000640 (LWP 4931) "test4" 0x00007ffff7ce57f8 in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffff6fffde0, rem=rem@entry=0x7ffff6fffde0)at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
(gdb) c
Continuing.
Thread A, id = 140737347847744, number = 4
Thread B, id = 140737337361984, number = 5
Thread A, id = 140737347847744, number = 6
Thread B, id = 140737337361984, number = 7
Thread Main, id = 140737353783104, number = 8
[Switching to Thread 0x7ffff7fa9740 (LWP 4927)]Thread 1 "test4" hit Breakpoint 1, main (argc=1, argv=0x7fffffffdee8) at test4.c:54
54            sleep(1);
(gdb) set scheduler-locking on
(gdb) c
Continuing.
Thread Main, id = 140737353783104, number = 9//可以看到此时除了main线程,线程A和线程B都已经锁住了Thread 1 "test4" hit Breakpoint 1, main (argc=1, argv=0x7fffffffdee8) at test4.c:54
54            sleep(1);
(gdb) set scheduler-locking off
(gdb) c
Continuing.
Thread A, id = 140737347847744, number = 10
Thread B, id = 140737337361984, number = 11
Thread B, id = 140737337361984, number = 12
Thread A, id = 140737347847744, number = 13
Thread Main, id = 140737353783104, number = 14//使用set scheduler-lockingoff命令,A和B线程不会被锁住Thread 1 "test4" hit Breakpoint 1, main (argc=1, argv=0x7fffffffdee8) at test4.c:54
54            sleep(1);
(gdb) n
Thread B, id = 140737337361984, number = 15
Thread A, id = 140737347847744, number = 16
48        for(int k = 0; k < MAX; k++)
(gdb) n
Thread A, id = 140737347847744, number = 17
Thread B, id = 140737337361984, number = 18
50            pthread_mutex_lock(&mutex);
(gdb) n
51        number++;
(gdb) n
52            printf("Thread Main, id = %lu, number = %d\n", pthread_self(), number);
(gdb) n
Thread Main, id = 140737353783104, number = 19
53            pthread_mutex_unlock(&mutex);
(gdb) set scheduler-locking step
(gdb) c
Continuing.
Thread A, id = 140737347847744, number = 20
Thread B, id = 140737337361984, number = 21//使用set scheduler-lockingstep命令,continue的时候A和B线程没有被锁住Thread 1 "test4" hit Breakpoint 1, main (argc=1, argv=0x7fffffffdee8) at test4.c:54
54            sleep(1);
(gdb) n
48        for(int k = 0; k < MAX; k++)
(gdb) n
50            pthread_mutex_lock(&mutex);
(gdb) n
51        number++;
(gdb) n
52            printf("Thread Main, id = %lu, number = %d\n", pthread_self(), number);
(gdb) n
Thread Main, id = 140737353783104, number = 22//使用set scheduler-lockingstep命令,next的时候A和B线程被锁住
53            pthread_mutex_unlock(&mutex);
(gdb) nThread 1 "test4" hit Breakpoint 1, main (argc=1, argv=0x7fffffffdee8) at test4.c:54
54            sleep(1);
(gdb) 

Core Dump基础

有时候写程序会出现 coredump 的错误,也就是内存溢出,程序挂掉。要去查看是程序中的那个地方导致了内存溢出,可以在GDB调试的时候加上 core 文件,core 文件里面记录了程序挂掉的一些重要信息。

调试命令

命令 解析
ulimt -a 看系统参数,core文件的默认大小是 0
ulimit -c unlimited 将core文件的大小修改为无限制

引用

gdb调试正在运行中的程序_gdb调试正在运行的程序-CSDN博客

深入理解GDB调试:多进程、多线程及核心文件剖析-CSDN博客

GDB-2——GDB调试多线程 - Hello-World3 - 博客园

Linux多线程调试没那么难,别就会一个printf! - 知乎

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

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

相关文章

qt cmake加入程序exe图标

可以看到qt自动编译出来的图标是默认的,如下图所示 我想要更改成自定义的图标,比如下方的样子 下边是操作步骤: 图标选择与转化成ico通过这个网站将正常图片转化成ico:https://www.bitbug.net/创建rc文件将ico复制到cmakelist的同级目录下,然后新建文本文件,里边输入如…

100道codeforces 2500

首先小小容斥一下,用1~r的减去1~l-1的。 1~r的,可以想到数位dp 设f[len][pre][mod]表示从低位数第len位,当前数字的值%2450为pre,当前用过的数字的lcm为mod的方案数 使用limit表示是否贴着上界 #include<bits/stdc++.h> using namespace std; typedef long long ll; …

第六轮easy~hard

题目1代码 #include<bits/stdc++.h> using namespace std;const int MAX = 2e+5; int ary[MAX],prefix[MAX]; int main() {int n; cin>>n;for(int i=1;i<=n;i++){cin>>ary[i];prefix[i] = prefix[i-1] + ary[i];}int minGap = 0x7fffffff, maxSum = 0x80…

代码随想录算法训练营day4 | 24.两两交换链表中的节点、19.删除链表的倒数第N个节点、160.相交链表、142.环形链表Ⅱ

24.两两交换链表中的节点点击查看代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next…

倾斜摄影OSGB瓦块大小重划分

在倾斜摄影数据生产过程中或者使用时,经常会遇到生产的瓦块过大或者过小的问题,如果重新生成一来费时费力,二来有些数据原片都不一定还有,因此很多用户提出能否开发一个osgb瓦块大小重新划分的功能。 现在它来了,2025年的第一个版本更新,我们把这个功能加上了,新…

DeepSeek本地安装部署以及对外提供服务

本地安装部署参考博客:https://blog.csdn.net/weixin_47061482/article/details/145577119,这里就不赘述了。 下面说一下对外提供deepseek服务。 场景:本地部署了deepseek之后,在公司如何使用服务,又或者说把本地服务提供给其他人使用。 工具:chatbox:一款 AI 客户端应用…

在.net8中使用OpenTelemetry来metric

OpenTelemetry可以说是可观测性里的中流砥柱,自然.net也能很好的与期交互。OpenTelemetry支持了很多语言,C#也在其中,下面的列子就是在一个api项目中,添加对OpenTelemetry的NuGet包的引用,来完成应用的metric的。基本思路是,第一步:在程序中引入OpenTelemetry相关包,并…

PyTorch 学习笔记:二分类神经网络实例

PyTorch 学习笔记:二分类神经网络实例 作者:BohengWebb 以下是菜鸟教程提供的一个二分类经典案例(有改动): import torch import torch.nn as nn import torch.optim as optim import matplotlib.pyplot as pltn_samples = 100 data = torch.randn(n_samples, 2) labels =…

OSGB层级截取

倾斜OSGB数据中,每个瓦块中的OSGB文件实际是一个金字塔层级的组织形式,按照层级进行组织,层级越大,模型越精细,同样的文件大小也越大,对渲染引擎的压力也越大。有些情况下不需要模型那么精细,因此可以通过删除相应层级的OSGB文件达到减少文件大小,降低渲染压力的目的。…

C#12:内联数组

之前,想把一个对象当集合使用,需要给这个类型构建索引器,为了foreach,还需要实现IEnumerable。public struct Season : IEnumerable {readonly string[] _arr;public Season(){_arr = new string[4];}public string this[int index]{get => _arr[index];set => _arr[…

C#12:主构造函数

record:record可以在定义类型时带参,这个参数会转成默认的属性public record PersonRecord(string FirstName, string LastName) {public string Name => $"{FirstName} {LastName}"; }在实例化完对象后,是可以直接使用这些属性的,但用record定义的类型,不会有…

.NET 8下的AOT

相比之前,AOT在.NET8的第5个预览版有了进一步的实现,给我的感觉是在一步步落地,虽然离生产还很远,但还是能看到希望的。使用AOT的API项目与传统的Web API项目在模版就作了区分,分别是“asp.net core api”和“asp.net core web api”,命令行创建项目的短名称是api和webap…