一、gdb基础知识
1、gdb是Linux环境下的一种调试工具,使用时在源程序生成是加上-g选项。
2、开始使用:gdb binFile;退出使用:ctrl+d或quit。
3、调试过程中常用的命令有:
(1)list命令
list linenum 显示程序第linenum行周围的程序
list function 显示函数名为function的函数的源程序
list 显示当前行后面的源程序
list - 显示当前行前面的源程序
(2)run(r)运行命令
run args run命令可以直接接命令行参数值,也可以在执行run之前通过set args +参数值实现。
(3)break(b)打断点
b linenum 在某行打断点
b +offset/-offset 在当前行号的前面或后面offset停住
b filename:linenum 在某文件的某行打断点
b filename:function 在某文件某个函数入口停住
b *address 在程序的运行地址处停住
b 没有参数再下一句停住
b where if cindition 在某个条件满足时,在某行停止
关闭断点:delete(d)bresakpoint-id
(4)单步命令
step count 一次性执行count步,如果有函数hiu进入函数
next count 一次性执行count,不进入函数
finish 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值以及参数信息
until 退出循环体
(5)continue命令
当程序被停住之后,可以使用continue(c)命令,恢复程序的运行知道程序结束或到达下一个断点。这里要注意如果没有断点程序是会直接结束的
(6)print(p)命令
这个命令比较常用,用来查看我们想看的内容。比如有关数组可以看全部,也可以从左到右某一部分:
print命令针对变量查看的输出格式有:
x 按十六进制格式显示变量
d 按十进制格式显示变量
u 按十六进制格式显示无符号整型
o 按八进制格式显示变量
t 按二进制格式显示变量
a 按字符格式显示变量
......
(7)watch命令
watch expr 为表达式expr设置一个观察点,一旦表达式值有变化,马上停住程序
rwatch expr 当表达式expr被读时。停住程序
awatch expr 当表达式的值被读或被写时,程序停住
info watchpoints 列出所有观察点(info指令通常可以去套)
(8)examine命令
x/u addr 查看内存中的值,“x/”后的n、f、u都是可选项
(9)jump命令
jump命令不会改变程序栈的内容,一般只在同一函数内跳转
jump linespec 指定下一跳语句的运行点,linespec可以是linenum,filename+linenum,+offset这几种形式
jump address 跳到代码行的地址
(10)ignal命令
使用signal信号名(如SIGINT)这种方式把信号发送给程序,如果程序注册了signal_handler函数,还可以进行相应的处理,帮助调试程序
(11)set命令
set args 设置命令行参数
set env environmentVarname=value设置环境变量。
(12)call命令
call function 强调调用某函数
强调调用某函数,它会显示函数返回值(如果函数返回值不是void)。print命令也可以完成该功能。
(13)disassemble命令
反汇编命令,查看执行时源代码的机器码
二、使用gdb调试多进程
1、代码调试:
2、gdb可以同时调试多个程序。
只需设置follow-fork-mode(默认值:parent)和detach-on-fork(默认值:on)即可。
parent on 只调试主进程(gdb默认)
child on 只调试子进程
parent off 同时调试两个进程,gdb和主程序,子进程block在fork位置
child off 同时调试两个进程,gdb和子进程,主进程block在fork位置
3、进入gdb调试模式
4、查看系统默认的follow-fork-mode和detach-on-fork
5、设置follow-fork-mode和detach-on-fork
6、用list命令查看源代码(按enter翻页),分别在子进程和父进程相应位置下断点
7、打断点
8、查看正在调试的进程:
显示gdb调试的所有inferior,gdb会为它们分配id。其中带有*得进程是正在调试的inferior。(gdb将每一个被调试程序的执行记录在一个名为inferior的结构中。一般情况下一个inferior对应一个进程,每个不同inferior有不同的地址空间。inferior有时候会在进程没有启动的时候就存在。)
9、切换调试的进程:inferior<infer number>
10、其他
(1)remove-inferior infno
删除一个infno号的inferior。如果inferior正在运行则不能删除,所以删除前需要先kill或者detach这个inferior。
(2)clone-inferior[-copies n] [infno]
复制n个编号是infno号的inferior。如果指不定n的话,就只复制一个inferior。如果不指定infno,则就复制正在调试的inferior。
(3)detach inferior
detach掉编号是infno的inferior。注意这个inferior还存在,可以再次用run命令执行它。
(4)kill inferior infno:
kill掉infno号inferior。注意这个inferior任然存在,可以再次用run等命令执行它。
(5)set schedule-multiple on|off
设为off:只有当前inferior会执行。
设为on:全部是执行状态inferior都会执行。
这个选项类似于多线程里的set。
(6)main info program-space
显示当前gdb一共管理多少地址空间
(7)set print inferior-events on|off
打开和关闭inferior状态的提示信息
show print inferior-events
查看print inferior-events设置的状态
(8)set follow-exec-mode new|same
设置same:当发生exec的时候,在执行exec的inferior上控制子进程。
设置为new:新建一个inferior给执行的子进程。而父进程的inferior任然保留,当前保留的inferior的程序状态是没有执行。
三、gdb调试多线程
1、调试代码
上面代码中主进程创建了3个子进程,他们是thread1,thread2和thread3,所以也就有3的线程。
2、使用gdb对多线程进行调试
gdb调试多线程的的常用命令:
(1)info threads 显示可以调试的所有线程
gdb会为每个线程分配一个id(和tid不同),编号一般从1开始。后面的id是指它的id。
(2)thread id 切换当前调试的线程·为指定id的线程
(3)break FileName.cpp:LineNum thread all:
所有线程都在文件FineName.cpp的第Linenum行有断点
(4)step:在step(单步)调试时,只有被调试的线程运行
(5)set non-stop on/off
当调试一个线程时,其它线程是否运行。
set pagination on/off
在使用backtrack时,在分页时是否停止
set target-async on/off:
同步和异步。同步,gdb在输出提示符之前等待程序报告一些线程已经终止的信息。而异步的则直接返回
show scheduler-locking
查看当前锁定线程的模式