赞
踩
本章介绍linux环境下使用gdb调试程序。
1.gdb调试条件
想要程序执行并可gdb调试,必须在编译的时候添加**-g**,例如(C语言):gcc test.c -o test -g
2. gdb命令介绍
2.1 gdb 启动
使用 gdb 可执行程序的名字指令后,可执行程序还没有开始跑起来,需要使用 start或run指令来启动执行程序
$ gdb 可执行程序的名字 //例如上述编译得到的test执行文件:gdb test
启动gdb, 启动执行程序如下图所示:
**2.2 gdb 设置参数 **
设置参数需要在启动执行文件之前设置,参数值可通过main函数的参数传递给main
(gsb) set args 参数1 参数2 参数3 .....
2.3 gdb 启动可执行程序
启动可执行程序有star和run两条指令,gdb启动后 启动可执行程序只能执行一次。start和run区别:
start:启动可执行程序执行到main函数便停止程序执行,直到gdb的新指令
run: 启动可执行程序执行到第一个断电便停止程序执行,若没有断点则执行到程序结束
(gdb) start
或
(gdb) run
2.4 gdb 退出
若想退出gdb调制,终端输入quit指令便可退出
(gdb) quit
下列讲解的gdb指令需在gdb 启动可执行程序后才能有效设置
2.5 list 显示文件与切换文件
list指令可以查看当前文件内容(启动执行程序main所在的文件为当前文件),默认查看10行,也可以使用set listsize 行数或set list 行数设置显示行数
显示文件指令操作举例如下:
(gdb) list //从第一行开始显示
(gdb) list 行号 //指定这行号对应的上下文代码, 默认情况下只显示10行内容
(gdb) list 函数名 //显示这个函数的上下文内容, 默认显示10行
切换当前文件到指定文件,切换成功后指定文件就变成当前文件,就可以查看该文件的内容了
(gdb) list 文件名:行号 //默认显示10行
(gdb) list 文件名:函数名 //默认显示该函数上下文,共10行
设置显示行数,即更改list默认显示行数
(gdb) set listsize 行数
或
(gdb) set list 行数
查看list一次可显示多少函数
(gdb) show list
或
(gdb) showlistsize
2.6 断点操作
gdb 断电顾名思义就是程序执行到断点处便停止执行,需等待下一步指令程序才能有所响应。相关断点操作都是使用指令break。
2.61 设置断点
//设置当前文件断点
(gdb) break 行号
(gdb) break 函数名 //停止在函数名所在的行号
//设置非当前文件断点
(gdb) break 文件名:行号
(gdb) break 文件名:函数名 //停止在函数名所在的行号
//设置条件断点
** 必须要满足某个条件, 程序才会停在这个断点的位置上
** 通常情况下, 在循环中条件断点用的比较多
(gdb) break 行数 if 变量名==某个值
2.6.2 查看断点
(gdb) info break
或
(gdb) info breakpoints
设置断点和显示断电如下图所示:
上图中Num ,Enb, What
Num: 断点的编号,删除断点或者设置断点状态的时候都需要使用
Enb: 当前断点的状态,y 表示断点可用,n 表示断点不可用
What: 描述断点被设置在了哪个文件的哪一行或者哪个函数上
2.6.3 删除断点
//需要 info b 查看断点的信息, 第一列就是编号
//删除断点
(gdb) d 断点的编号1 [断点编号2 ...]
# 举例:
(gdb) delete 1 # 删除第1个断点
(gdb) delete 2 4 6 # 删除第2,4,6个断点
//删除一个范围, 断点编号 num1 - numN 是一个连续区间
(gdb) d num1-numN
//举例, 删除第1到第5个断点
(gdb) d 1-5
2.6.4 设置断点状态
设置断点状态不同于删除断点,无效断点状态后断点任然在当需要的时候可以重新开启使用,而删除则是完完全全消失,需要的时候要重新设置
//由有效变无效状态转变 //让断点失效之后, gdb调试过程中程序是不会停在这个位置的 // disable == dis //设置某一个或者某几个断点无效 (gdb) disable 断点序号1 断点序号2 ...... //设置连续几个断点无效 (gdb) disable 断点序号1-断点序号n //由无效变有效状态转变 //设置某一个或者某几个断点由无效变有效 (gdb) enable 断点序号1 断点序号2 ...... //设置连续几个断点由无效变有效 (gdb) enable 断点序号1-断点序号n
2.7 调试命令
2.7.1 继续运行continue
如果调试的程序被断点阻塞了又想让程序继续执行,这时候就可以使用 continue 命令。程序会继续运行,直到遇到下一个有效的断点
(gdb) continue
2.7.2 手动打印信息
当程序被某个断点阻塞之后,可以通过一些命令打印变量的名字或者变量的类型,并且还可以跟踪打印某个变量的值
在 gdb 调试的时候如果需要打印变量的值。如果打印的变量是整数还可以指定输出的整数的格式,格式化输出的整数对应的字符表如下:
格式化字符 (/fmt) 说明
/x 以十六进制的形式打印出整数。
/d 以有符号、十进制的形式打印出整数。
/u 以无符号、十进制的形式打印出整数。
/o 以八进制的形式打印出整数。
/t 以二进制的形式打印出整数。
/f 以浮点数的形式打印变量或表达式的值。
/c 以字符形式打印变量或表达式的值。
print指令语法如下
(gdb) print 变量名
//如果变量是整形,默认输出10进制,若要更改输出类型可执行如下指令
(gdb) print/fmt 变量名
//如16进制输出,如下
(gdb) print/x 变量名 // /x 以十六进制的形式打印出整数。
2.7.3 打印变量类型
当调试的时候想知道变量名的类型可以使用ptype指令获取到变量类型,指令操作如下:
(gdb) pypte 变量名
2.7.4 自动打印信息
自动打印信息的指令为display,display与print一样都是打印变量信息,不同在于print执行一次指令只打印一次变量信息,而display指令执行一次则每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来。display适合频繁要打印变量信息或表达式的值使用。display指令操作如下
//在变量的有效取值范围内, 自动打印变量的值(设置一次, 以后就会自动显示)
(gdb) display 变量名
// 以指定的整形格式打印变量的值, 关于 fmt 的取值, 请参考 print 命令
(gdb) display/fmt 变量名
2.7.5 查看自动显示列表
(gdb) info display
操作如下图所示:
Num : 变量或表达式的编号,GDB 调试器为每个变量或表达式都分配有唯一的编号
Enb : 表示当前变量(表达式)是处于激活状态还是禁用状态,如果处于激活状态(用 y 表示),则每次程序停止执行,该变量的值都会被打印出来;反之,如果处于禁用状态(用 n 表示),则该变量(表达式)的值不会被打印。
Expression :被自动打印值的变量或表达式的名字。
2.7.6 取消/删除/禁用自动显示信息
取消/删除/禁用自动显示信息指令操作与断电指令操作相似,只是指令开头不同一样
// 命令中的 num 是通过 info display 得到的编号 (gdb) undisplay num1 num2 ... //编号可以是一个或者多个 (gdb) undisplay num1-numN // num1 - numN 表示一个范围 //或 (gdb) delete display num1 num2 ... //编号可以是一个或者多个 (gdb) delete display num1-numN //如果不想删除自动显示的变量,也可以禁用自动显示列表中处于激活状态下的变量或表达式 (gdb) disable display num1 num2 ... //编号可以是一个或者多个 (gdb) disable display num1-numN // num1 - numN 表示一个范围 //取消禁用自动显示(启用自动显示)指令如下 # 命令中的 num 是通过 info display 得到的编号, (gdb) enable display num1 num2 ... //编号可以是一个或者多个 (gdb) enable display num1-numN // num1 - numN 表示一个范围
2.8 单步调试
当程序阻塞到某个断点上之后,可以通过以下命令对程序进行单步调试:
2.8.1 step
step 命令可以缩写为 s, 命令被执行一次代码被向下执行一行,如果这一行是一个函数调用,那么程序会进入到函数体内部。
//从当前代码行位置, 一次调试当前行下的每一行代码
// 如果这一行是函数调用, 执行这个命令, 就可以进入到函数体的内部
(gdb) step
2.8.2 finish
如果通过 s 单步调试进入到函数内部,想要跳出这个函数体, 可以执行 finish 命令。如果想要跳出函数体必须要保证函数体内不能有有效断点,否则无法跳出。
//如果通过 s 单步调试进入到函数内部, 想要跳出这个函数体
(gdb) finish
2.8.3 next
next 命令和 step 命令功能是相似的,只是在使用 next 调试程序的时候不会进入到函数体内部
//如果这一行是函数调用, 执行这个命令, 不会进入到函数体的内部
(gdb) next
2.8.4 until
通过 until 命令可以直接跳出某个循环体,这样就能提高调试效率了。如果想直接从循环体中跳出,必须要满足以下的条件,否则命令不会生效:
1.要跳出的循环体内部不能有有效的断点
2.必须要在循环体的开始 / 结束行执行该命令
(gdb) until
2.9 设置变量值
在调试程序的时候,我们需要在某个变量等于某个特殊值的时候查看程序的运行状态,但是通过程序运行让变量等于这个值又非常困难,这种情况下就可以在 gdb 中直接对这个变量进行值的设置,或者是在单步调试的时候通过设置循环因子的值直接跳出某个循环,值设置的命令格式为: set var 变量名=值
// 可以在循环中使用, 直接设置循环因子的值
// 假设某个变量的值在程序中==90的概率是5%, 这时候可以直接通过命令将这个变量值设置为90
(gdb) set var 变量名=值
3.gdb 常用指令总结
1. gdb 可执行程序 //启动gdb 2. set args 参数1 参数2 ... //将参数传给main函数的输入参数argc[] 3. run(缩写r) //启动可执行程序(执行到第一个断电便停止运行),程序执行后才能设置断点,参数显示信息等指令操作 4. start //启动可执行程序(执行到main函数行便停止运行),程序执行后才能设置断点,参数显示信息等指令操作 5. quit(缩写q) //退出gdb调试 6. list(缩写l) // 列出源码默认10行(当前位置的上下共10行) list 行号 // 列出行号上下共10行的源码 list 函数名 // 列出函数名上下共10行的源码 list 文件名:行号 // 切换至文件名并列出该文件名行号上下共10行的源码 list 文件名:函数名 // 切换至文件名并列出该文件函数名上下共10行的源码 set listsize(缩写list) 行数 //设置显示的行数 7. break(缩写b) 行号 //停止在当前文件的行号 break 函数名 //停止在函数的第一行 break 文件名:行号 //停止在指定文件的行号 break 文件名:函数名 // 停止在指定文件的函数的第一行 break 行数 if 变量名==某个值 //必须要满足某个条件, 程序才会停在这个断点的位置上 通常情况下, 在循环中条件断点用的比较多 info break //查看断点信息 delete(缩写del或d) 断点编号1 断点编号2 ...... //删除指定一个或多个指定编号断点 delete 断点编号1-断点编号n //删除指定范围断点 disable(缩写dis) 断点编号1 断点编号2 ...... //禁用指定一个或多个指定编号断点 disable断点编号1-断点编号n //禁用指定范围断点 enable(缩写ena) 断点编号1 断点编号2 ...... //启用指定一个或多个指定编号断点 enable 断点编号1-断点编号n //启用指定范围断点 8. continue(缩写c) //程序继续运行,直到遇到下一个断点 9. display 变量名 //变量名自动显示 display/fmt 变量名 //若整形变量可指定输出格式输出 info display //查看自动显示列表 undisplay num1 num2 .... //取消指定一个或多个的自动显示 undisplay num1-numN //取消指定范围内的自动显示 disable display num1 num2 .... //禁用指定一个或多个的自动显示 disable display num1-numN //禁用指定范围内的自动显示 10. step //从当前代码行位置, 一次调试当前行下的每一行代码,会进入函数体内 11. finish //如果通过 s 单步调试进入到函数内部, 想要跳出这个函数体 12. next //next 命令和 step 命令功能是相似的,只是在使用 next 调试程序的时候不会进入到函数体内部 13. until //可以直接跳出某个循环体 14. set var 变量名=值 // 设置变量的值
参考 链接: https://subingwen.cn/linux/gdb/#5-3-4-until
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。