Linux 命令行入门学习资料 day_6

GDB 监视点 watch


一、什么是 watch?------ 变量的"监控摄像头"

之前学过的 break按位置暂停 (比如某一行代码),而 watch按数据变化暂停

watch 的作用

告诉 GDB 持续监视某个变量(或表达式),只要它的值发生变化,就立刻中断程序执行,并显示旧值和新值。

典型场景

  • 某个变量的值莫名其妙被修改,不知道在哪改的
  • 想要知道一个全局变量或关键局部变量何时被赋予新值
  • 代替在大量地方手动加 printf 来追踪变量变化

二、监视点的三种类型

GDB 根据监视的触发条件,将监视点分为三类:

类型 命令 触发条件
写监视点 (watchpoint) watch 表达式 当被监视的表达式的值被写入(修改)时触发
读监视点 (read watchpoint) rwatch 表达式 当被监视的表达式的值被读取时触发
读写监视点 (access watchpoint) awatch 表达式 当被监视的表达式的值被读取或写入时触发

最常用的是 watch,也就是写监视点。今天重点掌握它。


三、如何使用 watch ------ 完整流程演示

准备工作:写一个简单的测试程序

创建文件 watch_demo.c

c 复制代码
#include <stdio.h>

int sum = 0;  // 全局变量,方便全程监视

void add(int n) {
    sum += n;   // 这里会修改 sum
}

int main() {
    int i;
    for (i = 1; i <= 3; i++) {
        add(i);
        printf("After adding %d, sum = %d\n", i, sum);
    }
    return 0;
}

编译(必须加 -g,建议不要优化)

bash 复制代码
gcc -g -O0 watch_demo.c -o watch_demo

进入 GDB 并设置监视点

bash 复制代码
gdb ./watch_demo

1. 先给 main 函数设一个断点,确保程序跑起来后再设 watch

(因为 watch 要监视的变量必须存在于当前作用域)

gdb 复制代码
(gdb) break main
Breakpoint 1 at 0x...: file watch_demo.c, line ...
(gdb) run
Starting program: ./watch_demo

Breakpoint 1, main () at watch_demo.c:12
12	    for (i = 1; i <= 3; i++) {

2. 设置监视点:监视全局变量 sum

gdb 复制代码
(gdb) watch sum
Hardware watchpoint 2: sum

"Hardware watchpoint" 表示系统使用硬件寄存器来监视,速度很快。

3. 继续运行程序

gdb 复制代码
(gdb) continue
Continuing.

程序会一直运行,直到 sum 的值发生变化。

4. 触发监视点

当第一次执行 sum += n 后,GDB 会突然暂停:

复制代码
Hardware watchpoint 2: sum

Old value = 0
New value = 1
add (n=1) at watch_demo.c:7
7	}

它告诉我们:

  • 监视点编号 2
  • sum 的旧值是 0,新值变成了 1
  • 程序停在修改 sum 的那一行(实际上是 add 函数的第 7 行,即修改 sum 语句的结束)

此时你可以用 print n 查看参数,用 backtrace 查看调用栈。

5. 继续运行,观察每次变化

gdb 复制代码
(gdb) continue
Continuing.
After adding 1, sum = 1

Hardware watchpoint 2: sum

Old value = 1
New value = 3
add (n=2) at watch_demo.c:7
7	}

重复操作,每次 sum 被修改都会暂停,直到程序结束。


四、监视局部变量

如果监视的是局部变量,必须在它的作用域内设置 watch,并且一旦离开作用域,监视点会自动删除。

例子 :监视 main 中的循环变量 i

gdb 复制代码
(gdb) break main
(gdb) run
(gdb) watch i
Hardware watchpoint 3: i
(gdb) continue

但需要注意:当 i 在循环内频繁被修改,每次都会触发,可能过于频繁。如果只想在某个特定条件下暂停,可以用条件监视点(见后文)。


五、监视表达式

watch 不仅可以监视单个变量,还可以监视任何合法的表达式。只要表达式的值发生变化,就会触发。

示例 :监视 sum + i(虽然这不太常用,但展示灵活性)

gdb 复制代码
(gdb) watch sum + i

sumi 任何一个变化导致 sum + i 的结果改变时,都会触发。

注意:复杂表达式可能无法使用硬件监视点,此时 GDB 会自动降级为软件监视点,软件监视点会让程序单步执行,非常慢,应尽量避免。


六、条件监视点

就像断点可以加条件一样,watch 也可以加条件,只关心特定情况。

格式

gdb 复制代码
watch 变量
condition 监视点编号 条件

或者一步到位:

gdb 复制代码
watch 变量 if 条件

示例 :只监视 sum 被修改且新值大于 2 时才暂停。

gdb 复制代码
(gdb) watch sum
(gdb) condition 2 sum > 2

或者:

gdb 复制代码
(gdb) watch sum if sum > 2

这样,当 sum 从 1 变到 3 时会触发(新值 3 > 2),但之前 sum 从 0 变到 1 时不会触发。


七、管理监视点

监视点和断点共用相同的编号体系,所以可以用管理断点的命令来管理监视点。

命令 作用
info watchpointsinfo breakpoints 查看所有监视点和断点
delete 编号 删除指定监视点/断点
disable 编号 暂时禁用监视点
enable 编号 启用监视点
ignore 编号 count 忽略监视点触发 count 次(针对软件监视点)

示例

gdb 复制代码
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x... in main at watch_demo.c:12
2       hw watchpoint  keep y                      sum
(gdb) delete 2

就会删除对 sum 的监视。


八、硬件监视点 vs 软件监视点

  • 硬件监视点 (hw watchpoint)
    依赖处理器提供的调试寄存器,数量有限(一般 x86 有 4 个),但对程序运行速度几乎无影响。
  • 软件监视点 (sw watchpoint)
    当硬件监视点不够用或表达式复杂无法用硬件实现时,GDB 会使用软件监视点。其原理是每执行一条指令后都检查变量是否变化,导致程序运行极慢 。如果看到 Software watchpoint 提示,要尽量简化监视表达式。

查看监视点类型info breakpoints 中 Type 列会显示 hw watchpointwatchpoint(软件)。


九、实战综合示例:追踪一个神秘错误

假设有一个程序,某个变量 counter 莫名被清零,我们可以这样调试:

gdb 复制代码
(gdb) watch counter
Hardware watchpoint 1: counter
(gdb) run
...
Hardware watchpoint 1: counter

Old value = 100
New value = 0
0x... in some_function () at buggy.c:42

立刻就找到了清零的代码位置。


十、✅ watch 命令速查卡

命令 简写 作用 示例
watch 变量 wa 变量 当变量被写入时暂停 watch sum
rwatch 变量 rw 变量 当变量被读取时暂停 rwatch flag
awatch 变量 aw 变量 当变量被读或写时暂停 awatch status
watch 变量 if 条件 - 条件监视 watch x if x > 10
info breakpoints i b 列出所有监视点和断点 i b
delete 编号 d 编号 删除监视点/断点 d 2
disable 编号 - 禁用监视点 disable 3
enable 编号 - 启用监视点 enable 3

十一、练习(由易到难)

基础篇

  1. 使用上面的 watch_demo.c 程序,在 GDB 中对 sum 设置写监视点,运行并记录每次触发时的新值。
  2. 在同一个程序中,尝试对 main 中的局部变量 i 设置 watch i,观察触发频率。然后删除该监视点。
  3. 使用 awatch sum,观察程序是否在读取 sum 时也会暂停(如在 printf 中)。

进阶篇

  1. 编写一个小程序 swap_test.c,内容如下:

    c 复制代码
    #include <stdio.h>
    void swap(int *a, int *b) {
        int temp = *a;
        *a = *b;
        *b = temp;
    }
    int main() {
        int x = 5, y = 10;
        printf("Before: x=%d, y=%d\n", x, y);
        swap(&x, &y);
        printf("After: x=%d, y=%d\n", x, y);
        return 0;
    }

    在 GDB 中:

    • x 设置写监视点(注意:xmain 中的局部变量,需在进入 main 后设置)。
    • 运行程序,观察 x 是否在 swap 中被修改,GDB 会停在哪里?
    • backtrace 查看调用栈。
  2. 对指针变量设置监视点:在 swap 函数内,对 *a 设置 watch *a,观察它何时变化。

提高篇

  1. 编写一个程序,包含一个全局数组 int data[10]。在循环中修改 data[3] 的值。在 GDB 中对 data[3] 设置写监视点(直接 watch data[3])。注意观察,硬件监视点可能支持,但若提示软件监视点,解释原因并记录运行速度。
  2. 尝试条件监视:监视 sum 只在变为偶数时暂停(watch sum if sum % 2 == 0)。用之前的 watch_demo.c 验证。

十二、答案与关键点解析

基础篇

  1. 每次暂停输出新旧值,依次为 0→1, 1→3, 3→6。
  2. i 每次循环变化都会触发,非常频繁。
  3. awatch sum 会在 printf 读取 sum 时也触发(如果监视成功),通常硬件支持读写监视。

进阶篇

  1. 编译加 -g -O0watch x 必须在 main 断点后设置。当执行 swap(&x,&y) 时,*a 的修改会改变 x,GDB 会停在 *a = *b; 或下一行。backtrace 显示 swapmain
  2. swap 函数内 watch *a,会在 *a = *b 时触发,旧值 5,新值 10。

提高篇

  1. 对数组元素 data[3] 设置监视点通常可以用硬件监视点(如果支持)。若是软件监视点,运行会明显变慢。
  2. 条件监视:watch sum if sum % 2 == 0。当 sum 从 0 变 1(不触发),1 变 3(不触发),3 变 6(触发,因为新值 6 是偶数)。

十三、学习检查清单

  1. watchbreak 的根本区别是什么?
  2. 设置 watch x 后,什么时候程序会暂停?
  3. 如果监视的局部变量离开了作用域,会发生什么?
  4. 如何查看当前设置的所有监视点?如何删除一个监视点?
  5. 硬件监视点和软件监视点有什么区别?哪种更快?
  6. 怎样设置"只在新值为负数时才暂停"的监视点?

如果这些问题都能流畅回答,说明你已经把 watch 命令的核心用法完全吸收。现在,你可以用这把"变量监控刀"去精准地剖析任何程序中的数据变化。实际编程中,结合 breakprintwatch,你将拥有非常强大的调试能力。继续加油!

相关推荐
极客先躯8 小时前
高级java每日一道面试题-2026年04月18日-实战篇[Docker]-如何处理金融行业的时序数据容器化?
java·运维·docker·容器·金融·时序数据·高级面试
运维大师8 小时前
【K8S 运维实战】01-K8s架构深度剖析
运维·架构·kubernetes
liulilittle8 小时前
论无知:分布式
服务器·网络·分布式·并发·通信·竞态
Web极客码8 小时前
MariaDB 将成为 cPanel 中的默认数据库
服务器·mariadb·cpanel
HackTwoHub8 小时前
等级保护现场测评系统重磅更新,支持 AI 接入,可录入全品类资产清单,自动化巡检核查,批量导出测评归档文件
运维·人工智能·安全·web安全·网络安全·自动化·系统安全
川石课堂软件测试8 小时前
安全测试|服务器安全加固方法
服务器·功能测试·测试工具·jmeter·mysql·web安全·单元测试
2401_858286119 小时前
OS79.【Linux】POSIX信号量
linux·运维·服务器
公众号:fuwuqiBMC9 小时前
(转自“服务器BMC”)服务器BMC功能——DDR故障预测
运维·服务器·人工智能
会助力智能会务9 小时前
会务系统供应商怎么选?会助力智能会务系统,一站式数字化会务服务商
大数据·运维·人工智能
CHANG_THE_WORLD9 小时前
2.实现简单的循环通信
服务器·网络