一、 Linux命令行运行
gdb -q 进入gdb,不打印版本信息
gdb <program> 直接装载程序,但没有运行
gdb <program> <core_file> 该core文件是该program非法执行后dump出的
gdb -d <directory> 加入一个源程序搜索路径
二、 挂接正在运行的程序
gdb
gdb attach
detach 取消挂接
三、 gdb中运行的常用命令
help 查看帮助信息
file 进入gdb之后再装载程序
set 可指定运行参数,类似于 run 但没有立即run
show args 查看设置好的运行参数
next 或 n 不进入函数,仅把函数调用当成一条语句执行
step 或 s 进入函数
nexti 或 stepi 执行一条机器指令
finish 运行程序,直到当前函数完成返回;并打印函数返回时的堆栈地址和返回值及参数值等信息。
until 或 u 当不想在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
shell <shell_command> 即可运行shell命令
set environment = 设置环境变量
show environment
show environment
unset environment
四、 查看源代码
list - 显示当前行前面的源程序。
set listsize 设置一次显示源代码的行数。
show listsize 查看当前listsize的设置。
directory <dirname … > = dir <dirname … > 指定源文件的路径
加一个源文件路径到当前路径的前面。如果你要指定多个路径,UNIX下你可以使用“:”,Windows下你可以使用“;”。
directory 清除所有的自定义的源文件搜索路径信息。
show directories 显示定义了的源文件搜索路径。
五、 暂停方式
断点(BreakPoint)
观察点(WatchPoint)
捕捉点(CatchPoint)
信号(Signals)
线程停止(Thread Stops)。
- 断点
info breakpoints
break
break
break <line/function> if
clear 删除所有断点
clear
clear
delete 删除该断点编号的断点
disable 暂时失效
enable 再次使能 - watch(观察点)
info watchpoints
watch 为表达式或变量设置一个观察点,一旦表达式值有变化时,停住程序
rwatch 当表达式或变量被读时,停住程序
awatch 当表达式或变量被读或被写时,停住程序 - 捕捉点(CatchPoint)
可设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常。设置捕捉点的格式为:
catch
当event发生时,停住程序。event可以是下面的内容:
throw 一个C++抛出的异常。(throw为关键字)
catch 一个C++捕捉到的异常。(catch为关键字)
六、 查看栈信息
bt = backtrace
bt n是一个正整数,表示只打印栈顶上n层的栈信息。
bt <-n> -n表一个负整数,表示只打印栈底下n层的栈信息。
七、 gdb变量
可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。要定义一个gdb的变量,只需使用GDB的set命令。
GDB的环境变量和UNIX一样,也是以$起头。如:
set $foo = *object_ptr
使用环境变量时,gdb会在你第一次使用时创建这个变量,而在以后的使用中,则直接对其賦值。环境变量没有类型,你可以给环境变量定义任一的类型。包括结构体和数组。
show convenience 该命令查看当前所设置的所有的环境变量。
环境变量和程序变量的交互使用,将使得程序调试更为灵活便捷。例如
set $i = 0
print bar[$i++]->contents
输入这样的命令后,只用敲回车,重复执行上一条语句,环境变量会自动累加,从而完成逐个输出的功能。
于是你就不必像下面这样输入命令了。
print bar[0]->contents
print bar[1]->contents
print bar[2]->contents
八、 信号
可以告诉gdb需要处理哪一种信号。可以要求gdb在收到指定的信号时,立即停住正在运行的程序,以供进行调试。可以用gdb的handle命令来完成这一功能。
handle <signal> <keywords...>
在gdb中定义一个信号处理。信号可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO,SIGIOT,SIGKILL三个信号),也可以使用关键字all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被gdb停住,以供调试。其可以是以下几种关键字的一个或多个。
nostop 当被调试的程序收到信号时,gdb不会停住程序的运行,但会打出消息告诉你收到这种信号。
stop 当被调试的程序收到信号时,gdb会停住你的程序。
print 当被调试的程序收到信号时,gdb会显示出一条信息。
noprint 当被调试的程序收到信号时,gdb不会告诉你收到信号的信息。
pass
noignore 当被调试的程序收到信号时,gdb不处理信号。这表示,gdb会把这个信号交给被调试程序会处理。
nopass
ignore 当被调试的程序收到信号时,gdb不会让被调试程序来处理这个信号。
info signals
info handle 查看有哪些信号在被gdb检测中。
九、 用gdb简单分析死锁
当发生死锁时,进程会僵住,这时只需要杀死进程,让系统产生一个 core dump 文件,然后再对这个 core dump 文件进行分析即可。
比如,系统生成了core dump 文件,放在了/var/crash目录下,此时就可以使用 gdb 进行分析:
gdb /var/crash/<core_dump_file>
然后再:
info threads
thread <tid>
bt
即能发现死锁的位置
十、 多线程调试
info thread 查看当前进程的线程。
thread 切换调试的线程为指定tid的线程。
break file.c:100 thread all 在file.c文件第100行处为所有经过这里的线程设置断点。
thread applay [thread-id-list]/[all] args 在指定的线程上执行特定的命令args.
set print thread-events 用于设定是否提示线程启动或停止时的信息。
set libthread-db-search-path
set scheduler-locking off|on|step
off 不锁定任何线程,也就是所有线程都执行,这是默认值。
on 只有当前被调试线程会执行。
step 阻止其他线程在当前线程单步调试时,抢占当前线程。
只有当next、continue、util以及finish的时候,其他线程才会获得重新运行的机会。
non-stop模式
针对“一个线程中断在一个断点上,其他所有的线程都会被freeze”的情况, gdb 7.0引入了non-stop模式,即:除了断点有关的线程会被停下来,其他线程会继续执行。
设置non-stop模式的方法:
运行gdb后,开始run之前,输入下面的指令
set target-async 1
set pagination off
set non-stop on
十一、 gdb调试多进程
follow-fork-mode
set follow-fork-mode parent|child
show follow-fork-mode
parent:fork之后继续调试父进程,子进程不受影响。
child:fork之后调试子进程,父进程不受影响。
inferior
gdb称任何执行中的进程为inferior
inferior :切换到指定的inferior
info inferiors:列出当前被gdb调试的每个inferior信息
detach inferior :detach指定的inferior,允许其正常运行
十二、 一个多线程的代码
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
void * thread_hello(void * arg)
{
while(1) {
sleep(2);
std::cout<< "Hello\n";
}
}
void * thread_world(void * arg)
{
while(1) {
sleep(2);
std::cout<< "World\n";
}
}
int main()
{
pthread_t pid_hello, pid_world;
int ret = 0;
ret = pthread_create(&pid_hello, NULL, thread_hello, NULL);
if (ret!=0) {cout<<"Failed to start thread_hello!\n"; return -1;}
ret = pthread_create(&pid_world, NULL, thread_world, NULL);
if (ret!=0) {cout<<"Failed to start thread_world!\n"; return -1;}
while(1) {
sleep(5);
cout << "In main thread\n";
}
pthread_join(pid_hello, NULL);
pthread_join(pid_world, NULL);
return 0;
}