使用GDB中的watch来调试指来指去的指针

9 篇文章 2 订阅
本文介绍了如何使用GDB的watchpoint来调试C程序中的全局变量和堆栈、堆内存中的变量。通过设置watchpoint,可以在变量修改时中断程序,便于追踪代码中的问题。文章详细展示了在不同内存区域设置watchpoint的示例,并强调了变量生命周期对watchpoint的影响。
摘要由CSDN通过智能技术生成

  引言

        C代码中经常会有大量的指针在很多不同函数中传来传去,甚至还有强制类型转换,让阅读代码和调试BUG的人苦不堪言。更有甚者将全局变量指针赋值给局部变量,然后再作为参数传出并修改。

        这是官网的说明:http://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html#Set-Watchpoints

 说明

        watch是gdb众多命令中的一个,用来检测变量,当被监测的变量被修改时,会自动中断程序,此时用户就可以看到变量在哪里被修改了。

        我们都知道,C中的变量是有生命周期的,很显然,watch只能在变量的生命周期内进行监测,这一点一定要注意。很容易想通,变量存储在内存或者寄存器中,既然还没创建或者已经释放了,还怎么监测呢?

        由上可以得出:

        1.全局区:全局变量生命周期和整个程序一样,可以在初始化后进行watch;

        2.堆区:在被创建和释放前都可以watch;

        3.栈区:只能在函数内部watch

        理解了上面的3点,就可以开心的使用watch了。

注意

        注意事项:watch的断点分为硬断点和软断点,硬断点需要机器硬件支持,不仅速度快,而且断点可以精确到汇编指令级别。

        不同于break断点,生命周期结束后,watch断点会自动删除。

        开启硬断点的方法:set can-use-hw-watchpoints 1

 

        下面是用来演示的代码,功能很简单,只是一些赋值。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct INFO
{
        int age;
        char *name;
}ST_INFO;

//全局区
ST_INFO gInfo;

void set_name()
{
        char *name = (char*)malloc(20 * sizeof(char));
        strcpy(name, "hey suse");
        gInfo.name = name;
}
void set_age()
{
        gInfo.age = 22;
}

void motify(ST_INFO *pInfo)
{
        pInfo->name = "motify";
        pInfo->age = 66;
}

int main()
{
        //malloc后存储在堆区
        ST_INFO *pInfo = NULL;
        //存储在栈区
        ST_INFO info;

        info.name = "hello";
        info.age = 35;

        pInfo = (ST_INFO*)malloc(sizeof(ST_INFO));
        pInfo->name = "malloc";
        pInfo->age = 108;

        motify(pInfo);

        free(pInfo);

        set_age();
        set_name();

        pInfo = &gInfo;

        motify(pInfo);
        return 0;

}

全局

设置观测点

(gdb) watch gInfo.name 
Hardware watchpoint 1: gInfo.name

 可以看到提示是硬断点了

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/luogf/20210815/a.out 
Hardware watchpoint 1: gInfo.name

Old value = 0x0
New value = 0x601010 "hey suse"
set_name () at watch.c:17
17	}
(gdb) bt
#0  set_name () at watch.c:17
#1  0x000000000040062f in main () at watch.c:46

运行后程序在修改点停了下来,可以看到修改前的值Old value = 0x0,以及修改后的值New value = 0x601010 "hey suse";在set_name函数里修改了全局的name。

(gdb) c
Continuing.
Hardware watchpoint 1: gInfo.name

Old value = 0x601010 "hey suse"
New value = 0x400751 "motify"
motify (pInfo=0x600aa0) at watch.c:26
26		pInfo->age = 66;

这里将全局的地址赋值给了一个局部变量,然后在motify中修改,试想再多传几次,想要通过看代码去分析,大工程的代码能累死人。。。

堆区

(gdb) watch pInfo
No symbol "pInfo" in current context.

直接watch发现不行,因为此时pInfo还没创建呢,你需要先在pInfo创建后再watch才能成功。

(gdb) b 37
Breakpoint 8 at 0x4005df: file watch.c, line 37.
(gdb) r
Starting program: /home/luogf/20210815/a.out 

Breakpoint 8, main () at watch.c:37
37		pInfo = (ST_INFO*)malloc(sizeof(ST_INFO));
(gdb) watch pInfo.name 
Hardware watchpoint 9: pInfo.name

  pInfo没有开辟空间依然可以watch,下面在malloc时停了下来,初始值时0。

(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = <unreadable>
New value = 0x0
main () at watch.c:38
38		pInfo->name = "malloc";
(gdb) i b
Num     Type           Disp Enb Address            What
8       breakpoint     keep y   0x00000000004005df in main at watch.c:37
	breakpoint already hit 1 time
9       hw watchpoint  keep y                      pInfo.name
	breakpoint already hit 1 time

继续运行,修改了两次值,最后通过free释放,值变成了随机。

(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = 0x0
New value = 0x40075e "malloc"
main () at watch.c:39
39		pInfo->age = 108;
(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = 0x40075e "malloc"
New value = 0x400751 "motify"
motify (pInfo=0x601010) at watch.c:26
26		pInfo->age = 66;
(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = 0x400751 "motify"
New value = 0x400700 "H\203\370\377t\031\273\210\b`"

由于将pInfo指向了全局gInfo,这两个已经是一个值了,后面gInfo变化也会触发断点。

(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = 0x400700 "H\203\370\377t\031\273\210\b`"
New value = 0x601010 "hey suse"
main () at watch.c:50
(gdb) p pInfo 
$1 = (ST_INFO *) 0x600aa0
(gdb) p &gInfo 
$2 = (ST_INFO *) 0x600aa0
(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = 0x601010 "hey suse"
New value = 0x400751 "motify"
motify (pInfo=0x600aa0) at watch.c:26
26		pInfo->age = 66;
(gdb) c
Continuing.
Hardware watchpoint 9: pInfo.name

Old value = 0x601010 "hey suse"
New value = 0x400751 "motify"
motify (pInfo=0x600aa0) at watch.c:26
26		pInfo->age = 66;
(gdb) c
Continuing.

Watchpoint 9 deleted because the program has left the block in
which its expression is valid.
0x00007ffff7a66d20 in __libc_start_main () from /lib64/libc.so.6
(gdb) i b
Num     Type           Disp Enb Address            What
8       breakpoint     keep y   0x00000000004005df in main at watch.c:37
	breakpoint already hit 1 time
(gdb) 

生命周期结束后,watch断点会自动删除

栈区

  和堆区差不多,不过只能在函数内部查看。

Breakpoint 6, main () at watch.c:31
31		ST_INFO *pInfo = NULL;
(gdb) watch info.name
Hardware watchpoint 9: info.name
(gdb) c
Continuing.
Hardware watchpoint 9: info.name

Old value = 0x400470 "1\355I\211\321^H\211\342H\203\344\360PTI\307\300P\006@"
New value = 0x400758 "hello"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值