当前位置 博文首页 > 文章内容

    gdb 调试技巧总结

    作者: 栏目:未分类 时间:2020-11-14 18:00:23

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    GDB 基本命令

    如果想要使用gdb调试程序,再编译时必须加-g参数。我们可以使用如下两种方式进行调试:

    1. 如果是未启动的程序名,使用gdb 程序名开始调试当前程序,或者先启动gdb,再用file 可执行文件名来调试文件。

    2. 如果程序已启动,需要调试程序的进程,使用gdb -p 进程ID,来调试进程。或者先启动gdb,再attach 进程ID来调试进程。

    主要的命令和用法如下:

    命令 作用
    directory DIR 增加目录 DIR 到搜寻程序代码的目录列表 (如果你的程序代码和可执行档放在同一个目录下,就不须指定程序代码所在目录)
    l (list) 从第当前行开始例出源代码
    Enter (回车) 重复上一次输入的命令
    b (break) 设置断点,如break test.cpp:100断行数,break UserManager::GetUser断函数
    clear 清除断点,如clear XXX,XXX格式和上面b的格式相同
    info break 查看断点信息
    delete 清除断点,如delete NUM,NUM是在info break显示的断点编号,不加NUM表示删除所有断点
    disable 禁止断点,如disable NUM,NUM是在info break显示的断点编号,不加NUM表示禁止所有断点
    enable 启用断点,用法和disable类似
    r (run) 运行程序
    bt (backtrace) 显示程序堆栈信息
    p (print) 打印表达式的值
    display 在断点的停止的地方,显示指定的变量的值。
    set 设置变量的值。如set val=54 ,将54设置到val变量中
    n (next) 在触发断点之后,单步执行,不进函数调用
    s (step) 单步执行,会进入函数调用
    finish 继续执行,直到当前函数返回,并在调用函数的下一行停止
    u (until) 执行一行程序,若此时程序是在 for/while/do loop 循环的最后一行,则一直执行到循环结束后的第一行程序后停止
    return 强制从当前函数返回
    CTRL + C 在当前位置停止执行正在执行的程序,断点在当前行
    quit 退出gdb

    gdb 调试多线程

    假设现在有一个主线程创建了一个子线程。

    gdb调试时,设置断点,单步调试到pthread_create处的时候,这时候会创建子线程,会出现如下信息

    [New Thread 0x7ffff6fd1700 (LWP 6376)]
    

    默认情况下,gdb只跟踪主线程,新创建的线程都被阻塞在pthread_create函数处。

    info threads 可以调试的所有线程,gdb会为每个线程分配一个ID,这个ID和线程ID不同,ID号一般从1开始。

    如下,表示当前有两个线程1和2,*表示跟踪主线程1

    (gdb) info threads
      Id   Target Id         Frame 
      2    Thread 0x7ffff6fd1700 (LWP 6376) "test" 0x00007ffff70d0851 in clone ()
       from /lib64/libc.so.6
    * 1    Thread 0x7ffff7fee740 (LWP 6375) "test" main (argc=1, argv=0x7fffffffe2d8) at test.cpp:31
    

    thread ID 切换当前调试的线程为指定ID号,ID是gdb分配的序号,不是线程TID。

    set scheduler-locking off|on on锁定其他线程,只有当前选择调试的线程执行,off表示不锁定任何线程,当运行到断点处,将所有的线程都暂停下来,直到指定某个线程继续执行,如果在当前线程下使用continue的话会启动所有线程(GDB默认)。

    多线程调试控制指令

    thread apply ID1 ID2 ...IDn gdb_command 指定多个线程执行gdb中的command指令

    thread apply all command 指定所有线程执行gdb中的command指令

    non-stop模式

    上面说过一个线程中断在一个断点上,其他所有的线程都会被freeze。新版本的GDB中,引入了non-stop模式,在这个模式下:

    1. 当某个或多个线程在一个断点上,其他线程仍会并行运行

    2. 你可以选择某个被中断的线程,只让他运行。

    3. non-stop模式表示不停止模式,除了断点有关的进程会被停下来,其他线程会继续执行。

    设置non-stop模式,打开gdb后,在开始r之前,首先连续输入下面的指令

    set target-async 1
    set pagination off
    set non-stop on
    

    总结调试多线程的命令

    info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程

    thread ID(1,2,3…) 切换当前调试的线程为指定ID的线程

    break thread_test.c:123 thread all(例:在相应函数的位置设置断点break pthread_run1) 在所有线程中相应的行上设置断点

    thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command

    thread apply all command 让所有被调试线程执行GDB命令command

    set scheduler-locking 选项 command 设置线程是以什么方式来执行命令

    set scheduler-locking off 不锁定任何线程,也就是所有线程都执行,这是默认值

    set scheduler-locking on 只有当前被调试程序会执行

    set scheduler-locking on step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行

    线程池调试小技巧

    调试进程池和线程池中的程序一个不错的方法,是将池中的个数减少至1,观察是否正确,然后逐步增加线程数量,调试线程的同步是否正确

    gdb 调试core文件

    什么是core文件

    如果程序有问题,会产生“段错误(核心已转储)”时会生成具有堆栈信息和调试信息的文件,在编译时需要加-g选项使程序生成调试信息,比如gcc -g test.c -o test

    怎么配置生成core文件

    • core文件开关

    使用ulimit -c查看core开关,如果为0表示关闭,不会生成core文件

    使用ulimit -c [filesize]设置core文件大小,当最小设置为4之后才会生成core文件

    使用ulimit -c unlimited设置core文件大小为不限制,这是比较推荐的常用做法

    • core文件命名和保存路径

    core有默认的名称和路径,但是开发中通常会自己命名和指定保存路径。可以通过/proc/sys/kernel/core_pattern设置core文件名和保存路径,方法如下:

    echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern
    

    其中有一些参数含义如下:

    %p:insert pid into filename 添加pid

    %u:insert current uid into filename 添加当前uid

    %g:insert current gid into filename 添加当前gid

    %s:insert signal that caused the coredump into the filename 添加导致产生core的信号

    %t:insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间

    %h:insert hostname where the coredump happened into filename 添加主机名

    %e:insert coredumping executable name into filename 添加命令名

    关于core文件的调试

    比如现在有一个服务器程序编译后的二进制文件名是GameServer,宕机后生成的core文件是core.30132。调试core有以下两种方法:

    方法1:

    gdb GameServer core.30132
    

    方法2:

    gdb -c core.30132 GameServer
    

    在服务器开发中,如果服务器宕机,一般会生成一个core文件,我们可以用gdb来调试此core文件,并使用bt命令查看函数调用堆栈,就可以快速定位到程序的函数。

    GDB 分屏操作

    在GDB中使用分屏,我们可以很方便的一边查看代码,一边输入命令,主要有以下操作:

    layout:用于分割窗口,可以一边查看代码,一边测试。主要有以下几种用法:

    layout src:显示源代码窗口

    layout asm:显示汇编窗口

    layout regs:显示源代码/汇编和寄存器窗口

    layout split:显示源代码和汇编窗口

    layout next:显示下一个layout

    layout prev:显示上一个layout

    Ctrl + L:刷新窗口

    Ctrl + x,再按1:单窗口模式,显示一个窗口

    Ctrl + x,再按2:双窗口模式,显示两个窗口

    Ctrl + x,再按a:回到传统模式,即退出layout,回到执行layout之前的调试窗口