GDB再学习:断点调试之软件断点

Posted Stoneshen1211

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GDB再学习:断点调试之软件断点相关的知识,希望对你有一定的参考价值。


1 断点简介

关于断点,主要用来对程序进行调试。当我们在程序中设置断点之后,程序运行到我们设置断点的时候就会暂停运行,这样我们就可以对堆栈数据等进行分析。

断点根据类型的不同,分为软断点、硬断点、内存断点、事件断点。

2 软件断点

记得以前刚学51单片机的时候,使用IDE进行软件开发。测试点亮熄灭LED的时候,会设置一些断点,在线调试,来观察LED的点亮与熄灭。

我们在IDE中设置的这些断点就是软件程序断点。

当处理器在运行过程中,如果碰到了非法或者无效的指令,就会出现异常中断,软件程序断点就是利用这个特性来实现的。
当设置一个软件程序断点时,调试工具就在我们所想设置的内存位置上放置了一条非法的指令,同时将被替换的指令保留起来。
当程序运行到了被非法指令替换的地方时候,处理器所产生的异常中断一方面在中断服务程序中恢复被替换的指令,另一方面将控制权交给调试工具。
理论上说,软件程序断点可以设置n个,n值取决于内存容量。

以上引用自《专业嵌入式软件开发 全面走向高质高效编程》

3 程序准备

我们使用下面的测试程序进行讲解

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>

int j = 0;

int test2()
{
	char* s8Buf = NULL;
	
	strcpy(s8Buf, "8888");
	
	return 0;
}

int main()
{
	int i  = 0;
	
	for (i = 0; i < 60; i++)
	{
		j++;
		printf("-------->index %d\\n", i);
		sleep(1);
	}

	test2();
	
	return 0;
}

4 指令介绍

break指令可以设置程序的软断点。有以下几种设置方式:

通过函数名来设置断点;
通过行号的方式来设置断点;
通过文件名和行号的方式来设置断点。

4.1 通过函数名设置断点 break func [ if cond ]

通过函数名设置行号,则断点会在函数的开始处。
如下,在main函数的开始处设置断点:

(gdb) break main
Breakpoint 3 at 0x40058f: file test_gdb.c, line 19.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 

Breakpoint 3, main () at test_gdb.c:19
19		int i  = 0;
(gdb) 

[if cond]为预置的条件,当满足这个条件时候,程序将会在断点处暂停运行,如果不满足,则不会在断点处运行。

如下,设置当j为0时候,有断点,因为j的初始值为0,所以满足断点:

(gdb) break main if j == 0
Breakpoint 4 at 0x40058f: file test_gdb.c, line 19.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 

Breakpoint 4, main () at test_gdb.c:19
19		int i  = 0;
(gdb) 

如下,设置当j为1时候,有断点,因为j的初始值为0,所以不满足断点:

(gdb) break main if j == 1
Breakpoint 5 at 0x40058f: file test_gdb.c, line 19.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 
-------->index 0
-------->index 1
-------->index 2

4.2 通过行号的方式来设置断点 break line_number [ if cond ]

通过直接行号的方式,断点会在指定的行号出。
如下:

(gdb) break 25
Breakpoint 3 at 0x4005c2: file test_gdb.c, line 25.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 
-------->index 0

Breakpoint 3, main () at test_gdb.c:25
25			sleep(1);
(gdb) 

[ if cond ]则和4.1中的效果相同

4.3 通过文件名和行号的方式来设置断点break file.c:line_number [ if cond ]

效果和4.2相同,如下:

(gdb) break test_gdb.c:25
Breakpoint 4 at 0x4005c2: file test_gdb.c, line 25.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 
-------->index 0

Breakpoint 4, main () at test_gdb.c:25
25			sleep(1);
(gdb) 

使用break时候,每次运行到我们设置断点的地方都会暂停,如下:

(gdb) break 25
Breakpoint 5 at 0x4005c2: file test_gdb.c, line 25.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 
-------->index 0

Breakpoint 5, main () at test_gdb.c:25
25			sleep(1);
(gdb) continue
Continuing.
-------->index 1

Breakpoint 5, main () at test_gdb.c:25
25			sleep(1);
(gdb) continue
Continuing.
-------->index 2

Breakpoint 5, main () at test_gdb.c:25
25			sleep(1);
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
5       breakpoint     keep y   0x00000000004005c2 in main at test_gdb.c:25
	breakpoint already hit 3 times
(gdb) 

因此,GDB中提供了一个一次有效的指令tbreak.

4.4 一次有效指令 tbreak

tbreak的用法和上面break的用法一样,唯一的区别就是第一次运行到断点位置后,会删除断点,因此这个断点时一次有效的。

如下,当第一次断点之后,我们使用info breakpoints查看断点信息,断点被删除了。

(gdb) tbreak 25
Temporary breakpoint 6 at 0x4005c2: file test_gdb.c, line 25.
(gdb) r
Starting program: /home/test_demo/gdb/test_gdb 
-------->index 0

Temporary breakpoint 6, main () at test_gdb.c:25
25			sleep(1);
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) continue
Continuing.
-------->index 1
-------->index 2
-------->index 3
-------->index 4
-------->index 5

4.5 与正则表达式regex匹配的所有函数上设置断点 rbreak regex

在与正则表达式regex匹配的所有函数上设置断点。 此命令在所有匹配项上设置一个无条件断点,并打印它设置的所有断点的列表。

如下,在以test开头的函数中设置断点:

(gdb) rbreak test
Breakpoint 16 at 0x40056a: file test_gdb.c, line 10.
int test2();
(gdb) 

如下,给所有的函数设置断点:

(gdb) rbreak
Breakpoint 34 at 0x40058f: file test_gdb.c, line 19.
int main();
Breakpoint 35 at 0x40056a: file test_gdb.c, line 10.
int test2();
Breakpoint 36 at 0x400400
<function, no debug info> _init;
Breakpoint 37 at 0x400430
<function, no debug info> printf@plt;
Breakpoint 38 at 0x400440
<function, no debug info> __libc_start_main@plt;
Breakpoint 39 at 0x400450
<function, no debug info> sleep@plt;
Breakpoint 40 at 0x400470
<function, no debug info> _start;
Breakpoint 41 at 0x4004a0
<function, no debug info> deregister_tm_clones;
Breakpoint 42 at 0x4004e0
<function, no debug info> register_tm_clones;
Breakpoint 43 at 0x400520
<function, no debug info> __do_global_dtors_aux;
Breakpoint 44 at 0x400540
<function, no debug info> frame_dummy;
Breakpoint 45 at 0x4005f0
<function, no debug info> __libc_csu_init;
Breakpoint 46 at 0x400660
<function, no debug info> __libc_csu_fini;
Breakpoint 47 at 0x400664
<function, no debug info> _fini;
(gdb) 

4.6 查看断点信息 info breakpoints

使用这个指令,能够看到断点的编号,断点的状态,已经断点运行的次数。

在上面4.3的例子中的断点信息如下,breakpoint already hit 3 times 显示此断点已经运行了3次:

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
5       breakpoint     keep y   0x00000000004005c2 in main at test_gdb.c:25
	breakpoint already hit 3 times
(gdb) 

4.7 使断点无效 disable

直接使用disable 或者 disable breakpoints会使所有的断点失效;
使用disable number 或者 disable breakpoints number则会使指定的断点无效。

如下,使编号为62的断点无效:

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
62      breakpoint     keep y   0x000000000040059f in main at test_gdb.c:23
63      breakpoint     keep y   0x00000000004005ae in main at test_gdb.c:24
(gdb) disable 62
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
62      breakpoint     keep n   0x000000000040059f in main at test_gdb.c:23
63      breakpoint     keep y   0x00000000004005ae in main at test_gdb.c:24
(gdb) 

4.8 使能断点 enable

直接使用enable或者 enable breakpoints会使能所有的断点;
使用enable number 或者 enable breakpoints number则会使能指定的断点。

如下,使能编号为62的断点:

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
62      breakpoint     keep n   0x000000000040059f in main at test_gdb.c:23
63      breakpoint     keep y   0x00000000004005ae in main at test_gdb.c:24
(gdb) enable 62
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
62      breakpoint     keep y   0x000000000040059f in main at test_gdb.c:23
63      breakpoint     keep y   0x00000000004005ae in main at test_gdb.c:24
(gdb) 

4.9 断点的删除 delete

直接使用delete或者 delete breakpoints会删除所有的断点;
使用delete number 或者 delete breakpoints number则会删除指定的断点。

如下,删除编号为62的断点:

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
62      breakpoint     keep y   0x000000000040059f in main at test_gdb.c:23
63      breakpoint     keep y   0x00000000004005ae in main at test_gdb.c:24
(gdb) delete 62
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
63      breakpoint     keep y   0x00000000004005ae in main at test_gdb.c:24
(gdb) 

以上是关于GDB再学习:断点调试之软件断点的主要内容,如果未能解决你的问题,请参考以下文章

GDB再学习:断点调试之硬断点

GDB再学习:断点调试之硬断点

GDB再学习:断点调试之事件断点

GDB再学习:断点调试之事件断点

GDB再学习:断点调试之事件断点

GDB再学习:断点调试之数据断点