Linux程序调试-常用调试技巧
程序调试阶段:
测试:找出程序的错误或缺陷
固化:让程序错误可重现
定位:确定相关代码行
纠正:修改代码 修正错误
验证:确定修改解决了问题
1 gcc -Wall -pedantic -ansi //gcc 编译 产生编译的警告信息
1取样法:在程序中添加printf等输出程序执行过程中的信息,程序错误修复后需要删除
1 #ifdef DEBUG 2 printf("….\n"); 3 #endif
定义调试级别,输出不同类型的内容
1 #define BASIC_DEBUG 1 2 #define EXTRA_DEBUG 2 3 #define SUPER_DEBUG 4 4 #if (DEBUG & EXTRA_DEBUG) 5 printf... 6 #endif
C语言预处理器定义的一些宏可以帮助我们调试(符号前后各有两个下划线)
无需编译的调试技巧 定义全局变量debug 用户在调用程序执行时使用 -d 调试选项,决定是否打开调试模式
将调试信息存储于文件,可以方便自身或用户自行调试代码,查找问题
1 if (debug) { 2 sprintf(msg, ...) 3 write_debug(msg) 4 }
程序的受控执行
商业版本常见的调试器有adb、sdb、idebug、dbx等 能用那些调试器取决于UNIX系统
GNU使用调试器gdb,一些gdb的前端程序提供非常友好的界面,xxfdb,KDbg,ddd等
-g 选项是对程序进行调试性编译的常用选项,需要在编译每个文件时都加上这个选项,对链接器也要加上-g选项。(编译器会把这个标志自动传递给链接器)
调试信息会使可执行程序的长度成倍增加(最多10倍),虽然可执行程序的大小增加,但使用内存的数量和原来是一样的。
调试完后才能后,可以不经过编译将可执行文件中的调试信息删除
1 strip <file>
使用gdb进行调试
2019年12月3日
10:30
开始调试
1 //进入调试器 2 gdb ./xxx //xxx为可执行文件 此时进入gdb软件 help可查看gdb提供的命令选项 3 //运行 4 run [option] // [option]将作为参数传递给程序 在程序执行错误,gdb将在出错位置退出 若编译时使用了 -g选项 5 //则在程序停止后输出程序终止的位置
栈跟踪
在到达错误位置时,输入backtrance 简写 bt 或 where 输出调用出错函数的函数和出错函数的位置
检查变量
print 可以给出变量和其他表达式的内容,并将表达式的值赋给伪变量 $<number>
最后一次操作的结果总是以$开头,而倒数第二次的结果为$$
列出程序源代码
list
设置断点
1 break 21 //在21行处打断点 打断点之后可以用print 输出当前关注的变量值 2 cont //程序继续执行到下一个断点处 3 display //程序每次停在断点位置时,自动打印关心的变量值 4 command //指定程序在到达断点时执行的命令,以end结束 此时设置 >cont >end
程序每次运行到断点处,自动打印关心的内容,并自动调用程序继续执行指令 设定完成后程序将一直执行到最后 并在过程中输出值
使用调试器打补丁 gcc 可以在程序进行调试时 直接更改变量的值来进行调试
程序下一次调试,使用info display 和 info break 来查看当前显示与断点的内容
1 set variable n = n+1 //设置在调试时,将变量n的值 +1
深入学习gdb 强大的功能
1.在支持硬件断点的cpu上,gdb支持可以在符合某个条件时暂停程序运行
2.gdb可监控表达式的,即当某个表达式取一个特定的值时,gdb可以暂停程序的运行(这样会对性能造成影响)
3.断点、计数、条件可以结合在一起设置
4.gdb还可以将自己附在正在运行的程序上,对异常的程序可以在调试过程中直接进行修改,而不必停下编译并重启
可以在编译时用 gcc -O -g来同时获得程序优化和调试信息 但优化可能会改变程序执行顺序
5.调试崩溃的程序时,Linx通常会产生一个 核心转存储(core dump).这个文件是程序的内存映像文件
一些工具
lint splint LClint等 清理程序中的垃圾,严格编译程序,产生警告
函数调用工具
ctags 为程序中所有的函数创建索引,每个函数对应一个列表,列表列出函数调用位置
cxref 程序分析C语言源代码并生成一个交叉引用的表格
cflow 程序打印出一个函数调用树(function call tree),显示函数之间的调用关系,可以理清程序调用架构,理解操作流程,了解函数的改动将会产生什么样的影响
prof/gprof 产生执行存档
想要查找程序的性能问题时,一种常用的技巧是执行存档(execution profiling),需要特殊的编译选项,执行存档可以显示执行它所花费的时间具体用在哪些步骤上。
给编译器加上 -p 标志(针对prof程序) -pg 标志(针对gprof)
之后执行程序时,将生成mon.out(gmon.out)文件
断言 assert
测试某个假设是否成立,如果不成立就停止程序的运行
#include <assert.h> void assert(int expression)
1 assert //宏对表达式进行求值,如果结果为0,就向标准错误输出一些诊断信息,然后调用abort函数结束程序运行 2 3 #define NDEBUG //关闭断言宏
在产品中保留assert并不可取,因为不希望客户在看到一条assert之后程序强制退出,好的方法是编写自己的错误中断陷阱例程
内存调试
2019年12月3日
13:50
内存调试
1.内存泄露,malloc申请内存后赋给指针,指针的值被改变,此时没有任何指针指向申请的内存,程序运行时间长了之后将会越来越慢,导致内存耗尽
2.在一个已分配的内存块尾部的后面(或在它的前面)写数据,就很可能会损坏malloc库用于记录内存分配的数据结构。之后,一个malloc或free调用都会导致段错误(Segmentation fault)。此时检查错误发生的地点是很困难的。
ElectricFence可以使用Linux的虚拟内存机制来保护malloc 和 free使用的内存。
使用虚拟内存,在出现非法的内存访问时,引发段冲突信号并停止程序的运行
valgrind 可以检测出前边所说的很多问题,特别是可以检测出数组访问错误和内存泄露
在程序运行结束时进行内存泄露的检查 使用 valgrind --leak-check=yes 选项
原文地址:https://www.cnblogs.com/Mrwang-tju/p/12468628.html
- WCF中的Binding模型之一: Binding模型简介
- WCF中的Binding模型之一: Binding模型简介
- 2017最火的五篇深度学习论文 总有一篇适合你
- SplashScreenSource的妙用
- SplashScreenSource的妙用
- SplashScreenSource的妙用
- Nodejs学习笔记(十七)--- 浮点运算decimal.js
- AI时代让自己幸福更是一种能力
- 持续不断地推荐儿童不宜视频背后,YouTube是这样训练AI的
- 人工智能会导致大量失业,你怕吗
- 机器人产业链分析-中国机器人产业的发展机遇和挑战
- 如何与深度学习服务器优雅的交互?
- 比特币大跌又反弹30%,区块链技术与企业级有着怎样的关系?
- 十个实用MySQL函数
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 探索 React 内核:深入 Fiber 架构和协调算法
- [经验]使用Keil MDK+Jlink-OB下载失败的解决办法
- ESP8266两种工作模式数据传输测试
- 『真香警告』这33个超级好用的CSS选择器,你可能见都没见过。
- [踩坑]STM32外部8M晶体不起振会有什么现象?
- 干掉 GuavaCache:Caffeine 才是本地缓存的王
- 美团数据怎么爬,看看这个文章吧!
- [硬件]关于SPI Flash那些你不知道的事儿
- 「新特性」Spring Boot 全局懒加载机制了解一下
- 做olap一定要要了解的Druid存储结构
- 【ST开发板评测】使用Python来开发STM32F411
- 一文详解 Ansible 自动化运维!
- 手把手教你搭建织女星开发板RISC-V开发环境
- R语言多臂试验 - 我们应该考虑多重性吗?
- Stata估算观测数据的风险比