调试利器GDB(下)

本节我们研究gdb更深层的用法:

数据断点:

可以根据变量的值来监视变量。

数据断点本质是硬件断点,数量有限。

watch var_name告诉gdb我们关注var_name这个变量,如果它的值被改变了,程序运行就停止。

数据断点常常配合gdb里面的内存查看命令使用。

 

x是检查内存数据的命令。

上图中的意思是打印从0x804a024地址开始连续4个字节的数据,呈现格式以16进制打印。x代表16进制。

 

 

上图中/a代表打印地址。

变量断点和内存查看实验:

watch.c程序如下:

 1 #include <stdio.h>
 2 #include <pthread.h>
 3 #include <unistd.h>
 4 
 5 int g_var = 0;
 6 
 7 void* thread_func(void* args)
 8 {
 9     sleep(5);
10     
11     g_var = 1;
12 }
13 
14 int main()
15 {
16     int i = 0;
17     pthread_t tid = 0;
18     
19     pthread_create(&tid, NULL, thread_func, NULL);
20     
21     for(i=0; i<10; i++)
22     {
23         printf("g_var = %d\n", g_var);
24         
25         sleep(1);
26     }
27 }

 

 先编译运行一下:

 

子线程中将g_var的值改为1,影响到了主线程的工作,我们认为这是一个错误的程序,进行debug调试。

开始调试:

 

 使用watch监视g_var:

continue继续执行程序:

当g_var被改变的时候,程序停下了。图中提示g_var的值被改写了,是被thread_func函数中的第12行改写的(gdb表达的意思是程序执行到第12行时,g_var的值被改写了,意味着是第11行改写的)。

查看内存的值:

 

上图也验证了当前系统是小端系统。

继续执行:

本次调试,我们确定了是什么地方修改了g_var的值。

 

 函数调用相关:

为什么要打印函数调用栈呢?举个例子,当我们看一份开源代码的时候,我们想快速弄清楚函数的调用关系,这时可以在感兴趣的函数上打上断点,当程序断在这里时,可以用backtrace查看函数调用栈。

frame N可以跳转到某一个函数的上下文当中。切换过去之后可以查看一些函数参数信息等。

info fream可以查看栈帧信息。

 

每一次函数调用的活动记录就存在栈上,这就是栈帧。

 

 实验:

frame.c程序如下:

 1 #include <stdio.h>
 2 
 3 
 4 int sum(int n)
 5 {
 6     int ret = 0;
 7     
 8     if( n > 0 )
 9     {
10         ret = n + sum(n-1);
11     }
12     
13     return ret;
14 }
15 
16 
17 int main()
18 {
19     int s = 0;
20     
21     s = sum(10);
22     
23     printf("sum = %d\n", s);
24     
25     return 0;
26 }

先编译运行一下程序:

 

 

 启动gdb:

 

 打一个条件断点:

 

 

 继续执行:

程序在sum函数的第6行停下了。

backtrace打印了函数的调用信息。

main -> sum(10) -> sum(9) .... -> sum(0)

程序在sum(0)时停了下来。

next继续执行:

函数停在return ret的时候,我们通过info args打印当前栈帧这个函数参数的值,可以看到为0。

切换函数栈帧:

我们切换到7号栈帧上。

打印信息告诉我们,目前函数调用上下文里面语句停留在ret = n  + sum(n-1);这一行。

info args打印参数信息,info locals打印局部变量的值:

将栈帧切换回0号栈帧,并打印寄存器:

 

当前的sp的值是0xbfffee80。

打印当前栈帧的详细信息:

我们关注Previous frame's sp is 0xbfffeeb0这个信息。

这就是上一个栈帧sp的值。

调用这个函数之前,ebp的值被保存在了0xbfffeea8地址处,eip保存在了0xbfffeeac地址处。

打印函数调用之前ebp的值:

 

 继续验证上面的打印是否正确:

执行next,sum(0)返回,这就到了sum(1)的地方:

 

可以看到ebp的值和上一次的打印是一样的。esp的值也完全能对应上。

 

调试技巧:

 

whatis和ptype是动态查看符号的方法。

上图中在gdb中直接编译程序。

编译后用file载入运行。

符号查看:

从上图中可知,func是一个函数类型,具体为int(),返回值为int,没有参数。

实验:

tricks.c如下:

 1 #include <stdio.h>
 2 
 3 int g_var = 1;
 4 
 5 struct ST
 6 {
 7     int i;
 8     int j;
 9 };
10 
11 int func()
12 {
13     struct ST st[5] = {0};
14     int i = 0;
15     
16     for(i=0; i<5; i++)
17     {
18         st[i].i = i;
19         st[i].j = i * i;
20     }
21     
22     for(i=0; i<5; i++)
23     {
24         printf("st[%d].i = %d\n", i, st[i].i);
25         printf("st[%d].j = %d\n", i, st[i].j);
26     }
27 }
28 
29 int main()
30 {
31     static c_var = 2;
32     
33     func();
34     
35     return 0;
36 }

 

开始调试:

打印结果如下:

 

list是列出源文件的某一行的内容,但是相邻的几行也会打印出来。

设置显示的行数重新打印:

 

继续执行:

 

 使用display使得每次执行到这个断点的时候都自动打印。

 

最后程序正常退出:

 

我们再次直接run,上次设置的东西还都存在:

 

 undisplay可以取消之前的自动打印。

使用符号查看:

 

 ptype是打印详细的类型定义。

 

查看全局的变量符号:

info functions可以得到以下信息:

小结:

 

转载于:https://www.cnblogs.com/wanmeishenghuo/p/9821349.html

资源下载链接为: https://pan.quark.cn/s/ddc62c5d4a5d Windows Mobile 是微软在 0200 年代至 2010 年代初推出的移动操作系统,曾广泛应用于智能手机和平板电脑。开发者可以借助各种库和框架为其开发功能丰富的应用,其中 “32feet.NET” 是一个开源的 .NET 库,专为 .NET Framework 和 .NET Compact Framework 提供蓝牙开发支持。它包含多个命名空间,例如 InTheHand.Devices.Bluetooth、InTheHand.Net.Personal 和 InTheHand.Phone.Bluetooth,用于实现蓝牙设备交互功能。 InTheHand.Devices.Bluetooth 命名空间用于执行基础蓝牙操作,比如扫描附近设备、建立连接以及发现蓝牙服务等。InTheHand.Net.Personal 提供了更高级的功能,例如创建个人区域网络(PAN)、文件传输和串行端口模拟,便于开发者开发跨设备的数据共享应用。而 InTheHand.Phone.Bluetooth 主要针对 Windows Phone 平台,支持蓝牙配对、消息收发和蓝牙耳机控制等功能,不过由于 Windows Mobile 已停止更新,该命名空间更多适用于旧设备或项目。 压缩包中的文件列表看似是维基页面的渲染文件,可能是关于 32feet.NET 的使用教程、API 参考或示例代码。文件名如 13632.html、563803.html 等可能是页面 ID,涵盖蓝牙设备搜索、连接和数据传输等不同主题。 使用 32feet.NET 进行蓝牙开发时,开发者需要注意以下几点:首先,确保开发环境已安装 .NET Framework 或 .NET Compact Framework,以及 32feet.NET
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值