排错与调试

目录

set -x打印脚本运行时的所有信息

GDB调试

下载GDB

生成Debug版本可执行文件

把gdb的日志保存下来

GDB的常用命令

GDB调试带参数的程序

屏蔽前置信息

break普通断点

指定行号或函数名打断点

条件断点

删除断点

禁用断点

watch观察断点

查看变量或表达式的值

查看堆栈信息

backtrace命令

frame命令

core文件

生成core文件

第一步:设置core文件开关

永久修改core文件开关的方法

第二步:生成可执行文件,并运行

第三步:gdb error core 调试core文件。

代码检测工具

静态检测工具

动态调试工具

动态调试完整命令使用方法

动态检测中相关名词的解释


set -x打印脚本运行时的所有信息

  • 在运行脚本 .sh 文件时,可以在代码开头添加 set -x 命令打印运行脚本时的所有信息。

 

  • 也可以在执行文件时添加 sh -x 前缀

GDB调试

下载GDB

  • centos7中采用yum下载软件:yum install gdb
  • Ubuntu中采用apt-get下载软件:sudo apt-get install gdb
  • gdb -v 可以查看当前安装的 gdb版本

生成Debug版本可执行文件

注意:在编译可执行文件时,必须加 -g 生成Debug版本的可执行文件才可以被调试(默认生成的是release版本的,不可被调试)

 

把gdb的日志保存下来

  • 先进入 gdb 调试模式
  • set logging file debug.txt 将log调试信息保存在debug.txt文件中。
  • set logging on 表示从此时开始保存。

GDB的常用命令

  • gdb 可执行文件 (进入调试模式)
    • shell [命令] :执行shell命令

 

GDB调试带参数的程序

  • 先进入调试模式 : gdb main
  • 然后输入参数:set args 1 2 3 4 5 6 7 8 9
  • 使用show args 可以查看设置的参数

 

屏蔽前置信息

  • gdb启动时会打印一些免责条款,可以使用 -silent 或者 -quiet (-q)屏蔽掉

 

break普通断点

  • 可以缩写为 b

指定行号或函数名打断点

  • 语法格式:break [location]

 

条件断点

  • 语法格式:break [...] if [cond]
    • [...] 可以是上述表中的所有参数类型,用于指定打断点的位置
    • [cond] 是一个表达式
    • 整体意思是:每次执行到 [...] 位置时,都判断 [cond] 表达式,如果为 true 则停止。

删除断点

  • 方法一:clear location
    • location 可以为行号或函数名。
  • 方法二:delete [num]
    • num :可以为指定的断点编号,也可以不指定参数,即删除所有断点

禁用断点

  • 语法:disable [num...]
    • num... :表示可以有多个参数,同时取消所指定的所有断点
    • 若不设定num值,则取消所有的断点。

watch观察断点

  • 观察断点可以监控程序中某个变量或者表达式的值,只要发生改变,程序就会停止执行。
  • 语法:watch [cond]
    • cond :为表达式或变量
  • 和 watch 命令功能相似的,还有 rwatch 和awatch 命令。其中:
    • rwatch 命令:只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;
    • awatch 命令:只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。

查看变量或表达式的值

使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。

  • 方法一:print [cond] (可以缩写为 p)
    • 查看特定文件中的变量:print file::cond
    • 查看特定函数中的变量:print function::cond
  • 方法二:display [cond]
  • 方法三:info 系列
    • info break :打印所有的断点
    • info locals :打印所有的局部变量
    • info args :打印传入的参数
    • info fram :查看当前栈帧中的所有信息

查看堆栈信息

backtrace命令

  • backtrace 命令用于打印当前调试环境中所有栈帧的信息
  • 语法格式:backtrace [-full] [n]
    • n :为一个整数值,当为正整数时,表示打印最里层的 n 个栈帧的信息;n为负整数时,那么表示打印最外层n个栈帧的信息
    • -full :打印栈帧信息的同时,打印出局部变量的值。
    • 注意:当调试多线程程序时,该命令仅用于打印当前线程中所有栈帧的信息。如果想要打印所有线程的栈帧信息,应执行 thread apply all backtrace 命令。

frame命令

  • 方法一:frame spec
    • 根据栈帧编号或者栈帧地址,选定要查看的栈帧
  • 方法二: info frame
    • 依次打印出当前栈帧的所有信息

core文件

  • linux下可能需要更改文件:sudo vi /etc/security/limits.conf
  • 文件末尾添加:
    • (用户名) hard core unlimited
    • (用户名) soft core unlimited

生成core文件

第一步:设置core文件开关

  • 使用 ulimit -a 查看core文件信息
  • 如果 core file size 显示为 0 ,则表示没有打开core文件开关
  • 使用命令 :ulimit -c [kbytes] 设置系统允许生成的core文件大小
    • ulimit -c 0 不产生core文件
    • ulimit -c 100 设置core文件最大为100k
    • ulimit -c unlimited 不限制core文件大小

永久修改core文件开关的方法

  • vim /etc/p
  • rofile 进入文件在最底部添加 ulimit -c unlimited 保
  • 存并退出
  • 重启服
  • 务器或使用 source /etc/profile 命令使修改生效。

第二步:生成可执行文件,并运行

  • 若出现段错误,则会在运行程序的目录下生成core文件。

第三步:gdb error core 调试core文件。

代码检测工具

静态检测工具

  • 静态检测可以检测未使用的变量,类型不一致,使用未定义变量,无法执行的代码,忽略返回值,执行路径未返回,无限循环等错误
  • 安装splint:sudo apt install splint
  • splint error.c 检测代码

 

动态调试工具

  • 动态检测可以检测越界访问、使用未初始化的内存、堆内存释放不正确、内存泄漏、src和dst重叠等问题。
  • 安装valgrind:sudo apt install valgrind
  • 命令格式 valgrind [valgrind-options] [your-program] [your-program-options]
  • valgrind-options:
    • memcheck 是重量级内存检测工具。
    • cachegrind 检查程序中缓存使用出现的问题。
    • callgrind 检查程序中函数调用过程中出现的问题。
    • helgrind 检测多线程中的数据竞争问题。
    • drd 也用于分析多线程。与Helgrind类似,但是用不同的分析技术,所以可以检测不同的问题。
    • massif,检查程序中堆栈使用中出现的问题。
    • dhat 是一种不同类型的堆分析器。 它可以帮助您了解块生命周期、块利用率和布局效率低下的问题。
    • bbv 是一个实验性的 SimPoint 基本块向量生成器。 它对从事计算机体系结构研究和开发的人很有用。
  • 后面两个参数可以省略。
    • 例如:valgrind --tool=memcheck ./test

动态调试完整命令使用方法

  • 命令格式:valgrind [valgrind-options] [your-program] [your-program-options]
  • 例如:valgrind --tool=memcheck --log-file=./log ./check (将日志输出到指定文件中)
    • -tool=最常用的选项。运行valgrind中名为toolname的工具。默认memcheck。
    • h –help显示帮助信息。
    • -version显示valgrind内核的版本,每个工具都有各自的版本。
    • q –quiet安静地运行,只打印错误信息。
    • v –verbose更详细的信息,增加错误数统计。
    • -trace-children=no|yes跟踪子线程? [no]
    • -track-fds=no|yes跟踪打开的文件描述?[no]
    • -time-stamp=no|yes增加时间戳到LOG信息? [no]
    • -log-fd=输出LOG到描述符文件 [2=stderr]
    • -log-file=将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID
    • -log-file-exactly=输出LOG信息到 file
    • -log-file-qualifier=取得环境变量的值来做为输出信息的文件名。 [none]
    • -log-socket=ipaddr:port输出LOG到socket ,ipaddr:port
  • LOG信息输出
    • -xml=yes将信息以xml格式输出,只有memcheck可用
    • -num-callers= show callersin stack traces [12]
    • -error-limit=no|yes如果太多错误,则停止显示新错误? [yes]
    • -error-exitcode=如果发现错误则返回错误代码 [0=disable]
    • -db-attach=no|yes当出现错误,valgrind会自动启动调试器gdb。[no]
    • -db-command=启动调试器的命令行选项[gdb -nw %f %p]
  • 适用于Memcheck工具的相关选项:
    • -leak-check=no|summary|full要求对leak给出详细信息? [summary]
    • -leak-resolution=low|med|high how much bt merging in leakcheck [low]
    • -show-reachable=no|yesshow reachable blocks in leak check? [no]

动态检测中相关名词的解释

  • "definitely lost":确认丢失。程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。
  • "indirectly lost":间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与"definitely lost"一起出现,只要修复"definitely lost"即可。
  • "possibly lost":可能丢失。大多数情况下应视为与"definitely lost"一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址),然后通过运算得到这块内存起始地址,再释放它。例子可参考我的例程。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存的起始地址,但可以访问其中的某一部分数据,则会报这个错误。
  • "still reachable":可以访问,未丢失但也未释放。如果程序是正常结束的,那么它可能不会造成程序崩溃,但长时间运行有可能耗尽系统资源,因此笔者建议修复它。如果程序是崩溃(如访问非法的地址而崩溃)而非正常结束的,则应当暂时忽略它,先修复导致程序崩溃的错误,然后重新检测。
  • "suppressed":已被解决。出现了内存泄露但系统自动处理了。可以无视这类错误。这类错误我没能用例程触发,看官方的解释也不太清楚是操作系统处理的还是valgrind,也没有遇到过。所以无视他吧~

 

  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值