gdb是一个调试C和C++程序的功能强大的调试器,能在程序运行时观察程序的内部结构和内存使用情况,主要提供以下功能:
- 监视程序中变量的值变化;
- 设置断点,指定代码行上暂停执行;
- 单步执行代码;
- 分析崩溃程序产生的core文件;
在bash(大多数linux系统的默认shell)命令行下直接输入gdb,或指定调试程序:
gdb filename
注:在使用gcc编译时,加上-g选项,程序编译包含调试信息;
在软件开发中,一个很重要的步骤就是软件测试和排除错误。错误有时bug对程序没有多大影响,有时返回错误的结果,但严重的bug甚至会造成程序跑飞、系统死机。开发者找到错误并消灭它们,该行为称为"调试(debug)"
当bug出现时,仅仅去查看源码,很难找出问题所在,需要借助一些手段去找到该些bug,并消灭它们。程序调试常见的手段包括单步调试、硬件调试、打印信息、log文件。
单步调试:利用调试器进行单步调试(如IDE中的Jlink)适合新手,最大好处是直观,能够帮助找到问题。缺点是限制性大、速度慢。
硬件调试:利用产品的硬件(LED、蜂鸣器等)进行调试,该方法比较适合裸机程序。
打印信息:利用printf函数打印调试,比较常见,其好处是具有普遍性,几乎在所有的情况都能使用。
log文件:log文件(日志文件)是系统运行过程中在特定时候打印的一些调试信息。log文件记录了这些调试信息,以供后续追查问题。比较合适系统级或大型程序调试。
调试信息太少会导致找不到问题所在;调试信息太多会导致大量的无用信息淹没有用信息,有用信息无法被测试人员发现。
调试(DEGBUG)版本和发行(RELEASE)版本区别
DEBUG版本包含了调试信息输出的版本。在程序测试时发布的DEBUG版本,在程序运行是会打印调试信息的log文件,可以辅助测试人员判断程序的问题所在。坏处是输出调试信息占用了系统资源,拖慢了系统运行速度,因此DEBUG版本的性能低于RESEALE版本。RELEASE版本是最终发布版本,相较于DEBUG版本,去掉了所有的调试信息,所以程序的运行效率要更高。
debug宏的使用方法
#ifdef DEBUG
#define debug(fmt,args...) printf(fmt,##args)
#define debugX(level,fmt,args...) if(DEBUG >=level) printf(fmt,##args)
#else
#define debug(fmt,args...)
#define debugX(level,fmt,args...)
#endif /*DEBUG*/
看下u-boot 下common.h头文件,了解如何定义debug宏,使用debug会输出自定义的信息;若没有定义,则什么也不会输出,即不执行任何语句。
#define print_error(str) do{fprintf(stderr),"Oh God!/nFile:%s Line:%d Function:%s:/n",__FILE__,__LINE__,__func__);perror(str); return (EXIT_FAILURE);}while(0)
它不仅打印会导致出错的文件、行号、函数,还打印这个出错的原因。EXIT_FAILURE在系统中定义为1。也可以是exit(1),等。注意__FILE__等式C语言中的预定义宏,即是由C语言自己定义的。这些宏有特殊含义,如__FILE__表示当前正在编译的.c文件的文件名。值得注意的是,在Linux中有一些约定的习惯,如表示判断的函数,返回非0表示成功,返回0表示失败;表示操作性质的函数,返回0表示操作成功,返回非0表示操作失败。经典的strcmp函数,如果要比较的两个字符串相同,它是返回0的。
gdb调试
GDB 是 GNU 开源组织发布的一个强大的 UNIX 下调试程序工具。
一般来说,GDB具有以下四个方面功能
- 启动程序,可按照你自定义的要求随心所欲的运行程序;
- 可让调试程序在所指定的位置断点处停止;
- 当程序停止时,可检查此时你的程序中所发生的事情;
- 动态的改变程序的执行环境;
gdb常用的命令
编译生成执行文件 :gcc -g have_lunch.c -0 have_lunch
调用调试器gdb,装载子程序: gdb have_lunch
列出源码 :list
设置断点并调试,在源程序第11行处: break 11
设置断点,在函数func()入口处: break func()
查看断点信息:info break
运行程序 并在断点处停住: run
单挑语句执行:next(step)
继续运行程序:continue
打印遍历i的值:print i
(gdb) display 要显示值的表达式
查看函数堆栈:bt
(gdb) bt
#0 0x00007ffff7bce0a2 in wait () from /lib64/libpthread.so.0
#1 0x0000000000400b43 in main () at have_lunch.c:51
(gdb) finish 推出函数
Run till exit from #0 0x00007ffff7bce0a2 in wait () from /lib64/libpthread.so.0
main () at have_lunch.c:50
50 for(i=0;i<5;i++)
退出gdb:quit