gdb 调试技巧总结

GDB 基本命令

如果想要使用gdb调试程序,再编译时必须加-g参数。我们可以使用如下两种方式进行调试:

  1. 如果是未启动的程序名,使用gdb 程序名开始调试当前程序,或者先启动gdb,再用file 可执行文件名来调试文件。

  2. 如果程序已启动,需要调试程序的进程,使用gdb -p 进程ID,来调试进程。或者先启动gdb,再attach 进程ID来调试进程。

主要的命令和用法如下:

命令 作用
directory DIR 增加目录 DIR 到搜寻程序代码的目录列表 (如果你的程序代码和可执行档放在同一个目录下,就不须指定程序代码所在目录)
l (list) 从第当前行开始例出源代码
Enter (回车) 重复上一次输入的命令
b (break) 设置断点,如break test.cpp:100断行数,break UserManager::GetUser断函数
clear 清除断点,如clear XXX,XXX格式和上面b的格式相同
info break 查看断点信息
delete 清除断点,如delete NUM,NUM是在info break显示的断点编号,不加NUM表示删除所有断点
disable 禁止断点,如disable NUM,NUM是在info break显示的断点编号,不加NUM表示禁止所有断点
enable 启用断点,用法和disable类似
r (run) 运行程序
bt (backtrace) 显示程序堆栈信息
p (print) 打印表达式的值
display 在断点的停止的地方,显示指定的变量的值。
set 设置变量的值。如set val=54 ,将54设置到val变量中
n (next) 在触发断点之后,单步执行,不进函数调用
s (step) 单步执行,会进入函数调用
finish 继续执行,直到当前函数返回,并在调用函数的下一行停止
u (until) 执行一行程序,若此时程序是在 for/while/do loop 循环的最后一行,则一直执行到循环结束后的第一行程序后停止
return 强制从当前函数返回
CTRL + C 在当前位置停止执行正在执行的程序,断点在当前行
quit 退出gdb

gdb 调试多线程

假设现在有一个主线程创建了一个子线程。

gdb调试时,设置断点,单步调试到pthread_create处的时候,这时候会创建子线程,会出现如下信息

[New Thread 0x7ffff6fd1700 (LWP 6376)]

默认情况下,gdb只跟踪主线程,新创建的线程都被阻塞在pthread_create函数处。

info threads 可以调试的所有线程,gdb会为每个线程分配一个ID,这个ID和线程ID不同,ID号一般从1开始。

如下,表示当前有两个线程1和2,*表示跟踪主线程1

(gdb) info threads
  Id   Target Id         Frame 
  2    Thread 0x7ffff6fd1700 (LWP 6376) "test" 0x00007ffff70d0851 in clone ()
   from /lib64/libc.so.6
* 1    Thread 0x7ffff7fee740 (LWP 6375) "test" main (argc=1, argv=0x7fffffffe2d8) at test.cpp:31

thread ID 切换当前调试的线程为指定ID号,ID是gdb分配的序号,不是线程TID。

set scheduler-locking off|on on锁定其他线程,只有当前选择调试的线程执行,off表示不锁定任何线程,当运行到断点处,将所有的线程都暂停下来,直到指定某个线程继续执行,如果在当前线程下使用continue的话会启动所有线程(GDB默认)。

多线程调试控制指令

thread apply ID1 ID2 ...IDn gdb_command 指定多个线程执行gdb中的command指令

thread apply all command 指定所有线程执行gdb中的command指令

non-stop模式

上面说过一个线程中断在一个断点上,其他所有的线程都会被freeze。新版本的GDB中,引入了non-stop模式,在这个模式下:

  1. 当某个或多个线程在一个断点上,其他线程仍会并行运行

  2. 你可以选择某个被中断的线程,只让他运行。

  3. non-stop模式表示不停止模式,除了断点有关的进程会被停下来,其他线程会继续执行。

设置non-stop模式,打开gdb后,在开始r之前,首先连续输入下面的指令

set target-async 1
set pagination off
set non-stop on

总结调试多线程的命令

info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程

thread ID(1,2,3…) 切换当前调试的线程为指定ID的线程

break thread_test.c:123 thread all(例:在相应函数的位置设置断点break pthread_run1) 在所有线程中相应的行上设置断点

thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command

thread apply all command 让所有被调试线程执行GDB命令command

set scheduler-locking 选项 command 设置线程是以什么方式来执行命令

set scheduler-locking off 不锁定任何线程,也就是所有线程都执行,这是默认值

set scheduler-locking on 只有当前被调试程序会执行

set scheduler-locking on step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行

线程池调试小技巧

调试进程池和线程池中的程序一个不错的方法,是将池中的个数减少至1,观察是否正确,然后逐步增加线程数量,调试线程的同步是否正确

gdb 调试core文件

什么是core文件

如果程序有问题,会产生“段错误(核心已转储)”时会生成具有堆栈信息和调试信息的文件,在编译时需要加-g选项使程序生成调试信息,比如gcc -g test.c -o test

怎么配置生成core文件

  • core文件开关

使用ulimit -c查看core开关,如果为0表示关闭,不会生成core文件

使用ulimit -c [filesize]设置core文件大小,当最小设置为4之后才会生成core文件

使用ulimit -c unlimited设置core文件大小为不限制,这是比较推荐的常用做法

  • core文件命名和保存路径

core有默认的名称和路径,但是开发中通常会自己命名和指定保存路径。可以通过/proc/sys/kernel/core_pattern设置core文件名和保存路径,方法如下:

echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

其中有一些参数含义如下:

%p:insert pid into filename 添加pid

%u:insert current uid into filename 添加当前uid

%g:insert current gid into filename 添加当前gid

%s:insert signal that caused the coredump into the filename 添加导致产生core的信号

%t:insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间

%h:insert hostname where the coredump happened into filename 添加主机名

%e:insert coredumping executable name into filename 添加命令名

关于core文件的调试

比如现在有一个服务器程序编译后的二进制文件名是GameServer,宕机后生成的core文件是core.30132。调试core有以下两种方法:

方法1:

gdb GameServer core.30132

方法2:

gdb -c core.30132 GameServer

在服务器开发中,如果服务器宕机,一般会生成一个core文件,我们可以用gdb来调试此core文件,并使用bt命令查看函数调用堆栈,就可以快速定位到程序的函数。

GDB 分屏操作

在GDB中使用分屏,我们可以很方便的一边查看代码,一边输入命令,主要有以下操作:

layout:用于分割窗口,可以一边查看代码,一边测试。主要有以下几种用法:

layout src:显示源代码窗口

layout asm:显示汇编窗口

layout regs:显示源代码/汇编和寄存器窗口

layout split:显示源代码和汇编窗口

layout next:显示下一个layout

layout prev:显示上一个layout

Ctrl + L:刷新窗口

Ctrl + x,再按1:单窗口模式,显示一个窗口

Ctrl + x,再按2:双窗口模式,显示两个窗口

Ctrl + x,再按a:回到传统模式,即退出layout,回到执行layout之前的调试窗口

gdb 调试技巧总结

上一篇:Html5上传图片的预览


下一篇:MySQL相关丶