[调试技术] GDB概述和常用用法

前言:

linux环境下几乎只有gdb可用,windows环境下windbg也是以gdb作为底部承载,因此gdb的重要作用可见一斑,但gdb作为基础套件,其不具备界面展示,因此使用起来不是很方便,这里对其做简要的使用说明。




前提条件:

使用gdb进行调试必须满足以下至少一个条件:

1)在编译时使用了-g选项,那么得到的二进制文件便是包含调试信息的,那么此二进制文件是可调试的;

2) 编译时没使用-g选项增加调试信息,但有与此二进制文件配套的debuginfo包,那么可以将此debuginfo包与gdb一起运行,此时相当于把调试信息打入二进制文件中。

注:debuginfo也是在编译时生成的,通常是通过-g选项生成带有调试信息的二进制文件,然后再使用objcopy将调试信息从二进制文件中分离出来,后面会介绍objcopy的使用




DebugInfo的来龙去脉:

  • debuginfo是指gdb所使用的debug信息,比如使用gcc -g选项,编译的输出文件中就会包含debuginfo
  • 一般情况下,都是把debuginfo和可执行文件分开,因为放在一起,会导致可执行文件过大
  • 如何获得可执行文件和debuginfo呢?使用如下命令可以
objcopy --only-keep-debug ./a.out a.out.debug    

#这里拷贝出来,此时可执行文件中还是有debuginfo的,多出来一个.debug文件,原来的a.out大小不变
  • 如果把a.out瘦身呢?使用如下命令可以
objcopy --strip-debug ./a.out(也可以使用strip --strip-debug ./a.out)

#此时,在使用gdb来调试a.out的时候,已经不行了,报错no debugging symbols found
  • 该怎么使用debuginfo呢?使用如下命令即可
objcopy --add-gnu-debuglink=a.out.debug ./a.out
	
#此时,在使用gdb来调试a.out,发现可以了
  • 为什么加了有debuginfo ,调试的时候有些地方仍然没有debug信息

 -g 选项默认不会包括一些宏定义的信息。可以在编译时使用-g3




使用:

启动并调试:

gdb program

带core文件启动并调试:

gdb program core  (执行后,停在哪,系统就down在哪)

调试一个运行中的进程:

gdb program 1234  或 gdb - 1234  (1234是进程号)

过滤gdb产品信息运行gdb:

gdb --silent

 在gdb环境中运行shell命令:

shell ls

在gdb环境中运行make命令:

make all

转移gdb输出到文件中:

set logging on      set logging file filename   (filename是文件名)

设置代码搜索路径:

为gdb 设置 ffplay 的源码搜索路径:

gdb `find /home/ubuntu/_WORKSPACE/SourceCode/FFmpeg-n3.4.8 -type d -printf '-d %p '` ffplay

其他: 

#1  - 命令补全,和shell一样,用TAB补全,同样有双击TAB罗列可选项的功能

#2  - 基本命令
      run     启动程序 
      start   主函数处设置断点,启动程序,每次过来执行都会停住,相当于一个长期断点
      starti  主函数处设置断点,启动程序,仅在第一个过来执行时会挺住,相当于一次性断点
      set args  设置运行参数,进入交互界面后,set args arg1 arg2,依次设置参数1——arg1 和 参数2——arg2
      show args 查看已设置的参数
      continue  一直执行,知道下一个断点,若无断点,则一直执行到程序结束
      bt      输出当前调用栈
      n       step over 
      s       step into
      
      break   设置断点
                break lineno                      当前文件的指定行处
                break filename:lineno             特定文件的指定行处
                break functionname                当前文件的指定函数入口
                break filename:functionname       特定文件的指定函数入口
                break *address                    某个虚拟地址
                break                             下一条指令处
                break ... if xxx                  满足xxx条件,停在...处(...为上面提到的lineno、functionname等等)
                                                  比如:break printf if i>100
      info    查看相关信息
                info break                        查看断点信息
                info threads                      查看线程信息
                info r                            查看寄存器信息
                
      condition 为断点加条件(类似于break ... if xxx,更细化)
                假设已经设置了断点3
                condition 3 a>10                  当a>10的时候,在3号断点停住
                condition 3                       清除加在3号断点上的条件(比如上面的a>10)
                
      ignore 3 100                                进入断点3的前100次将被忽略,从101次开始断点才有效                
            
                                          
#3  - 多进程调试
      默认情况下,gdb跟踪父进程
      可以在任何时候设置跟踪子进程:set follow-fork-mode childe
      
      那么exec系列函数是否能够使用gdb跟踪呢?
      
#4  - 多线程调试
      info threads    查看所有线程(其中带*号的为当前线程)
      thread 2        切换到2号线程
      where           输出线程调用栈(对应bt)
      break ... thread 2  为2号线程打上断点(...为之前提到的lineno、functionname等等)
#1  输出字符串
      p (char *)字符串初始地址
      
#2  输出完整字符串
      gdb的字符串输出有长度限制,最多只能输出多少个,可使用show print elements查看
      当字符串商都超过这个限制时,可以通过set print elements N,来把这个限制扩展到N个字符
      
#3  gdb value <optimized out>的解决方式
        调整优化深度,默认优化深度为-O2,调整为-O0即可
        

#1    http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html

#2    打印表达式
            print 表达式:简记为 p ,其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,
                         那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。
            print a:将显示整数 a 的值
            print ++a:将把 a 中的值加1,并显示出来
            print name:将显示字符串 name 的值
            print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
            print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数
            display 表达式:在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输
                           出被设置的表达式及值。如: display a
            watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a
            whatis :查询变量或函数
            info function: 查询函数
            扩展info locals: 显示当前堆栈页的所有变量
            
#3    查询运行信息
            where/bt :当前运行的堆栈列表;
            bt backtrace 显示当前调用堆栈
            up/down 改变堆栈显示的深度
            set args 参数:指定运行时的参数
            show args:查看设置好的参数
            info program: 来查看程序的是否在运行,进程号,被暂停的原因。
            
#4          分割窗口
            layout:用于分割窗口,可以一边查看代码,一边测试:
            layout src:显示源代码窗口
            layout asm:显示反汇编窗口
            layout regs:显示源代码/反汇编和CPU寄存器窗口
            layout split:显示源代码和反汇编窗口
            Ctrl + L:刷新窗口
            
#5          更强大的工具 --    cgdb
            cgdb可以看作gdb的界面增强版,用来替代gdb的 gdb -tui。cgdb主要功能是在调试时进行代码的同步显示,这无疑增加了调试的方便性,
            提高了调试效率。界面类似vi,符合unix/linux下开发人员习惯;如果熟悉gdb和vi,几乎可以立即使用cgdb。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值