找回密码
 立即注册
首页 资源区 代码 GDB调试(一)

GDB调试(一)

厌外 3 天前
GDB调试

GDB简介

GDB的功能

GDB(GNU Debugger)是用于调试 C、C++ 等语言的强大工具。它允许开发者执行以下操作:

  • 启动程序并按照预期条件暂停(如断点处)。
  • 检查程序中的变量和内存状态。
  • 单步执行代码,观察每一步的变化。
  • 修改运行中的变量值以测试不同的假设。
  • 调试程序崩溃、段错误等问题。
GDB的优缺点

虽然现在大多数 IDE 都集成了强大的调试器,但 GDB 依然是开发者的首选工具之一,特别是在特定场景下。GDB 的优点包括:

  • 轻量级:作为命令行工具,GDB 占用资源少,适合在远程服务器或嵌入式系统上使用。
    功能强大:支持断点、单步执行、变量查看、调用栈查看、远程调试等功能,适合调试复杂的程序。
  • 远程调试:GDB 可以在本地调试远程运行的程序,非常适合服务器端应用或嵌入式开发。
但是,GDB 也有一些缺点:

  • 命令行操作有学习成本:相比 IDE 的图形化界面,GDB 的命令行操作对新手不太友好。
  • 缺乏图形界面:没有图形化界面,查看变量和执行流程不如 IDE 那样直观。
GDB使用

GDB编译

在使用 GDB 调试时,确保编译程序时使用 -g 选项生成调试信息。这些信息会帮助 GDB 识别源代码中的变量名、函数、行号等:
  1. gcc -g -o test1 test1.c
复制代码
如果没有加 -g,GDB 只能调试汇编层面的代码,无法看到源码中的具体行号和变量名称。
启动GDB

可以通过gdb+可执行文件来调试程序
  1. gdb test1
复制代码
1.png

测试程序

以下程序用于文件拷贝,可以将a.txt种的内容拷贝到b.txt
  1. //此程序演示文本文件拷贝 test1.c
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "test_show.h"
  6. int main(int argc, char *argv[])
  7. {
  8.     if(argc != 3)
  9.     {
  10.         printf("这是一个文件复制程序\n");
  11.         return -1;
  12.     }
  13.     FILE *srcfp, *dstfp;
  14.     srcfp = dstfp = 0;
  15.    
  16.     //以下定义静态数组和动态数据单纯用于gdb学习测试
  17.     int a[6] = {1,2,3,4,5,6};
  18.     a[1]++;
  19.     test2 *new_test = NULL;
  20.     new_test = malloc(sizeof(test2));
  21.     if(NULL == new_test)
  22.     {
  23.             printf("new_test is NULL\n");
  24.             return -1;
  25.     }
  26.     for(int i = 0; i < TEST_ARRAY; i++)
  27.     {
  28.             new_test->fff[i].aaa = i;
  29.             new_test->fff[i].bbb = i+1;
  30.             new_test->fff[i].ccc = 'a'+i;
  31.             new_test->fff[i].ddd = 'a' + i + 1;
  32.     }
  33.     show_array_result(new_test);
  34.    
  35.     //以只读的方式打开源文件,方式是rb
  36.     if((srcfp = fopen(argv[1], "r+")) == 0)
  37.     {
  38.         printf("fopen %s failed\n", argv[1]);
  39.         return -1;
  40.     }
  41.     //以只写的方式打开源文件,方式是wb
  42.     if((dstfp = fopen(argv[2], "w+")) == 0)
  43.     {
  44.         printf("fopen %s failed\n", argv[2]);
  45.         return -1;
  46.     }
  47.     int nread = 0; //每次读取到内容的字节数
  48.     char strbuf[50];//这里特意让数组大小小一点,方便后续多打印一些nloop
  49.     int nloop = 0;//记录while循环的次数
  50.     while(1)
  51.     {
  52.         //从源文件中读取数据,并写入到目标文件
  53.         memset(strbuf,0,sizeof(strbuf));
  54.         if((nread = fread(strbuf,sizeof(char),sizeof(strbuf),srcfp)) == 0)
  55.         {
  56.             break;
  57.         }
  58.         nloop++;
  59.         showresult(nloop);
  60.         fwrite(strbuf,1,nread,dstfp);
  61.     }
  62.     fclose(srcfp);
  63.     fclose(dstfp);
  64.     free(new_test);
  65.     printf("文件打印成功\n");
  66.     return 0;
  67. }
复制代码
  1. #include "test_show.h"
  2. void showresult(int nloop)
  3. {
  4.     int a = 0;
  5.     printf("nloop:%d\n", nloop);
  6.     a++;
  7. }
  8. void show_array_result(test2* new_test)
  9. {
  10.     if(NULL == new_test)
  11.     {
  12.             printf("new_test is null\n");
  13.             return;
  14.     }
  15.     for(int i = 0; i < TEST_ARRAY; i++)
  16.     {
  17.             printf("aaa:%d, bbb:%d, ccc:%c, ddd:%c\n", new_test->fff[i].aaa, new_test->fff[i].bbb, new_test->fff[i].ccc, new_test->fff[i].ddd);
  18.     }
  19. }
  20. //test_show.c
复制代码
  1. #include <stdio.h>
  2. #define TEST_ARRAY (4)
  3. typedef struct
  4. {
  5.     int aaa;
  6.     int bbb;
  7.     char ccc;
  8.     char ddd;
  9. }test1;
  10. typedef struct
  11. {
  12.     test1 eee;
  13.     test1 fff[TEST_ARRAY];
  14. }test2;
  15. void showresult(int nloop);
  16. void show_array_result(test2* new_test);
  17. //test_show.h
复制代码
  1. cc -g -o test1 test1.c test_show.c test_show.h
  2. ./test1 a.txt b.txt
  3. //运行结果
  4. aaa:0, bbb:1, ccc:a, ddd:b
  5. aaa:1, bbb:2, ccc:b, ddd:c
  6. aaa:2, bbb:3, ccc:c, ddd:d
  7. aaa:3, bbb:4, ccc:d, ddd:e
  8. nloop:1
  9. nloop:2
  10. nloop:3
  11. nloop:4
  12. nloop:5
  13. nloop:6
  14. nloop:7
  15. nloop:8
  16. 文件打印成功
复制代码
GDB常用命令

1.查看源代码

命令解析list查看源代码,默认显示10行list number指定查看行的代码,比如list 10,未指定行数则默认查看最近十行源码list fun查看fun函数源代码list file:fun/number查看file文件fun函数/第number行的源代码set listsize设置一次显示源代码的行数show listsize查看当前listsize的设置
2.png

2.程序运行参数

命令解析set args设置运行参数show args命令可以查看设置好的运行参数
3.png

3.断点的添加

使用break或者b命令添加断点
命令解析break function在进入指定函数时停住break n在指定行号停住,如(gdb) break 46break +offset/-offset在当前行号的前面或后面的offset行停住。offiset为自然数。break filename:linenum在源文件filename的linenum行处停住。break filename:function在源文件filename的function函数的入口处停住。break *address在程序运行的内存地址处停住,如如:(gdb) b *0x804835c。break条件判断比如break showresult if nloop==5watch 变量相当于给变量设置断点,每当变量发生变化就断在那里4.断点的删除

命令解析delete n删除n号断点delete删除所有断点clear n清除行n上所有断点disable/enable n临时关闭或者启用n号断点
4.png

5.png

6.png

5.程序运行进度调试

命令解析run|r从头开始执行程序,直到遇到断点continue|c继续执行程序(此时已经run过了),直到下个断点next|n执行下一行语句step|s单步进入finish跳出当前函数jump location跳转指令
7.png

6.打印程序相关信息

命令解析print file::variable打印文件中的变量print function::variable打印函数中的变量display 变量名实时跟踪并输出该变量的变化信息。和 print 命令一样,display 命令也用于调试阶段查看某个变量或表达式的值,它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。undisplay取消display的设置
8.png

9.png

7.修改程序相关信息

命令解析set该命令用来改变运行过程中的变量值
10.png

8.函数调用查看

命令解析backtrack命令产生一张列表,包含着从最近的过程开始的所有有效过程和调用这些过程的参数。info frame显示栈帧信息info frame命令会依次打印出当前栈帧的如下信息:
1、当前栈帧的编号,以及栈帧的地址;
2、当前栈帧对应函数的存储地址,以及该函数被调用时的代码存储的地址
3、当前函数的调用者,对应的栈帧的地址;
4、编写此栈帧所用的编程语言;
5、函数参数的存储地址以及值;
6、函数中局部变量的存储地址;
7、栈帧中存储的寄存器变量,例如指令寄存器(64位环境中用 rip 表示,32为环境中用eip 表示)、
堆栈基指针寄存器(64位环境用 rbp表示,32位环境用 ebp表示)等。
11.png

9.多线程/进程下调试GDB

命令解析-p 进程名对相关进程进行调试attach 进程名切换到相关进程info thread列出线程thread 线程名切换至线程info register列出寄存器info frame列出栈帧info files列出当前文件info share列出当前共享库引用

[转帖]gdb调试常见命令详细总结(附示例操作)_51CTO博客_gdb调试命令的使用及总结
Linux下GDB调试一篇入魂(GDB调试详解) - 简书
c语言gdb调试之精髓

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册