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

添加对该内存地址0x7ffff0000ad4watch:

(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的使用相关推荐

  1. android gdb 命令大全,ndk-gdb  |  Android NDK  |  Android Developers

    NDK 包含一个名为 ndk-gdb 的 Shell 脚本,可以启动命令行原生调试会话.偏好使用 GUI 的用户则应阅读在 Android Studio 中调试这篇文档. 要求 要运行命令行原生调试, ...

  2. Git/Ctags/Vim/GDB基础笔记

    >>>>>>>>>>>>>>>>>>>>>>>>> ...

  3. gdb常用调试命令汇总!

    在debug模式下,使用GDB进行调试,可以使用的命令汇总如下: (gdb) p *(*pHead)->next   这里声明语句ListNode** pHead,表示查看*pHead执行链表节 ...

  4. 一文带你看透 GDB 的 实现原理 -- ptrace真香

    文章目录 Ptrace 的使用 GDB 的基本实现原理 Example1 通过ptrace 修改 被追踪进程的内存数据 Example2 通过ptrace 对被追踪进程进行单步调试 Ptrace的实现 ...

  5. 使用 GDB 调试多进程程序

    使用 GDB 调试多进程程序 来源 https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/index.html GDB 是 linux 系统上常 ...

  6. linux(armv7/8)下gdb的安装及查看方法

    1. gdb安装 1.1 将gdb-10.1.tar.gz拷贝的/usr/local/目录下 (可以拷贝到任何你愿意的Linux目录下)或者进入 /usr/local中下载地址:http://ftp. ...

  7. gdb相关(栈和寄存器)

    GDB的常用调试命令大家可以查阅gdb手册就可以快速的上手了,在这儿就不给大家分享了,需要的可以到GDB的官网去下载手册.这里重点分享下GDB调试中的一些寄存器和栈的相关知识用于解决下列gdb调试时的 ...

  8. gdb+gdbserver

    内容摘要 远程调试环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接.使用 GDB标准程串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能.调试stub是嵌入式 ...

  9. gdb 查找动态库方法

    当GDB无法显示so动态库的信息或者显示信息有误时,通常是由于库搜索路径错误导致的,可使用set sysroot.set solib-absolute-prefix.set solib-search- ...

  10. GDB调试--以汇编语言为例

    #rpm -qa |grep  gdb 下载: 安装 #tar -zxvf #./configure #make 使用GDB 以汇编语言调试为例 汇编语言实现CPUID指令 CPUID cpuid是I ...

最新文章

  1. 时间不同单位之间的转换
  2. gdb工作原理(二)
  3. bzoj 1007 : [HNOI2008]水平可见直线 计算几何
  4. Video4Linux
  5. java.net.SocketException: Software caused connection abort: socket write erro
  6. Linux学习系列之Linux入门(一)linux安装与入门
  7. C#通过属性名字符串获取、设置对象属性值
  8. Flex-iframe在SWF中嵌入网页的组件(推荐)
  9. 囚徒困境、价格大战与 iPhone 的价格
  10. python3.6 - threading 多线程编程基础(1)
  11. 打造颠覆你想象中的高性能,轻量级的webform框架-----如何替换webform的垃圾控件(第一天)...
  12. 如何通过 OAuth 2.0 使 iOS Apps 集成 LinkedIn 登录功能?
  13. 一天搞懂深度学习(李宏毅)-学习笔记
  14. 流程图绘图工具 Gliffy 使用简介
  15. Windows自带的远程协助工具(非远程桌面)
  16. 基于大数据平台分析前程无忧大数据招聘信息实现数据可视化
  17. 基于go websocket写一个聊天室
  18. 外贸人如何在领英linkedin上高效开发客户
  19. C#控制键盘按键的常用方法
  20. java程序 下雨,利用SurfaceView实现下雨与下雪动画效果详解(Kotlin语法)

热门文章

  1. Portainer复制Docker容器
  2. Hanlp得到语义相似度的方法
  3. Redis学习---Redis操作之String
  4. bean type not found
  5. Xpath string()提取多个子节点中的文本
  6. 功能至上!国内外最实用的协作类软件盘点
  7. Xcode同一个Workspace中两个工程依赖于Undefined Symbol Error
  8. 2015.5.6(servlet基础)
  9. 5-35 有理数均值 (20分)
  10. 项目杂-备注-说明-其他