0%

GDB调试

    GDB是GUN(GUN is not unix)开源组织发布的,Unix/Linux操作系统下的一款基于命令行方式交互的调试工具。GDB支持调试多种语言,比如C/C++、Go、Objective-C、Pascal等等,但是最强大的、用的最多的是调试C/C++程序,作为一个C/C++程序员,要是你不会使用GDB,那可能都没脸出门了。

说明:参数 <program> 不包括符号“<>”。

  • 启动调试程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 可以直接从一个可执行的程序和core文件开始。
    gdb <program> <corefile>

    # 如果需要调试正在运行的进程。
    gdb program <processId>
    gdb -p <processId>
    gdb attach -p <processId>

    gdb -q # 关闭启动信息
    set confirm off # 关闭退出时确认退出提示信息
  • 设置启动参数,例如'-c 1 -t 100'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 启动时直接指定参数'-c 1 -t 100'。
    gdb -args <program> -c 1 -t 100

    # 通过交互方式设置参数。
    (gdb) set args -c 1 -t 100
    (gdb)
    (gdb) show args
    Argument list to give program being debugged when it is started is "-c 1 -t 100".

    # 运行时指定。
    gdb) run -c 1 -t 100
    Starting program: /root/lpyuan/Hera_tool/webbench -c 1 -t 100
    webbench: Missing URL.
    (gdb) show args
    Argument list to give program being debugged when it is started is "-c 1 -t 100".
    (gdb)
  • 运行信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    start                    # 指令执行到main()函数起始的位置,类似于在main函数设置一个断点。
    r (run) # 运行程序,程序会在第一个断点处停止,否则则是一直执行到结束🔚。
    c (continue) # 继续执行,直到下一个断点处(或者直接到运行结束)
    n (next) # 单步调试,下一步,遇到函数调用不会进入该函数,默认走一步,也可指定步数,如3步:n 3。
    s (step) # 单步调试,与next类似,区别在于遇到函数调用会直接跳入,也可以执行步数,如3步:s 3。
    until # 不想在循环里面单步调试,可以使用该指令直接运行程序直到退出循环体。
    until+行号 # 直接运行到指定行,不仅仅可以跳出循环。
    finish # 运行程序,接收当前函数调用并完成返回🔙,并且打印出函数返回时候的对战地址和返回值、参数等信息。
    call func(args) # 调用函数中的可见函数,并传递参数,函数调用也可以使用print。
    where/bt # 显示当前函数调用栈信息。
    up/down # 改边调用栈的深度,可以选择哪一帧(frame)。
    info functions # 显示当前进程的函数符号
    info program # 查看当前进程所处的状态,是否在运行,进程号,被中断暂停的原因等
    infi signals # 查看程序对应的中断信号处理方式。

    Note: 程序在执行的过程中如果使用run(r)或者start指令,则表示重启启动程序。

  • 断点调试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    b n (break num)           # 在第n行设置断点,也可以指定某个文件,如:b test.c:666
    b func # 在某个函数入口设置断点,如:b benchcore
    info b (info breakpoints) # 显示当前程序的断点设置情况。
    b func if a>b # 条件断点设置,如果a>b成立,则是触发断点。
    disable n # 暂定第n个断点。
    enable n # 启用第n个断点。
    delete n # 删除第n个断点。
    delete breakpoints # 清除程序目前设置的所有的断点。
    tb test.c:15 (tbreak) # 临时断点,断点只生效一次,触发后会自动删除,查看断点列表触发后不存在。
    ignore bnum count # 忽略断点,接下来的count次经过该断点都不会触发,直到count+1次时候会触发次断点。
  • 窗口相关

    1
    2
    3
    4
    5
    6
    layout                    # 分割窗口,如果有代码的话可以一遍看代码一遍跟踪。
    layout src (layout source)# 显示源代码窗口。
    layout asm # 显示反汇编的窗口
    layout regs # 显示源代码、反汇编、和CPU寄存器的窗口。
    layout split # 显示源代码和反汇编的窗口。
    Ctrl+L # 刷新窗口,类似于clear、cls等清屏操作。
  • 打印相关

    1
    2
    3
    4
    5
    6
    7
    8
    print 表达式              # print 后面可以加任何有效的表达式,可以是一个数字、变量、甚至函数调用。
    print 5 # 打印值5。
    print a=5 # 给a赋值5,然后打印出a的值。
    print ++a # 将a变量的值自增,并打印出来。
    print func(66) # 调用函数func,并传递参数值66。
    print func(a) # 将变量a的值作为参数,传递给func函数。
    i locals (info locals) # 查询当前堆栈页中所有的变量。
    whatis # 查询变量或者函数。
  • 查看源代码

    1
    2
    3
    4
    l (list)                 # 显示程序源代码,默认显示10行
    l n (list num) # 显示当前文件以n行前后10行代码,如:l 10
    l func # 列出函数名所在函数的代码,如:l benchcore
    list # 重复执行上一个list命令,输出下边的内容。
  • gdb配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # 在使用gdb的时候,如果我们每次进去之后都要重新配置启动参数、断点等繁琐的信息,那么效率就很低。
    # 我们可以通过配置文件,可以将这些一次性配置好,避免重复性工作。
    # 当gdb启动时,会读取HOME和当前目录下的配置文件,然后直接一次性执行里面的指令,这个文件通常为'.gdbinit'。
    # 如果需要在当前目录下配置.gdbinit文件,则还需要在HOME(~)目录下配置.gitinit文件,并输入以下指令,否则gdb路径保护会报错。
    set auto-load safe-path /
    # 当然我们也可以自己写一个配置文件,但是gdb不会自动读取,需要我们通过'source 自定义脚本'手动导入。
    [root@localhost Hera_tool]# gdb webbench
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
    Copyright (C) 2013 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /root/lpyuan/Hera_tool/webbench...(no debugging symbols found)...done.
    (gdb) source lpyuanGdb
    Breakpoint 1 at 0x400f7f
    (gdb) show args
    Argument list to give program being debugged when it is started is "-c 1 -t 100 http://lpyuan.club".
    (gdb) show b
    Ambiguous show command "b": backtrace, basenames-may-differ, breakpoint, build-id-core-loads, build-id-verbose.
    (gdb) info b
    Num Type Disp Enb Address What
    1 breakpoint keep y 0x0000000000400f7f <Socket>
    (gdb)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    # 打印STL容器中的内容
    python
    import sys
    sys.path.insert(0, "/home/xmj/project/gcc-trunk/libstdc++-v3/python")
    from libstdcxx.v6.printers import register_libstdcxx_printers
    register_libstdcxx_printers (None)
    end

    # 保存历史命令
    set history filename ~/.gdb_history
    set history save on

    # 记录执行gdb的过程
    set logging file ./.gdblog.txt
    set logging on

    # 退出时不显示提示信息
    set confirm off

    # 按照派生类型打印对象
    set print object on

    # 打印数组的索引下标
    set print array-indexes on

    # 每行打印一个结构体成员
    set print pretty on

    # 调试子进程
    set follow-fort-mode child
    set detach-on-fork on

    ......

    # 设置运行参数
    set args -c 1 -t 100 http://lpyuan.club

    # 设置断点
    b Socket

    ......

  • 生成gdb调试日志。使用gdb调试时候,我们可以将我们的调试的过程记录下来,方便后面或者别人帮忙一起分析。

    1
    2
    set logging file filename # gdb的默认日志文件为gdb.txt,我们也可以通过命令更改日志文件名。
    set logging on # 开启日志记录。
  • watch 监视内存断点

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 设置一个监视点,一旦表达式的值发生改变,立马强行终止当前调式程序,比较监视a变量,watch a。
    watch 表达式
    1. watch 变量的类型。
    (1)整形变量。
    int a;
    watch a: # 监视变量a的值。
    (2)指针变量
    char *a;
    watch a: # 此时监视的a变量这个地址,不是a执行的地址的值,查看的是*(&a)。
    watch *a: # 此时监视a所指向的地址的值的变化情况。
    (3)数组类型。
    watch 一个数字或者内存区间。
    char buf[128];
    watch buf: # 对数组的128个值进行监视,此时采用的是软中断,不是采用的硬件断点,软中断方式去检查内存变量是比较耗费CPU的。
    如果指明了精确的地址,则是采用的是硬件中断。

    2. 当设置的监视点是一个局部变量时,局部变量无效后,则监视点也无效。
    3. 与watch命令相似的还有两个命令
    (1)rwatch # 只要程序中出现读取目标变量(表达式)的值得操作,程序就会立即停止运行。
    (2)awatch # 只要程序中出现读取目标变量(表达式)的值或者改变值得操作,程序就会立即停止运行。

  • 加载带有符号信息可执行文件

    1
    2
    3
    # 调试没有符号信息的可执行文件,可以编译一个带有调试信息版本的程序。
    # 通过'file'参数加载符号,对其进行调试。
    (gdb) file webbench1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    [root@localhost Hera_tool]# gdb webbench
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
    Copyright (C) 2013 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /root/lpyuan/Hera_tool/webbench...(no debugging symbols found)...done.
    (gdb) file webbench1
    Reading symbols from /root/lpyuan/Hera_tool/webbench1...done.
    (gdb) directory ../
    Source directories searched: /root/lpyuan/Hera_tool/..:$cdir:$cwd
    (gdb)
  • 多进程调试

    follow-fork-mode detach-on-fork description
    parent on 单独调试主进程(默认情况下)
    child on 单独只调试子进程
    parent off 同时调试两个进程,gdb跟随主进程,子进程阻塞(block)在fork的位置
    child off 同时调试两个进程,gdb跟随子进程,主进程阻塞(block)在fork的位置

    GDB调试多进程的时候,如果该进程fork()出了一个子进程,那么GDB还是会继续调试当前进程不会自动的切换子进程调试,如果 我们在子进程里面设置了断点,那么子进程就会收到一个SIGTRAP信号并终止。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /root/lpyuan/Hera_tool/webbench...(no debugging symbols found)...done.
    (gdb) set follow-fork-mode child
    (gdb) set detach-on-fork on
    (gdb) set args -c -t 100 http://lpyuan.club
    (gdb) show follow-fork-mode
    Debugger response to a program call of fork or vfork is "child".
    (gdb) show detach-on-fork
    Whether gdb will detach the child of a fork is on.
    (gdb) show args
    Argument list to give program being debugged when it is started is "-c -t 100 http://lpyuan.club".
    (gdb) run

Note:

  1. 交互模式下,重复回车则是重复执行上一个命令。

  2. cgdb是一个更加强大的调试工具,交互命令和gdb一样,熟练使用gdb的同学也可以很快的上手。

Reference

[1] https://www.gnu.org/software/gdb/documentation/

[2] https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html

[3] https://wizardforcel.gitbooks.io/100-gdb-tips/content/index.html

小主,路过打个赏再走呗~