C++(Qt)软件调试---linux使用dmesg定位程序崩溃位置(14)

2023-10-19 22:20

本文主要是介绍C++(Qt)软件调试---linux使用dmesg定位程序崩溃位置(14),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++(Qt)软件调试—linux使用dmesg定位程序崩溃位置(14)

文章目录

  • C++(Qt)软件调试---linux使用dmesg定位程序崩溃位置(14)
    • 1、前言
    • 2、ELF文件
    • 3、常用工具
    • 4、使用dmesg定位异常位置
      • 1.1 异常发生在可执行程序中
      • 1.2 异常发生在动态库中

1、前言

在我们日常开发中,经常会遇见程序崩溃退出的情况,一般在linux下我们可以通过生成core文件来进行调试,定位出现异常位置,但是如果我们忘记了生成core文件或者程序在用户机器上运行没有生成core,就无法通过调试core文件定位异常,这时就可以使用dmesg中的信息帮助调试。

  • 不同的系统中dmesg可能存在差异,例如在麒麟系统中我就没有发现在程序崩溃后的dmesg日志;
  • 测试系统:ubuntu20.04

2、ELF文件

ELF(Executable and Linkable Format)是一种通用的二进制文件格式,主要用于在Unix和Linux系统中存储可执行程序、共享库、目标文件等。下面是对ELF文件的详细说明:

  1. 文件头(File Header)

    • ELF文件以一个固定大小的文件头开始,包含了文件的基本信息,如文件类型、目标体系结构、入口点地址等。
  2. 程序头表(Program Header Table)

    • 程序头表是一个表格,其中包含了关于ELF文件中各个程序段(段是一种内存分配单位)的描述信息,如段的类型、文件偏移、虚拟内存地址、大小等。
  3. 节头表(Section Header Table)

    • 节头表包含了有关ELF文件中各个节(段内的逻辑分区,例如代码段、数据段)的描述信息,包括名称、类型、大小、偏移等。
      • .init(_init)init节通常指的是程序的初始化代码段,它是程序执行的起点,init节的入口点是程序的起始地址,也就是操作系统将开始执行的地方。这个入口点通常是可执行文件的文件头中指定的地址。
      • .text(代码节):这个节包含了程序的机器代码指令,即可执行代码部分。它是可执行文件中最重要的节之一。
      • .data(数据节):数据节包含程序中的全局和静态变量,以及初始化的全局和静态变量的数据值。这些数据可以在程序的整个生命周期中被访问和修改。
      • .rodata(只读数据节):这个节包含只读的数据,通常是常量、字符串字面值等。这些数据不能在运行时被修改。
      • .bss(未初始化数据节):该节包含全局和静态变量的未初始化数据,也就是说,它们在程序加载时不会被初始化,而是在运行时初始化为零或空值。
      • .plt(Procedure Linkage Table):用于延迟绑定动态链接的节,主要用于共享库。
      • .got(Global Offset Table):全局偏移表包含了用于动态链接的全局变量和函数的地址。
      • .debug(调试信息节):包含了调试信息,如符号表、源代码映射等,有助于调试和分析程序。
      • .textrel(重定位节):包含了代码中需要进行动态重定位的信息,用于处理位置无关代码。
      • .comment(注释节):包含了关于程序的注释信息,通常不会影响程序的执行。
      • .strtab(字符串表节):包含了节名、符号名等字符串的表格,用于字符串的索引和查找。
  4. 段数据(Section Data)

    • ELF文件包含了各种段,其中包括代码段、数据段、只读段、只写段等,这些段包含了程序的实际数据和指令。
  5. 符号表(Symbol Table)

    • 符号表存储了程序中定义和引用的符号(如函数和变量)的信息,包括符号名称、地址、大小等。它在调试和链接过程中非常有用。
  6. 重定位表(Relocation Table)

    • 重定位表包含了需要在链接时进行地址修正的信息,以确保程序正确地在内存中加载和执行。
  7. 动态链接信息(Dynamic Linking Information)

    • 如果ELF文件支持动态链接(共享库),则包含了动态链接信息,包括共享库的名称和相关信息。
  8. 字符串表(String Table)

    • 字符串表存储了各种字符串,如符号名称、段名称等,这些字符串可以通过索引在ELF文件中引用。
  9. 版本信息(Version Information)

    • 如果文件支持版本控制,包含了与版本相关的信息,以便在动态链接时选择正确的共享库版本。
  10. 其他信息

    • ELF文件还可以包含其他特定于目标体系结构和应用程序的信息,如程序入口点、对齐要求、文件权限等。

3、常用工具

  • file:查看文件基本信息。
  • ldd:查看一个可执行文件或共享库文件所依赖的动态链接库。
  • nm:用于查看二进制可执行文件或共享库中符号信息的工具。
  • strings :用于从二进制文件中提取可打印的字符序列,通常用于查找文件中的文本。
  • strip:用于去除可执行文件中的符号表信息的 Linux 命令。
  • readelf:显示有关ELF文件的信息。
  • objdump:用于查看和分析可执行文件、目标文件和共享库的工具,通常与GNU Binutils一起提供。它能够提供有关这些文件的详细信息,包括程序代码、数据段、符号表、重定位表等等。
  • netstat:用于显示网络连接、路由表、接口统计、Masquerade 连接等网络相关信息的命令行工具。
  • ps:用于显示当前系统的进程信息。
  • top/htop:用于监视系统进程的命令行工具,通常在Unix和类Unix系统中使用。它提供了关于系统中运行的进程的实时信息,包括CPU使用率、内存使用率、进程列表以及其他系统性能相关的信息。
  • dmesg:用于查看和分析Linux操作系统内核消息的命令。它提供了有关系统启动、硬件检测、设备驱动程序加载和内核错误等信息的详细报告。
  • addr2line:将地址转换为文件名和行号。
  • tcpdump:一个强大的网络抓包工具,用于捕获和分析网络数据包。

4、使用dmesg定位异常位置

  • 测试程序:C++、Qt

    #include "widget.h"
    #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
    {ui->setupUi(this);
    }Widget::~Widget()
    {delete ui;
    }void Widget::on_pushButton_clicked()
    {QWidget* w = nullptr;
    //    w->show();                      // 异常发生在动态库中int* a = nullptr;*a = 10;                          // 异常发生在可执行程序中}
    

1.1 异常发生在可执行程序中

  • 执行程序并出现崩溃;

  • 使用dmesg命令查看程序异常日志(有时需要使用sudo dmesg);

    [44741.877559] untitled4[14899]: segfault at 0 ip 00005598c5d3b8e4 sp 00007ffd7505a2b8 error 6 in untitled4[5598c5d3b000+1000]
    [44741.877582] Code: ff ff ff 48 89 ef be 38 00 00 00 5d e9 c5 f9 ff ff 0f 1f 44 00 00 f3 0f 1e fa 48 83 ef 10 eb d6 66 0f 1f 44 00 00 f3 0f 1e fa <c7> 04 25 00 00 00 00 00 00 00 00 0f 0b 66 2e 0f 1f 84 00 00 00 00
    
    • untitled4[14899]:出现异常的程序和进程号;
    • segfault at [地址]: segfault发生的内存地址。
    • ip [指令指针地址]: 引起segfault的指令指针在虚拟内存中的地址。
    • sp [栈指针地址]: 引起segfault的栈指针的地址。
    • error [错误代码]: segfault的错误代码,通常以非零值表示错误。
    • in [发生异常的文件] [文件加载进内存首地址+偏移量]: 引起segfault的二进制文件的路径和函数名称。
  • 这里会用到两类地址;

    1. 内存地址: 内存地址是指计算机内存中的物理地址或虚拟地址,用于在运行时定位程序的指令、数据和堆栈等内容。内存地址是动态的,会随着程序的执行而变化,特别是在使用虚拟内存的系统中,操作系统会将内存地址映射到物理内存或磁盘上。内存地址是程序在运行时实际使用的地址,它们与物理内存或虚拟内存中的存储位置相对应。dmesg中记录的就是程序崩溃时指令指针在内存中的地址;
    2. 可执行文件中的地址: 可执行文件中的地址是编译后的程序的内部地址空间,通常用于编译器和链接器在构建可执行文件时确定代码、数据和符号的相对位置。这些地址在编译时和链接时分配,并在可执行文件中保存。它们通常是相对地址,用于在可执行文件内部定位数据和指令。可执行文件中的地址是静态的,不会随程序的执行而改变。
  • 所以要使用dmesg的地址定位异常位置就需要将内存地址转换为可执行文件中的地址;

  • 由于init节的入口点是程序的起始地址,所以文件中的地址 = 指令指针地址 - 文件加载进内存首地址 + init节地址

    • 可通过nm命令或者 objdump -p命令查看init节地址 ;

      在这里插入图片描述

    • 00005598c5d3b8e4 - 5598c5d3b000 + 3000 = 38E4

    • 使用addr2line -e 可执行程序 地址 -Cfi就可如下图所示得到出现异常的函数和所在文件、在文件中的行号。

      在这里插入图片描述

    • 注意:如果是使用Release模式编译的不包含调试符号则只能看到出现异常的函数,不能具体到文件和行号。

      在这里插入图片描述

1.2 异常发生在动态库中

  • 当异常出现在动态库中是dmesg日志信息如下所示;

    [47072.125853] untitled4[15938]: segfault at 28 ip 00007f885dca8f7e sp 00007ffe035bc640 error 4 in libQt5Widgets.so.5.12.5[7f885db0e000+61d000]
    [47072.125882] Code: 48 89 df be 01 00 00 00 5b 48 8b 40 68 ff e0 90 66 90 66 2e 0f 1f 84 00 00 00 00 00 48 8b 05 b1 ec 6a 00 53 48 89 fb 48 8b 38 <48> 8b 43 28 8b 70 0c 48 8b 07 ff 90 a8 00 00 00 83 f8 04 74 2d 83
    
  • 由于可执行程序和动态库的堆栈是相互独立的,并不是在同一个堆栈,所以当异常出现在动态库中时dmesg日志信息中的地址是动态库在内存中的地址;

  • 所以文件中的地址 = 指令指针地址 - 文件加载进内存首地址

  • 00007f885dca8f7e - 7f885db0e000 = 19AF7E

  • 使用ldd查看动态库路径;

    在这里插入图片描述

  • 使用addr2line -e 动态库 地址 -Cfi就可如下图所示得到出现异常的函数和所在文件、在文件中的行号。

    在这里插入图片描述

{__/}
(̷ ̷´̷ ̷^̷ ̷`̷)̷◞~❤
| ⫘ |

这篇关于C++(Qt)软件调试---linux使用dmesg定位程序崩溃位置(14)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/242741

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数