Linux环境下gdb程序调试

  • 这篇文章将会介绍gdb以及一些常用的gdb调试指令;

gdb介绍

gdb是linux中的调试器,由于linux是命令行式的操作,所以要进行调试也一定是以命令行的方式进行,相比于win下vs等IDE的调试使用起来操作比较繁琐,但是程序调试的思路都是大致的。

但是在某些开发场景并没有设计专门的IDE,这种情况下是没有办法用IDE进行调试的,这个时候只能使用gdb调试了。

俗话说一名合格的程序员,大部分的时间都是在debug调试,可见熟悉gdb调试是至关重要的了!


进入gdb调试环境

  1. 创建mytest.c的源文件,并写入如下代码用于调试;

在这里插入图片描述

编译及运行结果:

在这里插入图片描述

进入gdb环境进行调试:

  • 指令:gdb + 程序名称

在这里插入图片描述

但是再次版本下,我们发现输入gdb指令:l 0的时候,报错:

在这里插入图片描述

原因是默认情况下,我们在linux下使用gcc/g++默认生成的程序都是release版本,这种发布的版本是不带调试信息的,无法进行调试,是给用户使用的;

我们需要调试,就得编译的时候带选项-g告知编译器编译debug可调式版本的程序!
在这里插入图片描述

我们进一步观察能发现,release版本的成虚要比debug版本更小,因为优化,抹去了调试用的信息等:


指令学习

成功进入gdb调试环境并且能够调试了,我们介绍常用指令的学习

l(list)指令

l(list):显示出可执行程序内的代码,方便观察

在这里插入图片描述

当我们用l指令配合一个数字的时候:l + num表示从num行开始显示代码;

此时只能显示10行代码:,接着继续按回车,就能接着显示后续的10行代码;

在这里插入图片描述

当我们用l指令配合两个数字(用逗号隔开)的时候:l num1,num2表示显示从num1行到num2行的代码;
在这里插入图片描述

当我们使用l+函数名的时候:l addToVal 表示显示addToVal函数的代码,同样每次显示10行;

在这里插入图片描述

b(break)指令

b + 行数: 表示在指定行添加断点(breakpoint)

break+函数名: 进入指定函数,在其作用域内第一行有效代码设置断点

在第5行和第10行加断点:

在这里插入图片描述

在addToVal函数第一行代码处设置断点:

在这里插入图片描述

info b指令

info b: 显示出所有断点的信息

在这里插入图片描述

d指令

d + 断点编号:删除该编号的断点

在这里插入图片描述
d : 删除所有的断点

在这里插入图片描述

(注意,断点编号不是行号,d之前需要用info查一下断点的编号Num)

r(run)指令

r(run):程序运行指令,有断点运行到第一个断点处,无断点运行整个程序;

无断点的情况下运行完了整个程序:

在这里插入图片描述

运行到第一个断点处:
在这里插入图片描述

显示断点的编号以及中断位置所处的函数名当前文件名以及断点行号

n(next)指令

n(next) : 在程序已经run的基础上,逐过程执行,遇到函数调用不会进入直接执行完毕,类似VS中Debug调试的F10

在这里插入图片描述

s(step)指令

s(step) :在程序已经run的基础上, 逐语句执行,遇到函数可进入函数内部观察细节,类似VS中Debug调试的F11

在这里插入图片描述

c(continue)指令

c(continue) : 在程序已经run的基础上,从当前断点跳跃到下一个断点处,类似于VS中Debug调试的F5

在这里插入图片描述

在24行addToVal()函数入口处的断点处停下,用c指令,直接跳转到了26行的断点,期间的addToVal()和Print()函数都已被执行!

bt(breaktrace)指令

bt :查看各级函数调用的栈帧信息(栈帧号和所属函数等)以及参数

在这里插入图片描述
由于面试被问到这个指令,做以下扩充:

  • bt(backtrace) break step next continue 这几个指令 务必清晰;是最基本常用的;

bt + 栈帧数量 --> 这对于调用栈帧比较多的情况很有用处,可以忽略掉不太关心的那些栈帧。比如执行 bt 2 ,则只显示两个栈帧。

f(frame) + 栈帧号 -->切换栈帧,每一个栈帧所对应的程序的运行上下文都不同,比如栈帧 1 的局部变量和栈帧 2 的局部变量都不相同,只有切换到某个具体的栈帧之后才能查看该栈帧对应的局部变量信息
f(frame) + 栈帧地址 -->切换栈帧; 帧地址是栈帧所对应的地址。如果程序崩溃,栈回溯信息可能会遭到破坏,这时就可以使用该命令通过栈帧地址来进行栈帧切换

i(info) + locals -->查看当前帧的所有局部变量的值
i(info) + args --> 查看当前帧所有的函数参数和值

i(info) + f(frame) + 栈帧号/地址 -->查看栈帧的详细信息

此外,gdb怎么调试多线程(每个线程有自己的handler函数,本质上也是个栈帧)?

info+thread 显示当前可调试的所有线程,拿到线程ID
thread+线程ID 切换到某个线程下,紧接着用bt查看当前线程的栈帧,break打上断点等操作

finish指令

finish: 在某个函数内部时,不想再执行该函数,可以用finish直接结束函数,从而跳出该函数,1.之后回到这个函数的调用处,等待进一步的命令;2.得到这个函数的返回值;
在这里插入图片描述

p(print)指令

p(print)+变量名 : 打印当前栈帧内的变量的值

在这里插入图片描述
p(print)+(表达式) : 打印当前战阵括号内表达式的值

在这里插入图片描述

display指令

display 临时变量 : 跟踪一个变量,变量常驻在屏幕上,每次停下来都显示他的值;有点像VS的监视窗口中添加监视的变量;

在这里插入图片描述

undisplay指令

undisplay+临时变量编号 : 使其不再常驻在屏幕上 (与display配合使用,起相反作用)

在这里插入图片描述

until指令

until+行号 :直接跳至指定的有效代码行,一般用于直接跳出某个循环或递归

在这里插入图片描述

disable命令

diable+断点号 : 禁用指定的断点

在这里插入图片描述
disable b: 禁用所有断点

在这里插入图片描述

enable命令

启用断点,和上面disable用法一样,不再描述;

猜你喜欢

转载自blog.csdn.net/wtl666_6/article/details/128524245