Linux下多so文件情形的dump文件异常定位(基于qBreakpad)

如果对linux下如何生成dump,以及如何利用dump文件定位崩溃点,不清楚,可以先参考此文《Linux下Qt生成dump文件并定位bug(基于qBreakpad)》

在上文中,我们以单文件程序为例,当异常发生于单文件程序内部时,定位崩溃点过程进行了说明。

本文中,将着重讲解App+多个So动态库文件的开发形式下,异常发生于so文件中,该如何来定位问题。

一、生成dump

按照一样的方式,在主程序App中,调用qBreakpad,以异常发生时,自动生成dump。代码如下:

main.cpp:

#include <QCoreApplication>
#include "my1.h"
#include "my2.h"
#include "QBreakpadHandler.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QBreakpadInstance.setDumpPath("crashes"); // 设置生成dump文件路径

    My1 xx;
    xx.add(1, 2);

    My2 yy;
    yy.sub(2, 1);

    return a.exec();
}

并增加了对2个动态库my1、my2的调用,该2个库导出类如下:

my1.h:

#ifndef MY1_H
#define MY1_H

#include "my1_global.h"
class MY1SHARED_EXPORT My1
{
public:
    My1();
    int add(int a, int b);
};

#endif // MY1_H

my1.cpp:

#include "my1.h"

My1::My1()
{
}

int My1::add(int a, int b)
{
    *((int*)0) = 10; // 此处人为造成异常发生
    return (a + b);
}

my2.h:

#ifndef MY2_H
#define MY2_H

#include "my2_global.h"
class MY2SHARED_EXPORT My2
{
public:
    My2();
    int sub(int a, int b);
};

#endif // MY2_H

my2.cpp:

#include "my2.h"

My2::My2()
{
}

int My2::sub(int a, int b)
{
    return (a - b);
}

运行程序时,可直接在Qt Creator中,点击运行,这样,不用设置环境变量亦可找到依赖的my1、my2的so库。如下:

在这里插入图片描述

非常简单的测试,当程序在main函数中,执行到xx.add(1, 2)行时,会发生异常,并在crashes目录下生成dump文件。如下:

在这里插入图片描述

二、生成带调试信息的程序和so库

在App.pro、My1.pro、My2.pro中,分别添加如下内容,以实现在release模式下,亦可生成带调试信息的程序和so库。

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO

生成的调试信息,就在程序和so文件内部,相比无调试信息时,文件变大了。

到此我们得到了如下4个东西。

dump文件:

在这里插入图片描述

带调试信息的App:

在这里插入图片描述

带调试信息的my1动态库:

在这里插入图片描述

带调试信息的my2动态库:

在这里插入图片描述

后面3者,主要用来导出符号文件,以配合dump文件,进行定位。

三、使用dump_syms和minidump_stackwalk定位异常

1、生成符号文件

进入App所在目录。

导出App符号文件“App.sym”

dump_syms App > App.sym

导出my1库的符号文件“libMy1.so.sym”

dump_syms ../My1/libMy1.so > libMy1.so.sym

此处符号文件名需要,参考该文件内容第一行末尾字符,进行修改,如下:

在这里插入图片描述

故,应将文件名“libMy1.so.sym”,改为“libMy1.so.1.sym”。

导出my2库的符号文件“libMy2.so.sym”

dump_syms ../My2/libMy2.so > libMy2.so.sym

以my1库符号文件相同方式,进行改名,将文件名“libMy2.so.sym”,改为“libMy2.so.1.sym”。

特别注意:

需要将sym文件放置到特定路径下,方可在后续生成的堆栈信息中,查看到崩溃发生的文件名和行号。否则,堆栈信息中,只能看到内存地址。下一步,将介绍,如何放置到特定路径。

2、将符号文件移动到特定路径

我们在App程序所在目录下,创建symbols目录,并在该目录下继续创建,如下类似的目录结构:

在这里插入图片描述

解释:

  • 第一级目录,固定为symbols;
  • 第二级目录,为即将放入的符号文件名称,如qBreakpadTest.sym,则目录名为qBreakpadTest;
  • 第三级目录,在sym文件中第一行内容,有一串16进制编号,将其作为目录名;
    在这里插入图片描述

建立好以上路径后,将相应的*.sym移动到此路径下。

最后,所有符号文件,放置完毕,目录效果如下:

在这里插入图片描述

可以看到App.sym、libMy1.so.1.sym、libMy2.so.1.sym三个符号文件均放置妥当。

3、生成崩溃处调用堆栈信息

执行如下命令,生成调用堆栈信息:

minidump_stackwalk ./crashes/275976b1-dc56-42b7-db518985-a5150714.dmp ./symbols > error.log
  • 第一个参数,是dump文件名;
  • 第二个参数,固定为./symbols,应该是指定符号文件位于当前symbols目录下默认路径位置;
  • 第三个参数,将命令执行结果,写入到error.log文件中。

生成的堆栈调用信息文件error.log,内容如下:

在这里插入图片描述

一般找到“crashed”字样,与它最近的一行,就是发生崩溃时,程序的调用堆栈,可以很清楚的看到,崩溃发生在my1.cpp文件,第9行。

到此,我们顺利通过dump文件、带调试信息的程序文件、带调试信息的so文件,成功定位到了bug所在。

四、总结

对于这种App+多so的形式,生成dump也是比较容易的,和单App时没有区别。

但是,在通过dump和符号文件,进行异常定位时,符号文件的生成,以及放置到特定路径下,这个过程较繁琐。

若一个App调用了50个so,那么因为不知晓具体异常发生于哪个so上,故需要将App、50个so进行导出符号,并按特定路径进行组织,放置好,方可使用minidump_stackwalk工具,对异常位置进行定位。

因此,由App和多个so文件,生成,完整的symbols符号目录,这个过程建议由脚本,自动化完成。

可以使用python开源工具symbolstore.py,其github地址:https://github.com/MozillaReality/symbolgenerator,有兴趣可以去研究一下。

特别注意:

  • 欲定位异常,至少需要dump文件、带调试信息的主程序文件、带调试信息的所有So文件。

本文涉及工程代码:

https://gitee.com/bailiyang/cdemo/tree/master/Qt/57qBreakpadTest/AppAndMultiSo



若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!

同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。

在这里插入图片描述

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值