设为首页 加入收藏

TOP

Linux环境下的C/C+基础调试技术2――程序控制(一)
2014-11-23 21:42:12 来源: 作者: 【 】 浏览:12
Tags:Linux 环境 C/C 基础 调试 技术 程序 控制

上节:html">Linux环境下的C/C++基础调试技术1――初步了解(2010.12.5更新)

Author:gnuhpc
WebSite:blog.csdn.net/gnuhpc

1.让程序停下来的三种模式

断点(breakpoint):让程序在特定的地点停止执行。
观察点(watchpoint):让程序在特定的内存地址(或者是一个涉及多个地址的表达式)的值发生变化时停止执行。注意,你不能给一个尚没有在栈帧中的表达式或变量设定观察点,换句话说,常常在程序停下来后才去设置观察点。在设定观察点后,栈帧中不存在所监控的变量时,观察点自动删除。
捕捉点(catchpoint):让程序在发生特定事件时停止执行。
注:

GDB文档中统称这三种程序暂停手段为breakpoint,例如在GDB的delete命令的帮助手册中就是这么描述的,它实际上指代的是这三种暂停手段,本文中以breakpoints统称三种模式,以中文进行分别称呼。
GDB执行程序到断点(成为断点被hit)时,它并没有执行断点指向的那一行,而是将要指向断点指向的那一行。
GDB是以机器指令为单位进行执行的,并非是以程序代码行来进行的,这个可能会带来一些困惑,下文有例子详述。
2.GDB breakpoints的查看

命令:i b = info breakpoints。返回列表每一列的含义如下:

Identi er :breakpoints的唯一标识。
Type :该breakpoints属于上述三种模式中的哪一个(breakpoint, watchpoint, catchpoint)
Disposition:该breakpoints下次被hit以后的状态(keep,del,dis分别对应保留、删除、不使能)
Enable Status:该breakpoints是否使能。
Address:该breakpoints物理地址。
Location :若属于断点则指的是断点在哪个文件的第几行,若是观察点则指的是被观察的变量
3.GDB 程序控制的设置

断点设置:
设置普通断点:break function/line_number/filename:line_number/filename:function. 该断点在被删除或不使能前一直有效。
设置临时断点:tbreak function/line_number/filename:line_number/filename:function. 该断点在被hit一次后自动删除。
设置一次性断点:enable once breakpoint-list,这个与临时断点的不同是该断点会在被hit一次后不使能,而不是删除。
设置正则表达式断点:rbreak regexp 注意该正则表达式是grep型的正则,不是perl或shell的正则语法。
设置条件断点:break break-args if (condition) ,例如break main if argc > 1。
这个与观察点不同的是,观察点只要所观察的表达式或变量的值有变化程序就停下,而条件断点必须满足所指条件。条件断点在调试循环的时候非常有用,例如break if (i == 70000) 。
在已经添加的断点上加上条件使用cond id condition,例如:cond 3 i == 3;想去掉条件转化为普通断点则直接使用cond id,例如,cond 3。
注意,这里的条件外的括号有没有都行,条件中可以使用<, <=, ==, !=, >, >=, &&, ||,&, |, ^, >>, <<,+, -, x, /, %等运算符,也可以使用方法,例如:break test.c:myfunc if ! check_variable_sanity(i),这里的方法返回值一定要是int,否则该条件就会被误读。
删除断点:
delete breakpoint_list 列表中为断点的ID,以空格隔开
delete 删除全部断点
clear 删除下一个GDB将要执行的指令处的断点
clear function/filename:function/line_number/filename:line_number 删除特定地点的断点
使能断点:enable breakpoint-list
不使能断点:disable breakpoint-list
跳过断点:ignore id numbers 表示跳过id表示的断点numbers次。
注意:
若设置断点是以函数名进行的话,C++中函数的重载会带来麻烦,该同名函数会都被设置上断点。请使用如下格式在C++中进行函数断点的设置:TestClass::testFunc(int)
设置的断点可能并非是你想放置的那一行。例如:
1: int main(void)

2: {

3: int i;

4: i=3;

5: return 0;

6: }
我们不使用编译器优化进行编译,然后加载到GDB中,如下:
$ gcc -g3 -Wall -Wextra -o test1 test1.c
$ gdb test1
(gdb) break main
Breakpoint 1 at 0x6: file test1.c, line 4.
我们发现显然#4并非是main函数的入口,这是因为这一行是该函数第一行虽然产生了机器码,但是GDB并不认为这对调试有帮助,于是它就将断点设置在第一行对调试有帮助的代码上。

我们使用编译器优化再进行编译,情况会更加令人困惑,如下:

$ gcc -O9 -g3 -Wall -Wextra -o test1 test1.c
$ gdb test1
(gdb) break main
Breakpoint 1 at 0x3: file test1.c, line 6.

GCC发现i变量一直就没有使用,所以通过优化直接忽略了,于是程序第一行产生机器码的代码恰好是main函数的最后一行。

因此,建议在不影响的情况下,程序调试时将编译器优化选项关闭。

同一行有多个断点时,程序只会停下一次,实际上GDB使用的是其中ID最小的那个。
在多文件调试中,常常希望GDB在并非当前文件的部分设置断点,而GDB默认关注的是含有main函数的文件,此时你可以使用list functionname、或者单步调试等方式进入另一个文件的源代码中进行设置,此时你设置的行号就是针对这个文件的源代码了。
当你利用代码行进行断点设置时,重新编译程序并在GDB中reload后,断点可能因为你代码行数的变化而发生相对位置变化(GDB指向的行数),这样的情况下使用DDD直接对原断点进行拖动是最方便的方法,它不会影响该断点的状态和条件,只会改变它所指的位置,从而省去了del一个断点后再在新位置添加设置新断点的麻烦。
在DDD中还可以Redo和Undo对断点的操作。
观察点设置:
设置写观察点:watch i ; watch (i | j > 12) && i > 24 && strlen(name) > 6,这是两种观察点(包含读写等)设置的方式(变量或表达式)。写观察点在该变量被写入后程序立刻中止。注意,很多平台都有硬件支持的观察点,默认GDB是优先使用的就是这些,若暂时不可用,GDB会使用VM技术实现观察点,这样的好处是硬件的速度较快。
设置读观察点:rwatch。
设置读写观察点:awatch
举例:下列简单程序,可以首先在main函数入口设置断点,然后在该断点被hit时设置观察点。 1: #include

2:

3: int main(int argc, char **argv)

4: {

5: int x = 30;

6: int y = 10;

7:

8: x = y;

9:

10: return 0;

11: }
这是个非常简单的程

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇malloc与sizeof的合用的陷阱 下一篇C语言编译全过程收藏

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: