- 上一篇文章我们学习了如何使用GDB进行软件断点调试和硬件断点调试:【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试
- 本篇文章继续上一篇文章的学习,如何使用GDB的数据断点监测内存中的变量是否被改变
1 GDB的数据断点
先来了解一下什么是GDB中的数据断点:
- 在GDB中设置数据断点用于监测一个内存中的变量,在程序运行的时候,如果该变量被改变,则程序就会被GDB终止执行,并显示变量被改变的地方。
- 数据断点的本质是硬件断点
- 在GDB中使用watch命令来设置数据断点
- watch命令的用法为:watch var_name
可以使用watch进行设置数据断点,我们还可以查看程序运行中的所有内存中的数据。
命令语法为:
- x /Nuf address
其中/Nuf中的N、u、f三个位置的含义是:
- N - 需要打印的单元数
- u - 每个单元的大小,比如字节,字,双字等
- f - 数据打印的格式 ,如八进制,十六进制等
如下图示例是显示4个单元,每个单元为1字节,以十六进制数显示:
-
x 命令中参数u对应的几种单位:
-
打印格式对应的几种选项:
1.1 利用查看内存的x命令进行系统大小端的判断
学会了x命令的用法,可以按如下图的方式判断系统大小端:
2 使用GDB进行监视变量的改变与查看内存实际代码案例分析
watch.c程序
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int g_var = 0;
void* thread_func(void* args)
{
sleep(5);
g_var = 1;
}
int main()
{
int i = 0;
pthread_t tid = 0;
pthread_create(&tid, NULL, thread_func, NULL);
for(i=0; i<10; i++)
{
printf("g_var = %d\n", g_var);
sleep(1);
}
}
上面的程序非常的简单,就是在main函数中创建一个线程thread_func,然后在thread_func函数中改变一个全局变量
首先我们先编译运行上述程序:
- gcc -g -lpthread watch.c -o test.out
运行结果如下动态图:
我们可以看出,我们程序跑着跑着g_var变量就变了。假设这个变量我们不想让它改变,但是有时候你调用了其他人写的接口函数,很有可能就把我们不想改变的变量改变了,所以这个时候需要找到变量在什么时候被改变,以及在哪里被改变。
上述是一个小程序所以我们很容易知道是在thread_func函数中改变的g_var变量,而且也能够知道在什么时候变量被改变。但是如果在一个大型程序中,就很难查找。
此时GDB的数据断点就派上用场了。
我们可以使用GDB对变量g_var进行数据断点的设置,当g_var发生变化时,程序就会自动停止运行,此时我们就可以知道程序运行到哪里了。
首先依次输入以下命令:
- gdb tset.out
- start
进入到GDB调试模式并启动程序后再程序入口处停止。
然后使用watch命令对g_var变量设置数据断点:
watch g_var
并使用info breakpoints 查看断点是否设置成功
上述步骤如下图所示:
打好数据断点后让程序执行,输入continue命令即可,显示如下动态图所示:
上述动态图中,运行着运行着就停止了,停止后显示如下:
从上述图中我们可以知道在watch.c程序的thread_func函数中的12行,导致了g_var的改变,是从Old value=0改变到New value=1的。我们很容易就找到了发生改变的地方,如果在大型程序中,这是很快。
当然,我们还可以使用上面学习的 x 命令,来查看g_var所在内存的内容。首先我们需要查看g_var变量的的内存地址:
print /a &g_var 输入这条命令,显示如下:
得到g_var的地址后,使用 x 命令查看它的内存,查看方式是4单元,1字节,16进制方式,如下图:
很明显,我们显示了g_var内存地址的连续4字节的内容。
- 到此,我们已经通过这个简单的示例,学会了如何检测程序运行过程中的内存变化。例子随简单,但是也能够提现内存监测的重要性。
3 总结
- 本文学会使用GDB 进行内存监测
- 学会如何使用GDB数据断点调试程序
本文章参考狄泰软件学院相关课程
想学习的可以加狄泰软件学院群,
群聊号码:199546072
学习探讨加个人(可以免费帮忙下载CSDN资源):
qq:1126137994
微信:liu1126137994
学习交流资源分享qq群:962535112