在多线程编程时,当我们需要调试时,有时需要控制某些线程停在断点,某些线程继续执行。有时需要控制线程的运行顺序。有时需要中断某个线程,切换到其他线程。这些都可以通过gdb实现。
下图为多线程与多进程调试的通用常用命令,应该熟练掌握下面几种命令的使用。
gdb调试多线程
多线程调试的主要任务是准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的结果就是维护一个叫thread list的链表。
下面我们以以下多线程的程序为例,在gdb模式下测试各种命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <stdio.h> #include <pthread.h> #include <stdlib.h> int count = 0; void *pthread_run(void *arg) { int i = 0; while(i < 100) { i++; count += i; } return NULL; } int main() { pthread_t pth1; pthread_t pth2; pthread_create(&pth1,NULL,&pthread_run,NULL); pthread_create(&pth2,NULL,&pthread_run,NULL); pthread_join(pth1,NULL); pthread_join(pth2,NULL); printf("count: %d\n",count); return 0; } |
① 在编译程序时加上-g。如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。使用gdb+可执行程序进入gdb调试模式。
② list [行号]:表示列出第几行附近的代码,默认显示10行,可以摁下l选项顺次列出(list可缩写为l)。
③ info break:查看断点信息。break [行号],表示在程序的第几行设置断点(break可简写为b)。
④ r:即run,表示运行程序。上面设置了断点,因此会在第一个断点处停住。
⑤ delete [断点号]:表示删除单个断点。delete 1-10:删除一个断点的集合,表示删除1到10所有的断点。
⑥ n:即next,单步调试模式,表示单条语句执行。
⑦ p [变量名]:打印变量的值,p为printf的缩写。
⑧ bt:查看函数的堆栈信息。
⑨ thread apply all bt:让所有线程都打印堆栈信息。thread apply ID command :让ID线程执行命令command。thread apply all command :让所有线程执行命令command。
⑩ info threads:显示当前可调试的所有线程,gdb为每一个线程分配一个ID号。*表示正在调试的线程。thread [线程ID]:切换到当前要调试的线程ID。
⑪ c:continue,与C/C++中的continue完全一致。
⑫ finish:退出当前函数(本例中为pthread_run)。
⑬ q:即quit,表示退出gdb模式。
gdb调试多进程
在Linux(CentOS6.5)默认设置下,调试多进程程序时gdb只会调试父进程,为了可以对父子进程都做到调试,我们需要做一些设置。
follow-fork-mode
|
detach-on-fork
|
具体说明
|
parent
|
on
|
只调试父进程
|
child
|
on
|
只调试子进程
|
parent
|
off
|
调试调试两个进程,gdb跟父子进程block在fork位置
|
child
|
off
|
同时调试两个进程,gdb跟父子进程block在fork位置
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t id = fork(); int val = 0; if(id < 0)//创建失败 { perror("fork"); exit(1); } else if(id == 0)//child { int i = 0; for(i = 0;i < 5;i++) { printf("val: %d\n",val+i); } } else //father { int j = 0; while(j < 3) { printf("father: %d",j*j); j++; } } return 0; } |


④ maint info program-spaces:显示当前gdb一共管理了多少地址空间。
⑤ detach inferior [进程编号]:detach掉某一进程的编号,但是这个进程还存在,让它自由运行完,detach掉的进程会显示null。
⑥ kill inferior [进程编号]:kill掉某进程,但是此进程还存在,可再次使用run等命令执行它,被kill掉的进程会显示null。
⑦ remove-inferior [进程编号]:删除某一个inferior。如果该inferior正在运行,则不能删除,因此删除之前必须先kill或detach掉。
⑧ set schedule-multiple:设置为off表示只有当前的inferior会被执行,设置为on,表示所有执行状态的inferior都会被执行。
⑨ set print interior-events on/off:用来打开和关闭inferior状态的提示信息。
当然,gdb多线程的断点、单步调试、运行等命令同样适用于多进程的调试,这里也就不一一列举了。上述仅仅是一些常用命令的举例,想了解其他命令请自己动手尝试。
发表于2017-06-09 16:03 沙发
报告博主,有bug,list+行号 应该是:列出第几行附近的10行源码。不是第几行开始的代码
发表于2017-06-09 16:28 地下1层
修改了![[憨笑]](https://www.1024do.com/wp-content/themes/Unite-1/images/smilies/hanx.gif)