精华内容
下载资源
问答
  • gdb调试
    千次阅读
    2022-03-23 20:12:53

    C++程序员必备知识


    什么是GDB??

    • GDB是GNU软件系统社区提供的调试工具,同GCC配套组成一套完整的开发环境,GDB是Linux和许多许多Unix系统中的标准开发环境。
    • GDB主要的四个功能:
      1. 启动程序,可以按照自定义的要求随心所欲的运行程序
      2. 可以让被调试的程序在所指定位置的断点出停住(断点可以是条件表达式)
      3. 当程序被停止时,可以检查此时程序所发生的事
      4. 可以改变程序,将一个BUG产生的影响修正,从而测试其它BUG

    准备工作

    • 通常,在为调试而编译时,必须关掉编译器的优化现象(-0n),并打开调试选项 -g,另外,’-wall‘在尽量不影响程序行为的情况下打开,提示所有的warning
    • -g选项的作用是在可执行文件中加入源代码信息,比如可执行程序文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能够找到源文件(-g的文件会比不加的大,而且我们在GDB中查看的时源文件的代码)

    非调试命令

    • 启动GDB
      1. gdb 可执行文件
    •  查看代码(默认显示10行)
      1. l/list
      2. l  行号(函数名) ---->当前文件
      3. l  文件名:行号(函数名)---->跨文件
    •  设置查看代码的行数(针对list)
      1. show list/listsize
      2. set     list/listsize   行数
    •  设置断点
      1. b/break
      2. b  行号(函数名)
      3. b  文件名:行号(函数名)
      4. b   行号  if i == 9                        —设置条件断点
      5. delete/del/l   断点的编号
      6. info/i                                           —查看所有断点
      7. i     b                                           —查看断点信息
      8. dis/display    断点编号                —设置断点无效
      9. ena/enable   断点编号                —设置断点生效 

     GDB调试

    • 运行GDB程序(开始调试的第一步)
      1. start                                            —程序停在第一行
      2. run                                              —遇到断点才停
    •  继续运行,到下一个断点停
      1. c/continue
    • 向下执行一行代码(遇到函数不会进入函数体)
      1. n/next
    •  变量操作
      1. p/print     变量名                         —打印变量值
      2. ptype      变量名                         —打印变量类型
    •  向下执行一行代码(遇到函数会进入函数体)
      1. s/step
      2. finish(跳出函数体)                      —函数体里没有断点是前提
    •  自动变量操作
      1. display  num                              —自动打印指定变量的值
      2. i/info      display                         —查看自动打印变量的信息
      3. undisplay    编号                        —取消自动打印指定变量
    •  其它操作
      1. set     var     变量=变量值
      2. until(跳出循环体)                        —循环里没断点是前提
    更多相关内容
  • 使用gdb调试core文件,可以帮助我们快速定位程序出现段错误的位置。当然,可执行程序编译时应加上-g编译选项,生成调试信息。 当程序访问的内存超出了系统给定的内存空间,就会产生Segmentation fault (core dumped)...
  • -g:在可执行文件中加入源码信息,比如:可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件都嵌入到可执行文件中,而是在调试时必须保证gdb能找到源文件。这些调试信息包括行号、变量的类型和...
  • GDB(GNU symbolic debugger)简单地说就是一个调试工具。它是一个受通用公共许可证即GPL保护的自由软件。 像所有的调试器一样,GDB可以让你调试一个程序,包括让程序在你希望的地方停下,此时你可以查看变量、...
  • gdb调试

    2022-02-18 17:53:26
    1.gdb是什么? 官网介绍: GDB, the GNU Project debugger, allows you to see what is... GDB是GNU工程调试器,让你能够看到程序内部是如何执行的,或者在程序崩溃的时刻程序在干什么。说白了就是一个调试程序的工

    1.gdb是什么?

    官网介绍:

      GDB, the GNU Project debugger, allows you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed.
    
      GDB是GNU工程调试器,让你能够看到程序内部是如何执行的,或者在程序崩溃的时刻程序在干什么。说白了就是一个调试程序的工具。
    
      GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:
    
      GDB可以做四类事情来帮助你捕捉实际中的bug。
    
    • Start your program, specifying anything that might affect its behavior.

      启动程序,查看影响程序行为的任何细节。
      
    • Make your program stop on specified conditions.

      让你的程序在特定条件下停止。
      
    • Examine what has happened, when your program has stopped.

      测试当你的程序停止时到底发生了什么。
      
    • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.

    2.demo

    下面均以此有问题的程序test_error.c说事。
    
    #include<stdio.h>
    
    int main()
    {    
        int* pNum = NULL;
        *pNum = 100;
        return 0;
    }
    
      首先编译程序然后进入调试状态:
    
    • 其中-g是要生成符号文件,否则当使用gdb调试时会提示没有符号文件,如下图所示。

     

     

    3.gdb命令以及调试

    首先apt-get install gdb进行安装。

    • gdb a.out :进入调试状态。

    • list :列出程序代码,包含行数 然后就可以设置断点了。

    • break(r):设置断点:b 3或者b main 在第三行或者main函数处设置断点。

    • run(r):程序执行。

    • print(p) 变量 :查看变量在当前断点处的信息。

    • info b :查看断点信息。

    • next(n):单步执行。

      以下是一个简单的调试过程:

     

    4.调试崩溃core文件

        在我们运行程序时经常会遇见:段错误,核心已转储之类的提示。或者只有段错误,注意在这种情况下是因为ulimit的问题,所以没有生成崩溃信息文件。
    

    当我们需要调试一个崩溃程序时,首先得生成崩溃信息文件:core。

    • ulimit -c 查看允许的崩溃文件大小,如果没有开启则结果是0.
    • ulimite -c unlimited手动开启即可.

    接下来启动gdb运行以下命令:

    gdb a.out core
    

    gdb会直接定位到你的崩溃代码处!如下图:

     然后就会直接跳到崩溃代码处。此处是因为p为空指针却给赋了值!

     5.调试nodejs

    注意在gdb中设置参数的方法:set args a b c

    当nodejs调用了C++插件,而插件中存在崩溃时,也可以用gdb来调试。

     直接在js中调用时可能看不出直接问题:

    此时启用gdb调试: 

     此时问题直接定位到了。刚开始gdb进去的时候是不能给.node设置断点的(或者我不会),r之后会加载进去,之后输入list则会显示出demo.cc的代码,此时可利用b、n进行断点设置及单步运行调试。

    另外:貌似可以直接给库文件打断点:此时其实需要源文件 

     

    6.收工

    perfect!
    
    展开全文
  • GDB调试详细命令

    2018-06-01 16:23:05
    GDB详细手册,文档内部分内容: //查看运行中的线程 (gdb) info thread //查看线程 (gdb) thread <n> //切换为线程id (gdb) bt //backtrace 打印堆栈 (gdb) break xx.cpp:xx thread all //在所有线程上打断点 (gdb) ...
  • Linux GDB调试文档

    2019-02-13 11:23:02
    使用GDB调试,英文版。对于从事 Linux C/C++ 后台开发的读者来说,GDB 调试是需要熟练掌握的一项技能
  • GDB调试打印STL PROTOBUF

    2017-09-14 14:42:19
    GDB调试打印STL PROTOBUF,只要放到.gdbinit文件中就可以直接打印MAP LIST VECTOR SET DEQUEUE等等STL容器里装的东西了。还有PROTOBUF里装的东西也可以打印出来,调试时看PB协议很方便。
  • GDB调试应用指南Guide
  •  test是要调试的程序,由gcc test.c -g -o test生成。进入后提示符变为(gdb) 。 2)查看源码 (gdb) l  源码会进行行号提示。  如果需要查看在其他文件中定义的函数,在l后加上函数名即可定位到这个函数的定义及...
  • gdb调试解二进制炸弹

    2017-12-28 10:47:59
    二进制炸弹简单教程及示例。 简述二进制炸弹的构造原理,以及如何在linux环境下使用gdb调试拆弹。
  • gdb调试手册

    2018-08-17 17:45:44
    gdb使用手册,详细介绍gdb在linux操作系统下的使用步骤
  • GDB调试命令手册.pdf

    2021-10-18 08:09:09
    GDB调试命令手册.pdf
  •  一、下载gdb-*.tar.gz源代码  http://ftp.gnu.org/gnu/gdb/  二、编译 GDB  #tar zxvf gdb-*.tar.gz  2.1、编译GDB Server  #cd gdb-*  #./configure --target=arm-linux --prefix=/usr/local/arm-gdb...
  • GDB调试手册.pdf

    2019-06-17 13:39:44
    介绍GDB的使用调试方法,自己积累的经验调试 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等 IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这...
  • gdb用来调试程序,分析程序的重要工具,海思HIxx是华为海思芯片推出的一些列用于开发IPC、NVR、XVR、DVR的视频处理芯片,被海康、大华、宇视、长视等大型安防厂商广泛采用。在进行软件开发过程中不免出现各种个样的...
  • GDB调试方法

    千次阅读 2022-01-18 16:00:23
    文章目录启动GDB调试coredump的设置与调试常用命令列表部分命令详解break/binfo break以及断点的enable、disable和deleteprint/p 和 ptypethread及info threadwatch常用调试技巧使 print 打印显示完整多线程下锁定...

    GDB最详细的文档请参考GDB Documentation。其中给出的关于GDB的简介非常精炼:

    The purpose of a debugger such as GDB is to allow you to see what is going on “inside” another program while it executes—or what another program was doing at the moment it crashed.
    GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:

    • Start your program, specifying anything that might affect its behavior.
    • Make your program stop on specified conditions.
    • Examine what has happened, when your program has stopped.
    • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.

    使用GDB进行调试时,为了查看完整的符号信息,在编译程序时需要加上选项-g -O0,以保留调试符号信息。比如编译 redis 时,我们需要在make时如下操作:

    make CFLAGS="-g -O0"
    

    如果是C++的程序则使用编译器选项CXXFLAGS

    启动GDB调试

    有三种方法启动GDB调试:

    • gdb elf-file —— 直接调试目标程序
    • gdb -p pid —— 附加到某个正在执行的进程
    • gdb elf-file core —— 调试coredump产生的core文件

    当我们想要调试某个正在运行的进程而不想重新启动它以致于实时数据丢失,则可以将调试器附加(attach)到这个进程。比如我们的系统上有redis服务器正在运行,进程号时31055:

    ps -ef | grep redis
    book      31055   2554  0 03:41 ?        00:00:00 redis-server *:6379
    

    那么通过指令sudo gdb -p 31055就可以attach到redis进程:

    ......
    Attaching to process 31055
    [New LWP 31056]
    [New LWP 31057]
    [New LWP 31058]
    [New LWP 31059]
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    0x00007f53c3d9fd67 in epoll_wait (epfd=5, events=0x7f53c3925b40, 
        maxevents=4192, timeout=100) at ../sysdeps/unix/sysv/linux/epoll_wait.c:30
    30	../sysdeps/unix/sysv/linux/epoll_wait.c: No such file or directory.
    

    此时调试器会将进程暂停,待我们完成调试后,可以输入detach指令使进程继续正常执行。

    coredump的设置与调试

    如果程序崩溃时产生了核心转储文件“core”(比如出现段错误、栈溢出),则会使相关问题的调试工作顺利许多。但首先我们需要通过ulimit -a指令来查看当前Linux环境是否允许产生core文件:

    $ ulimit -a
    core file size          (blocks, -c) unlimited		# <----- 不能是0,最好为 unlimited
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 7641
    max locked memory       (kbytes, -l) 65536
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 7641
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    

    一般来说系统默认core file size为0,我们可以直接通过指令ulimit -c unlimited将其设置为无限大,因为一个复杂程序的core文件往往都是比较大的。

    除此之外,core 文件默认出现在可执行文件所在的目录,我们也可以手动设置其产生目录,并且可以配置core文件的命名格式以便于区分。方法就是在/etc/sysctl.conf文件中添加如下配置项:

    kernel.core_pattern=home/core_dump/core-%e-%p-%t
    

    注意根据自己的环境设置正确的目录,如果只指定core文件命名而不带路径则默认生成到执行文件所在目录。然后再执行sudo sysctl -p /etc/sysctl.conf后,通过cat /proc/sys/kernel/core_pattern就可以查看配置是否正常生效。

    而命名中的格式控制参数如下:

    符号含义
    %p<pid>
    %u<uid>
    %g<gid>
    %s导致dump的信号的编号
    %t出现dump的时间戳
    %e可执行文件的名称
    %hhostname

    常用命令列表

    命令缩写说明
    runr开始运行
    continuec暂停的程序继续运行
    nextn运行至下一行(单步执行)
    steps如果有调用函数,进入调用的函数内部
    until <n>u运行到当前文件指定行n再停下来
    finishfi执行完当前函数,返回到上一层函数调用处暂停
    return [n]-直接结束当前函数并可返回指定值n,到上一层函数调用处
    jump <n> | <*addr>j将当前程序执行流跳转到指定行n或地址addr
    print <val>p打印变量或寄存器值
    backtracebt查看当前线程的调用堆栈
    framef切换到当前调用线程的指定栈帧,栈帧号通过bt查看
    thread <id>-切换到指定线程
    break <line> | <file:line> | <function>b添加断点到某行或某个函数入口
    tbreaktb添加临时断点,只起效一次
    delete <n>del删除断点,断点号n通过 info break 查看
    enable <n>-启用某个断点
    disable <n>-禁用某个断点
    watch <val> | <*addr>-监视某一个变量或内存地址的值是否发生变化
    listl显示源码
    info-查看断点/线程等信息,可以查看的内容非常多
    ptype-查看变量类型
    disassembledis查看汇编代码
    set args-设置程序启动时的命令行参数
    show args-查看设置的命令行参数

    部分命令详解

    break/b

    • break function —— 在名为 function 的函数入口处添加断点(函数第一行语句)
    • break line —— 在当前文件的第 line 行添加一个断点
    • break file:line —— 在指定文件的第 line 行添加一个断点

    我们可以先用list来直接查看代码,然后再通过break来给特定的行打断点,这样有助于我能观察程序进入了某一个分支。

    list 命令默认只能显示10行代码,可以通过指令set listsize N来修改该参数。

    此外,还可以添加条件断点,即命令break [line] if [condition]。此处的 condition 语法与C语言一致。

    info break以及断点的enable、disable和delete

    通过info break来查看都打了哪些断点,以及某个断点经过了几次;每个断点会有对应的编号,enable、disable和delete则可以设置某个编号的断点起效、失效以及删除该断点。

    (gdb) info break
    Num     Type           Disp Enb Address            What
    2       breakpoint     keep y   0x0000555555597fd2 in aeApiPoll at ae_epoll.c:113
    	breakpoint already hit 1 time
    

    其中的Enb字段就是指示断点是否被Enable。

    如果 disable 命令和 enable 命令不加断点编号,则分别表示禁用和启所有断点。delete 不加编号号 ,则表示删除所有断点 。

    print/p 和 ptype

    print用于查看变量,甚至可以查看整个结构体的所有成员以及结构体中的某个成员变量。对于变量的操作方式与C语言中是一致的,可以取指针的内容,也可以取变量的内存地址。

    查看eventLoop指针指向的结构体的内容:

    (gdb) print *eventLoop
    $1 = {maxfd = 7, setsize = 10128, timeEventNextId = 1, events = 0x7ffff6c7d040, fired = 0x7ffff6cce2c0, timeEventHead = 0x7ffff6c15140, stop = 0, apidata = 0x7ffff6c7bd80, 
      beforesleep = 0x55555559bcf0 <beforeSleep>, aftersleep = 0x55555559bf40 <afterSleep>, flags = 0}
    

    查看结构体中的整形变量maxfd的值:

    (gdb) p eventLoop->maxfd
    $2 = 7
    

    如果在 C++ 对象中,可以通过 p this 来显示当前对象的地址,也可以通过 p *this 来列出当前对象的各个成员的值,还可以使用p a + b + c来打印三个变量的结果值。
    p func()命令打印函数的返回结果,比如可以用p strerror(errno)将错误码对应的文字信息打印出来。

    ptype命令则可以输出某个变量的类型。

    (gdb) ptype eventLoop
    type = struct aeEventLoop {
        int maxfd;
        int setsize;
        long long timeEventNextId;
        aeFileEvent *events;
        aeFiredEvent *fired;
        aeTimeEvent *timeEventHead;
        int stop;
        void *apidata;
        aeBeforeSleepProc *beforesleep;
        aeBeforeSleepProc *aftersleep;
        int flags;
    } *		# <---最后这里有个 *,表示这是一个指针
    

    thread及info thread

    从下面的运行结果可以看到,redis-server运行时建立了5个线程,当前我们位于Id为1的线程。

    (gdb) info thread
      Id   Target Id         Frame 
    * 1    Thread 0x7ffff7fdbf80 (LWP 5233) "redis-server" aeMain (eventLoop=0x7ffff6c230f0) at ae.c:484
      2    Thread 0x7ffff6521700 (LWP 5234) "bio_close_file" 0x00007ffff74199f3 in futex_wait_cancelable (private=<optimized out>, expected=0, 
        futex_word=0x55555595fcc8 <bio_newjob_cond+40>) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
      3    Thread 0x7ffff5d20700 (LWP 5235) "bio_aof_fsync" 0x00007ffff74199f3 in futex_wait_cancelable (private=<optimized out>, expected=0, 
        futex_word=0x55555595fcf8 <bio_newjob_cond+88>) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
      4    Thread 0x7ffff551f700 (LWP 5236) "bio_lazy_free" 0x00007ffff74199f3 in futex_wait_cancelable (private=<optimized out>, expected=0, 
        futex_word=0x55555595fd28 <bio_newjob_cond+136>) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
      5    Thread 0x7ffff4d1e700 (LWP 5237) "jemalloc_bg_thd" 0x00007ffff74199f3 in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x7ffff6e073b0)
        at ../sysdeps/unix/sysv/linux/futex-internal.h:88
    

    通过thread n可以切换到其他线程,然后通过bt去查看当前该线程的栈帧信息。

    watch

    对某个变量或地址添加watch可以监听该变量或地址,当变量或内存地址发生变化时GDB将暂停,类似与break的效果。

    watch可以监听整形变量、指针、数组等等,通过info watch可以查看设置了哪些watch,然后通过delete来删除某个编号的watch。

    常用调试技巧

    使 print 打印显示完整

    当使用 print 命令打印一个字符串或者数组时, 如果该输出太长导致显示不全,我们可以通过set print element 0命令使打印变得完整。

    多线程下锁定当前调试线程

    GDB调试过程中也有可能发生线程切换,如果我们希望只调试某个线程,不希望线程切换导致函数中的某个局部变量发生变化,可以通过set scheduler-locking on来锁定当前调试线程,同时通过set scheduler-locking off可以关闭锁定。

    调试多进程

    通过fork()产生子进程时,GDB默认会继续跟踪父进程,那么有两种方法可以调试子进程:

    1. 先调试父进程,在fork()出子进程后,再另开一个终端 attach 上子进程进行调试。
    2. GDB提供了一个选项为follow-fork,可以使用通过show follow-fork mode来查看:
     (gdb) show follow-fork mode
    Debugger response to a program call of fork or vfork is "parent".
    

    通过set follow-fork child可以使调试器跟踪子进程。

    展开全文
  • Linux下的简单C程序gcc编译、gdb调试
  • opwrt gdb调试工具.zip

    2020-08-12 22:04:49
    在嵌入式设备上运行openwrt时,为了调试应用程序,而制作的gdb调试工具,可以直接在嵌入式设备上进行应用程序的调试
  • Linux课件:GDB调试简明指南.pdf
  • 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_numpy 使用 Python 和 Numpy 在 gdb 调试器中分析 C/C++ 矩阵我在修改了的代码以与 python 3 兼容。
  • linux GDB调试

    千次阅读 2021-12-14 17:18:38
    本章介绍linux环境下使用gdb调试程序。 1.gdb调试条件 想要程序执行并可gdb调试,必须在编译的时候添加**-g**,例如(C语言):gcc test.c -o test -g 2. gdb命令介绍 2.1 gdb 启动 使用 gdb 可执行程序的名字指令后...
  • GDB调试技巧

    千次阅读 2021-08-03 17:16:48
    gdb (运行程序):gdb lt-snmpd
  • GDB调试STL和Json

    2016-05-11 18:28:22
    用于gdb调试过程中打印json对象。由于gdb脚本的递归有问题,打印数组中包含多个对象时打印有问题 命令“pjson object”。此脚本基于http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt修改,可以用于...
  • gdb调试常用命令总结

    2019-04-28 11:02:54
    gdb调试常用命令总结, gdb调试线程挂住问题打印堆栈信息等
  • gdb调试官方文档

    2019-01-28 15:58:00
    gdb调试官方文档官方文档,PDF清晰版,带目录,文字可选择。
  • 用的创龙的开发版7020的平台,调试的3个子进程,自己总结的,反正能调试通,亲测可用使用,贡献出来
  • gdb 调试core文件

    2022-04-18 17:16:34
    gdb exe文件 core文件 @2;bt 查看栈 @3;f N 进入某个函数,其中N是整数,是 bt 命令展示的栈号 @4;p x/[nfu] <addr> 展示某个内存地址的变量信息 x/<n/f/u> <addr>  n、f、u是可选的参数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,937
精华内容 39,974
关键字:

gdb调试

友情链接: 异常值剔除matlab.zip