欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > 调试器-gdb/cgdb使⽤ 扩展 watch set var 条件断点

调试器-gdb/cgdb使⽤ 扩展 watch set var 条件断点

2025/3/21 13:44:23 来源:https://blog.csdn.net/LJY_CF/article/details/146406154  浏览:    关键词:调试器-gdb/cgdb使⽤ 扩展 watch set var 条件断点

1-1样例代码

wlw.c

#include <stdio.h>
int Sum(int s, int e)
{int result = 0;for (int i = s; i <= e; i++){result += i;}return result;
}
int main()
{int start = 1;int end = 100;printf("开始运行\n");int n = Sum(start, end);printf("结果是: [%d-%d]=%d\n", start, end, n);return 0;
}

1-2调试工具

  • 程序的发布⽅式有两种,默认是 debug 模式和 release 模式, Linux gcc/g++ 出来的⼆进制程序,默认是release 模式。

  • 要使⽤gdb调试,必须在源代码⽣成⼆进制程序的时候,加上 -g 选项,如果没有添加,程序⽆法被编译

⚠️:不能用gcc 因为 gdb是调试工具,gcc是编译工具   

 make和Makefile  在这有讲解

生成可执行文件a1 

 1-3 cgdb常⻅使⽤

第一步 先下载

安装cgdb:

• Ubuntu: sudo apt-get install -y cgdb

• Centos: sudo yum install -y cgdb

 第二步进入cgdb

cgdb 可执行文件

 1-4 指令

命令格式作用样例
list / l显示源代码,从上次位置开始,每次列出 10 行list 10
list / l 函数名列出指定函数的源代码list main
list / l 文件名:行号列出指定文件的源代码list mycmd.c:1
r / run从程序开始连续执行run
n / next单步执行,不进入函数内部next
s / step单步执行,进入函数内部step
break / b [文件名:] 行号在指定行号设置断点break 10
break test.c:10
break / b 函数名在函数开头设置断点break main
info break / info b查看当前所有断点的信息info break
finish执行到当前函数返回,然后停止finish
print / p 表达式打印表达式的值print start+end
p 变量打印指定变量的值p x
set var 变量 = 值修改变量的值set var i=10
continue / c从当前位置开始连续执行程序continue
delete / d breakpoints删除所有断点delete breakpoints
delete / d breakpoints n删除序号为 n 的断点delete breakpoints 1
disable breakpoints禁用所有断点disable breakpoints
enable breakpoints启用所有断点enable breakpoints
info breakpoints / info i breakpoints查看当前设置的断点列表info breakpoints
display 变量名跟踪显示指定变量的值(每次停止时)display x
undisplay 编号取消对指定编号的变量的跟踪显示undisplay 1
until 行号执行到指定行号until 20
backtrace / bt查看当前执行栈的各级函数调用及参数backtrace
info locals / info i locals查看当前栈帧的局部变量值info locals
quit退出 GDB 调试器quit

小知识:进入页面 esc 暂停 用⬆️⬇️箭头可以翻代码,i 回到指令页面 

list/l

显⽰源代码,从上次位置开始,每次列出 10⾏

 list/l 函数名

列出指定函数的源代码

 list/l ⽂件名:⾏号

 列出指定⽂件的源代码

 r/run

 从程序开始连续执⾏

break/b [⽂件名:]⾏号

在指定⾏号设置断点

break 10 break test.c:10

 info break/b

查看当前所有断点的信息

 ⚠️:End 断点可以被使能 ---》开始或关闭

 print/p 表达式

打印表达式的值  print start+end

 

p 变量

打印指定变量的值k

扩展 

watch <变量名>

1. watch 命令概述

watch 是 GDB 中一个非常实用的命令,主要用于在程序运行过程中监视特定表达式(通常是变量)的值。一旦被监视的表达式的值发生改变,GDB 就会暂停程序的执行,这样开发者可以及时捕获变量值的变化,进而分析程序的运行状态和可能存在的问题。

2. 基本语法和示例

2.1 监视变量
  • 语法watch <变量名>
  • 示例
    假设我们有一个简单的 C 程序:
#include <stdio.h>int main() {int num = 0;for (int i = 0; i < 5; i++) {num += i;}return 0;
}

在 GDB 中对 num 变量进行监视:

(gdb) watch num
Hardware watchpoint 1: num

这里设置了一个硬件监视点,当 num 的值发生变化时,GDB 会暂停程序。当程序执行到 num += i; 语句时,由于 num 的值会改变,GDB 就会暂停程序并给出相应提示。

2.2 监视表达式
  • 语法watch <表达式>
  • 示例
    如果我们要监视 num + i 这个表达式的值的变化,在 GDB 中可以这样操作:
(gdb) watch num + i
Hardware watchpoint 2: num + i

当 num + i 的计算结果发生变化时,GDB 会暂停程序。

3. 相关配套命令

3.1 info watchpoints
  • 作用:查看当前设置的所有监视点的信息,包括监视点编号、监视的表达式、触发条件等。
  • 示例
(gdb) info watchpoints
Num     Type           Disp Enb Address    What
1       hw watchpoint  keep y              num
2       hw watchpoint  keep y              num + i

这里显示了两个监视点的相关信息。

3.2 delete watchpoints <编号>
  • 作用:删除指定编号的监视点。
  • 示例
(gdb) delete watchpoints 2
(gdb) info watchpoints
Num     Type           Disp Enb Address    What
1       hw watchpoint  keep y              num

删除了编号为 2 的监视点后,再次查看监视点信息,只剩下编号为 1 的监视点。

3.3 disable watchpoints <编号> 和 enable watchpoints <编号>
  • 作用disable watchpoints <编号> 用于禁用指定编号的监视点,禁用后该监视点不会触发程序暂停;enable watchpoints <编号> 则用于重新启用被禁用的监视点。
  • 示例
(gdb) disable watchpoints 1
(gdb) info watchpoints
Num     Type           Disp Enb Address    What
1       hw watchpoint  keep n              num
(gdb) enable watchpoints 1
(gdb) info watchpoints
Num     Type           Disp Enb Address    What
1       hw watchpoint  keep y              num

先禁用了编号为 1 的监视点(Enb 列变为 n 表示禁用),之后又重新启用(Enb 列变为 y 表示启用)。

4. 注意事项

  • 硬件监视点限制:大多数系统对硬件监视点的数量是有限制的,一般可能只有 4 个左右。如果需要监视的变量较多,可能会受到硬件资源的限制。
  • 性能影响:使用 watch 命令会对程序的性能产生一定的影响,因为 GDB 需要不断检查监视表达式的值是否发生变化。在调试大型程序时,这种性能影响可能会更加明显。

(提示:此处可以插入一张 GDB 中设置监视点并触发暂停的终端截图,展示 watch 命令的实际效果)

set var

一、验证变量值错误引发的问题

程序运行异常可能源于变量值错误。利用 set var 赋予变量预期值,观察程序是否恢复正常,从而判断该变量是否为问题根源。

  • 场景:计算结果错误,怀疑某变量取值异常。
  • 示例
    #include <stdio.h>  
    int main() {  int a = 5, b = 3;  int result = a + b; // 预期结果为 10,实际错误  printf("Result: %d\n", result);  return 0;  
    }  
    

    调试操作
    (gdb) break 4  
    (gdb) run  
    (gdb) print a  // 查看 a=5  
    (gdb) print b  // 查看 b=3  
    (gdb) set var a = 7  // 假设 a 应为 7  
    (gdb) continue  
    // 若结果正确,说明原 a 的值错误是问题原因  
    

二、修正变量值排查程序流程

通过修改变量值,改变程序执行路径,验证逻辑是否符合预期。

  • 场景:条件判断因变量值错误进入错误分支。
  • 示例
    #include <stdio.h>  
    int main() {  int flag = 0;  if (flag) {  printf("Enter correct branch\n");  } else {  printf("Enter wrong branch\n"); // 预期应进正确分支  }  return 0;  
    }  
    

    调试操作:
    (gdb) break 4  
    (gdb) run  
    (gdb) set var flag = 1  // 强制设为 1  
    (gdb) continue  
    // 若进入正确分支,说明原 flag 值错误导致流程问题  
    

三、模拟特殊值触发隐藏问题

给变量赋边界值、特殊值,暴露隐藏的逻辑错误(如数组越界)。

  • 场景:数组索引越界导致程序崩溃。
  • 示例
    #include <stdio.h>  
    int main() {  int arr[5] = {1,2,3,4,5};  int index = 5;  printf("Value: %d\n", arr[index]); // 越界  return 0;  
    }  
    
    调试操作:
    (gdb) break 4  
    (gdb) run  
    (gdb) set var index = 4  // 设为合法值  
    (gdb) continue  
    // 若程序正常,说明原 index 越界是问题源头  
    

通过 set var 主动干预变量值,观察程序行为变化,可快速缩小问题范围,精准定位因变量值异常导致的程序错误,是调试中分析问题原因的关键手段。

条件断点概述

在调试程序时,普通断点会在每次执行到断点位置时暂停程序,这在某些情况下可能会导致不必要的暂停,浪费调试时间。而条件断点可以根据特定的条件来决定是否暂停程序,这样可以更精准地定位问题,提高调试效率。以下详细介绍添加条件断点的两种常见方式。

方式一:直接添加条件断点

基本语法

在 GDB 中,直接添加条件断点的基本语法为:

break <行号或函数名> if <条件表达式>

其中,<行号或函数名> 指定了断点的位置,<条件表达式> 是一个布尔表达式,当程序执行到断点位置且该条件表达式的值为真时,GDB 才会暂停程序。

示例代码

以下是一个简单的 C 语言示例代码,用于演示直接添加条件断点:

#include <stdio.h>int main() {int i;for (i = 0; i < 10; i++) {printf("i = %d\n", i);}return 0;
}
调试过程

假设我们希望在 i 等于 5 时暂停程序,在 GDB 中可以这样操作:

(gdb) break 5 if i == 5
Breakpoint 1 at 0x11223344: file test.c, line 5.
(gdb) run
Starting program: /path/to/your/program 
i = 0
i = 1
i = 2
i = 3
i = 4
Breakpoint 1, main () at test.c:5
5           printf("i = %d\n", i);
(gdb) print i
$1 = 5

在上述示例中,我们使用 break 5 if i == 5 命令在第 5 行添加了一个条件断点,只有当 i 的值等于 5 时,程序才会暂停。

方式二:给已有断点追加条件

基本语法

给已有断点追加条件的基本语法为:

condition <断点编号> <条件表达式>

其中,<断点编号> 是已存在断点的编号,可以通过 info breakpoints 命令查看,<条件表达式> 是要添加的条件。

示例代码

还是使用上面的示例代码。

调试过程

首先,我们先添加一个普通断点:

(gdb) break 5
Breakpoint 1 at 0x11223344: file test.c, line 5.

然后,使用 condition 命令给这个断点追加条件:

(gdb) condition 1 i == 5
(gdb) info breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x0000555555555122 in main at test.c:5stop only if i == 5

接着运行程序:

(gdb) run
Starting program: /path/to/your/program 
i = 0
i = 1
i = 2
i = 3
i = 4
Breakpoint 1, main () at test.c:5
5           printf("i = %d\n", i);
(gdb) print i
$1 = 5

在这个示例中,我们先添加了一个普通断点,然后使用 condition 命令给该断点追加了条件 i == 5,使得只有当 i 等于 5 时,断点才会触发。

注意事项

  • 条件表达式的合法性:条件表达式必须是有效的布尔表达式,并且在断点位置处引用的变量必须已经定义。
  • 断点编号的准确性:在使用 condition 命令时,要确保指定的断点编号是正确的,否则可能会导致条件添加到错误的断点上。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词