GDB学习笔记(一)

GDB学习笔记(一)

1、可以再调用GDB时在命令行上制定-tui(即"终端用户界面")
 或者在GDB中使用ctrl+X+A组合键进入TUI模式。ctrl+X+A也可以退出TUI界面
2、在TUI下通过↑和↓键来实现代码的查看,通过ctrl+P和ctrl+N来实现浏览以前的
 GDB命令。 在GDB中可以通过list指令来实现更改源代码窗口中显示的代码区
 域
3、单步调试,step指令会进入函数,next指令会执行该函数当前行的下一行。
4、恢复操作,continue命令通知调试器恢复执行并继续,知道遇到断点为止。
5、临时断点:tbreak有效期限为首次到达制定行为止。
6、检查变量:在GDB中使用print+变量名来输出变量的当前值
7、监视点:在程序执行期间,假设要在变量z改变值时查看程序的状态。可以执行
watch z
当运行程序时,每当z的值发生了变化,GDB就会暂停执行。也可以设置
基于条件表达式(z>29)的监视点:
watch (z > 29)
监视点的生命周期与这个变量的生命周期是一样的。
8、上下移动调用栈:在GDB中可以用¨frame 1¨指令查看前一个帧,当前正在执行的函
数帧被编号为0,其父帧被编号为1。GDB的up命令将你带到条用栈中的下一个父
帧,down则引向相反的方向。backtrace命令会显示整个栈。
9、联机帮助:在GDB中,可以通过help命令访问文档。help breakpoints.
程序的几种出错情况所对应的调试():
① 、无限循环:
情况的判定:程序一直没有输出结果(程序无法结束);
问题的锁定:通过不断的使用continue和ctrl+c让进程不断的运行-中断
-运行-中断,这个就可以看出程序一直都在那个循环中执行,之后改变
循环的条件就可以了。
② 、输出不正确结果:
③ 、段错误(Segmentation fault):当程序试图访问不允许访问的内存时,发生
了段错误。一般是由于数组索引超出了边界或者采用了错误的指针。
10、启动文件的使用:
在退出gdb之前,为了丢失在gdb中键入的指令,可以将断点和设置的其他命令放在
一个gdb启动文件中,然后每次启动gdb时会自动加载他们。gdb的启动文件默认名为
.gdbinit。
第一大主题:停下来环顾程序:
一、暂停机制:有三种方式可以通知GDB暂停程序的执行
① 、断点:在特定位置暂停执行;
② 、监视点:当特定内存位置的值变化时,暂停执行;
③ 、捕获点:当特定事件发生时暂停执行;
二、断点概述:break 30可以认为该指令让程序在源代码的第29行到第30行之间等

三、跟踪断点:每一个断点(断点、监视点、捕获点)都被标示为从1开始的唯一整
数标识符,这个标识符用来执行该断点上的各种操作。
① 、GDB中的断点列表info breakpoint(i b)
Num(整数标识符)Type(断点类型)Disp(断点类型暂时(del)还是永久(keep))
Enb(是否可用)Address(断点地址)What(其他信息,在那个函数的第几行)
四、设置断点:
① 、break
break function:在函数function()的入口出设置断点;
break line_number:在当前活动源代码文件的line_number行出设置断点;
break filename:line_bumber:在源代码文件filename的line_number出
设置断点,如果filename不在当前的文件中则可以给出相对或绝对路
径;
break filename:function:在文件filename中的function()函数的入口出设
置断点;
② 、break的生命周期:该断点的有效性会持续到被删除、禁用或者退出GDB。但
是使用临时断点tbreak时,它是首次到达后就会被自动删除的断点。临时断
点的使用参数与break的相同;
③ 、当GDB使用多个断点中断同一行代码时,他只会中断一次。即,当它到达该
行代码时,如果恢复执行,会忽略恰好在同一行上的其他断点。并且,GDB
中触发该行中断的断点的标示编号肯定是最小的断点;
五、断点设置的使用:
在任何给定的时间,GDB都有一个焦点,可以将他看成当前的¨活动¨文件。这意味
着除非命令做出了限制,否则都是在具有GDB的焦点的文件上执行命令。GDB的默
认焦点文件为main.c。但是当发生如下动作时,焦点会转移:
① 、向不同的源文件应用list命令;
② 、进入位于不同的源代码文件中的代码;
③ 、当在不同的源代码文件中执行代码时GDB遇到了断点;
六、删除和禁用断点:
删除断点:
① 、delete breakpoint_list:
删除断点使用数值标识符,如:delete 2:删除标示为2的断点,
delete 2 4删除标示为2 、4的断点;
delete:删除所有断点。
② 、clear:清除GDB将执行的下一个指令处的断点。
clear function ,
clear filename:function ,
clear line_number ,
clear filename:line_number:
这些命令根据位置清除断点。
禁用断点:
disable breakpoint-list:禁用断点,
enable breakpoint-list:启动断点;
七、断点属性:
(1)标识符(num):断点的唯一标识符;
(2)类型(Type):这个字段指出该断点是断点、监视点还是捕获点;
(3)部署(Disp):每个断点都有一个部署,指示断点下次引起GDB
暂停程序的执行后该断点上会发生什么事情,可能的部署有一下三
种:
1)、保持(keep),下次到达断点后不改变断点,这是断点默认
值;
2)、删除(del),下次到达断点后删除该断点,使用enable once
命令设置的断点属性;
3)、禁用(dis),下次到达断点时会禁用该断点。使用enable
once命令设置的断点
(4)启动状态(Enb):这个字段说明断点当前是启用还是禁用的;
(5)地址(Address):这是内存中设置断点的位置;
(6)位置(What):显示了断点所在位置的行号和文件名;对于监视点,这
个字段表示正在监视那个变量。
此外,info breakpoint命令也能指出特定断点引起GDB停止程序执行了
多少次。
八、恢复执行:
1)使用step和next¨单步¨调试程序;
next&step的区别和参数:next永远都不会离开main函数,每执行一次next
GDB就会执行一行main函数的代码,step在没有遇到函数调用时与next相同
,当遇到函数调用时,step会进入被调用的函数里面的第一行代码。如:
next 3(step 3)就是相当于执行了三次next(step)
2)使用continue使GDB无条件地恢复程序的执行,直到它遇到下一个断点或
者程序结束;
3)使用finish 或者until命令恢复:程序继续执行直到遇到某个预先确定的
条件,到达另一个断点或者程序结束。
4)until实际上做的时执行程序,直到它到达内存地址比当前内存地址更高
的机器指令,而不是直到到达源代码中一个更大的行号。until命令也可以
接受源代码中的为止作为参数,如:until 17运行到第17行,until swap:
运行到swap函数入口,until swapper.c:swap:运行到swapper.c的swap函
数的入口处。
九、条件断点:
设置条件断点的语法为:
break break-args if (condition)其中break-args是可以传递给break
以指定断点位置的任何参数。将已有的断点设置为条件断点:
cond break_point_num condition
删除条件保留断点:cond break-point-num
十、断点命令列表:
用途:让程序在指定的断点前执行预先设定的gdb指令;
用法: commads break-point-number //在break-point-number上使用
//断点命令列表
(silent) //通过把silent放在最前面可以使得gdb的输出更加
//整洁

commands //在该断点出执行commands指令

end //使用end结束执行
tmp->left = makenode(x);
tmp->left = makenode(x);
也可以通过上面的步骤重新定义该断点的命令列表。
一个可能会用到的实例:
commands break-point-number
(silent)

commands

continue
end
在gdb下使用宏定义:
一个可能用到的实例:
define print_and_go
printf $arg0 , $arg1
continue
end
一个可能用到的使用方式:
commands 1
silent
print_and_go “messege %d\n” n
end
需要注意的是print_and_go的两个参数之间没有逗号
可以使用show user显示宏定义列表
十一、监视点:指示GDB每当某个表达式改变了值就暂停执行的指令。
其表达式:watch args
监视点的声明周期:在args(变量)声明之后到变量弹出栈之前的监视
点声明才有效,之外的声明全为无效而自动删除。且,只能监视单线程
的变量。
第二大主题:检查和设置变量:
一、检查动态数组:
例如,x = (int )malloc(25sizeof(int));
x[3] = 12;
查看x的全部元素;
可以使用: p *x@25指令来打印x的所有元素。
其一般形式为:*pointer@number_of_elements
也可以使用强制类型变换:p (int [25]) *x
二、监视局部变量
通过info locals命令得到当前栈帧中所有局部变量的值列表。
三、直接检查内存
print和display命令允许指定可选的格式:p/x y(以16进制显示变量y),其他常
用的格式为c表示字符,s表示字符串,f表示浮点。可以临时禁用某个显示项:
dis disp display-number:临时禁用显示列表中的条目display-number
重新启用条目:enable disp display-number
完全删除显示的条目:undisp display-number
四、从GDB中设置变量
在GDB中设置程序中的变量:set x = 12(这会将x的当前值改成12)
通过GDB的set args命令设置程序的命令行参数。
GDB可以使用info args命令显示参数的信息
五、GDB自己的变量
① 、使用值历史:p $1(输出历史值 1 所 指 的 地 址 的 内 容 ) p ∗ 1所指的地址的内容) p * 1p(使用特殊历史变量$输出历史值)
② 、 方便变量:
第三大主题:程序崩溃处理:
生成核文件:
ulimit -c core_size:可以使用ulimit命令控制核心文件的创建。core_size表示生成
的核心文件最大不得超过core_sizeKB字节。
但是我在调试我的文件传输项目时却没能生成core文件,所有的操作都正确并且还
做了一个测试也正确的生成了core文件。可以在client端就是没有生成核文件。网
上猜测的原因是在生成core文件之前进程被系统强杀了。
如何调试核文件:
gdb core_product_file core:gdb后面的core_product_file是生成core文件的可执行
文件。进入之后通过backtrace来查看程序崩溃时发生在哪一行代码上。
使用frame backtrace_number可以将程序回退到backtrace_num那一行的代码上执行。
string_point = ´0´;与string_point = ‘\0’;不一样,后者的字符串长度比前者
少一个字符
第四大主题:多活动上下文中的调试:
调试客户、服务器网络程序时:
① 、在GDB中手工执行对connect的调用时,必须去掉这种
类型强制转换,如果保留了这样的类型强制转化,将会得到错误的信息。
② 、如果在GDB中进行了connect并且成功了,就不能在让程序在执行一遍connect了,
因为试图打开已经打开的套接字是一个错误。可以使用jump命令跳过该行,比如
connect 在第31行,则执行下一行代码:jump 32。
③ 、在shell界面上使用strace ./client IP-addr可以跟踪客户端程序做过的所有系
统调用
…待续…
第五大主题:特殊主题:
根本无法编译或加载:
语法错误消息中的¨幽灵¨行号。在编译出错时,指出的错误行号很可能是正确的
代码。在这个时候可以通过二分搜索法来查找错误。首先可以根据编译的错误提
示确定一个大体的范围,如: bintree.c: In function ‘insert’:这里是说
insert函数有问题。所以,我们可以将insert函数全部注释掉,之后再编译,如
果没有和刚才一样的错误就表示错误的确在insert函数里面。如果还有刚才的错
误则表示错误在insert之外。这就是二分搜索法的一次应用。以第一种情况为例
,利用二分法的思想将循环体内的代码注释掉,再次调试,如果没有出现刚才的
错误则表示错误在循环体内。就这样以此类推直到找到出错的一行。
缺少库:
动态库和静态库的使用。可以使用ldd命令检查程序需要哪个库,如果有,操作系
统可以何处找到他们。ldd a.out//这个指令是用来查看a.out需要哪个库。如果
有库没有搜索到,则可以向该搜索路径中添加所缺少库的路径,其指令为:
setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:path_to_lib
2、开源软件中库的用法:如果程序编译时找不某些必须的下载到的库使用上面的
设置环境变量也没有用。这问题往往在于配置文件调用的名为pkgconfig的程序,
pkgconfig搜索.pc文件(后缀为.pc,前缀是库的名称,例如文件libgcj.pc中包
含库文件libgcj.so
的位置)的默认目录取决于pkgconfig本身的位置。可以使用
指令:setenv PKG_CONFIG_PATH /usr/lib/pkgconfig:/usr/local/lib/pkgconfig
调试GUI程序:
…待续…
第六大主题:其他工具:
当光标在一个括号上时,键入百分号会将光标移动到配对的括号上。这个命令是
跟踪不对称括号的一个极佳方法;
语法突出显示模式中某些颜色难以阅读,可以通过如下代码关闭/打开突出显示:
synax off
synax on
这个指令是在vim的命令模式下执行的。
在vim 的命令模式下,执行指令:make可以实现在编辑器下编译文件,并能看到所
有的编译信息。再次按下Enter可以回到编辑器下编辑文件,但是,这时的光标会
位于产生第一条警告或错误的代码行上。
修复完当前的错误之后,在命令模式下输入cnext可以显示下一个错误或警告;
cprevious显示上一个错误或警告;cc电视当前错误或警告。
在使用gcc编译时,要养成添加参数-Wall的习惯,添加上-Wall参数不但可以检查
语法问题,还可以检查像if(a = b)这样的低级非语法错误。
C语言中的错误报告:
使用errno可以生成错误代码,通过错误代码可以查看具体的错误原因。但是,使
用errno的代码可能不是完全可移植的。errno不能告诉你发生了错误,只能告诉
你为什么发生某个错误。对errno的正确使用是:
1)执行对库或系统函数的调用;
2)使用函数的返回值判断是否发生了某个错误;
3)如果发生了某个错误,使用errno确定为什么发生这个错误;
另外,可以使用perror或者strerror将错误代码变为相应的错误信息。
更好地使用strace和ltrace:
strace显示的是系统调用的函数名;
strace的使用:strace ./a.out
其输出的结果的一般格式:
被调用系统函数名 (圆括号括起来的系统调用参数)=号后面的系统调用返回值
ltrace的使用:
ltrace显示的是调用的库函数;
静态代码检查器:lint与其衍生
splint的使用:
splint可以扫描代码,不编译代码,仅仅警告错误、可能的错误和严格的C语
言编码标准的差距;
使用:splint test.c
显示格式:splint警告的第一行指出发生警告的文件名和函数,下面一行提
供了警告的行号和位置。接着是警告的描述,以及关于如何抑制这种警告的
说明。
splint的一些很可能会用到的参数:
1) +weak,弱严格检查,最为常用;
2) +standard,默认模式;
3) +checks,中度严格检查;
4) +strict,高度严格检查;
其中+号表示将相应的参数功能打开,-号表示将相应的功能关闭。
与splint更为详细的使用:请参考这里
调试动态分配的内存(DAM):
…待续…

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值