linux下gdb调试应用程序

作者: 李云鹏(qqliyunpeng@sina.cn) 
版本号: 20170424 
更新时间: <2020-08-12> 
原创时间: <2017-04-24> 
版权: 本文采用以下协议进行授权,自由转载 - 非商用 - 非衍生 - 保持署名 | Creative Commons BY-NC-ND 3.0,转载请注明作者及出处.
更新内容: 2019-01-03, 主要是完善

更新内容: 2020-08-12, 完善 gdb -tui 时候的操作,并给出一些问题的解决办法

1. 简介


        GDB,是GNU工程调试器,允许你去查看在程序运行的时候里边的东西,或者查看当程序crash的那一刻,其他程序正在做啥。为了获取行为中的bug,GDB可以做的主要有4件事:

  • 开始你的程序,指定可能影响程序的任意行为
  • 让你的程序停止在指定的条件下
  • 检查你的程序停止时发生了什么
  • 改变程序中的一些东西,然后可以查看改变的东西对一个bug和其他的影响

 

2. 开启图形化界面


2.1 简介

想要对应用程序用gdb调试需要在编译的时候添加-g选项

然后就可以将输出的文件进行gdb调试了,假如输出的文件是a.out。则

gdb -tui -q a.out 或者是 gdb a.out然后按ctrl+x+a 就如如下的界面

 

 

【1】-tui 选项是这个界面的关键,-q表示的是不打印(gdb)之前的好多声明

【2】此界面有好处也有坏处,好处是代码实时的显示在上边,缺点也很明显,供操作显示的界面小了,如果你想打印出一个函数的反汇编,那他的劣势就很明显了

 

2.2 更多操作

2.2.1 更多窗口

GDB TUI 模式下共有四个常用的窗口

  • cmd ) command 命令窗口,可以输入调试命令
  • ( src ) source 源码窗口,显示当前行,断点等信息
  • ( asm ) assembly 汇编代码窗口
  • ( reg ) register 寄存器窗口

在命令窗口中输入 layout + 窗口 类型来打开窗口,如

> layout asm   --- > 汇编窗口打开

2.2.3 调整窗口大小

使用命令 winheight

使用格式: winheight <win_name> [+ | -] <#lines>

例子:将代码窗口的高度扩大5行代码

> winheight src + 5

2.2.4 命令行中的历史命令

在命令行窗口中也是有历史输入的命令的,使用方法是 ctrl + p,在历史命令中下一个是 ctrl + n

 

2.3 问题解决

当调试过程中有时候 src 界面中显示的混乱了,有了一些割裂的感觉,此时我们希望src界面刷新下,可以使用 ctrl + x + a 退出 tui 模式,然后重新键入 ctrl + x + a 调用 tui 模式,问题得到解决。

 

3. 基本操作(红色部分是简写)


3.1 基本命令

list [linenum/function] -- 显示linenum周围的源代码或者是显示函数名function的函数的源代码

        ”list -” -- 显示当前行之前的固定行,固定行的重新设定可以用如下命令 set listsize [count],如果只是想看一下用show listsize就可以

        "list +" -- 显示后边

        list [first], [last] -- 显示从first到last行之间的代码

        list ,[last] -- 从当前行到last之间的代码

        当单步运行后使用这个命令打印运行行周围的代码

file -- 加载某个可执行文件,当进入gdb时,用这个命令来加载要调试的程序

start -- 开始调试程序,程序指针会指向main中的第一行

run -- 如果是这个,相对于start来说会找断点,停到断点出,如果没有断点,则执行完

next -- 单步运行,如果遇到函数,不会进入函数执行

step -- 单步运行,如果有函数,进函数继续单步运行。如果后边跟数字,表示执行多步。

continue -- 继续执行,直到遇到断点

finish -- 执行到返回

 

3.2 断点相关操作:

break <function>    在进入指定函数时停住
break <linenum>    在指定行号停住。
break +/-offset    在当前行号的前面或后面的offset行停住。offiset为自然数。
break filename:linenum    在源文件filename的linenum行处停住。
break ... if <condition>    ...可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环语境中,可以设置break if i=100,表示当i为100时停住程序。

 

delete    删除所有断点
delete breakpoint [n]    删除某个断点
disable breakpoint [n]    禁用某个断点
enable breakpoint [n]    使能某个断点

clear 清除所有断点

 

3.3 显示相关

自动显示观察的变量: -- 就是在每运行一次,都会有显示

        display {a,b...}

删除显示的变量

        undisplay {a,b...}

        delete display {a,b....}

不删除,只是使能和屏蔽

        enable display

        disable display

dispay部分的格式控制同print中的格式控制一样

 

还有一种需求是,当每个变量只在他变化的时候显示:

        watch{a,b...}

 

info 命令: -- 列出相关的所有信息

        info break :查看一共多少个break

        info display:查看一共有多少个display

        info locals: 查看当前程序栈的局部变量

        info args: 查看当前程序栈的参数,即如果是一个函数,便是函数所有的传入的参数

        info registers xx: 查看寄存器xx

 

print 命令: -- 打印

打印出数组:

①动态数组 -- 比如说当一个数组传到函数中,在函数中的入参是没有数据边界的指针

        p *[数组首地址]@[数组中元素的长度]

②静态数组

        p [数组首地址]

输出时的格式控制

        x(hex)  按十六进制格式显示变量。
        d(decimal)  按十进制格式显示变量。
        u(unsigned decimal)  按十进制格式显示无符号整型。
        o(octal)  按八进制格式显示变量。
        t(binary)  按二进制格式显示变量。 
        a(address)  按十六进制格式显示变量。
        c(char)  按字符格式显示变量。
        f(float)  按浮点数格式显示变量。

使用时是这个样子:p/a [你要打印的变量]

 

backtrace 命令: -- 打印堆栈(函数调用栈的所有信息)

        简写是 bt

        当罗列出所有的堆栈后,想要跳转到相应的堆栈中去执行,需要用  f [bt命令罗列的数字]  

 

3.4 显示源代码的内存

        example <address>  --  查看指定地址的内存地址的值,具体格式是 x/[n][f][u]

        n 表示需要显示的内存单元个数,内存单元指的是 u 定义的大小

        f 表示需要显示的格式

                x(hex) 按十六进制格式显示变量。
                d(decimal) 按十进制格式显示变量。
                u(unsigned decimal) 按十进制格式显示无符号整型。
                o(octal) 按八进制格式显示变量。
                t(binary) 按二进制格式显示变量。
                a(address) 按十六进制格式显示变量。
                c(char) 按字符格式显示变量。
                f(float) 按浮点数格式显示变量

        u 表示每个单元的大小,按字节数来计算,默认是4字节,可选值:b: 1 byte  h: 2 bytes  w: 4 bytes  g: 8 bytes

        如果想要查看某个函数在源文件中的 行号 和内存中的 起始地址 和 结束地址,info line 函数名字/*内存地址

        你也可以查看源代码的当前执行的机器码,用disassemble命令会把目前内存中的指令dump出来,一般他后边跟的是行号,函数名。

 

3.5 线程相关命令

        info threads  --  打印出现在所以线程

        thread [上边罗列出来的线程的号]   --  跳转到相应的线程中去执行

当然,如果在线程中设置断点的话,当程序运行起来后会相应的跳转到相应的位置停下来,相应的线程也会跳过去,然后单步执行的时候会在相应的线程中继续执行。

 

4 问答

①当单步运行时,我运行到了函数的结尾 "}",函数有返回值,我如何查看此时函数的返回值?

(gdb) info registers eax

上边的命令的意思是打印 eax 寄存器,x86计算机会将函数返回值放在eax寄存器中。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值