qBreakpad - LINUX捕获程序崩溃异常

前言

目前参与的项目需要从 Windows 平台移植到 arm-Linux 平台,之前项目上使用的异常奔溃收集库不适用于 Linux,因此亟需一个跨平台的奔溃采集库(实在不想维护两套代码)。这时我们发现了 google breakpad ,由于是基于 Qt 的开发,我还注意到了 qBreakpad 这个开源项目。

Google - Breakpad

BreakpadGoogle 公司开发的开源 跨平台C++崩溃检测库。Breakpad可以捕获发布给用户的应用程序的崩溃,并记录软件崩溃的调试信息到 minidump 文件中。调试信息包括错误行号,报错详情,堆栈错误(stack traces)。

qBreakpad

qBreakpad 是一个使用 google-breakpad 的Qt第三方库,可以很方便的用于检测软件奔溃。但是这个项目最近一次维护是在4年前了,使用时发现了一些错误,想提交到 GitHub,但苦于没有 ISS,目前的想法是自行维护并开源…git地址确定后将在留言放出。当然遇到的那些坑,在本文也会告知解决方法。

编译

Breakpad

本地编译 x86_64_linux

根据 BreakpadGitHub-README ,编译非常简单:

# 克隆仓库
git clone https://github.com/cmzy/beakpad.git
# 如果嫌github慢,可使用 https://gitee.com/jyu_hsy/breakpad.git

cd breakpad

# configure 配置,若未知configure提供了哪些参数,可使用 ./configure -help
./configure

# make it
sudo make

由于这里最终的目标是 qBreakpad,这里的编译只是为了生成所需的 dump_syms & microdump_stackwalk 而已,通过以下指令查看其文件类型:

# 我目前只用到dump_syms & microdump_stackwalk

file beakpad/src/tools/linux/dump_syms

file beakpad/src/processor/microdump_stackwalk

ps:编译时会提示找不到 /breakpad/src/third_party/lss/linux_syscall_support.h

这时需要将 linux-syscall-support 拉取下来,然后将 linux_syscall_support.h 放到指定路径:

git clone https://gitee.com/jyu_hsy/linux-syscall-support.git

cp linux-syscall-support/lss/linux_syscall_support.h ./breakpad/src/third_party/lss

交叉编译 arm_linux

若之前已经配置了 configure,建议删除后重新克隆项目:

# 克隆仓库
git clone https://github.com/cmzy/beakpad.git
# 如果嫌github慢,可使用 https://gitee.com/jyu_hsy/breakpad.git

cd breakpad
# configure 配置,若未知configure提供了哪些参数,可使用 ./configure -help

# 交叉编译设置
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++
./configure --host=aarch64-linux-gnu

sudo make
# 嫌慢的可以使用 sudo make -j4

ps
这里生成的 dump_syms & microdump_stackwalk 是在目标板上运行的,我们同样可以通过 file 查看其类型。

qBreakpad

源码下载

git clone --recursive https://github.com/buzzySmile/qBreakpad.git

# 这里使用 --recursive 将会去克隆以下两个项目:
# google-breakpad [master]- https://chromium.googlesource.com/breakpad/breakpad
# linux-syscall-support [master] - https://chromium.googlesource.com/linux-syscall-support

# 由于某些原因我们是克隆不下来的,因此建议使用:
git clone https://github.com/buzzySmile/qBreakpad.git
git clone https://github.com/cmzy/beakpad.git
git clone https://github.com/adelshokhy112/linux-syscall-support.git

# 然后将 beakpad 放至qBreakpad/third_party/beakpad
# 然后将 linux-syscall-support/lss 放至qBreakpad/third_party

qBreakpad 编译

  • QTCreator 打开 qBreakpad/handler/handler.pro
  • 选择你的 Kits 构建即可(这里可以是本地编译也可以是交叉编译,取决于你的Kits)
  • 构建完成,我们将得到 qBreakpad.a

使用

使用过程遇到问题请先查看本文 Q&A 部分!

添加静态库

//project.pro

# link qBreakpad library
unix:!macx: LIBS += -L$$PWD/qbreakpad -lqBreakpad
INCLUDEPATH += $$PWD/qbreakpad
DEPENDPATH += $$PWD/qbreakpad
unix:!macx: PRE_TARGETDEPS += $$PWD/qbreakpad/libqBreakpad.a

使用静态库

//main program

#include <QBreakpadHandler.h>
//...
QBreakpadInstance.setDumpPath(QLatin1String("crashes"));
//...

添加debug设置

//project.pro

# 生成调试信息
QMAKE_CFLAGS_RELEASE += -g
QMAKE_CXXFLAGS_RELEASE += -g

# 禁止优化
QMAKE_CFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE -= -O2

dump_syms

添加完成后,在软件奔溃时,将在 ./crashes(当然这取决于你的 setDumpPath() )路径下生成 dmp 文件,dmp文件并不能直接查看,我们使用 dump_syms读取调试信息并生成Breakpad 符号文件。

./dump_syms ./appname > appname.sym

minidump_stackwalk

tools / minidump_stackwalk 可以获取一个 minidump 及其相应的符号,并产生一个符号化的 stacktrace。通常我们需要重定向一下:

./minidump_stackwalk -s xxx.dmp appname.sym > error.log

error.log

查看 error.log,我们只能看到奔溃时堆栈地址,例如在主程序 0x835c 上奔溃,我们可以直接使用以下指令查看奔溃的具体函数及其所处的行号:

addr2line 0x835c -e appname -f

debug lib.so

对于动态库,若想通过 dump 定位,需要在编译动态库时加上 -g禁止优化, Qt Project 中配置如下:

//libprojectname.pro

TEMPLATE = lib

#加入调试信息
QMAKE_CFLAGS_RELEASE += -g
QMAKE_CXXFLAGS_RELEASE += -g

#禁止优化
QMAKE_CFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE -= -O2

重新编译生成 testosapp 后,通过 minidump_stackwalk 生成 error.log,·假设 error.log 如下:

Operating system: Linux
                  0.0.0 Linux 4.4.194-59119-g968ba5005831 #583 SMP Tue Jul 14 15:10:24 CST 2020 aarch64
CPU: arm64
     6 CPUs

GPU: UNKNOWN

Crash reason:  SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available

Thread 0 (crashed)
 0  libtestos.so.1 + 0x6d0
     x0 = 0x0000000000000000    x1 = 0x0000000000000001
     x2 = 0x0000000000000000    x3 = 0x0000007f980063c0
     x4 = 0x00000055aeb65ca0    x5 = 0x0000000000000000
     x6 = 0x0000007fd4414590    x7 = 0x0000000000000000
     x8 = 0x0000000000000042    x9 = 0x000002180093006e
    x10 = 0x0000000000000000   x11 = 0x0000000000000010
    x12 = 0x0000007fa337faf8   x13 = 0x0000000000000000
    x14 = 0x0000000000000093   x15 = 0x000000000000006e
    x16 = 0x000000557a081b80   x17 = 0x0000007fa396c6bc
    x18 = 0x0000000000ff0000   x19 = 0x00000055aeb65ca0
    x20 = 0x0000007fd4414590   x21 = 0x0000000000000000
    x22 = 0x0000007fa31d5230   x23 = 0x0000000000000026
    x24 = 0x0000000000000001   x25 = 0x0000000000000000
    x26 = 0x0000000000000001   x27 = 0x0000007fd44135f8
    x28 = 0x0000007f8c0117f0    fp = 0x0000007fd4413410
     lr = 0x000000557a056438    sp = 0x0000007fd44133f0
     pc = 0x0000007fa396c6d0
    Found by: given as instruction pointer in context

    //...

同样可以通过以下指令查看库中的奔溃位置:

addr2line 0x6d0 -e libosname -f

Q&A

Q1

qt.qpa.plugin: Could not find the Qt platform plugin “eglfs” in “”
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

A1

libEGL.so & libGLESv2.so 移动至 /usr/lib 即可。

Q2

使用qBreakpad.a时出现:
/home/hsy/SW/Qt5.9.3/Project/test-qBreakpad/qBreakpad/libqBreakpad.a(exception_handler.o):在函数‘google_breakpad::ExceptionHandler::SimulateSignalDelivery(int)’中:
exception_handler.cc:(.text+0xef4):对‘breakpad_getcontext’未定义的引用
/home/hsy/SW/Qt5.9.3/Project/test-qBreakpad/qBreakpad/libqBreakpad.a(exception_handler.o):在函数‘google_breakpad::ExceptionHandler::WriteMinidump()’中:
exception_handler.cc:(.text+0x11e2):对‘breakpad_getcontext’未定义的引用

A2

检查后发现问题出在我们构建动态库的工程中:

// in handler - breakpad.pri

// Add this code:
SOURCES +=        $$BREAKPAD_PATH/common/linux/breakpad_getcontext.S \

Q3

使用 qBreakpad.a 时出现:error:reference to 'once_flag' is ambiguous

A3

该问题主要出现在使用了 std 的项目中,std 中也定义了 once_flag

因此需要修改我们的头文件cell_once.h

inline static void qCallOncePerThread(Function func)
{
    using namespace CallOnce;
    if (!CallOnce::once_flag()->hasLocalData()) {
        CallOnce::once_flag()->setLocalData(new QAtomicInt(CO_Request));
        qCallOnce(func, *CallOnce::once_flag()->localData());
    }
}

参考鸣谢

GitHub - cmzy/beakpad

GitHub - buzzySmile/qBreakpad

12.5-使用Qt实现跨平台C++崩溃捕获,看这一篇就足够了(Breakpad)

google breakpad /qbreakpad 在 arm移植

QT中使用google breakpad捕获程序崩溃异常

02-跨平台的Qt程序崩溃之前生成Dump文件Breakpad

跨平台的Qt程序崩溃生成Dump文件Breakpad

addr2line命令

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值