利用GDB对程序进行调试
第一章初涉调试会话
调试工具
- GDB,Unix下最常用的调试工具
- DDD,基于GUI的调试器,大多数工具都是GDB的GUI前端。
- Eclipse,IDE也是一种调试工具
atoi( )把字符串变为整数,头文件是include<stdlib.h>
gcc -g -Wall -o insert_sort ins.c
-g选项可以让编译器将符号表(对应于程序的变量和代码行的内存地址列表)保存在生成的可执行文件里中。
这样才能在调试会话的过程中引用源代码中的变量和行号,比如“在第30行停止”或者“输出x的值”。
gdb insert_sort -tui可以在调试的时候显示源代码
可以用Ctrl+X+A来打开或者关闭源代码的窗口
run + 参数运行程序
Ctrl+C可以停止程序,开程序结束在那一行
然后continue,再看看程序结束在那一行
$1是GDB输出的第一个值,$2、$3等表示的值统称为调试会话的值历史。
break 30 if num_y==1,设置条件断点
clear命令用来删除断点
clear 30
info break用来查找设置的端点
先设断点,再来为断点添加条件
break 36
cond 3 new_y==19
next和step都是单步调试,如果没有在函数中设置断点,next不会进入到函数中,而step会进入到函数中
第二章停下来环顾程序
gdb符号调试器,可以暂停程序的执行,暂停以后,调试器提供了变量检查、跟踪执行路径等机会。
暂停机制
断点: breakpoint
监视点: hw watchpoint
捕获点: catch fork
一开始这三个都被称为断点
GDB中关于位置的含义非常灵活,它可以指各种源代码、代码地址、源代码文件中的行号或者函数的入口等。
GDB断点停止的那一行并不是最后执行的代码,而是将要执行的下一行的代码。
GDB工作针对的是机器语言指令,然而可以使用源代码行,是因为可执行文件包含了额外的信息。
跟踪断点
创建断点时GDB会告知你分配给该断点的编号。
info breakpoints可以查看断点
delete 1 3 4
可以删除断点1,监视点3及捕获点4
设置断点
break function,在函数function的入口,第一行可执行代码处设置断点
break line_number,在当前活动源代码文件的line_number处设置断点
break filename:line_number,如果filename不在当前工作目录中,则可以给出相对路径名
tbreak foo.c:10,这个设置的是临时断点
GDB设置的断点位置可能与请求将断点放置位置不同。
在调试完成之前永远不应当优化代码。
如果同一行源代码有多个断点时,只会有一个断点触发中断,而且出发中断的点将是标识符编号最小的点。
(gdb) break swapper.c:1
(gdb) break swapper.c:swap
(gdb) break swap
这三个做的都是同一件事,就是在swap( )的上方设置中断。
在任何给定的时间,GDB都有一个焦点,可以将它看作当前活动的文件。
除非对命令做了限定,否则都是在具有GDB的焦点的文件上执行命令。
转移焦点的方法:
对不同的源文件使用list命令
进入位于不同的源代码文件中的代码
当在不同的源代码文件中执行代码时遇到GDB断点
断点的持久性
在调试会话期间不应该退出GDB。例如,当发现并修复了一个程序的错误,但是其他程序错误仍然存在时,
不应当退出GDB然后重新进来使用程序的新版本。
这样做有些繁琐,而且还得重新设置断点。
如果在修改和重新编译代码时没有退出GDB,那么在下次执行GDB的run命令时,GDB会感知到代码已经被修改,并自动重新加载新版本。
断点是会移动的,如果断点设置的是在某一行停留,但是对代码修改后会造成原来断点这一行的代码不一样,但是断点仍是停留在这一行。
删除和禁用断点
delete breakpoint_list
delete: 删除所有断点
clear: 清除GDB将执行的下一个指令处的断点。
GDB中禁用断点
disable 3
enable 1 5
enable once breakpoint-list
在断点下次引起GDB暂停执行后被禁用,就是执行完这一次后就被禁用了,和tbreak有点像,但是tbreak是用完一次就删除。
浏览断点属性
每个断点都有属性,比如行号、加在断点上的条件(如果有的话)
创建的每个断点都被赋予唯一的整数标识符
info breakpoints
Num 标识符
Type 这个断点是断点、监视点还是捕获点
Disp 这个断点在在引起程序暂停后会发生什么
Enb 启用状态,这个断点当前是启用还是禁用
Address 在内存中设置断电的位置
What 显示断点所在的行号和文件名称
恢复执行
continue
next 单步调试,执行函数,但是不会在函数中暂停,而是在调用之后的第一条语句暂停,永远不会离开main,单步越过函数
step 单步调试,在函数中的第一个语句处暂停,单步进入函数
单步调试源代码是遇到函数调用,一般使用next比step好,在这种情况下使用next之后,立即要检查调用的结果是否正确
next可以节省调试每一行的精力和时间。
next和step后面可以接数字
continue 接数字代表忽略下面的几个断点
finish 简写fin,指示GDB恢复执行,直到恰好在当前栈帧完成之后为止。
也就是说如果你不是在main( )中,finish命令会导致GDB恢复执行,直到恰好在函数返回为止。
但是如果之间有断点,finish都会在断点处暂停。
finish不会进一步咱函数中暂停(除非有断点在里面)。
until命令,简写为u,通常不会进一步在循环中暂停,除了循环中间的断点。
until执行程序,直到到达当前循环体外的下一行源代码。
until命令也可以接受源代码中的位置作为参数
条件断点
有时候需要告诉调试器,只有当符合条件是才在断点处停止。
break break-args if (condition)
例如:
break test.c:myfun if ! check_variable_sanity(i)
break 44 if strlen(mystring)==0
可以对正常断点设置条件以将它们转变为条件断点。
比如设置了断点3作为无条件断点,但是系在系统加入条件3,只要键入:
(gdb) cond 3 i==3
如果以后要删除条件,但是要保持该断点,只要键入
(gdb) cond 3
断点命令列表
当GDB遇到断点时,几乎总是要查看变量,如果反复遇到同一断点,将反复查看相同的便两个,让GDB在每次达到某个断点时自动执行一组命令,从而自动完成这一过程
使用commands命令设置命令列表
commands breakpoint-number
...
commands
...
end
如果感觉系统给的提示太多了,可以使用silent命令,它必须是命令列表里面的第一个命令,是GDB安静地出发断点。
如果命令列表最后一个命令式continue,GDB将在完成命令列表的命令后继续自动执行程序
在GDB中还可以使用define命令创建宏。
show user可以得到所有宏的列表
GDB命令与表达式很丰富,可以使用自定义的函数,只要它们被链接到执行文件中即可
可以使用它们的返回值,只要它们的返回值类型为int。
监视点
监视点是一种特殊的断点,其特点在于不是在固定的某一行暂停,而是监视某个变量或表达式的值是否发生改变
如果改变了就会暂停
该表达式可以非常简单:
(gdb) watch i
没当改变i的值时就会暂停,表达式也可以非常复杂
(gdb) watch ( i | j > 12) && i > 24 && strlen(name) > 6
断点与源代码的一个位置关联,但是c语言有严格的作用域规则,所以只能监视存在且在作用域内的变量,一旦变量不再存在与调用栈的任何帧当中,
GDB会自动的删除监视点。
设置监视点:
当var存在且在作用域中时,
watch var
这个命令会导致每次var改变值时GDB都中断,监视点简单方便
GDB实际上是在var的内存位置改变值时中断,一般情况下,是否使用监视点监视变量或变量的地址并没有关系
但是在处理指向指针的指针时很重要。
硬件监视点
虚拟内存监视点
软件自身监视点
表达式
GDB中的表达式包含很多内容:
GDB方便变量
程序中的任何在作用域内的变量
任何种类的字符串、数值或字符常量
预处理器宏
条件、函数调用、类型强制转换和所用语言定义的运算符
第三章 检查和设置变量
仅仅用print来显示变量的值有些过于简单了
变量的高级检查和设置
如果用print来打印结构体:
(gdb) p tmp->val
(gdb) p tmp->left
(gdb) p tmp->right
左指针的实际值,即实际内存地址,但是指针是非0或0这一实时很重要。
输出完整结构
(gdb) p *tmp
由于tmp指向该结构,因此*tmp是这个结构本身
display则要求每次暂停时就输出指定条目,比如:
(gdb) dispay *tmp
使用GDB的commands命令
如果希望在给定节点上查看子节点的值:
(gdb) commands 1
> p tmp->val
> if (tmp->left != 0)
> p tmp->left->val
> else
> printf "%s\n", "none"
> end
> if ( tmp->right != 0)
> p tmp->right->val
> else
> printf "%s\n" "none"
> end
> end
printf( )命令也很强大,跟C里面对应的命令类似
使用call命令
GDB里面也可以用call来调用源代码里面的函数
(gdb) cmmands 2
> printf "*********** current tree ************"
> call printtree(root)
> end
此外可以动态修改断点的命令集,或者简单地通过定义一个空集合来取消该命令。
GDB中打印动态数组
对于静态数组,GDB可以用:
print x
来打印整个数组,但是对用malloc或者new创建的动态数组,则只会打印地址,
print *x也只会打印数组的第一的元素
p *pointer@number_of_elements
p (int [25]) *x
类型强制转换
监视局部变量
info locals命令可以得到当前栈帧中所有局部变量的值列表
直接检查内存
执行显示格式
(gdb) p/x y
临时禁用某个显示项
(gdb) dis disp 1
显示项可以用info disp查看
重新启用则可以用:
(gdb) enable disp 1
要完全删除显示的条目,可以用undisplay,
(gdb) undisp 1
设置变量值
set x=12
会将x的当前值改成12
可以通过set args设置程序的命令行参数
(gdb) set args 1 52 19 11
并不会立即将argv[1]改成1,argv[2]改成52,而是在下次run的时候生效
检查当前函数参数的命令:
info args
GDB自己的变量
使用历史值,比如$1,$2等
print *$
这是一个特殊的历史变量
方便变量
假设有个指针变量p,在不同的时候表示链表中不同的节点,可能在调试的时候希望记录特定的节点的历史
(gdb) set $q=p
(gdb) p *$q
这里的变量$q称为方便变量
待续......
第4章 程序崩溃处理
第5章 多活动上下文中的调试
第6章 特殊主题
第7章 其他工具
利用GDB对程序进行调试的更多相关文章
- 3、利用GDB进行程序调试
本文将用一个实际例子讲解如何通过GDB进行程序调试. 首先,我们需要理解的是GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,其产生和调试的目的是让调试者知道,程序在执行时内部发生了什么 ...
- 学习4412开发板gdb和gdbserver的调试
因为有很多的小伙伴是从单片机转过来的,用惯了单片机上的JLINK调试程序,换到Linux上非常的不习惯.确实,如果能设置断点,单步调试,查看变量,那确实是太爽了,那么在我们的Linux可以做到吗,答案 ...
- 20145311利用gdb调试汇编代码
利用GDB调试汇编代码 首先编写c语言原代码,我使用的是同学分析过的代码 #include<stdio.h>short addend1 = 1;static int addend2 = 2 ...
- 利用GDB在远程开发机进行调试
由于一些环境的制约,很多同学都可能需要在开发机上进行调试,但由于开发机资源的限制,在开发机上直接进行本地的GDB环境配置就成了难题,这个时候其实我们可以利用GDB中自带的gdbserver工具就可以进 ...
- 利用GDB进行多线程调试
一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 ...
- 利用QEMU+GDB搭建Linux内核调试环境
前言 对用户态进程,利用gdb调试代码是很方便的手段.而对于内核态的问题,可以利用crash等工具基于coredump文件进行调试. 其实我们也可以利用一些手段对Linux内核代码进行gdb调试,qe ...
- C++雾中风景番外篇3:GDB与Valgrind ,调试代码内存的工具
写 C++的同学想必有太多和内存打交道的血泪经验了,常常被 C++的内存问题搅的焦头烂额.(写 core 的经验了)有很多同学一见到 core 就两眼一抹黑,不知所措了.笔者 入"坑&quo ...
- 调试多线程 & 查死锁的bug & gcore命令 & gdb对多线程的调试 & gcore & pstack & 调试常用命令
gdb thread apply all bt 如果你发现有那么几个栈停在 pthread_wait 或者类似调用上,大致就可以得出结论:就是它们几个儿女情长,耽误了整个进程. 注意gdb的版本要高于 ...
- MATLAB调用C程序、调试和LDPC译码
MATLAB是一个很好用的工具.利用MATLAB脚本进行科学计算也特别方便快捷.但是代码存在较多循环时,MATLAB运行速度极慢.如果不想放弃MATLAB中大量方便使用的库,又希望代码能迅速快捷的运行 ...
随机推荐
- 如何在Win8中设置虚拟热点共享上网(转)
摘自:http://www.enet.com.cn/article/2013/0408/A20130408273749.shtml 在Windows 7中,我们可以通过网络与共享中心的“设置新的连接和 ...
- PHP API中,MYSQL与MYSQLI的持久连接区别
转载自:http://www.cnxct.com/some-differences-between-mysql-and-mysqli-of-persistent-connection/ 很久很久以前, ...
- eclipse 在Servers窗口创建一个Tomcat 6.0 Server失败
web项目部署到tomcat除了用eclipse插件,eclipse也有一个Servers窗口来部署. 问题背景:Servers窗口,我之前创建过一个Tomcat v6.0 Server,后来我把 ...
- 【java设计模式】之 代理(Proxy)模式
代理模式的核心作用就是通过代理,控制对对象的访问.这跟实际中是一样的,比如说明星都有经纪人,这就是一个代理,比如有人要找某明星拍戏,那么首先处理这事的是他的经纪人,虽然拍戏需要自己拍,但是拍戏前后的一 ...
- vsftp添加用户及测试
上一篇我们讲了vsftp安装以及配置,这篇我们讲下如何添加用户,然后我们测试一下,看看是否成功. 首先说下添加用户,如图执行命令即可: 这里简单解释一下:第一条命令是添加用户,第二条命令是设置用户密码 ...
- wap站、手机APP 接入支付宝、微信、银联支付。
一.wap站 ①.支付宝接入 1.开发前准备:申请一个通过实名认证的企业支付宝账号,并申请开通手机WAP支付功能. 2.流程 参数准备: 企业支付宝账号的PID(也叫ParnerID)和KEY,如果使 ...
- Oracle 11g的Deferred Segment Creation
本篇主要介绍Oracle 11g中推出的“延迟段创建”(Deferred Segment Creation)特性,以及当我们使用这种特性时,需要注意的问题. 1)Deferred Segment Cr ...
- Js操作Select大全(取值、设置选中等等)
jquery操作select(取值,设置选中) 每一次操作select的时候,总是要出来翻一下资料,不如自己总结一下,以后就翻这里了. 比如<select class="selecto ...
- jquery中 $ 和 jQuery 及 $() 的区别
用过jquery的人都知道,jquery有两种用法,一种是$,还有一种是jQuery,那么这两种方式在使用上有什么区别呢? 答案是这两种用法没什么区别,只是别名而已,用$要比jQuery简短一些.方便 ...
- Python学习笔记011——内置函数exec()
1 描述 把一个字符串当成语句执行 exec() 执行储存在字符串或文件中的 Python 语句,相比于 eval() , exec() 可以执行更复杂的 Python 代码. exec函数和ev ...