• GDB 调试工具使用指南


    GDB 概述
      GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具。也许大多数开发人员比较喜欢那种图形界面方式的,像 VC 、 BCB 等 IDE 的调试,但如果你是在 UNIX 平台下做软件开发,你会发现 GDB 这个调试工具有比 VC 、 BCB 的图形化调试器更强大的功能。所谓 “ 寸有所长,尺有所短 ” 就是这个道理。
      一般来说, GDB 可以帮助你完成以下几个方面的功能:

    启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
    可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
    当程序被停住时,可以检查此时你的程序中所发生的事。
    动态的改变你程序的执行环境。
      从上面看来, GDB 和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现 GDB 这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。下面我们一一来看。

    基础操作
      要使用 GDB 调试,需要在编译程序的时候加上 -g 参数,例如:

    $ gcc -g test.c -o test
    1
      启动 GDB 调试 test 程序:

    $ gdb test
    1
      执行 run(简写 r)运行程序,但是通常,你的命令行程序需要带上参数,那么就需要指定参数运行,例如:

    (gdb) run -d /dev/mtd2
    1
      另一种方法是使用 set args,例如:

    (gdb) set args -d /dev/mtd2
    1
      几乎每一次调试,我们都会设置断点,单步运行。GDB 设置断点的方式很灵活,使用 break(简写 b)。
      例如,在源程序第 232 行处设置断点:

    (gdb) break 232
    1
      在 function() 函数入口处设置断点:

    (gdb) break function
    1
      如果程序包含多个文件,我们还需要指定源文件,例如在 main.c 文件的第8行设置断点:

    (gdb) break main.c:8
    1
      查看断点信息:

    (gdb) info break
    1
      删除断点使用 delete(简写 d),其后的数字可以通过 info break 查看,例如删除第1个断点:

    (gdb) delete 1
    1
      执行单条语句,也就是单步运行使用 next(简写 n)命令。
      继续运行程序,使用 continue(简写 c)命令。
      使用 finish 命令退出函数。
      当程序在断点处停下来后,我们可能需要打印变量的值, 使用 print(简写 p)命令,可以打印基本类型,也可以打印复合类型,例如:

    (gdb) print count
    1
      很不幸,如果程序出错甚至崩溃,我们应该勇敢地面对它,使用 backtrace(简写 bt)命令查看函数堆栈。例如,我刚遇到了一个“Program received signal SIGSEGV, Segmentation fault.”错误:

    (gdb) backtrace
    #0  0x4007fc13 in _IO_getline_info () from /lib/libc.so.6
    #1  0x4007fb6c in _IO_getline () from /lib/libc.so.6
    #2  0x4007ef51 in fgets () from /lib/libc.so.6
    #3  0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10
    #4  0x40037f5c in __libc_start_main () from /lib/libc.so.6
    1
    2
    3
    4
    5
    6
      通常,我们只关心自己的代码,因此使用 frame 命令切换到3号堆栈帧(stack frame3),看看程序到底是在哪里崩溃的:

    (gdb) frame 3
    #3  0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10
    10        fgets(buf, 1024, stdin)
    1
    2
    3
      这样我们就可以定位到程序在 fgets() 函数处遇到了麻烦,对于这个例子,显然我们需要关注 fgets() 的参数,特别是指针类型的变量,因为这很可能是由于访问非法内存导致的。
      程序调试完,可以使用 kill(简写 k)杀死当前程序,或者使用 quit(简写 q)退出 gdb 调试。

    远程调试
      前面例子是使用 gdb 调试本机程序,但是对于嵌入式开发,通常我们使用的是交叉编译环境,这样就会给调试带来一定的麻烦。
      有时候我们需要在成品机上进行调试,然而成品机把调试串口裁剪掉了。
      另外,嵌入式设备的存储容量有限,但是 gdb 调试过程需要配合源代码进行,因为 gdb 会加载对应的源代码来辅助调试,比如对于要查看一个结构体变量的内部数据时,就会去寻找该结构体在源代码中的具体定义,从而更好地解析每个数据域的内容。
      当然我们可以把源代码拷贝到嵌入式设备上,然后调试、修改、调试…… 很快我们就会发现这实在太抓狂了!
      因此,我们需要远程调试,通过 gdbserver 工具直接在嵌入式设备中调试程序。为了能够实现远程调试,需要将设备与 PC 连接到同一个网络。
      然后在设备端使用 gdbserver 启动一个远程调试会话,还是以我们的 test 程序为例,指定端口为 1234:

    # gdbserver :1234 test
    1
      在 PC 机上则直接输入 gdb 命令启动 GDB 调试工具,然后指定 ip 和端口,连接到设备端进行远程调试:

    (gdb) target remote 192.168.3.100:1234
    1
      接下来就会出现与之前的本地调试一样的提示画面了,后续的操作和本地调试也是一样的,Bingo!

  • 相关阅读:
    Unity C# 反编译
    java finalize方法总结、GC执行finalize的过程
    Android性能调优篇之探索垃圾回收机制
    深入理解JVM(一)——JVM内存模型
    Android性能调优篇之探索JVM内存分配
    HashMap实现原理分析
    [干货]2017已来,最全面试总结——这些Android面试题你一定需要
    2017年最全的30个Android面试题,你将如何回答?
    Android2017进阶知识点、面试题及答案(精选版)
    Android2017最新面试题(3-5年经验个人面试经历)
  • 原文地址:https://www.cnblogs.com/lidabo/p/16377771.html
Copyright © 2020-2023  润新知