一、gdb简介
GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。 对于一名Linux下工作的c/c++程序员,gdb是必不可少的工具。
二、gdb基本命令使用
查看断点
info break [n] – n断点号 简写:i b
设置断点
break filename:linenum 在源文件filename的linenum行处停住。
break 在进入指定函数时停住
break … if …可以是上述的参数,condition表示条件,在条件成立时停住。比如在文件thread.c中,可以设置break if sum == 4,表示当sum为4时停住程序。
例如:
gdb)b thread.c:64 if sum == 4
删除禁用断点
delete 删除所有断点 简写:d
delete breakpoint [n] 删除某个断点
disable breakpoint [n] 禁用某个断点
enable breakpoint [n] 使能某个断点
恢复程序运行和单步调试
continue 继续运行程序直到下一个断点 简写:c
next 逐过程步进,不会进入子函数 简写:n
setp 逐语句步进,会进入子函数 简写:s
until 运行至当前语句块结束 简写:u
finish 运行至函数结束并跳出,并打印函数的返回值
变量的调试
打印变量值的格式:
print(可简写为p)打印变量内容
p temp;默认十进制打印
p /x temp;按十六进制打印
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
打印基本类型,结构体、数组等
(1)打印基本类型,结构体、数组等,则 直接p 变量,即可把对应变量的值(包括其成员)全部打印出来
(2)如果变量是指针变量,要打印内容,需要p *变量,如果海思p 变量,则只会打印对应的地址。
(3)除了可以打印全部内容,也可以打印成员变量,包括结构体的成员,数组元素等。只需p 变量成员。
设置变量
set var 变量=xxx
打印全局变量与局部变量
如果你的局部变量和全局变量发生冲突(重名),一般情况下是局部变量会隐藏全局变量,如果一个全局变量和一个函数中的局部变量同名时,如果当前停止点在函数中,用print显示出的变量的值会是函数中的局部变量的值。如果此时你想查看全局变量的值时,你可以使用“::”操作符:
file::variable
function::variable
可以通过这种形式指定你所想查看的变量,是哪个文件中的或是哪个函数中的。例如,查看文件thread.c中的全局变量x的值:
gdb) p ‘thread.c’::sum --文件要加上单引号 查看文件的全局变量sum
gdb) p sdd::sum --查看函数sdd的局部变量sum
观察点(WatchPoint):
在变量读、写或变化时中断,这类方式常用来定位bug。
watch 变量 变量发生变化时中断
rwatch 变量 变量被读时中断
awatch 变量 变量值被读或被写时中断
使用步骤如下:
- 使用break在要观察的变量所在处设置断电;
- 使用run执行,直到断点;
- 使用watch设置观察点;
- 使用continue观察设置的观察点是否有变化。
调试方式运行程序
(1)调试启动无参程序
gdb 可执行文件
gdb thread
(2)调试启动带参程序
gdb 可执行文件
set args 参数
run运行
gdb thread
gdb)set args a b c
gdb)r
注:show args 命令可以查看设置好的运行参数。
(3)在线调试程序
gdb attach 进程ID
注:如果程序已经在运行,需要使用gdb attach 进程ID,在线调试,不会再开进程。如果程序还没运行,使用gdb 可执行文件,则会启动进程。
三、gdb应用例子
(1)线程卡死问题
在Linux上,执行有多线程的程序时,可能因为各种原因而导致卡死,比如死锁现象,很难快速定位问题,借助gdb attach在线调试即可排查程序卡死问题(死锁问题)。
多线程调试命令:
- bt:查看函数调用栈的所有信息,当程序执行异常时,可通过此命令查看程序的调用过程;
- info threads:显示当前进程中的线程;
- thread id:切换到具体的线程id,一般切换到具体的线程后再执行bt等操作。
排查步骤:
1、info threads 查看有哪些线程
2、thread id 切换到可疑线程
3、 bt 查看函数调用栈的所有信息,即可定位死锁问题。
gdb测试例程:
#include <pthread.h>
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
int sum = 9;
typedef struct student
{
char name[24];
int age;
int six;
}stu;
pthread_mutex_t info_mutex;
void *myroutinue(void *arg)
{
//stu student;
//student = *(stu *)arg;
stu *student = arg;
int a;
printf("pthread_self( ) = %x\n",pthread_self( ));
prctl(PR_SET_NAME,"Thread_snmp",0,0,0);
pthread_detach(pthread_self( ));
while(1)
{
int mun=0;
pthread_mutex_lock(&info_mutex);
mun++;
//pthread_mutex_unlock(&info_mutex);
printf("student.name = %s\n",student->name);
printf("student.age = %d\n",student->age);
printf("student.six = %d\n",student->six);
printf("mun1 = %d\n",mun);
sleep(2);
}
}
int sdd()
{
int a=4;
a+=5;
int sum =8;
return a;
}
int main(char argc,char **argv)
{
int mun=0,i,n;
for(n=0;n<argc;n++)
{
printf("argv[%d] = %s\n",n,argv[n]);
}
int sum = 0;
pthread_t tid;
stu *student;
int va = 6;
int stud[12] = {8,8,3,4,5,6,7,3};
stu stu1;
stu1.age = 17;
stu1.six = 165;
pthread_mutex_init(&info_mutex, NULL);
void *p = (void*)malloc(sizeof(stu));
student = (stu *)p;
strcpy(student->name,"chenjiaguang");
student->age = 16;
student->six = 43;
pthread_create(&tid , NULL , myroutinue , p);
printf("tid = %x",tid);
pthread_mutex_lock(&info_mutex);
mun++;
pthread_mutex_unlock(&info_mutex);
sdd();
for(i=0;i<10;i++)
{
sum++;
}
while(1)
{
mun++;
printf("mun = %d\n",mun);
sleep(2);
}
return 0;
}
测试效果:
运行gdb attach ip
(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7f7231ac4700 (LWP 104014) "thread" 0x00007f72313a030d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
2 Thread 0x7f72312d3700 (LWP 104015) "Thread_snmp" __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
(gdb) thread 2
[Switching to thread 2 (Thread 0x7f72312d3700 (LWP 104015))]
#0 __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
135 ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: 没有那个文件或目录.
(gdb) bt
#0 __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1 0x00007f72316a7dbd in __GI___pthread_mutex_lock (mutex=0x6020c0 <info_mutex>) at ../nptl/pthread_mutex_lock.c:80
#2 0x0000000000400923 in myroutinue (arg=0x12e1420) at thread.c:27
#3 0x00007f72316a56ba in start_thread (arg=0x7f72312d3700) at pthread_create.c:333
#4 0x00007f72313db41d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
从上面可以看出,是在pthread_mutex_lock死锁,只有锁,没有解锁,从而导致死锁。