1. print 打印结果显示完整
当使用 print
命令打印一个字符串或者字符数组时,如果该字符串太长,print
命令默认显示不全的,我们可以通过在 GDB
中输入
set print element 0
命令设置一下,这样再次使用 print
命令就能完整地显示该变量的所有字符串了。
2. 为函数添加断点失效
有时候一个函数明明存在,并且我们的程序也存在调试符号,使用
break functionName
添加断点时 GDB
却提示:
Make breakpoint pending on future shared library load? y/n
即使输入 y
命令,添加的断点可能也不会被正确地触发,此时需要改变添加断点的方式,使用该函数所在的代码文件和行号添加断点就能达到效果。
3. 多线程下禁止线程切换
假设现在有 5 个线程,除了主线程,工作线程都是下面这样的一个函数:
void thread_proc(void* arg)
{
//代码行1
//代码行2
//代码行3
//代码行4
//代码行5
//代码行6
//代码行7
//代码行8
//代码行9
//代码行10
//代码行11
//代码行12
//代码行13
//代码行14
//代码行15
}
为了能说清楚这个问题,我们把四个工作线程分别叫做 A、B、C、D。
假设 GDB
当前正在处于线程 A 的代码行 3 处,此时输入 next
命令,我们期望的是调试器跳到代码行 4 处;或者使用 u 代码行10
,那么我们期望输入 u
命令后调试器可以跳转到代码行 10 处。
但是在实际情况下,GDB
可能会跳转到代码行 1 或者代码行 2 处,甚至代码行 13、代码行 14 这样的地方也是有可能的,这不是调试器 bug
,这是多线程程序的特点,当我们从代码行 4 处让程序 continue
时,线程 A 虽然会继续往下执行,但是如果此时系统的线程调度将 CPU
时间片切换到线程 B、C 或者 D 呢?那么程序最终停下来的时候,处于代码行 1 或者代码行 2 或者其他地方就不奇怪了,而此时打印相关的变量值,可能就不是我们需要的线程 A 的相关值。
为了解决调试多线程程序时出现的这种问题,GDB
提供了一个在调试时将程序执行流锁定在当前调试线程的命令:
set scheduler-locking on
当然也可以关闭这一选项,使用
set scheduler-locking off
4. 使用 GDB 调试多进程程序
这里说的多进程程序指的是一个进程使用 Linux
系统调用 fork()
函数产生的子进程,没有相互关联的进程就是普通的 GDB
调试,不必刻意讨论。
在实际的应用中,如有这样一类程序,如 Nginx
,对于客户端的连接是采用多进程模型,当 Nginx
接受客户端连接后,创建一个新的进程来处理这一路连接上的信息来往,新产生的进程与原进程互为父子关系,那么如何用 GDB
调试这样的父子进程呢?一般有两种方法:
- 用
GDB
先调试父进程,等子进程fork
出来后,使用gdb attach
到子进程上去,当然这需要重新开启一个session
窗口用于调试,gdb attach
的用法在前面已经介绍过了; GDB
调试器提供了一个选项叫follow-fork
,可以使用show follow-fork mode
查看当前值,也可以通过set follow-fork mode
来设置是当一个进程fork
出新的子进程时,GDB
是继续调试父进程还是子进程(取值是child
),默认是父进程( 取值是parent
)。
(gdb) show follow-fork mode
Debugger response to a program call of fork or vfork is "parent".
(gdb) set follow-fork child
(gdb) show follow-fork mode
Debugger response to a program call of fork or vfork is "child".
(gdb)