GDB(GNU Debugger)是一个用于调试程序的强大工具。它是GNU项目的一部分,支持多种编程语言,包括C、C++等。GDB 提供了一组命令和功能,允许跟踪检查程序的内部状态,跟踪代码的执行过程,以及定位和修复程序中的错误。
GDB(GNU Debugger)
GDB Server(gdbserver)
主要包含如下区别:
总体而言,使用 GDB 和使用 IDE 中的调试工具之间的选择通常取决于个人偏好、项目需求以及开发环境。
#include <stdio.h>
void accessInvalidMemory() {
int *ptr = NULL; // 故意将指针设置为NULL
*ptr = 42; // 试图访问NULL指针
}
int main() {
accessInvalidMemory(); // 调用会导致Segmentation fault的函数
return 0;
}
定位流程与操作
@ubuntu:$ gcc -g Segmentation_fault.c -o Segmentation_fault
@ubuntu:GDB_debug$ gdb ./Segmentation_fault -q
Reading symbols from ./Segmentation_fault...done.
(gdb) b main
Breakpoint 1 at 0x617: file Segmentation_fault.c, line 9.
(gdb) list
1 #include <stdio.h>
2
3 void accessInvalidMemory() {
4 int *ptr = NULL; // 故意将指针设置为NULL
5 *ptr = 42; // 试图访问NULL指针
6 }
7
8 int main() {
9 accessInvalidMemory(); // 调用会导致Segmentation fault的函数
10 return 0;
(gdb) r
Starting program: GDB_debug/Segmentation_fault
Breakpoint 1, main () at Segmentation_fault.c:9
9 accessInvalidMemory(); // 调用会导致Segmentation fault的函数
(gdb) s
accessInvalidMemory () at Segmentation_fault.c:4
4 int *ptr = NULL; // 故意将指针设置为NULL
(gdb) n
5 *ptr = 42; // 试图访问NULL指针
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x000055555555460a in accessInvalidMemory () at Segmentation_fault.c:5
5 *ptr = 42; // 试图访问NULL指针
(gdb) bt
#0 0x000055555555460a in accessInvalidMemory () at Segmentation_fault.c:5
#1 0x0000555555554621 in main () at Segmentation_fault.c:9
(gdb) n
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) n
The program is not being run.
结论
查看调用栈
(gdb) bt
#0 0x000055555555460a in accessInvalidMemory () at Segmentation_fault.c:5
#1 0x0000555555554621 in main () at Segmentation_fault.c:9
问题出在:函数accessInvalidMemory,代码的第五行
说明与解释:
为什么不一直用next?还用step?
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *thread_function(void *arg) {
for (int i = 0; i < 5; ++i) {
printf("Thread %ld: Iteration %d\n", (long)arg, i);
sleep(1);
}
return NULL;
}
int main() {
pthread_t thread1, thread2;
// 创建两个线程
pthread_create(&thread1, NULL, thread_function, (void *)1);
pthread_create(&thread2, NULL, thread_function, (void *)2);
// 等待线程结束
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
编译
gcc -g multithread_demo.c -o multithread_demo -lpthread
执行
gdb ./multithread_demo -q
1、查看整体进程中的线程执行结果:
@ubuntu:$ gdb ./multithread_demo -q
Reading symbols from ./multithread_demo...done.
(gdb) b main
Breakpoint 1 at 0x81d: file multithread_demo.c, line 13.
(gdb) run
Starting program: GDB_debug/multithread_demo
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at multithread_demo.c:13
13 int main() {
(gdb) n
17 pthread_create(&thread1, NULL, thread_function, (void *)1);
(gdb) n
[New Thread 0x7ffff77c2700 (LWP 335)]
18 pthread_create(&thread2, NULL, thread_function, (void *)2);
(gdb) info threads
Id Target Id Frame
- 1 Thread 0x7ffff7fdb740 (LWP 130537) "multithread_dem" main () at multithread_demo.c:18
(gdb) n
Thread 1: Iteration 1
Thread 2: Iteration 0
Thread 1: Iteration 2
Thread 2: Iteration 1
Thread 1: Iteration 3
Thread 2: Iteration 2
Thread 1: Iteration 4
Thread 2: Iteration 3
[Thread 0x7ffff77c2700 (LWP 335) exited]
22 pthread_join(thread2, NULL);
(gdb) n
Thread 2: Iteration 4
[Thread 0x7ffff6fc1700 (LWP 1407) exited]
24 return 0;
(gdb) n
25 }
(gdb) n
[Inferior 1 (process 130537) exited normally]
(gdb) n
The program is not being run.
2、子线程被创建后,gdb跟踪子线程及主线程
@ubuntu:GDB_debug$ gdb ./multithread_demo -q
Reading symbols from ./multithread_demo...done.
(gdb) set detach-on-fork off
(gdb) b main
Breakpoint 1 at 0x81d: file multithread_demo.c, line 13.
(gdb) run
Starting program: GDB_debug/multithread_demo
[Thread debugging using libthread_db enabled]
13 int main() {
(gdb) n
17 pthread_create(&thread1, NULL, thread_function, (void *)1);
(gdb) n
[New Thread 0x7ffff77c2700 (LWP 9522)]
Thread 1: Iteration 0
18 pthread_create(&thread2, NULL, thread_function, (void *)2);
(gdb) n
[New Thread 0x7ffff6fc1700 (LWP 9523)]
Thread 2: Iteration 0
Thread 2: Iteration 1
Thread 2: Iteration 2
Thread 2: Iteration 3
Thread 2: Iteration 4
8 sleep(1);
(gdb)
6 for (int i = 0; i < 5; ++i) {
(gdb)
7 printf("Thread %ld: Iteration %d\n", (long)arg, i);
(gdb)
Thread 1: Iteration 1
8 sleep(1);
(gdb)
6 for (int i = 0; i < 5; ++i) {
(gdb)
7 printf("Thread %ld: Iteration %d\n", (long)arg, i);
(gdb)
Thread 1: Iteration 2
8 sleep(1);
(gdb)
6 for (int i = 0; i < 5; ++i) {
(gdb)
7 printf("Thread %ld: Iteration %d\n", (long)arg, i);
(gdb)
Thread 1: Iteration 3
8 sleep(1);
(gdb)
6 for (int i = 0; i < 5; ++i) {
(gdb)
7 printf("Thread %ld: Iteration %d\n", (long)arg, i);
(gdb)
Thread 1: Iteration 4
8 sleep(1);
(gdb)
6 for (int i = 0; i < 5; ++i) {
(gdb)
10 return NULL;
(gdb)
11 }
命令解释
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
int num =10;
while(num==10){
sleep(2);
printf("this 1is child,pid = %d\n",getpid());
}
printf("this 2is child,pid = %d\n",getpid());
printf("this 3is child,pid = %d\n",getpid());
}
else
{
int mnum=5;
while(mnum==5){
sleep(5);
printf("this 4is parent,pid = %d\n",getpid());
}
}
return 0;
}
编译
gcc -g multiprocess_demo_2.c -o multiprocess_demo_2
gdb 跟踪子进程:
@ubuntu:GDB_debug$ gcc -g multiprocess_demo_2.c -o multiprocess_demo_2
@ubuntu:GDB_debug$ gdb ./multiprocess_demo_2 -q
Reading symbols from ./multiprocess_demo_2...done.
(gdb) b main
Breakpoint 1 at 0x722: file multiprocess_demo_2.c, line 5.
(gdb) set follow-fork-mode child
(gdb) r
Starting program: /home/xj/Desktop/huangrui/project_1/GDB_debug/multiprocess_demo_2
Breakpoint 1, main () at multiprocess_demo_2.c:5
5 pid_t pid = fork();
(gdb) n
[New process 109167]
[Switching to process 109167]
main () at multiprocess_demo_2.c:6
6 if(pid == 0)
(gdb) info inferiors
Num Description Executable
1 <null> GDB_debug/multiprocess_demo_2
* 2 process 109167 GDB_debug/multiprocess_demo_2
(gdb) this 4is parent,pid = 109163
this 4is parent,pid = 109163
n
8 int num =10;
(gdb) n
9 while(num==10){
(gdb) this 4is parent,pid = 109163
n
10 sleep(2);
(gdb) n
11 printf("this 1is child,pid = %d\n",getpid());
(gdb) this 4is parent,pid = 109163
p num=this 4is parent,pid = 109163
9
$1 = 9
(gdb) n
this 1is child,pid = 109167
9 while(num==10){
(gdb) n
14 printf("this 2is child,pid = %d\n",getpid());
(gdb) n
this 2is child,pid = 109167
15 printf("this 3is child,pid = %d\n",getpid());
(gdb) this 4is parent,pid = 109163
n
this 3is child,pid = 109167
26 return 0;
(gdb) n
27 }(gdb) nthis 4is parent,pid = 109163
__libc_start_main (main=0x55555555471a <main>, argc=1, argv=0x7fffffffe328, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe318)
at ../csu/libc-start.c:344
344 ../csu/libc-start.c: No such file or directory.
(gdb) n
[Inferior 2 (process 109167) exited normally]
(gdb) n
The program is not being run.
(gdb) quitthis 4is parent,pid = 109163
set follow-fork-mode的作用:set follow-fork-mode parent 是 GDB 的一个命令,用于在多进程调试时控制在 fork() 调用之后 GDB 应该跟踪哪个进程。
解释:
前面是单子进程的调试
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid1, pid2;
pid1 = fork();
if (pid1 == 0) {
// 子进程1
printf("Child Process 1 (PID: %d)\n", getpid());
// 子进程1的工作
} else {
pid2 = fork();
if (pid2 == 0) {
// 子进程2
printf("Child Process 2 (PID: %d)\n", getpid());
// 子进程2的工作
} else {
// 父进程
printf("Parent Process (PID: %d)\n", getpid());
// 父进程的工作
// 父进程通常需要等待子进程结束
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
}
}
return 0;
}
调试步骤(步骤有删减):
@ubuntu:GDB_debug$ gdb ./multiprocess_demo -q
Reading symbols from ./multiprocess_demo...done.
(gdb) b main
Breakpoint 1 at 0x722: file multiprocess_demo.c, line 7.
(gdb) b fork
Breakpoint 2 at 0x5f0
(gdb) set detach-on-fork off
(gdb) set follow-fork-mode child
(gdb) catch fork
Catchpoint 3 (fork)
(gdb) run
Starting program: GDB_debug/multiprocess_demo
Breakpoint 1, main () at multiprocess_demo.c:7
7 pid1 = fork();
(gdb) n
Breakpoint 2, __libc_fork () at ../sysdeps/nptl/fork.c:49
49 ../sysdeps/nptl/fork.c: No such file or directory.
(gdb) n
Catchpoint 3 (forked process 109279), 0x00007ffff7ac67cc in __libc_fork () at ../sysdeps/nptl/fork.c:135
135 in ../sysdeps/nptl/fork.c
(gdb)
[New process 109279]
Reading symbols from GDB_debug/multiprocess_demo...done.
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.27.so...done.
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.27.so...done.
__libc_fork () at ../sysdeps/nptl/fork.c:142
142 ../sysdeps/nptl/fork.c: No such file or directory.
(gdb) info inferiors
Num Description Executable
1 process 109275 GDB_debug/multiprocess_demo
* 2 process 109279 GDB_debug/multiprocess_demo
(gdb) n
main () at multiprocess_demo.c:8
8 if (pid1 == 0) {
(gdb)
10 printf("Child Process 1 (PID: %d)\n", getpid());
(gdb) n
Child Process 1 (PID: 109279)
28 return 0;
(gdb) n
29 }
(gdb) n
[Inferior 2 (process 109279) exited normally]
(gdb) n
The program is not being run.
(gdb) info inferiors
Num Description Executable
1 process 109275 GDB_debug/multiprocess_demo
* 2 <null> GDB_debug/multiprocess_demo
(gdb) inferior 1
[Switching to inferior 1 [process 109275] (GDB_debug/multiprocess_demo)]
[Switching to thread 1.1 (process 109275)]
#0 0x00007ffff7ac67cc in __libc_fork () at ../sysdeps/nptl/fork.c:135
135 ../sysdeps/nptl/fork.c: No such file or directory.
(gdb) n
main () at multiprocess_demo.c:8
8 if (pid1 == 0) {
(gdb)
13 pid2 = fork();
(gdb) n
(gdb)
[New process 109280]
Reading symbols from GDB_debug/multiprocess_demo...done.
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.27.so...done.
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.27.so...done.
__libc_fork () at ../sysdeps/nptl/fork.c:142
142 ../sysdeps/nptl/fork.c: No such file or directory.
(gdb)
main () at multiprocess_demo.c:14
14 if (pid2 == 0) {
(gdb)
16 printf("Child Process 2 (PID: %d)\n", getpid());
(gdb)
Child Process 2 (PID: 109280)
28 return 0;
(gdb)
29 }
(gdb)
[Inferior 3 (process 109280) exited normally]
(gdb) info inferiors
Num Description Executable
1 process 109275 GDB_debug/multiprocess_demo
* 3 <null> GDB_debug/multiprocess_demo
(gdb) n
The program is not being run.
(gdb) info inferiors
Num Description Executable
1 process 109275 GDB_debug/multiprocess_demo
* 3 <null> GDB_debug/multiprocess_demo
(gdb) continue
The program is not being run.
(gdb) n
The program is not being run.
(gdb) info inferiors
Num Description Executable
1 process 109275 GDB_debug/multiprocess_demo
* 3 <null> GDB_debug/multiprocess_demo
(gdb) inferior 1
[Switching to inferior 1 [process 109275] (GDB_debug/multiprocess_demo)]
[Switching to thread 1.1 (process 109275)]
#0 0x00007ffff7ac67cc in __libc_fork () at ../sysdeps/nptl/fork.c:135
135 ../sysdeps/nptl/fork.c: No such file or directory.
main () at multiprocess_demo.c:14
14 if (pid2 == 0) {
(gdb)
20 printf("Parent Process (PID: %d)\n", getpid());
(gdb)
Parent Process (PID: 109275)
23 waitpid(pid1, NULL, 0);
(gdb) n
24 waitpid(pid2, NULL, 0);
(gdb) n
28 return 0;
(gdb) info inferiors
Num Description Executable
* 1 process 109275 GDB_debug/multiprocess_demo
(gdb) n
29 }
(gdb) n
[Inferior 1 (process 109275) exited normally]
(gdb) n
The program is not being run.
如下是对上面的进行的备注:
再次逻辑与命令说明
这样就可以单独的调试某个进程了
在这里我简单说明下连接的三个基本流程流程:
这个内容的实操我会在后面的文档中体现出来,一篇文档内容过多,比较冗余