当前位置: 首页 > news >正文

调试工具之GDB的基本使用

GDB基本使用

GDB是Linux下一款非常强大的调试软件,其实就是GNU Debugger的缩写。接下来我们学习一下他的基本使用。
例子函数,其中只有一个ds18b20的采集温度函数和一个主函数:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>int measure_temp(float *temp);int main(int argc,char *argv[])
{float 				   temp = 0;measure_temp(&temp);printf("the temp:%f\n",temp);return 0;
}int measure_temp(float *temp)
{int					   fd = -1;//打开ds18b20时候的文件描述符int					   found = -1;//是否找到chip的参数。char            	   *w1_path = "/sys/bus/w1/devices/"; //文件名的前半段,28-后面不能确定,因为设备号会变化,我们一会获取。char				   chip[32];//文件名的后半段,-28char				   ds_path[128];//拼凑出全部的路径名DIR					   *dirp = NULL;//打开w1时返回的DIR类型文件指针struct dirent          *direntp = NULL;//是readdir后返回的文件夹信息结构体指针char				   buf[1024];char 				   *ptr;//用来指向温度值if (NULL == temp){printf("mesure_temp arguments error:[%s]\n",strerror(errno));return -1;}printf("measure_temp arguments right!\n");//打开devices文件夹if ( NULL == (dirp = opendir(w1_path)) ){printf("open w1_path error:[%s]\n",strerror(errno));return -2;}printf("open w1_path DIR[%p] success!\n",dirp);//readdir查找这个文件夹下有什么while(NULL != (direntp=readdir(dirp))){if (strstr(direntp->d_name,"28-")){strncpy(chip,direntp->d_name,sizeof(chip));//duancuowufound = 1;}}closedir(dirp);if (found < 0){printf("nofind \"-28\" \n");return -3;}printf("find chip success[%s]\n",chip);snprintf(ds_path,sizeof(ds_path),"%s%s/w1_slave",w1_path,chip);printf("ds_path:%s\n",ds_path);if ((fd = open(ds_path,O_RDONLY)) < 0){printf("open error[%s]\n",strerror(errno));return -4;}int i;int *p = NULL;p = &i;//read fd memset(buf,0,sizeof(buf));if ( read(fd,buf,sizeof(buf)) <=0 ){printf("error:[%s]\n",strerror(errno));return -5;}//printf("temperature:[%s]\n",buf);if ( NULL == (ptr = strstr(buf,"t=") )){printf("nofound error[%s]\n",strerror(errno));return -6;}//printf("%s\n",ptr);ptr += 2;*temp = atof(ptr)/1000;return 0;
}

(1)首先我们使用 gcc 直接生成的程序是没有调试信息的,所以我们要使用 gcc -g 命令来生成一个带有调试信息版本的目标文件。

在这里插入图片描述

(2)然后我们用 gdb 来打开这个目标文件,其实就是让带有调试信息的二进制文件在我们 gdb 的这个 “盒子” 里面进行运行。 用 gdb + 目标文件 命令来运行它。

在这里插入图片描述

(3)之后我们就可以开始调试啦!如何让 test_gdb.o 这个文件在gdb中跑起来呢?在 gdb 中输入 run 就可以了。

在这里插入图片描述

(4)不过我们发现,这和不使用 gdb 跑程序没有什么区别,所以我们学习如何增加断点。

增加断点是通过 break 命令来实现的,他有三种基本的使用形式,如下:

(gdb) break main               	# 在 main 函数处设置断点
(gdb) break my_program.c:10    	# 在 my_program.c 文件的第 10 行设置断点
(gdb) break my_function        	# 在 my_function 函数处设置断点

(5)这里假设我们程序异常退出了,但我们不清楚导致退出的错误是发生在 measure 测温函数内还是函数之前,我们就可以在进入这个函数之前,设置一个断点,然后运行它。
在这里插入图片描述我们可以看到,程序成功运行到了这个函数前,没有抛出异常,那么我们就可以确定,异常是在 measure 测温函数内的了。

(6)使用 next 单步执行,但是不进入到函数内部。

在这里插入图片描述

(7)也可以使用step单步执行,但是会进入到函数内部。

在这里插入图片描述

(8)使用bt命令或者backtrace命令显示调用的栈信息:

在这里插入图片描述

(9)显示所有的断点:

在这里插入图片描述

(10)删除特定的某一个断点:

在这里插入图片描述

运行到某一个断点后,要直接运行到下一个断点,使用continue 或者 c 就可以了。若后面没有断点了,那么就会一直运行到结束或者某个循环里面。

命令汇总:

(gdb) break main               	# 在 main 函数处设置断点
(gdb) break my_program.c:10    	# 在 my_program.c 文件的第 10 行设置断点
(gdb) break my_function        	# 在 my_function 函数处设置断点(gdb) next                     # 或 (gdb) n 单步执行,不进入函数内部
(gdb) step                     # 或 (gdb) s 单步执行,进入函数内部
(gdb) finish                   # 运行到当前函数返回的位置
(gdb) until                    # 运行到循环结束的位置(gdb) run                      # 启动程序
(gdb) continue                 # 或 (gdb) c 继续运行直到下一个断点(gdb) backtrace                # 或 (gdb) bt 显示调用栈
(gdb) frame n                  # 切换到调用栈中的第 n 帧
(gdb) info frame               # 显示当前帧的信息
(gdb) info locals              # 显示当前帧的局部变量(gdb) info breakpoints         # 或 (gdb) info b 显示所有断点
(gdb) delete breakpoint_number # 或 (gdb) d breakpoint_number 删除特定断点
(gdb) clear                    # 删除当前行的断点
(gdb) disable breakpoint_number# 禁用特定断点
(gdb) enable breakpoint_number # 启用特定断点

当然,我们也可以在运行过程中对某些变量进行查看和修改:
在这里插入图片描述

这里用到的命令是:

print 变量名  			#打印变量的值,注意,没有print,没有f。
set var 变量 =# 改变某个变量的值
http://www.lryc.cn/news/414692.html

相关文章:

  • C++ //练习 16.14 编写Screen类模板,用非类型参数定义Screen的高和宽。
  • 【Java】深度解析监视器的组成原理
  • Day14-Servlet后端验证码的实现
  • MySQL:数据库权限与角色
  • 等保测评练习卷25
  • 《python语言程序设计》2018第6章第28题 掷骰子 两个色子,分别是1到6
  • Java方法递归
  • 目标跟踪那些事
  • 【Git】 如何将一个分支的某个提交合并到另一个分支
  • 【嵌入式之RTOS】什么是消息队列
  • 9-springCloud集成nacos config
  • 市场主流 AI 视频生成技术的迭代路径
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——1.c++入门(2)
  • 【Python系列】深入理解 Python 中的 `nonlocal` 关键字
  • Flask目录结构路由重定向简单实例讲解——轻量级的 Python Web 框架
  • 破解PyCharm插件更新难题:让IDE焕发新生
  • cmake常用命令学习
  • K8S可视化管理平台KubeSphere
  • Bugku-CTF-聪明的php
  • 【MySQL进阶】MySQL主从复制
  • 本地部署文生图模型 Flux
  • 谷粒商城实战笔记-127-全文检索-ElasticSearch-整合-测试复杂检索
  • 解锁PyCharm:破解依赖库导入之谜
  • JSON-Viewer插件:json格式查看器
  • HDFS块信息异常,spark无法读取数据
  • TCP协议概述
  • SpringSecurity-3(认证和授权+SpringSecurity入门案例+自定义认证+数据库认证)
  • 英国AI大学排名
  • 渗透测试与高级攻防技术(二)网络安全技术的前沿探讨:渗透测试与高级攻防
  • Windows系统下安装mujoco环境的教程【原创】