GDB watch的使用
GDB watch的使用
rtoax 2021年3月
由于寄存器限制,GDB最多支持4个watchpoint。
1. 准备工作
先看一眼gdb watch帮助信息:
Set a watchpoint for an expression.
Usage: watch [-l|-location] EXPRESSION
A watchpoint stops execution of your program whenever the value of
an expression changes.
If -l or -location is given, this evaluates EXPRESSION and watches
the memory to which it refers.
为了详细表述GDB watch的使用,首先给出一个简单的demo(为清晰,删除log部分代码,完整代码见文末):
#include <malloc.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <string.h>#define NR_CELLS 8
#define NR_VTY NR_CELLSstruct cell_struct {int id;char name[60];
};struct vty_struct {int id;int task_id;int sock_id;char name[60];
};static struct cell_struct *my_cells = NULL;
static struct vty_struct *my_vty = NULL;void* test_task_fn(void* unused)
{struct cell_struct *new_cells = malloc(sizeof(struct cell_struct)*NR_CELLS);struct vty_struct *new_vtys = malloc(sizeof(struct vty_struct)*NR_VTY);my_cells = new_cells; //保存内存引用my_vty = new_vtys; //保存内存引用pthread_exit(NULL);
}int main ()
{pthread_t thread_id;pthread_create(&thread_id, NULL, test_task_fn, NULL);pthread_join(thread_id, NULL);/* `my_cells` 将越界,写坏 `my_vty` */memset(&my_cells[NR_CELLS], 0x0, sizeof(struct cell_struct)*4);memset(&my_vty[0], 0xff, sizeof(struct vty_struct));return 0;
}
编译源程序:
gcc clobber.c -pthread -g -o clobber.out
运行程序:
./clobber.out
在程序中,下面位置内存访问越界,在不使用任何调试工具的时候,将写坏结构my_vty
:
/* `my_cells` 将越界,写坏 `my_vty` */memset(&my_cells[NR_CELLS], 0x0, sizeof(struct cell_struct)*4);
但是,这在程序运行过程中是不显示任何错误信息。接下来使用gdb watch
对这个程序进行调试。
2. gdb watch
使用gdb启动需要调试的程序:
$ gdb --quiet clobber.out
(gdb)
首先查看需要设置断点的位置,当你的服务器中存在源代码时,可以使用list进行源码查看,或者直接使用函数名进行断点设置:
(gdb) break test_task_fn
上面的断点test_task_fn
,因为我们的内存是在这个函数中分配的,在这个函数中设置断点,并单步执行:
(gdb) run
...
Breakpoint 1, test_task_fn (unused=0x0) at clobber.c:28
28 struct cell_struct *new_cells = malloc(sizeof(struct cell_struct)*NR_CELLS);
(gdb) step
29 struct vty_struct *new_vtys = malloc(sizeof(struct vty_struct)*NR_VTY);
(gdb)
31 my_cells = new_cells; //保存内存引用
(gdb)
32 my_vty = new_vtys; //保存内存引用
(gdb)
33 pthread_exit(NULL);
查看申请的内存空间:
(gdb) p my_vty[0].task_id
$1 = 0
(gdb) p &my_vty[0].task_id
$2 = (int *) 0x7ffff0000ad4
添加对该内存地址0x7ffff0000ad4
的watch
:
(gdb) watch *0x7ffff0000ad4
Hardware watchpoint 2: *0x7ffff0000ad4
继续运行程序:
(gdb) c
Old value = 65332
New value = 0
0x00007ffff788098a in __memset_sse2 () from /usr/lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install libgcc-4.8.5-39.el7.x86_64
上面,watchpoint检测到内存地址被修改,查看具体栈信息:
(gdb) bt
#0 0x00007ffff788098a in __memset_sse2 () from /usr/lib64/libc.so.6
#1 0x0000000000400b54 in main () at clobber.c:89
上面的修改,对应源代码中的:
/* 将 越界,写坏 `my_vty` */memset(&my_cells[NR_CELLS], 0x0, sizeof(struct cell_struct)*4);
这是一次非法的访问。同样,另外的一次修改为正常访问,
memset(&my_vty[0], 0xff, sizeof(struct vty_struct));
不过也会被gdb watch捕获:
(gdb) c
Continuing.
Hardware watchpoint 2: *0x7ffff0000ad4Old value = 0
New value = -1
0x00007ffff7880979 in __memset_sse2 () from /usr/lib64/libc.so.6
(gdb) bt
#0 0x00007ffff7880979 in __memset_sse2 () from /usr/lib64/libc.so.6
#1 0x0000000000400b77 in main () at clobber.c:94
(gdb) c
Continuing.
3. 完成代码
/*** 测试 gdb watch 调试* * (gdb) watch * [addr]* * 作者:荣涛* 日期:2021年3月30日*/
#include <malloc.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <string.h>#define NR_CELLS 8
#define NR_VTY NR_CELLSstruct cell_struct {int id;char name[60];
};struct vty_struct {int id;int task_id;int sock_id;char name[60];
};static struct cell_struct *my_cells = NULL;
static struct vty_struct *my_vty = NULL;static void set_cell(struct cell_struct *cell, int id, char *name) {assert(cell && "set_cell: Cell is NULL.");cell->id = id;snprintf(cell->name, sizeof(cell->name), "%s:%d", name, id);
}
static void set_vty(struct vty_struct *vty, int id, char *name) {assert(vty && "set_vty: VTY is NULL.");vty->id = id;vty->task_id = 0xff33 + id; //创建进程vty->sock_id = 0xee44 + id; //创建 socketsnprintf(vty->name, sizeof(vty->name), "%s:%d", name, id);
}
void show_cells() {assert(my_cells && "show_cells: Cell is NULL.");int i;for(i=0; i< 8; i++) { printf("%4d - %s\n", my_cells[i].id, my_cells[i].name);}
}
void show_vtys() {printf("--------------------------------\n");assert(my_vty && "show_vtys: VTY is NULL.");int i;for(i=0; i< 8; i++) { printf("%4d - %s, %x, %x\n", my_vty[i].id, my_vty[i].name, my_vty[i].task_id, my_vty[i].sock_id);}
}void* test_task_fn(void* unused)
{printf("new thread.\n"); struct cell_struct *new_cells = malloc(sizeof(struct cell_struct)*NR_CELLS);struct vty_struct *new_vtys = malloc(sizeof(struct vty_struct)*NR_VTY);int i;for(i=0; i<NR_CELLS; i++) {set_cell(&new_cells[i], i+1, "cell");}my_cells = new_cells;for(i=0; i<NR_VTY; i++) {set_vty(&new_vtys[i], i+1, "vty");}my_vty = new_vtys;pthread_exit(NULL);
}/* The main program. */
int main ()
{pthread_t thread_id;pthread_create(&thread_id, NULL, test_task_fn, NULL);pthread_join(thread_id, NULL);printf("task exit.\n");show_vtys();/* 将 越界,写坏 `my_vty` */memset(&my_cells[NR_CELLS], 0x0, sizeof(struct cell_struct)*4);// show_cells();show_vtys();memset(&my_vty[0], 0xff, sizeof(struct vty_struct));show_vtys();printf("Exit program.\n");return 0;
}
GDB watch的使用相关推荐
- android gdb 命令大全,ndk-gdb | Android NDK | Android Developers
NDK 包含一个名为 ndk-gdb 的 Shell 脚本,可以启动命令行原生调试会话.偏好使用 GUI 的用户则应阅读在 Android Studio 中调试这篇文档. 要求 要运行命令行原生调试, ...
- Git/Ctags/Vim/GDB基础笔记
>>>>>>>>>>>>>>>>>>>>>>>>> ...
- gdb常用调试命令汇总!
在debug模式下,使用GDB进行调试,可以使用的命令汇总如下: (gdb) p *(*pHead)->next 这里声明语句ListNode** pHead,表示查看*pHead执行链表节 ...
- 一文带你看透 GDB 的 实现原理 -- ptrace真香
文章目录 Ptrace 的使用 GDB 的基本实现原理 Example1 通过ptrace 修改 被追踪进程的内存数据 Example2 通过ptrace 对被追踪进程进行单步调试 Ptrace的实现 ...
- 使用 GDB 调试多进程程序
使用 GDB 调试多进程程序 来源 https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/index.html GDB 是 linux 系统上常 ...
- linux(armv7/8)下gdb的安装及查看方法
1. gdb安装 1.1 将gdb-10.1.tar.gz拷贝的/usr/local/目录下 (可以拷贝到任何你愿意的Linux目录下)或者进入 /usr/local中下载地址:http://ftp. ...
- gdb相关(栈和寄存器)
GDB的常用调试命令大家可以查阅gdb手册就可以快速的上手了,在这儿就不给大家分享了,需要的可以到GDB的官网去下载手册.这里重点分享下GDB调试中的一些寄存器和栈的相关知识用于解决下列gdb调试时的 ...
- gdb+gdbserver
内容摘要 远程调试环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接.使用 GDB标准程串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能.调试stub是嵌入式 ...
- gdb 查找动态库方法
当GDB无法显示so动态库的信息或者显示信息有误时,通常是由于库搜索路径错误导致的,可使用set sysroot.set solib-absolute-prefix.set solib-search- ...
- GDB调试--以汇编语言为例
#rpm -qa |grep gdb 下载: 安装 #tar -zxvf #./configure #make 使用GDB 以汇编语言调试为例 汇编语言实现CPUID指令 CPUID cpuid是I ...
最新文章
- 时间不同单位之间的转换
- gdb工作原理(二)
- bzoj 1007 : [HNOI2008]水平可见直线 计算几何
- Video4Linux
- java.net.SocketException: Software caused connection abort: socket write erro
- Linux学习系列之Linux入门(一)linux安装与入门
- C#通过属性名字符串获取、设置对象属性值
- Flex-iframe在SWF中嵌入网页的组件(推荐)
- 囚徒困境、价格大战与 iPhone 的价格
- python3.6 - threading 多线程编程基础(1)
- 打造颠覆你想象中的高性能,轻量级的webform框架-----如何替换webform的垃圾控件(第一天)...
- 如何通过 OAuth 2.0 使 iOS Apps 集成 LinkedIn 登录功能?
- 一天搞懂深度学习(李宏毅)-学习笔记
- 流程图绘图工具 Gliffy 使用简介
- Windows自带的远程协助工具(非远程桌面)
- 基于大数据平台分析前程无忧大数据招聘信息实现数据可视化
- 基于go websocket写一个聊天室
- 外贸人如何在领英linkedin上高效开发客户
- C#控制键盘按键的常用方法
- java程序 下雨,利用SurfaceView实现下雨与下雪动画效果详解(Kotlin语法)