gdb debugging [multi-process, multi-thread]

1. Introduction to gdb

  • The gdb tool is a debugging tool in the Linux environment. (This article is tested in the centos6.5 environment)
  • The -g option must be added when compiling the source file.
  • Start debugging: gdb binfile
  • Exit method quit or ctrl+d.

Common commands for gdb debugging process:

   list/l 行号:显示源代码,接着上次的位置往下列,每次列10行。
   list/l 函数名:列出某个函数的源代码。
   r或run:运行程序。
   s或step:进入函数调用
   breaktrace(bt):查看各级函数调用及参数
   info(i) locals:查看当前栈帧局部变量的值
   info break :查看断点信息。
   finish:执行到当前函数返回,然后挺下来等待命令
   print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
   set var:修改变量的值
   quit:退出gdb
   break(b) 行号:在某一行设置断点
   break 函数名:在某个函数开头设置断点
   continue(或c):从当前位置开始连续而非单步执行程序
   run(或r):从开始连续而非单步执行程序
   delete breakpoints:删除所有断点
   delete breakpoints n:删除序号为n的断点
   disable breakpoints:禁用断点
   enable breakpoints:启用断点
   info(或i) breakpoints:参看当前设置了哪些断点
   display 变量名:跟踪查看一个变量,每次停下来都显示它的值
   undisplay:取消对先前设置的那些变量的跟踪
   until X行号:跳至X行
   p 变量:打印变量值
   n 或 next:单条执行

2. Debugging multiple processes

By default, gdb will only debug the main process. If you want to debug multiple processes, you need to make some settings:
1. The show follow-fork-mode command and the show detach-on-fork
write picture description here command are to view these two modes Settings:
The default follow-fork-mode is parent, detach-on-fork is on, and only the main process is debugged at this time.
2. The commands set follow-fork-mode and set detach-on-fork
can reset these two modes for multi-process debugging
. Follow-fork-mode has two options: [ parent ] and [ child ]
detach- There are two options for on-fork: [ on ] and [ off ]
Then there are the following four cases, each with different meanings:

1.parent                   on               只调试主进程(GDB默认)
2.child                    on               只调试子进程
3.parent                   off              同时调试两个进程,gdb跟主进程,子进程block在fork位置
4.child                    off              同时调试两个进程,gdb跟子进程,主进程block在fork位置

Set it as follows:
write picture description here

Test file:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/wait.h>
  5 #include<stdlib.h>
  6 int main()
  7 {
  8 pid_t pid;
  9 pid=fork();
 10 if(pid<0)
 11 {
 12  
 13     perror("fork");
 14     exit(1);
 15  
 16 }
 17 if(pid==0)
 18 {//child
 19 printf("I am Child,My id is:%d,My fathers id is:%d\n",getpid(),getppid());
 20  
 21 }
 22 if(pid>0)
 23 {//father
 24 printf("I am Father,My id is:%d\n",getpid());
 25 wait(NULL);                                                                                                                                                                                   
 26 }
 27  
 28     return 0;
 29 }

3. Next, set breakpoints in the parent and child processes respectively:
write picture description here
4. Run the program and query the running process:
write picture description here
write picture description here
For each debugged process, the operating system will assign him an inferior structure to describe the debugging of the process information, and assign an id to it, each process corresponds to an inferior, each different inferior has a different address space, and sometimes the inferior exists when the process has not been started.
5. Switch the debugged process:

inferior<infer number>

write picture description here
6. Other operations
Add debugging process

1.add-inferior [-copies n] [-exec executable]

Add one or more debug processes, n represents the number to be added, if not specified, one is added by default, and executable is the path of the debug file. If not specified, the program will be left blank. After adding, you can use the file command to re-specify the execution program. At this time, the process associated with the Inferior created is not started.
Delete the inferior numbered inferno. If the program is running, it cannot be deleted, it must be detached or killed first.

2.remove-inferior inferno

Copy n inferiors numbered inferno. If n is not specified, copy one. If inferno is not specified, the current process is copied by default.

3.clone-inferior [n][inferno]

Detach separates the inferior numbered inferno. Note that even if detached, the inferior still exists, waiting for the user to use the run command again to make it run.

4.detach-inferior inferno

Kill the Inferior numbered inferno. Note that even if it is removed, the Inferior still exists, waiting for the user to use the run command again to make it run.

5.kill-inferior inferno

6.set schedule-multiple on|off

When set to off: only the current Inferior will be executed
When set to on: All Inferiors in the execution state will be executed

7.scheduler-locking

Note that when scheduler-locking is on, even if scheduler-multiple is on, only the current thread of the current process will execute. The default is step. It can be viewed by show sheduler-locking,

8.set follow-exec-mode new|same

Set to new: When an exec occurs, control the child process on the inferior that executes the exec.
Set to the same: Create a new Inferior for the executing child process. The parent process's Inferior is still retained, and the program state of the currently retained Inferior is not executed.

9. set print inferior-events

It is used to set the status prompt information of Inferior, which can be set to on or off.

10.maint info program-spaces

Used to view how much address space is currently managed by GDB.


3. Debugging multithreading

gdb supports debugging multithreading by default. Like the main thread, the new thread block is where it was created.
Test file:

  1 #include<stdio.h>
  2 #include<pthread.h>
  3     
  4 void *run1(void *arg)
  5 {   
  6 printf("I am thread 1,My id is:%d\n",pthread_self());
  7 }   
  8 void * run2(void *arg)
  9 {   
 10     printf("I am thread2 ,My id is:%d\n",pthread_self());
 11 }   
 12  int main()
 13 {   
 14     pthread_t t1,t2;
 15     pthread_create(&t1,NULL,run1,NULL);
 16     pthread_create(&t2,NULL,run2,NULL);
 17     pthread_join(t1,NULL);
 18     pthread_join(t2,NULL);
 19     return 0;
 20 }
 21       

Two threads are created here, so there are three threads in total. Here are two breakpoints inside the two thread functions respectively.
write picture description here
1. Common commands for debugging multithreading

1.info threads

When debugging multiple threads, gdb will assign a thread id to each thread, generally starting from 1, where the thread id is different from t1. We can look at the thread situation, since our first breakpoint is in thread run1, thread 2 is running.

2.thread ID

Switch the debugging thread, the ID is the thread number.

3.show scheduler-locking
  set  scheduler-locking on|off|step

Check the thread lock status and set the thread lock status. When set to on, lock the rest of the threads, and only the current thread will run. Set to off to not lock any threads, default value. When set to step, only the thread being debugged will run.

4.thread apply id1 id2 id3 commond
  thread apply all commond

The first is to let the specified threads 1, 2, and 3 execute the commond command, and the second is that all threads execute the commond command.

5.break FileName.cpp:LinuNum thread all: 

All threads have a breakpoint at line LineNum of the file FileName.cpp.

6.set target-async on/ff

Synchronous and asynchronous. Synchronous, gdb waits for the program to report that some thread has terminated before outputting the prompt. Asynchronous, on the other hand, returns directly.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325169727&siteId=291194637