精华内容
下载资源
问答
  • gdb调试命令
    2022-02-17 15:19:49
    ## 以下命令后括号内为命令的简化使用,比如
    run r ),直接输入命令r 就代表命令run
    $(gdb)help(h)  # 查看命令帮助,具体命令查询在gdb中输入help + 命令
    $(gdb)run(r)    # 重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文
    件)
    $(gdb)start    # 单步执行,运行程序,停在第一行执行语句
    $(gdb)list(l) # 查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函
    数)
    $(gdb)set # 设置变量的值
    $(gdb)next(n)   # 单步调试(逐过程,函数直接执行)
    $(gdb)step(s) # 单步调试(逐语句:跳入自定义函数内部执行)
    $(gdb)backtrace(bt) # 查看函数的调用的栈帧和层级关系
    $(gdb)frame(f) # 切换函数的栈帧
    $(gdb)info(i) # 查看函数内部局部变量的数值
    $(gdb)finish # 结束当前函数,返回到函数调用点
    $(gdb)continue(c) # 继续运行
    $(gdb)print(p) # 打印值及地址
    $(gdb)quit(q) # 退出gdb
    
    $(gdb)break+num(b) # 在第num行设置断点
    $(gdb)info breakpoints # 查看当前设置的所有断点
    $(gdb)delete breakpoints num(d) # 删除第num个断点
    $(gdb)display # 追踪查看具体变量值
    $(gdb)undisplay # 取消追踪观察变量
    $(gdb)watch # 被设置观察点的变量发生修改时,打印显示
    $(gdb)i watch # 显示观察点
    $(gdb)enable breakpoints # 启用断点
    $(gdb)disable breakpoints # 禁用断点
    $(gdb)x # 查看内存
    x/20xw
    显示20个单元,16进制,4字节每单元
    $(gdb)run argv[1] argv[2] # 调试时命令行传参
    $(gdb)set follow-fork-mode child

    Tips:
    1. 编译程序时需要加上 -g ,之后才能用 gdb 进行调试: gcc -g main.c -o main
    2. 回车键:重复上一命令
    更多相关内容
  • gdb是一个在UNIX环境下的命令行调试工具。如果需要使用gdb调试程序,请在gcc时加上-g选项。下面的命令部分是简化版,比如使用l代替list等等
  • GDB调试命令详解

    万次阅读 多人点赞 2021-03-15 22:30:23
    GDB是什么 调试程序 程序中出现的语法错误可以借助编译器解决;但逻辑错误则只能靠自己解决。实际场景中解决逻辑错误最高效的方法,就是借助调试工具对程序进行调试。 所谓调试(Debug),就是让代码一步一步慢慢...

    GDB是什么

    调试程序

    程序中出现的语法错误可以借助编译器解决;但逻辑错误则只能靠自己解决。实际场景中解决逻辑错误最高效的方法,就是借助调试工具对程序进行调试。

    所谓调试(Debug),就是让代码一步一步慢慢执行,跟踪程序的运行过程。比如,可以让程序停在某个地方,查看当前所有变量的值,或者内存中的数据;也可以让程序一次只执行一条或者几条语句,看看程序到底执行了哪些代码。

    也就是说,通过调试程序,我们可以监控程序执行的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。

    GDB的作用

    GDB 全称“GNU symbolic debugger”,从名称上不难看出,它诞生于 GNU 计划(同时诞生的还有 GCC、Emacs 等),是 Linux 下常用的程序调试器。发展至今,GDB 已经迭代了诸多个版本,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada等。实际场景中,GDB 更常用来调试 CC++程序。

    总的来说,借助 GDB调试器可以实现以下几个功能:

    程序启动时,可以按照我们自定义的要求运行程序,例如设置参数和环境变量;

    可使被调试程序在指定代码处暂停运行,并查看当前程序的运行状态(例如当前变量的值,函数的执行结果等),即支持断点调试;

    程序执行过程中,可以改变某个变量的值,还可以改变代码的执行顺序,从而尝试修改程序中出现的逻辑错误。

    GDB安装

    1、通过包管理器进行安装

    $ yum -y install gdb
    

    2、源码安装GDB

    gdb源码包上面下载相应的版本进行安装即可。

    3、查看GDB版本

    输入gdb -v,即可查看当前安装的gdb的版本。

    $ gdb -v
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-94.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/>.
    

    如果显示出gdb的版本,也说明了安装成功。

    GDB的用法

    常用调试命令

    GDB 的主要功能就是监控程序的执行流程。这也就意味着,只有当源程序文件编译为可执行文件并执行时,并且该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等),GDB才会派上用场。

    所以在编译时需要使用 gcc/g++ -g 选项编译源文件,才可生成满足 GDB 要求的可执行文件

    调试命令 (缩写)作用
    (gdb) break (b)在源代码指定的某一行设置断点,其中xxx用于指定具体打断点位置
    (gdb) run (r)执行被调试的程序,其会自动在第一个断点处暂停执行。
    (gdb) continue (c)当程序在某一断点处停止后,用该指令可以继续执行,直至遇到断点或者程序结束。
    (gdb) next (n)令程序一行代码一行代码的执行。
    (gdb) step(s)如果有调用函数,进入调用的函数内部;否则,和 next 命令的功能一样。
    (gdb) until (u)
    (gdb) until (u) location
    当你厌倦了在一个循环体内单步跟踪时,单纯使用 until 命令,可以运行程序直到退出循环体。
    until n 命令中,n 为某一行代码的行号,该命令会使程序运行至第 n 行代码处停止。
    (gdb) print (p)打印指定变量的值,其中 xxx 指的就是某一变量名。
    (gdb) list (l)显示源程序代码的内容,包括各行代码所在的行号。
    (gdb) finish(fi)结束当前正在执行的函数,并在跳出函数后暂停程序的执行。
    (gdb) return(return)结束当前调用函数并返回指定值,到上一层函数调用处停止程序执行。
    (gdb) jump(j)使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码。
    (gdb) quit (q)终止调试。

    示例:

    $ ls
    main.cpp
    $ g++ -g -o test main.cpp
    $ ls
    main.cpp  test
    $ gdb test         <-- 启动gdb进行调试
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-94.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 /home/zhuyong/project/linux/blog/gdb/test...done.
    (gdb)
    

    gdb启动时会默认打印一堆免责条款,通过添加 --silent(或者 -q--quiet)选项,可将这部分信息屏蔽掉。

    下面先用个例子运行下上述调试命令

    $ gdb test -q      <-- 启动gdb进行调试
    Reading symbols from /home/zhudi/project/linux/blog/gdb/test...done.
    (gdb) l            <-- 显示带行号的源代码
    1	#include <iostream>
    2	using namespace std;
    3
    4	int main() {
    5	    int sum = 0;
    6	    int n = 1;
    7	    while (n <= 100) {
    8	        sum += n;
    9	        n++;
    10	    }
    (gdb)              <-- 默认情况下,l 选项只显示 10 行源代码,如果查看后续代码,按 Enter 回车键即可
    11	    cout << "sum = " << sum << endl;
    12
    13	    return 0;
    14	}
    15
    (gdb) b 7          <-- 在第7行源代码处打断点
    Breakpoint 1 at 0x4008d3: file main.cpp, line 7.
    (gdb) r            <-- 运行程序,遇到断点停止
    Starting program: /home/zhudi/project/linux/blog/gdb/test
    
    Breakpoint 1, main () at main.cpp:7
    7	    while (n <= 100) {
    Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 libgcc-4.8.5-39.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64
    (gdb) print n      <-- 查看代码中变量 n 的值
    $1 = 1             <-- 当前 n 的值为 1,$1 表示该变量 表示该变量所在存储区的名称
    (gdb) b 13
    Breakpoint 2 at 0x40090e: file main.cpp, line 13.
    (gdb) n            <-- 单步执行程序
    8	        sum += n;
    (gdb) n            <-- 单步执行程序
    9	        n++;
    (gdb) c            <-- 继续执行程序
    Continuing.
    sum = 5050
    
    Breakpoint 2, main () at main.cpp:13
    13	    return 0;
    (gdb) print sum     <-- 查看 sum 的值    
    $2 = 5050           <-- 当前 sum 的值为 5050
    (gdb) q             <-- 退出调试
    A debugging session is active.
    
    	Inferior 1 [process 8449] will be killed.
    
    Quit anyway? (y or n) y     <-- 确认是否退出调试,y 为退出,n 为不退出
    

    接下来分别介绍下各个命令的用法

    GDB 断点调试

    启动程序

    根据不同场景的需要,GDB 调试器提供了多种方式来启动目标程序,其中最常用的就是run 指令,其次为 start 指令。也就是说,runstart 指令都可以用来在 GDB 调试器中启动程序,它们之间的区别是:

    • 默认情况下,run 指令会一直执行程序,直到执行结束。如果程序中手动设置有断点,则 run指令会执行程序至第一个断点处;

    • start 指令会执行程序至main()主函数的起始位置,即在main()函数的第一行语句处停止执行(该行代码尚未执行)。

    break命令

    break 命令(可以用b 代替)常用的语法格式有以下 2 种。

    1(gdb) break location      // b location
    2(gdb) break ... if cond   // b .. if cond
    
    1. 第一种格式中,location 用于指定打断点的具体位置,其表示方式有多种,如表 1 所示。
    location的值含义
    linenumlinenum 是一个整数,表示要打断点处代码的行号。要知道,程序中各行代码都有对应的行号,可通过执行 l(小写的 L)命令看到。
    filename:linenumfilename 表示源程序文件名;linenum 为整数,表示具体行数。整体的意思是在指令文件 filename 中的第 linenum 行打断点。
    + offset
    - offset
    offset 为整数(假设值为 2),+offset 表示以当前程序暂停位置(例如第 4 行)为准,向后数 offset 行处(第 6 行)打断点;-offset 表示以当前程序暂停位置为准,向前数 offset 行处(第 2 行)打断点
    functionfunction 表示程序中包含的函数的函数名,即 break 命令会在该函数内部的开头位置打断点,程序会执行到该函数第一行代码处暂停。
    filename:functionfilename 表示远程文件名;function 表示程序中函数的函数名。整体的意思是在指定文件 filename 中 function 函数的开头位置打断点。
    1. 第二种格式中,… 可以是表 1 中所有参数的值,用于指定打断点的具体位置;cond 为某个表达式。整体的含义为:每次程序执行到 … 位置时都计算 cond 的值,如果为 True,则程序在该位置暂停;反之,程序继续执行。另外也可以用condition 为断点设置命中条件。

    tbreak和rbreak命令

    tbreak 命令可以看到是 break 命令的另一个版本,tbreakbreak 命令的用法和功能都非常相似,唯一的不同在于,使用 tbreak 命令打的断点仅会作用 1 次,即使程序暂停之后,该断点就会自动消失。

    breaktbreak 命令不同,rbreak命令的作用对象是 CC++ 程序中的函数,它会在指定函数的开头位置打断点。语法格式

    (gdb) tbreak regex
    

    其中 regex 为一个正则表达式,程序中函数的函数名只要满足 regex条件,tbreak 命令就会其内部的开头位置打断点。值得一提的是,tbreak 命令打的断点和 break 命令打断点的效果是一样的,会一直存在,不会自动消失。

    示例

    $ gdb test -q
    Reading symbols from /home/zhudi/project/linux/blog/gdb/test...done.
    (gdb) l
    4	
    5	void cb_one() {
    6	    cout << "cb_one" << endl;
    7	}
    8	void cb_second() {
    9	    cout << "cb_second" << endl;
    10	}
    11	
    12	int main() {
    13	    int sum = 0;
    (gdb) 
    14	    int n = 1;
    15	    while (sum < 100) {
    16	        sum += n;
    17	        n++;
    18	        cout << "sum = " << sum << endl;
    19	        sleep(1);
    20	        cb_one();
    21	        cb_second();
    22	    }
    23	    cout << "sum = " << sum << endl;
    (gdb) b 16                  <-- 在第16行打断点
    Breakpoint 1 at 0x400959: file main.cpp, line 16.
    (gdb) r                     <-- 启动程序
    Starting program: /home/zhudi/project/linux/blog/gdb/test 
    
    Breakpoint 1, main () at main.cpp:16
    16	        sum += n;       <--16行暂停
    (gdb) b +2                  <--在当前位置之后的2行处设置断点
    Breakpoint 2 at 0x400963: file main.cpp, line 18.
    (gdb) c
    Continuing.
    
    Breakpoint 2, main () at main.cpp:18
    18	        cout << "sum = " << sum << endl;
    (gdb) b 19 if sum>2         <-- 条件断点
    Breakpoint 3 at 0x40098c: file main.cpp, line 19.
    (gdb) c
    Continuing.
    sum = 1
    cb_one
    cb_second
    
    Breakpoint 1, main () at main.cpp:16
    16	        sum += n;
    (gdb) c
    Continuing.
    
    Breakpoint 2, main () at main.cpp:18
    18	        cout << "sum = " << sum << endl;
    (gdb) c
    Continuing.
    sum = 3
    
    Breakpoint 3, main () at main.cpp:19
    19	        sleep(1);
    (gdb) p sum
    $1 = 3
    (gdb) rbreak cb_*            <-- 匹配所有以cb_开头的函数
    Breakpoint 4 at 0x400901: file main.cpp, line 6.
    void cb_one();
    Breakpoint 5 at 0x400923: file main.cpp, line 9.
    void cb_second();
    Breakpoint 6 at 0x400a17: file main.cpp, line 26.
    (gdb) c
    Continuing.
    
    Breakpoint 4, cb_one () at main.cpp:6
    6	    cout << "cb_one" << endl;     <-- 在cb_one函数的第一行暂停
    (gdb) c
    Continuing.
    cb_one
    
    Breakpoint 5, cb_second () at main.cpp:9
    9	    cout << "cb_second" << endl;  <-- 在cb_second函数的第一行暂停
    

    删除或禁用断点

    删除断点

    如果之前建立的断点不再需要或者暂时不需要,该如何删除或者禁用呢?常用的方式有 2 种:

    1. 使用 quit 命令退出调试,然后重新对目标程序启动调试,此方法会将消除上一次调试操作中建立的所有断点;
    2. 使用专门删除或禁用断点的命令,既可以删除某一个断点,也可以删除全部断点。

    无论是普通断点、观察断点还是捕捉断点,都可以使用 clear 或者 delete 命令进行删除。

    clear 命令可以删除指定位置处的所有断点,常用的语法格式如下所示:

    (gdb) clear location
    

    参数location 通常为某一行代码的行号或者某个具体的函数名。当 location 参数为某个函数的函数名时,表示删除位于该函数入口处的所有断点。

    delete 命令(可以缩写为 d)通常用来删除所有断点,也可以删除指定编号的各类型断点,语法格式如下:

    delete [breakpoints] [num]
    

    其中,breakpoints 参数可有可无,num 参数为指定断点的编号,其可以是delete 删除某一个断点,而非全部。

    如果不指定 num参数,则 delete 命令会删除当前程序中存在的所有断点。

    禁用断点

    禁用断点可以使用 disable 命令,语法格式如下:

    disable [breakpoints] [num...]
    

    breakpoints 参数可有可无;num...表示可以有多个参数,每个参数都为要禁用断点的编号。如果指定 num...disable 命令会禁用指定编号的断点;反之若不设定 num...,则 disable 会禁用当前程序中所有的断点。

    对于禁用的断点,可以使用enable 命令激活,该命令的语法格式有多种,分别对应有不同的功能:

    enable [breakpoints] [num...]                        激活用 num... 参数指定的多个断点,如果不设定 num...,表示激活所有禁用的断点
    enable [breakpoints] once num…                 临时激活以 num... 为编号的多个断点,但断点只能使用 1 次,之后会自动回到禁用状态
    enable [breakpoints] count num...      临时激活以 num... 为编号的多个断点,断点可以使用 count 次,之后进入禁用状态
    enable [breakpoints] delete num…               激活 num.. 为编号的多个断点,但断点只能使用 1 次,之后会被永久删除。
    

    其中,breakpoints 参数可有可无;num...表示可以提供多个断点的编号,enable命令可以同时激活多个断点。

    观察断点监控变量值的变化

    观察断点

    要知道,GDB 调试器支持在程序中打 3 种断点,分别为普通断点、观察断点和捕捉断点。其中 break 命令打的就是普通断点,而 watch 命令打的为观察断点。

    使用 GDB 调试程序的过程中,借助观察断点可以监控程序中某个变量或者表达式的值,只要发生改变,程序就会停止执行。相比普通断点,观察断点不需要我们预测变量(表达式)值发生改变的具体位置

    (gdb) watch cond
    

    watch 命令功能相似的,还有 rwatchawatch 命令。其中:

    • rwatch 命令:只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;
    • awatch 命令:只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。

    示例

    $ gdb test -q
    Reading symbols from /home/zhudi/project/linux/blog/gdb/test...done.
    (gdb) start
    Temporary breakpoint 1 at 0x400949: file main.cpp, line 13.
    Starting program: /home/zhuyong/project/linux/blog/gdb/test 
    
    Temporary breakpoint 1, main () at main.cpp:13
    13	    int sum = 0;
    (gdb) l
    8	void cb_second() {
    9	    cout << "cb_second" << endl;
    10	}
    11	
    12	int main() {
    13	    int sum = 0;
    14	    int n = 1;
    15	    while (sum < 100) {
    16	        sum += n;
    17	        n++;
    (gdb) watch sum        <-- 设置观察断点
    Hardware watchpoint 2: sum
    (gdb) c
    Continuing.
    Hardware watchpoint 2: sum
    
    Old value = 0
    New value = 1
    main () at main.cpp:17
    17	        n++;       <-- sum值发生变化,程序暂停
    

    查看变量或表达式的值

    对于在调试期间查看某个变量或表达式的值,GDB 调试器提供有 2 种方法,即使用 print 命令或者 display命令。

    print 命令

    它的功能就是在 GDB 调试程序的过程中,输出或者修改指定变量或者表达式的值。

    print 命令可以缩写为 p,最常用的语法格式如下所示:

    (gdb) print num
    (gdb) p num
    

    其中,参数 num 用来代指要查看或者修改的目标变量或者表达式。

    当程序中包含多个作用域不同但名称相同的变量或表达式时,可以借助::运算符明确指定要查看的目标变量或表达式。::运算符的语法格式如下:

    (gdb) print file::variable
    (gdb) print function::variable
    

    其中 file用于指定具体的文件名,funciton 用于指定具体所在函数的函数名,variable表示要查看的目标变量或表达式。

    另外,print也可以打印出类或者结构体变量的值。

    #### display 命令

    print 命令一样,display 命令也用于调试阶段查看某个变量或表达式的值,它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。

    也就是说,使用 1 次 print 命令只能查看 1 次某个变量或表达式的值,而同样使用 1 次 display 命令,每次程序暂停执行时都会自动打印出目标变量或表达式的值。因此,当我们想频繁查看某个变量或表达式的值从而观察它的变化情况时,使用 display 命令可以一劳永逸。

    display 命令没有缩写形式,常用的语法格式如下 2 种:

    (gdb) display expr
    (gdb) display/fmt expr
    

    注意,display 命令和 /fmt 之间不要留有空格。以 /x 为例,应写为 (gdb)display/x expr。

    GDB单步调试

    根据实际场景的需要,GDB 调试器共提供了 3 种可实现单步调试程序的方法,即使用 nextstepuntil 命令。换句话说,这 3 个命令都可以控制 GDB调试器每次仅执行 1 行代码,但除此之外,它们各自还有不同的功能。

    next命令

    next 是最常用来进行单步调试的命令,其最大的特点是当遇到包含调用函数的语句时,无论函数内部包含多少行代码,next 指令都会一步执行完。也就是说,对于调用的函数来说,next 命令只会将其视作一行代码。

    next 命令可以缩写为n 命令,使用方法也很简单,语法格式如下:

    (gdb) next count
    

    step命令

    通常情况下,step 命令和next命令的功能相同,都是单步执行程序。不同之处在于,当step 命令所执行的代码行中包含函数时,会进入该函数内部,并在函数第一行代码处停止执行。

    step 命令可以缩写为 s命令,用法和 next 命令相同,语法格式如下:

    (gdb) step count
    

    until命令

    until 命令可以简写为 u 命令,有 2 种语法格式,如下所示:

    1(gdb) until
    2(gdb) until location
    

    其中,参数 location为某一行代码的行号。

    不带参数的 until命令,可以使 GDB调试器快速运行完当前的循环体,并运行至循环体外停止。注意,until 命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until命令才会发生此作用;反之,until命令和 next 命令的功能一样,只是单步执行程序。

    return命令

    实际调试时,在某个函数中调试一段时间后,可能不需要再一步步执行到函数返回处,希望直接执行完当前函数,这时可以使用 finish命令。与finish 命令类似的还有 return 命令,它们都可以结束当前执行的函数。

    finish命令

    finish 命令和 return命令的区别是,finish命令会执行函数到正常退出;而 return 命令是立即结束执行当前函数并返回,也就是说,如果当前函数还有剩余的代码未执行完毕,也不会执行了。除此之外,return命令还有一个功能,即可以指定该函数的返回值。

    jump命令

    jump 命令的功能是直接跳到指定行继续执行程序,其语法格式为:

    (gdb) jump location
    

    其中,location 通常为某一行代码的行号。

    也就是说,jump 命令可以略过某些代码,直接跳到 location处的代码继续执行程序。这意味着,如果你跳过了某个变量(对象)的初始化代码,直接执行操作该变量(对象)的代码,很可能会导致程序崩溃或出现其它 Bug。另外,如果 jump跳转到的位置后续没有断点,那么 GDB会直接执行自跳转处开始的后续代码。

    GDB search 命令

    调试文件时,某些时候可能会去找寻找某一行或者是某一部分的代码。可以使用 list 显示全部的源码,然后进行查看。当源文件的代码量较少时,我们可以使用这种方式搜索。如果源文件的代码量很大,使用这种方式寻找效率会很低。所以 GDB中提供了相关的源代码搜索的的search命令。

    search 命令的语法格式为:

    search <regexp>
    reverse-search <regexp>
    

    第一项命令格式表示从当前行的开始向前搜索,后一项表示从当前行开始向后搜索。其中regexp 就是正则表达式,正则表达式描述了一种字符串匹配的模式,可以用来检查一个串中是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串。很多的编程语言都支持使用正则表达式。

    查看堆栈信息

    backtrace 命令

    backtrace 命令用于打印当前调试环境中所有栈帧的信息,常用的语法格式如下:

    (gdb) backtrace [-full] [n]
    

    其中,用 [ ] 括起来的参数为可选项,它们的含义分别为:

    • n:一个整数值,当为正整数时,表示打印最里层的 n 个栈帧的信息;n为负整数时,那么表示打印最外层n个栈帧的信息;

    • -full:打印栈帧信息的同时,打印出局部变量的值。

    注意,当调试多线程程序时,该命令仅用于打印当前线程中所有栈帧的信息。如果想要打印所有线程的栈帧信息,应执行thread apply all backtrace命令。

    frame 命令

    frame命令的常用形式有 2 个:

    1. 根据栈帧编号或者栈帧地址,选定要查看的栈帧,语法格式如下:
    (gdb) frame spec
    

    该命令可以将 spec 参数指定的栈帧选定为当前栈帧。spec 参数的值,常用的指定方法有 3 种:

    1. 通过栈帧的编号指定。0 为当前被调用函数对应的栈帧号,最大编号的栈帧对应的函数通常就是 main() 主函数;
    2. 借助栈帧的地址指定。栈帧地址可以通过 info frame 命令(后续会讲)打印出的信息中看到;
    3. 通过函数的函数名指定。注意,如果是类似递归函数,其对应多个栈帧的话,通过此方法指定的是编号最小的那个栈帧。

    除此之外,对于选定一个栈帧作为当前栈帧,GDB 调试器还提供有updown两个命令。其中,up命令的语法格式为:

    (gdb) up n
    

    其中 n为整数,默认值为 1。该命令表示在当前栈帧编号(假设为 m)的基础上,选定 m+n为编号的栈帧作为新的当前栈帧。

    相对地,down 命令的语法格式为:

    (gdb) down n
    

    其中n为整数,默认值为 1。该命令表示在当前栈帧编号(假设为 m)的基础上,选定m-n 为编号的栈帧作为新的当前栈帧。

    1. 借助如下命令,我们可以查看当前栈帧中存储的信息:
    (gdb) info frame
    

    该命令会依次打印出当前栈帧的如下信息:

    • 当前栈帧的编号,以及栈帧的地址;
    • 当前栈帧对应函数的存储地址,以及该函数被调用时的代码存储的地址
    • 当前函数的调用者,对应的栈帧的地址;
    • 编写此栈帧所用的编程语言;
    • 函数参数的存储地址以及值;
    • 函数中局部变量的存储地址;
    • 栈帧中存储的寄存器变量,例如指令寄存器(64位环境中用 rip 表示,32为环境中用eip 表示)、堆栈基指针寄存器(64位环境用 rbp表示,32位环境用 ebp表示)等。

    除此之外,还可以使用info args命令查看当前函数各个参数的值;使用info locals命令查看当前函数中各局部变量的值。

    调试正在执行的程序

    如果调试正在执行中的程序,首先需要找到正在运行程序的进程号PID,之后可以用下面三个命令进行调试,进入正常的调试流程。

    1) gdb attach PID
    2) gdb 文件名 PID
    3) gdb -p PID
    

    示例:

    # ps -aux | grep test           <-- 找到正在运行程序的进程号PID
    root     17997  0.0  0.0  12540  1064 pts/0    S+   10:19   0:00 ./test
    root     18088  0.0  0.0 112812   972 pts/1    S+   10:20   0:00 grep --color=auto test
        
    # gdb attach 17997 -q           <-- 用gdb进行调试
    attach: No such file or directory.
    Attaching to process 17997
    Reading symbols from /root/project/blog/gdb/test...done.
    Reading symbols from /lib64/libstdc++.so.6...(no debugging symbols found)...done.
    Loaded symbols for /lib64/libstdc++.so.6
    Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done.
    Loaded symbols for /lib64/libm.so.6
    Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done.
    Loaded symbols for /lib64/libgcc_s.so.1
    Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
    Loaded symbols for /lib64/libc.so.6
    Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
    Loaded symbols for /lib64/ld-linux-x86-64.so.2
    0x00007f61ea02b840 in __nanosleep_nocancel () from /lib64/libc.so.6
    

    注意,当 GDB 调试器成功连接到指定进程上时,程序执行会暂停。如上所示,程序暂停至第 6 行代码num++的位置,此时可以通过断点调试、逐步运行等方式监控程序的执行过程。例如:

    (gdb) l                        
    warning: Source file is more recent than executable.
    1	#include <iostream>
    2	#include <unistd.h>
    3	using namespace std;
    4	
    5	int main() {
    6	    int sum = 0;
    7	    int n = 1;
    8	    while (true) {
    9	        sum += n;
    10	        n++;
    (gdb) 
    11	        cout << "sum = " << sum << endl;
    12	        sleep(1);
    13	    }
    14	    cout << "sum = " << sum << endl;
    15	
    16	    return 0;
    17	}
    18
        
        
    (gdb) b 10
    Breakpoint 1 at 0x400869: file main.cpp, line 10.
    (gdb) c
    Continuing.
    
    Breakpoint 1, main () at main.cpp:10
    10	        n++;
    (gdb) p sum
    $1 = 2145
    (gdb) c
    Continuing.
    
    Breakpoint 1, main () at main.cpp:10
    10	        n++;
    (gdb) p sum
    $2 = 2211
    (gdb)
    

    注意,当调试完成后,如果想令当前程序进行执行,消除调试操作对它的影响,需手动将 GDB 调试器与程序分离,分离过程分为 2 步:

    1. 执行 detach 指令,使GDB调试器和程序分离;

    2. 执行 quit(或q)指令,退出GDB调试。

    调试执行异常崩溃的程序

    Linux操作系统中,当程序执行发生异常崩溃时,系统可以将发生崩溃时的内存数据、调用堆栈情况等信息自动记录下载,并存储到一个文件中,该文件通常称为core 文件,Linux 系统所具备的这种功能又称为核心转储(core dump)。幸运的是,GDBcore 文件的分析和调试提供有非常强大的功能支持,当程序发生异常崩溃时,通过GDB 调试产生的 core文件,往往可以更快速的解决问题。

    这里就先不写如何设置core dump文件目录了,可以自行了解。

    写个程序验证一下:

    #include <stdio.h>
    
    int main() {
        char *a = NULL;
        *a = 2;
        
        return 0;
    }
    

    编译运行

    $ g++ -g -o test core.cpp 
    $ ./test
    Segmentation fault (core dumped)      <-- 发生段错误,并生成了 core 文件
    

    可以根据生成时间查找core dump文件

    ls /home/homework/coresave -hl | grep test
    -rw-rw-rw- 1 root      root      400K Mar 13 15:08 core.test.27725.1615619332
    -rw-rw-rw- 1 root      root      400K Mar 13 15:26 core.test.7791.1615620408
    -rw-rw-rw- 1 root      root      540K Mar 11 10:29 core.test.1868.1615429740
    -rw-rw-rw- 1 root      root      400K Mar 13 15:07 core.test.26880.1615619264
    -rw-rw-rw- 1 root      root      404K Mar  3 19:42 core.test.28802.1614771771
    

    gdb进行调试

    $ gdb test /home/homework/coresave/core.test1.7791.1615620408 -q
    Reading symbols from /home/zhudi/project/linux/blog/gdb/test...done.
    
    warning: core file may not match specified executable file.
    [New LWP 7791]
    Core was generated by `./test'.
    Program terminated with signal 11, Segmentation fault.
    #0  0x00000000004005bd in main () at core.cpp:5
    5	    *a = 2;
    

    由此可见,程序崩溃了在第五行,定位到了出现问题的代码位置。

    本文参考

    GDB调试教程

    本文作者:zhuyong
    原文链接:https://zhuyongchn.github.io
    关于博主:欢迎关注左侧公众号,获取更多干货。
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
    展开全文
  •   gdb(GNU symbolic debugger)是GNU开源组织发布的一个强大的Linux下的程序调试工具(GNU Project 调试器),它使你可以查看另一个程序在“执行”期间正在执行的操作,或该程序崩溃时正在执行的操作。...

    1. 什么是gdb

      gdb(GNU symbolic debugger)是GNU开源组织发布的一个强大的Linux下的程序调试工具(GNU Project 调试器),它使你可以查看另一个程序在“执行”期间正在执行的操作,或该程序崩溃时正在执行的操作。
      gdb主要可以如下4个方面的事情:
      (1)启动我们的程序,可以按照我们的自定义的要求随心所欲的运行程序。
      (2)使程序在指定条件下停止。
      (3)检查程序停止时发生的情况。
      (4)更改程序中的内容,以便我们可以尝试纠正一个错误的影响,然后继续学习另一个错误。

    2. gdb调试命令

      写在前面:gdb调试的是可执行文件,而且这个可执行文件必须带有调试信息才行(gcc编译时必须带有-g参数),而非.c文件(源文件),例如我们有一个名为e_test的可执行文件,启动e_tset调试的方法为:gdb ./e_test 。
    在这里插入图片描述

    2.1 运行指令(Program running commands)

    说  明:以下这些命令用于运行程序。
    指  令

    • (gdb) run(简称 r):全速运行程序,直到遇到“断点”或“程序产生错误”时停止。
    • (gdb) continue (简称 c):继续运行程序,直到遇到下一个断点或错误。
    • (gdb) finish :运行程序,直到当前函数(function)执行完成。
    • (gdb) step(简称 s):执行下一行程序(若下一行是个函数,则会进入函数体内)。
    • (gdb) step N (简称 s N) :执行下N行代码。
    • (gdb) stepi (简称 si):执行完一条机器指令,然后停止并返回到调试器。
    • (gdb) next (简称 n):执行下一行代码,与s类似,但是next不进入函数体。
    • (gdb) nexti (简称 ni):执行一条机器指令。如果是一个函数调用,则该命令将继续执行,直到函数返回。
    • (gdb) until (简称 u):在堆栈中上升一层,该命令用于避免单步执行循环多次。
    • (gdb) until N (简称 u N):执行运行程序,直到当前行前面已经运行了N行代码。

    2.2 断点指令(Breakpoint commands)

    说  明:该命令在指定位置设置软件断点,断点可以是函数名、行号或指令地址。
    指  令

    • (gdb) b main:在main函数入口设置断点。
    • (gdb) b:在当前行设置断点。
    • (gdb) b \<n>:在第n行设置断点。
    • (gdb) b +\<n>:在当前行之后(forward)的第n行设置断点。
    • (gdb) b -\<n>:在当前行之前(backward)的第n行设置断点。
    • (gdb) b \<function>:在function函数处设置断点。
    • (gdb) b \<filename>:<linenum>:在某个文件(filename)的第linenum行设置断点。
    • (gdb) b <filename>:<function> :在某个文件(filename)的函数(function)处设置断点。
    • (gdb) b * \<address> :在地址(address)处设置断点。

    2.3 回溯指令(Backtrace command)

    说  明:回溯指令(简称bt)可以打印整个堆栈的信息。在任何时候,均可以通过输入系统中断字符(Ctrl + c)停止回溯。
    指  令

    • (gdb) bt:查看栈信息。
    展开全文
  • linux gdb调试命令详解

    千次阅读 2021-09-15 15:08:15
    list命令可以所写为l,可以列出所调试程序的代码(前提是代码与可执行程序在同一服务器上),其居具体使用方法如下: list+lineNumber,打印指定行附近的代码。如list 45,gdb会将45行前后的代码打印在屏幕上。 ...

    目录

    1. list 命令

    2. run 命令

    3. quit命令

    4. break命令

    5. delete命令

    6. 逐步调试

    6.1 next 

    6.2 step < count>

    6.3 set step-mode

    6.4 call

    6.5 finish

    6.6 until

    6.7 disassemble

    6.8 stepi(缩写si)和nexti(缩写ni)

    7. contine命令

    8. print命令

    9.set命令

    10. watch命令

    11. return命令

    12. info命令

    13. bt命令

    14. whatis和ptype 命令

    15. 回车符

    16. help命令

    17. start命令

    18. handle命令


    1. list 命令

    1. list命令可以所写为l,可以列出所调试程序的代码(前提是代码与可执行程序在同一服务器上),其居具体使用方法如下:
    2. list+lineNumber,打印指定行附近的代码。如list 45,gdb会将45行前后的代码打印在屏幕上。
    3. 直接输入list,gbd会将gdb当前所处的行以及后面的代码打印在屏幕上。
    4. 输入list -,gbd会将gdb当前所处的行前面的代码打印在屏幕上。
    5. list+functionName,打印名称为functionName的函数的上下文的代码。

    2. run 命令

            在gdb中使用run(可以缩写为r)命令运行程序,一般启动进程后会配合set args设置进程入参。如set args 10 20,相当于把args设置为3,argv[1]为10,argv[2]为20。

            show args可以查看运行时参数。​​​​​​

    3. quit命令

    在gdb中使用quit(可以缩写为q)命令退出正在运行的程序。

    4. break命令

    在使用gdb调试时使用break(可以缩写为b)命令来设置断点,有如下几种方法:

    • break < function >
      在进入指定的函数function时既停止运行,C++中可以使用class::function或function(type, type)格式来指定函数名称
    • break < lineNumber>
      在指定的代码行打断点
    • break +offset/break -offset
      在当前行的前面或后面的offset行打断点,offset为自然数
    • break filename:lineNumber
      在名称为filename的文件中的第lineNumber行打断点
    • break filename:function
      在名称为filename的文件中的function函数入口处打断点
    • break *address
      在程序运行的内存地址处打断点
    • break
      在下一条命令处停止运行
    • break … if < condition>
      在处理某些循环体中可使用此方法进行调试,其中…可以是上述的break lineNumber、break +offset/break -offset中的参数,其中condition表示条件,在条件成立时程序即停止运行,如设置break if i=100表示当i为100时程序停止运行。
      查看断点时,也可以使用info命令如info breakpoints [n]、info break [n]其中n 表示断点号来查看断点信息。

    5. delete命令

    delete命令可以用来删除断点。其中:

    • delete breakpoints删除所有断点。
    • delete breakpoints n,删除编号为n的断点,n是info breakpoints得到的。

    disable breakpoints命令可以禁用断点,enable breakpoints可以启用断点。

    6. 逐步调试

    使用gdb工具调试可以使用next命令单步执行程序代码,next的单步不会进入函数的内部,与next对应的step命令则在单步执行一个函数时进入函数内部,类似于VC++中的step into.其用法如下:

            6.1 next <count>

            单步跟踪,如果有函数调用不会进入函数,如果后面不加count表示一条一条的执行,加count表示执行后面的count条指令。

            6.2 step < count>

            单步跟踪,如果有函数调用则进入该函数(进入该函数前提是此函数编译有Debug信息),与next类似,其不加count表示一条一条执行,加上count表示自当前行开始执行count条代码指令。

            6.3 set step-mode

            set step-mode on用于打开step-mode模式,这样在进行单步跟踪时,程序不会因为没有debug信息而不停止运行,这很有利于查看机器码,可以通过set step-mode off关闭step-mode模式

            6.4 call

           call name 调用和执行一个函数。

            6.5 finish

           运行程序直到当前函数完成并打印函数返回时的堆栈地址和返回值及参数值等信息。

            6.6 until

           运行程序直到退出循环体

            6.7 disassemble

           简写为disas,查看当前函数的汇编指令,并显示下一条要执行的执令。

            6.8 stepi(缩写si)和nexti(缩写ni)

            stepi和nexti用于单步跟踪一条及其指令,一条程序代码有可能由数条机器指令完成,stepi和nexi可以单步执行机器指令。

    7. contine命令

            当程序遇到断点停止运行后可以使用continue(缩写为c)命令恢复程序的运行到下一个断点或直到程序结束。

    8. print命令

            print可以缩写为p,可以通过print命令查看参数或程序运行数据,print是可以指定输出内容格式的,具体方法如下:

    • x按16进制格式显示变量
    • d按十进制显示变量
    • u按十六进制格式显示无符号整形
    • o按八进制格式显示变量
    • t按二进制格式显示变量
    • c按字符格式显示变量
    • f按浮点数格式显示变量

            可以使用display命令设置一些自动显示的变量,当程序暂停运行或单步跟踪时,这些变量会自动显示。

            如果要修改变量的值也可以使用print命令如:print g_top = 24。

            使用print查看程序运行时的数据时,每一个print都会被gdb记录下来并且以 (美元符号)1、(美元符号)2…这样的方式为每一个print命令编号,我们可以使用这个编号来访问以前的表达式,如print $1会打印出第一次打印的表达式的值。

    9.set命令

    set para=value,可以给变量赋值。

    10. watch命令

    watch命令一般来观察某个表达式(变量也可视为一种表达式)的值是否发生了变化,如果由变化则程序立即停止运行,其具体用法如下:

    • watch < expr>
      为表达式(变量)expr设置一个观察点一旦其数值由变化,程序立即停止运行
    • rwatch < expr>
      当表达式expr被读时,程序立即停止运行
    • awatch < expr>
      当表达式expr的值被读或被写时程序立即停止运行
    • info watchpoints
      列出当前所设置的所有观察点

    11. return命令

    如果在函数中设置了调试断点,在断点后还有语句没有执行完,这个时候我们可以使用return命令强制函数忽略还没有执行的语句并返回。可以直接使用return命令用于取消当前函数的执行并立即返回函数值,也可以指定表达式如 return < expression>那么该表达式的值会被作为函数的返回值。

    12. info命令

    info命令可以用来在调试时查看寄存器、断点、观察点和信号等信息。其用法如下:

    • info registers:查看除了浮点寄存器以外的寄存器。
    • info all-registers: 查看所有的寄存器包括浮点寄存器。
    • info registers < registersName>:查看指定寄存器。
    • info break: 查看所有断点信息。
    • info watchpoints: 查看当前设置的所有观察点。
    • info signals info handle: 查看有哪些信号正在被gdb检测。
    • info line: 查看源代码在内存中的地址。
    • info threads: 可以查看多线程。

    13. bt命令

    bt命令的作用书打印程序的堆栈,gdb调试过程中输入bt可以清晰的看到函数的调用路径。where命令也有相同的作用。

    14. whatis和ptype 命令

    这两个命令可以显示变量的类型,ptypewhatis的功能更强,他可以提供一个结构的定义

    15. 回车符

    gdb在执行完一个命令后不输入任何命令直接回车,gdb会默认执行上一个命令。

    16. help命令

    进入gdb后可以使用help命令查看gdb的使用方法。

    17. start命令

    开始调试,停在第一行代码处。

    18. handle命令

            gdb通常可以捕捉到发送给它的大多数信号,通过捕捉信号,它就可决定对于正在运行的进程要做些什么工作。例如,按CTRL-C将中断信号发送给gdb,通常就会终止gdb。但是你或许不想中断gdb,真正的目的是要中断gdb正在运行的程序,因此,gdb要抓住该信号并停止它正在运行的程序,这样就可以执行某些调试操作。

    handle命令可控制信号的处理,他有两个参数,一个是信号名,另一个是接受到信号时该作什么。几种可能的参数是:

    • nostop 接收到信号时,不要将它发送给程序,也不要停止程序。
    • stop 接受到信号时停止程序的执行,从而允许程序调试;显示一条表示已接受到信号的消息(禁止使用消息除外)
    • print 接受到信号时显示一条消息
    • noprint 接受到信号时不要显示消息(而且隐含着不停止程序运行)
    • pass 将信号发送给程序,从而允许你的程序去处理它、停止运行或采取别的动作。
    • nopass 停止程序运行,但不要将信号发送给程序。

    例如,假定你截获SIGPIPE信号,以防止正在调试的程序接受到该信号,而且只要该信号一到达,就要求该程序停止,并通知你。要完成这一任务,可利用如下命令:

    (gdb) handle SIGPIPE stop print

    请注意,UNⅨ的信号名总是采用大写字母!你可以用信号编号替代信号名如果你的程序要执行任何信号处理操作,就需要能够测试其信号处理程序,为此,就需要一种能将信号发送给程序的简便方法,这就是signal命令的任务。该命令的参数是一个数字或者一个名字,如SIGINT。假定你的程序已将一个专用的SIGINT(键盘输入,或CTRL-C;信号2)信号处理程序设置成采取某个清理动作,要想测试该信号处理程序,你可以设置一个断点并使用如下命令:

    (gdb) signal 2

    continuing with signal SIGINT⑵

    该程序继续执行,但是立即传输该信号,而且处理程序开始运行。

    展开全文
  • GDB调试命令大全

    2014-11-26 15:42:44
    C++的GDB调试命令大全,方便GDB调试使用
  • GDB调试命令手册.pdf

    2021-10-18 08:09:09
    GDB调试命令手册.pdf
  • GDB调试命令手册..pdf

    2020-10-19 19:43:06
    gdb gdb 常用的 命令 常用的 命令 backtrace ( backtrace ( 显示程序中的当前位置和表示如何到达当前位置的栈跟踪 同义 显示程序中的当前位置和表示如何到达当前位置的栈跟踪 同义 :where breakpoint :where ...
  • gdb调试命令用法.txt

    2021-05-15 14:20:56
    Linux gdb调试命令
  • linux gdb调试命令.pdf

    2020-04-28 19:55:32
    Linux gdb常用调试命令,里边总结了,常用调试命令,core文件调试,多线程调试,以及如何将内存输出到文件等内容
  • 比较全面的gdb调试命令

    千次阅读 2016-07-22 18:26:25
    比较全面的gdb调试命令
  • gdb调试命令手册[借鉴].pdf
  • Linux的gdb调试命令(详细)

    千次阅读 2020-03-03 11:02:54
    我们知道gdb调试命令是非常多的, 我们不可能完全记住有些记住的用法也可能不太熟悉,那么我们在使用的过程中,如果希望查看某个命令的帮助信息,可以使用gdb调试帮助信息 启动gdb后,进入gdb的调试环境中,就可以...
  • gdb调试命令及基本使用姿势,C/C++调试工具gdb的基本使用姿势,linux下gdb调试,gdb调试工具,gdb调试命令,gdb调试教程,gdb调试实例一、gdb命令1、运行命令run:(简写 r) ,其作用是运行程序,当遇到断点后,程序...
  • Gdb调试命令

    2015-09-09 17:34:50
    GDB调试程序一GDB概述————GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有...
  • gdb调试常用命令总结

    2019-04-28 11:02:54
    gdb调试常用命令总结, gdb调试线程挂住问题打印堆栈信息等
  • 收集的一些GDB调试命令以及一些案例分析,相当实用,
  • 本文将主要介绍linux下的gdb调试工具常用的命令和具体的使用实例。 二、调试过程介绍 2.1 编译程序加参数时生成调试信息 -g 和 -ggdb 都是令 gcc 生成调试信息,但是它们也是有区别的 选项 解析 g 该选项...
  • gdb调试命令大全

    2013-06-03 17:39:17
    gdb调试命令大全
  • gdb调试命令

    千次阅读 2019-06-19 11:17:11
    GDB调试程序 GDB是一个强大的命令行调试工具。大家知道命令行的强大就是在于,其可以形成执行序列,形成脚本。UNIX下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优势在于,它们可以...
  • GDB调试命令手册

    2013-11-09 22:29:55
    软件开发最重要的是调试自己的程序,其中gdb调试很重要,这本手册能帮助你迅速上手gdb,充分了解gdb
  • GDB调试详细命令

    2018-06-01 16:23:05
    GDB详细手册,文档内部分内容: ...(gdb) thread apply ID1 ID2 command //让一个或多个线程执行GDB命令 (gdb) set scheduler-locking off|on|step //只有当前函数,当前线程执行 完整版本请下载该手册!
  • gdb调试命令及其含义

    千次阅读 2019-04-25 22:37:58
    gdb是Linux下非常实用的程序调试插件,因为Linux默认在gcc生成a.out时生成的是Release版本,在ELF段中不存在Debug相关段,所以需要在编译时在命令最后加上 -g 标识,标识生成Debug版本,也因为Debug是在ELF段中插入...
  • gdb调试基本命令(非常详细)

    千次阅读 2021-02-05 14:52:37
    本文介绍使用gdb调试程序的常用命令。 简介 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。同时GDB也...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 61,334
精华内容 24,533
关键字:

gdb调试命令

友情链接: house.rar