对于源码分析的环境是:window下可以利用Source insight进行代码框架性的了解:如可以快速查看函数的定义或者应用等,它的可视化提供了很强大的功能。在linux下使用Source Navigator也可以达到可实现效果。如果是比较细的调试还是使用gcc 它可以利用tui方式或者DDD方式来补助。
错误类型:1.死循环 ------Ctrl+C 然后list可以找到死循环的位置
2.异常中断 -----可以通过转储核心来进行调试3.第三种就是和预想不合结果: 断点的方法和下面讲的主要方法:
段错误 :一般是越界,访问非法内存空间
信号处理---- 》转储核心
gdb namefile.o -tui方式;ctrl+X+A进行gbd tui切换; Ctrl+p Ctrl+N 来实现gdb代码记忆回滚
. TUI模式下有4个窗口,
(cmd)command 命令窗口. 可以键入调试命令
(src)source 源代码窗口. 显示当前行,断点等信息
(asm)assembly 汇编代码窗口
(reg)register 寄存器窗口
layout
用以修改窗口布局
help layout
layout src
layout asm
layout split
可以实现想正常term下的左右上下移动:
我们可以通过focus命令来调整焦点位置,默认情况下是在src窗口,通过focus next命令, 焦点就移到cmd窗口了,这时候就可以像以前一样,通过方向键来切换到上一条命令和下一条命令。
help focus
focus cmd
focus src
break 30 if num_y==1 或者 condition 1 num_y==1
临时断点:
tbreak
如果要重用老的命令行参数 直接用run来运行。(一般调试的时候开3个终端,一个gdb(一般不关),一个用来vim ,一个用来编译)
run 命令后面加命令行参数;
显示当前的代码:
list
info break的到断点信息 delete 断点序号(如3等)
break num行号
break path/file.c:num
break function
clear除下一个断点
clear foo
断点的可用性设置(不想删除自是暂时设置其属性)
enable disable
设置一次性属性
(enable once breakpoint-list)
下一步
n 有交互性,即是可以看到输入输出
s(真正的下一行代码指令)它不会有交互性
finish恢复执行到函数返回后;
until 能跳出循环然后执行下一步;
使用gdb调试程序的时候,有时候需要设定多个断点,重复执行某些操作,而这些操作写起来比较麻烦,这个时候就应该想起来用gdb命令脚本了,它能够很好的完成这些工作。
以设置多个断点为例,我写的命令脚本为
---------------------------------------------------
#filename: .gdbinit
#gdb will read it when starting
file test_gdbscript
set args hello
b main
b foo
r
---------------------------------------------------
有两种方式来使用这个脚本:
1)启动gdb时候
gdb在启动的时候,会在当前目录下查找".gdbinit"这个文件,并把它的内容作为gdb命令进行解释,所以如果我把脚本命名为".gdbinit",这样在启动的时候就会处理这些命令。
2)gdb运行期间
可以使用 source script-file 来解释gdb命令脚本script-file
断点命令列表:(多次同一个断点要求做一样事情的时候,可以利用断点命令列表来方便查看调试)
commands breakpoint-num
commands
end
如:
break foo (它的标示符是1)
silent ------不用标记断点时候的代码信息
printf "foo was pass %d",n ------ commands
continue ------- 下一个继续下一步
end
创建宏来方便其他程序和其他代码中方便利用做同样类型的实现
define print_info
printf $arg0,$arg1
continue
end
断点命令列表作为一个宏的形式来调用
commands 1
silent
print_info "foo was pass %d\n" n
end
watch i>4 监视点的设立,当i变化到》4的时候那么就停下来,
watch j 当j变化的时候就停下来
由于watch是有作用域的所以它要先定义后才能生效,超出作用域将自动取消
显示和检查变量:
1.print 如果是在输出数值的时候只想输出一部分那么可以这样用:
p *array@len
@的左边是数组的首地址的值,也就是变量array所指向的内容,右边则是数据的长度,其保存在变量len中,其输出结果,大约是下面这个样子的:
(gdb) p *array@len
$1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}
3.还可以利用commands对于没次到断点时都执行它的command内容,这部分在断点命令列表中有讲
如:b 37
commands 1
p temp->val
if(temp->left!=0)
p tmp->left->val
else
printf "%s\n" "none"
end
if
....
else
end
end
4.利用commands中call 要执行的函数
commands 2
printf "......you data......"
call printdata(root)
end
C++中引用gdb(gdb主要是用在C中,C++一般都在集成环境中进行调试如:QT,vC++)
p *node::root ----------root是node类中的Static指针类型
ptype node --------可以看到node的类型;
gdb对于多线程程序:
follow-fork-mode 对于父进程fork子进程,它可以控制是对父进程 还是对子进程进行调试;
set follow-fork-mode child|parent
parent:继续调试父进程,子进程不受影响
child:调试子进程,父进程不受影响
它可以配合detach-on-fork来完成
Set detach-on-fork [on|off]
默认下detach-on-fork为on,所以默认条件下不是调试的进程不受影响。
如果设置为off那么不被调试的进程会被suspended阻塞起来。
如果对于有很多代的进程,即是有父-子-孙….这样就不能用上面的进行调试了,
可以利用attach进行进程调试:(detach用来分离调试)
(ps –ef|grep process_name找到该进程,然后通过pstree –H process_id来查看它们的关系)
启动用gdb,attach该进程:但是现在有一个问题那就是attach的进程不可控,它已经在运行了。
解决方法:1.可以通过设置特殊条件来实现:
1. 在编译运行程序的时候加一个条件,让子程序是在睡眠,而不是运行
2. 当gdb进去之后设置了断点,我们把使其条件满足,然后才开始运行
3.至于这段代码所采用的条件,看你的偏好了。比如我们可以检查一个指定的环境变量的值,或者检查一个特定的文件存不存在。以文件为例,其形式可以如下:
void debug_wait(char *tag_file)
{
while(1)
{
if (tag_file存在)
睡眠一段时间;
else
break;
}
}
把这段代码加在子开始的地方就行了。这可以通过删除文件来进行条件的满足!
如果已经确定了自己要调试的文件代码;那么还可以用下面方法来进行:
Gdb wrapper
这这种方法可以不用设置条件,只是要编辑一个文件就行了。
1. 很多时候父进程fork后是,子进程会调用exec族函数执行新代码。那么我们可以把exec调的文件编成一个文件shell文件里面的内容是:
#!/bin/sh
Xterm –e gdb execwantto.binary(即是exec要进行执行的代码二进制文件)
Xterm –e 是为了有中断可以进行gdb交互控制;
如果程序在exec的时候还传人了参数可以改成这样:
xterm -e gdb --args execwantto.binary$@
这个方法首先要我们找到exec要执行的二进制文件execwantto.binary。
如果是远程要利用VNC进行远程调试。
Info inferiors可以查看现在调试中的进程,有*的表示正在attch的进程!
Inferior <infer number>可以进行切换
Detach inferior infer_number 和 detach process_ip等价
多线程:
咨询线程: infothreads
切换调试进程:thread<thread number>
多线程,多进程调试例子请看:http://blog.csdn.net/pbymw8iwm/article/details/7876797
3). 设置捕捉点(CatchPoint)
设置捕捉点来捕捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常。设置捕捉点的格式如下:
Catch
如:catch exec
Catch fork
当event发生时,停住程序。event可以是下面的内容:
1、throw 一个C++抛出的异常。(throw为关键字)
2、catch 一个C++捕捉到的异常。(catch为关键字)
3、exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用)
4、fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用)
5、vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用)
6、load 或 load 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)
7、unload 或 unload 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)