C++(Qt)软件调试---linux下生成/调试Core文件(3)

#软件调试

C++(Qt)软件调试—linux下生成/调试Core文件(3)

文章目录

  • C++(Qt)软件调试---linux下生成/调试Core文件(3)
    • 前言
    • 1、C++生成Core和使用GDB调试
      • 1、环境
      • 2、C++生成Core文件
      • 3、使用gdb工具调试core可定位段错误位置;
      • 4、修改生成的Core文件路径和名称
      • 5、实现过程及结果
    • 2、Qt程序生成Core和使用GDB调试
      • 1、环境
      • 2、Qt生成Core文件
      • 3、调试Qt程序生成的Core文件
      • 4、Qt在Release模式下调试Core文件

更多精彩内容
个人内容分类汇总
C++软件调试、异常定位

Windows下封装的崩溃报告模块

前言

  • 什么是Core文件,有什么用

    Core文件是在程序崩溃或异常终止时由操作系统生成的一个二进制文件,它包含了进程在崩溃前的内存映像。Core文件的作用是帮助程序员分析程序崩溃的原因,进行程序调试。

    当程序崩溃时,Core文件中存储了进程的堆栈、寄存器、内存等信息。程序员可以使用调试工具如GDB来分析Core文件,以确定程序崩溃的原因。通过分析Core文件,程序员可以了解程序在崩溃前发生的情况,包括变量的值,函数调用的堆栈信息等,从而找到程序中的错误。

    Core文件还可用于恢复程序状态。如果程序在处理大量数据时崩溃,程序员可以使用Core文件来恢复程序状态,从崩溃点开始进行调试,以便更快地找到问题并修复它。

    总之,Core文件是程序调试和故障排除中的重要工具,可以帮助程序员快速定位并解决程序中的错误。

1、C++生成Core和使用GDB调试

1、环境

  • 测试系统:

    • ubuntu-16.04.6-desktop-i386.iso
    • ubuntu-22.04.2-desktop-amd64.iso
  • 为了排除其它影响,每个测试的系统环境都是在虚拟机中新配置的纯净环境,没有安装任何其它软件和进行任何配置。

2、C++生成Core文件

  1. 创建一个文件夹Code

    mkdir Code
    
  2. 进入Code文件夹,创建一个main.cpp文件

    cd Code
    touch main.cpp
    
  3. 打开main.cpp,写入下列代码

    touch main.cpp 
    
    #include 
    
    int main()
    {
        char* str = NULL;
        *str = 'a';
        return 0;
    }
    
  4. 在ubuntu环境下,默认不生成core文件,需要生成core文件时,需要使用ulimit进行设定;

    注意: 此命令设置的core文件大小只在当前终端,当前用户有效,重新打开一个终端窗口或者切换用户就会失效;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第1张图片

    ulimit-c”命令设置或获取core文件大小限制,该限制指定进程崩溃时可以创建的核心转储文件的最大大小。

    核心转储文件包含崩溃时进程内存的映像,这对于调试崩溃原因非常有用。

    “-c”选项以块或字节为单位指定核心文件大小限制,具体取决于系统配置。

    # 列出当前终端所有资源限制
    ulimit -a 
    
    # core文件大小
    ulimit -c
    
    # 设置生成core文件的大小:1024k
    ulimit -c 1024
    
    # 设置生成core文件的大小:不受限制(推荐使用这个,因为如果是Qt之类的程序生成的Core文件会很大,如果指定的大小不够则可能生成的Core文件无法使用)
    ulimit -c unlimited
    

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第2张图片

  5. 如果您想让 ‘ulimit -c unlimited’ 命令永久生效,您需要在系统启动时将其添加到 shell 配置文件中。具体的配置文件路径可能会因操作系统而异,一些常见的配置文件路径如下:

   - /etc/profile (适用于所有用户)
   - ~/.bashrc (适用于当前用户)
   - /etc/bashrc (适用于所有用户)

您可以使用文本编辑器打开适当的文件,并将 ‘ulimit -c unlimited’ 命令添加到文件的末尾。

保存文件后,使用source .bashrc命令立即生效或者下次启动系统时,该命令将自动执行并永久生效。

但是永久生效就意味着系统中只要由程序异常结束就会生成Core文件,这会导致系统中垃圾文件越来越多,所以除非必要,还是使用临时设置。

如果设置了永久生效,建议将指定生成Core路径时使用绝对路径,将所有生成的Core文件放到同一个文件夹下,方便管理。

  1. 编译main.cpp文件,用-g选项生成的调试信息来显示崩溃或错误时的源代码、变量和堆栈跟踪;

    g++ main -g
    
  2. 使用./a.out命令执行编译后的可执行程序,会出现段错误segmentation fault (core dumped),并在当前路径生成core文件;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第3张图片

3、使用gdb工具调试core可定位段错误位置;

命令为 gdb 可执行程序 Core文件

如下图所示可看出段错误为main.cpp文件中main()函数中,位于文件第6行;

C++(Qt)软件调试---linux下生成/调试Core文件(3)_第4张图片

C++(Qt)软件调试---linux下生成/调试Core文件(3)_第5张图片

4、修改生成的Core文件路径和名称

core_pattern文件是一个系统文件,用来指定生成Core文件的路径和文件名格式。可以通过修改core_pattern文件来更改Core文件的生成路径和文件名格式。

【临时设置(立即生效)】在Linux系统中,core_pattern文件通常位于/proc/sys/kernel/core_pattern路径下。可以使用命令行编辑器如vi或nano来编辑该文件。

需要注意的是,core_pattern文件是一个虚拟文件,它是在内存中创建的,并不是一个真正的文件。因此,修改core_pattern文件的设置选项只在当前系统运行时有效,重启系统后设置会被恢复为默认值

【永久设置(需要重启)】如果要永久更改设置选项,可以在系统启动时执行相应的命令,或者修改 /etc/sysctl.conf 文件中的相应设置选项。

可以到/etc/sysctl.conf中,在文件末尾添加上core文件的存储路径(然后重启系统):

kernel.core_pattern=core_%e_%p_%t
  1. 默认生成的Core文件名就是Core,所以后面生成的会覆盖之前生成的文件,如果想要不覆盖可用自己修改生成的文件名;

  2. 进入root用户模式;

    sudo su
    
  3. 查看/proc/sys/kernel/core_pattern文件原始配置;

    cat /proc/sys/kernel/core_pattern
    或者
    sysctl kernel.core_pattern
    
  4. 修改/proc/sys/kernel/core_pattern文件中Core生成路径、文件名配置;

    # 表示在可执行程序当前路径生成Core文件,文件名格式为core_%e_%p_%t
    echo "core_%e_%p_%t" > /proc/sys/kernel/core_pattern
    或者
    sudo sysctl -w kernel.core_pattern="core_%e_%p_%t"
    
    # 表示在可执行程序当前路径下的Cores文件夹中(需要自己手动创建Cores文件夹)生成Core文件,文件名格式为core_%e_%p_%t
    echo "./Cores/core_%e_%p_%t" > /proc/sys/kernel/core_pattern
    
    # 表示在绝对路径/home/mhf/Cores/中(需要自己手动创建Cores文件夹)生成Core文件,文件名格式为core_%e_%p_%t
    echo "/home/mhf/Cores/core_%e_%p_%t" > /proc/sys/kernel/core_pattern
    

    如果不包含路径,则core_pattern文件中的内容为【在执行文件当前路径】创建相应的core文件;

    如果包含路径,则需要保证路径存在,否则不会生成Core文件;

    注意:如果生成的路径的权限比较高,也不会生成Core文件,例如:

    # 表示在绝对路径/Cores/中(需要自己手动创建Cores文件夹)生成Core文件,文件名格式为core_%e_%p_%t
    # /Cores路径需要root权限,如果使用普通用户权限执行a.out则不会生成Core文件,需要使用sudo ./a.out执行才可以生成
    echo "/Cores/core_%e_%p_%t" > /proc/sys/kernel/core_pattern
    

    其中可选参数列表为:

    %p:将进程ID(PID)插入文件名
    %u:将进程的真实用户ID(RUID)插入文件名
    %g:将进程的真实组ID(RGID)插入文件名
    %s:将生成Core文件时,进程的信号编号插入文件名
    %t:将内核转储发生的UNIX时间戳(秒级)插入文件名
    %h:将主机名插入文件名
    %e:将核心转储可执行文件名插入文件名

5、实现过程及结果

  • 显示(core dumped)表示成功生成Core文件。
  • ubuntu16.04使用过程及结果如下

C++(Qt)软件调试---linux下生成/调试Core文件(3)_第6张图片

  • ubuntu22.04使用过程及结果如下

C++(Qt)软件调试---linux下生成/调试Core文件(3)_第7张图片

2、Qt程序生成Core和使用GDB调试

1、环境

  • 系统:ubuntu22.04
  • Qt版本:V5.14.2

2、Qt生成Core文件

  1. 打开一个终端,如下图所示,将生成的Core文件大小设置位为不限制,设置core生成文件名称,防止覆盖;

  2. 由于这两项设置是临时的,重新打开一个终端窗口或者通过点击图标方式运行Qt都无效,只能在当前终端窗口通过命令行运行Qt编译的可执行程序在异常时才可以生成Core文件;

  3. 如果是通过点击图标运行的Qt编译生成的可执行程序,需要在当前终端窗口通过命令行运行可执行程序才可以生成core文件;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第8张图片

  4. Qt程序启动后新建一个工程;

  5. 在pro文件添加DESTDIR = $$PWD/bin,将编译后的可执行程序放到bin文件夹下;

  6. 在代码中编写一个空指针异常代码、一个除0异常代码;

  7. 使用debug编译运行后,分别点击空指针异常代码和除0异常代码的按键;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第9张图片

  8. 在点击异常代码的按键后,程序会异常退出,在可执行程序所在的bin文件夹下可看到生成了两个Core文件;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第10张图片

  9. 从下图中可看出生成的两个core文件非常大,所以:

    1. 最好使用ulimit -c unlimited指定无限大小的Core,否则生成的Core大小不足,则无法使用;
    2. 没必要时必要将ulimit -c unlimited设置为永久有效,否则系统可能中会生成非常多的core文件,导致内存不足。

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第11张图片

3、调试Qt程序生成的Core文件

  1. 在上一节中使用C++生成的Core文件我们通过GDB命令行去调试,定位异常位置;

  2. 这里同样使用GDB命令行进行调试;

    1. 可用看出异常位置在../untitled/widget.cpp文件中的第29行,位于Widget::on_pushButton_2_clicked()函数中;
    2. 异常原因是:Arithmetic exception.

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第12张图片

  3. 同样使用GDB命令行调试空指针生成的core文件

    1. 只能看出异常原因是Segmentation fault.(段错误),无法直接看出是异常发生位置是在哪个文件,哪一行,哪个函数;
    2. 先不用急, 后面我会将如何使用QtCreator调试生成的Core文件,会更加简单方便,并且也可以直接显示出异常位置是在哪个文件,哪一行,哪个函数;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第13张图片

    1. 这里看不到异常位置可能是不在这个堆栈内,可以使用bt命令打印函数调用信息(堆栈);

      1. 可以看到定位异常在widget.cpp文件中的21行的Widget::on_pushButton_clicked()函数内;

      C++(Qt)软件调试---linux下生成/调试Core文件(3)_第14张图片

4、Qt在Release模式下调试Core文件

  1. 在debug和Release编译的程序发生异常退出时都会生成Core文件,但是release模式默认下生成的可执行程序经过编译器优化,不方便调试和定位异常位置;

  2. 使用Release默认生成的可执行程序进行调试结果如下,通过GDB的bt命令打印堆栈信息可以看出异常位置在Widget::on_pushButton_clicked() 函数中,没有具体到哪个文件,哪一行;

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第15张图片

  3. Release模式下,可用通过在pro文件添加下列三行代码关闭打印输出的信息,经过测试,如果添加了DEFINES += QT_NO_DEBUG_OUTPUT则无法定位异常位置(Debug模式不影响);

    DEFINES += QT_NO_DEBUG_OUTPUT    # 关闭调试信息输出 qDebug()    ---  无法定位异常位置
    DEFINES += QT_NO_INFO_OUTPUT     # 关闭普通信息输出 qInfo()     ---  不影响
    DEFINES += QT_NO_WARNING_OUTPUT  # 关闭警告信息输出 qWarning()  ---  不印象
    

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第16张图片

  4. Release模式下,在pro文件添加下列三行代码,生成调试信息,可定位到异常位置在哪个文件,哪个函数,哪一行;

    # QMAKE_CC += -g是一个QMake变量,它将-g选项添加到C编译器命令行选项中。-g选项指示编译器生成调试信息以及目标代码。
    # 调试信息包含有关源代码的详细信息,例如文件名、行号和变量名。在调试程序时,这些信息对开发人员非常有用,因为它们可以跟踪程序的执行并识别错误的位置。
    # 请注意,添加-g标志会增加目标文件和可执行文件的大小,因此不希望在程序的最终发布版本中包含调试信息。
    QMAKE_CC += -g
    # QMAKE_CXX += -g是一个QMake变量,它将-g选项添加到C++编译器命令行选项中。-g选项指示编译器生成调试信息以及目标代码。
    QMAKE_CXX += -g
    # QMAKE_LINK += -g是一个QMake变量,它将-g选项添加到链接器命令行选项中。-g选项指示链接器将调试信息包含在可执行文件中。
    QMAKE_LINK += -g
    

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第17张图片

  5. Release模式下同时添加-gDEFINES += QT_NO_DEBUG_OUTPUT可定位到异常位置在哪个文件,哪个函数,哪一行;

  6. 只需要在pro文件中加上下列三行代码,就可以在生成的可执行程序中包含调试信息;

    • 其实感觉这个功能比较鸡肋,Debug编译的程序就已经带有了调试信息,所以如果调试问题最好使用Debug模式编译,而Release是编译发布程序的模式,经过优化后去除调试信息,以获得更高的性能和较小的程序文件;
    • 而加上这三行代码后在可执行程序中包含调试信息,哪就和Debug没什么区别了,性能比较低了;
    • 当然,有些问题会在Release模式下出现,在Debug模式下不会出现,这种情况就可以使用这三行代码。
    # QMAKE_CC += -g是一个QMake变量,它将-g选项添加到C编译器命令行选项中。-g选项指示编译器生成调试信息以及目标代码。
    # 调试信息包含有关源代码的详细信息,例如文件名、行号和变量名。在调试程序时,这些信息对开发人员非常有用,因为它们可以跟踪程序的执行并识别错误的位置。
    # 请注意,添加-g标志会增加目标文件和可执行文件的大小,因此不希望在程序的最终发布版本中包含调试信息。
    QMAKE_CC += -g
    # QMAKE_CXX += -g是一个QMake变量,它将-g选项添加到C++编译器命令行选项中。-g选项指示编译器生成调试信息以及目标代码。
    QMAKE_CXX += -g
    # QMAKE_LINK += -g是一个QMake变量,它将-g选项添加到链接器命令行选项中。-g选项指示链接器将调试信息包含在可执行文件中。
    QMAKE_LINK += -g
    
  7. 从下图可以看出所有模式生成的Core文件大小都一样,但是Debug模式编译生成的可执行程序是Release模式编译的可执行程序的大小的31倍左右,而Release模式加-g后编译生成的可执行程序大小和Debug模式生成的大小差不多。

    C++(Qt)软件调试---linux下生成/调试Core文件(3)_第18张图片

你可能感兴趣的:(#,C++软件调试,qt,linux,c++,Core,GDB)