您的位置:首页 > 编程语言 > C语言/C++

【C语言】gdb调试器入门

2015-09-21 10:46 260 查看

前言

    作为一名计算机系的学生,接触编程也有两年时间了,一个比较深的感受:光会码代码是远远不够的,调试代码的能力十分重要!

    经常有同学说,这个我知道思路,代码也打出来了,为什么跑出来的结果总是不如我所愿!打代码1小时,调试1天这种事常常发生。

    当然,这并不是我们打代码的能力不够,再好的程序员也会因为各种原因打出有bug的程序,debug是家常便饭。

    两年以来,我身边的人(包括我),大部分在debug的时候用的是“打印法”——在源代码中加入大量的输出语句来观察代码执行过程中发生的事情。诚然,这种方法简单易行,对于少量的代码,用此法是比较方便的,但是一旦代码量增加,程序复杂起来,就容易乱上加乱了。

    最近接触了gdb调试器,功能十分强大,希望以后在实战中能够熟悉这个工具,利用它来完成调试。

gdb主要功能

监视程序中变量的值的变化

设置断点,使程序在指定的代码行上暂停执行,便于观察

单步执行代码

分析崩溃程序产生的core文件

使用时的一些问题

1.单步执行时,不进入标准库函数内部,在gdb中执行下列命令:

show debug-file-directory
#显示路径为 /usr/lib/debug
set debug-file-directory
#将路径设置为空
show debug-file-directory
#显示路径为空
#每一次进入gdb都需要重新设置一次
#单步执行时,可以用next,不进入函数内部


2.用gdb调试,使用gcc编译时加上-g选项,将调试信息加到程序中:

gcc -ggdb3 -o test test.c
#-ggdb3为最大限度包含调试信息


调试步骤

1.调用gdb

gdb test


2.设置断点并调试

(gdb)break main
#在main函数内第一个非简单赋值语句处中断
(gdb)break 行号
#break可用‘b’代替
(gdb)run
#执行程序
(gdb)step
#单步执行,可用‘s’代替,会显示行号+该行代码(下一步准备执行的代码)
#类似的有next,但是next不跟踪到函数内部
(gdb)print 表达式
(gdb)print 变量=表达式
(gdb)print 开始表达式@要打印的连续内存空间大小
#打印表达式or变量的值,编号并存入历史记录中。$n表示第n个print命令,$$n表示从当前编号倒着数的第n+1个
(gdb)display 表达式
#每当运行到断点,就显示表达式的值
(gdb)quit
#退出gdb
(gdb)finish
#强制退出调试


显示数据命令

#1.display和print命令
#2.内存检查命令
x/format address
#format:<n/f/u>,分别代表显示单元的个数,格式,字节数。
#如x/2c:显示2个单元,char型,4个字节(u参数缺省,默认为4)
#3.printf命令
#4.set命令:显示并修改数据
set variable height=200


设置断点

break test:21   #文件test的第21行
break printmessage  #函数printmessage处设置断点
continue    #恢复程序运行(至下一断点或结束)
cont 2  #忽略断点2次
condition 1 checksum>700    #当表达式满足时,1号断点才中断
tbreak 41   #在41行处设置断点,只中断一次
enable 断点编号 #恢复暂时失效的断点
disable 断点编号    #使断点失效
delete  断点编号    #删除断点
clear   断点行号    #清除断点


设置观察窗口

watch counter>15    #当counter>15时才停下来,counter的取值需在作用域内


查看栈信息

#使用backtrace或者bt
frame <n>   #frame 0表示栈顶,frame 1表示栈的第一层
#info args:显示当前函数的参数名及值
#info locals:显示当前函数中所有局部变量及值


查看源程序

list <linenum>  #显示第linenum行周围的源程序
list <function> #显示函数的源程序


搜索源代码

forward-search <regexp> #向前搜索,regexp为正则表达式
reverse-search <regexp> #向后搜索


查看汇编代码

disassemble func    #查看函数func的汇编代码


改变程序的执行

set var width = 47  #改变变量的取值
jump <linespec> #跳转到某个运行点
jump <address>  #跳转到某个内存地址
#jump不会改变当前程序栈中的内容,谨慎使用!
return <expression> #强制函数返回


程序崩溃:core dump分析

gdb test core.****  #将core装载进gdb,查找崩溃原因及位置
bt  #打印栈桢指针(可知道每个函数被执行的最后一行)


结语

    以上只是我在学习过程中的一些笔记,没有很具体的举例子说明,比较抽象。建议初学者根据知识点,找个例子一步步实操一下,熟能生巧,学起来也就十分轻松了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: