使用breakpad收集native奔溃日志及dump解析

使用breakpad收集native奔溃日志及dump解析,第1张

使用breakpad收集native奔溃日志及dump解析 使用breakpad收集native奔溃日志及dump解析

本文是学习使用breakpad的一个总结,在这过程中看了很多博客,但是相对有用的有以下几篇:

  1. Android使用Google Breakpad进行崩溃日志管理
  2. breakpad的正确编译和常规用法
  3. Google Breakpad 学习笔记

环境:win10 linux 子系统,ubuntu 20,android-ndk-r20

一、源码编译

先到github下载google/breakpad的源码,在ubuntu下编译。
总共遇到了三个问题(实际算两个问题),基本没什么大问题即可编译成功。

1.1 文件结尾问题

用windows的git clone代码有这个文件结尾的问题,导致各种失败。直接在ubuntu中clone代码可以避免这种麻烦。

1.2 找不到文件:third_party/lss/linux_syscall_support.h

fatal error: third_party/lss/linux_syscall_support.h: No such file or directory

去这个仓库linux-syscall-support下载并丢到对应目录即可

1.3 "rsp"过时导致失败

下载2这个文件后编译报错:
./src/third_party/lss/linux_syscall_support.h:2146:75: error: listing the stack pointer register ‘rsp’ in a clobber list is deprecated [-Werror=deprecated]
2146 | : “rsp”, “memory”, “r8”, “r10”, “r11”, “rcx”);

根据提示,定位到代码,把"rsp"从列表中删除即可

1.4 编译结果
  1. client: /src/client/linux/libbreakpad_client.a,此文件可以编译进android 的app,完成native crash的捕捉和生成minidump文件;
  2. dump_syms: /src/tools/linux/dump_syms,用于提取so库的sym符号文件;
  3. minidump_stackwalk: /src/processor/minidump_stackwalk,用于将.dmp minudump文件和.sym文件合成可读的堆栈信息;
二、接入breakpad(奔溃收集堆栈信息)

可参考Android使用Google Breakpad进行崩溃日志管理

三、解析dump

linux 环境下进行

3.1 准备工作

将以下文件拷贝到一个目录(如果不拷贝到同一个目录则需要在不同的目录执行):

  1. /src/tools/linux/dump_syms/dump_syms
  2. /src/processor/minidump_stackwalk
  3. 准备带符号表的so(buildintermediatesCXXdebug)
  4. 准备收集到的奔溃堆栈文件(如:fde85952-3123-497b-83708b84-58dd1e16.dmp)
3.2 解析dump

假设so:libbreakpad

# 1.dump_syms 提取特定so库的符号信息
./dump_syms libbreakpad.so > libbreakpad.so.sym
head -n1 libbreakpad.so.sym
# MODULE Linux arm64 659648E1F0DF9DFFD7E92A56FED08B930 libbreakpad.so
# 2.根据上面的生成目录结构,libbreakpad.sym移动到该目录
mkdir -p ./symbol/libbreakpad.so/8D8810A6193BEF7CE4FA900D3945461A0
mv libbreakpad.so.sym ./symbol/libbreakpad.so//8D8810A6193BEF7CE4FA900D3945461A0/

# 3.调用minidump_stackwalk命令,将dmp文件和sym文件合成可读的crashinfo.txt
./minidump_stackwalk be8144d6-9733-4d78-1841a6aa-e70a16f7.dmp  ./symbol > crashinfo.txt

经过以上步骤可以得到堆栈信息,并且能看到奔溃所在的代码行

Operating system: Android
                  0.0.0 Linux 4.4.126 #1 SMP PREEMPT Thu Oct 21 15:23:47 CST 2021 aarch64
CPU: arm64
     6 CPUs

GPU: UNKNOWN

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

Thread 0 (crashed)
 0  libbreakpad.so!Java_com_bottle_breakpad_Breakpad_testCrash [breakpad.cpp : 48 + 0x0]
     x0 = 0x00000076d403e180    x1 = 0x0000007ffca69c74
     x2 = 0x0000000000000000    x3 = 0x00000076d4095a00
     x4 = 0x0000007ffca6a0e8    x5 = 0x00000076baa1b45b
     x6 = 0x0000000000000000    x7 = 0x0000000000000000
     x8 = 0x0000000000000000    x9 = 0x0000000000000001
    x10 = 0x0000000000430000   x11 = 0x00000076d8349b30
    x12 = 0x00000000000000c4   x13 = 0x0000000000000072
    x14 = 0x00000076d7e9e170   x15 = 0xa2f74dbe36d6b483
    x16 = 0x00000076d4bcf5b0   x17 = 0x00000076d29d93f8
    x18 = 0x0000000c00000000   x19 = 0x00000076d4095a00
    x20 = 0x00000076d3aa8cb0   x21 = 0x00000076d4095a00
    x22 = 0x0000007ffca69f1c   x23 = 0x00000076baa1b45b
    x24 = 0x0000000000000004   x25 = 0x4238bf38fb418304
    x26 = 0x00000076d4095a98   x27 = 0x4238bf38fb418304
    x28 = 0x0000000000000001    fp = 0x0000007ffca69d38
     lr = 0x00000076bacc9004    sp = 0x0000007ffca69c60
.......

如果没有经过步骤1,2,没生成符号表,直接使用第三步解析dump。则不能直接定位到代码行,此时需要addr2line来定位

 ./minidump_stackwalk be8144d6-9733-4d78-1841a6aa-e70a16f7.dmp > nosymbol_crashinfo.txt
Operating system: Android
                  0.0.0 Linux 4.4.126 #1 SMP PREEMPT Thu Oct 21 15:23:47 CST 2021 aarch64
CPU: arm64
     6 CPUs

GPU: UNKNOWN

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

Thread 0 (crashed)
 0  libbreakpad.so + 0x24400
     x0 = 0x00000076d403e180    x1 = 0x0000007ffca69c74
     x2 = 0x0000000000000000    x3 = 0x00000076d4095a00
     x4 = 0x0000007ffca6a0e8    x5 = 0x00000076baa1b45b
     x6 = 0x0000000000000000    x7 = 0x0000000000000000
     x8 = 0x0000000000000000    x9 = 0x0000000000000001
    x10 = 0x0000000000430000   x11 = 0x00000076d8349b30
    x12 = 0x00000000000000c4   x13 = 0x0000000000000072
    x14 = 0x00000076d7e9e170   x15 = 0xa2f74dbe36d6b483
    x16 = 0x00000076d4bcf5b0   x17 = 0x00000076d29d93f8
    x18 = 0x0000000c00000000   x19 = 0x00000076d4095a00
    x20 = 0x00000076d3aa8cb0   x21 = 0x00000076d4095a00
    x22 = 0x0000007ffca69f1c   x23 = 0x00000076baa1b45b
    x24 = 0x0000000000000004   x25 = 0x4238bf38fb418304
    x26 = 0x00000076d4095a98   x27 = 0x4238bf38fb418304
    x28 = 0x0000000000000001    fp = 0x0000007ffca69d38
     lr = 0x00000076bacc9004    sp = 0x0000007ffca69c60
     pc = 0x00000076d29d9400
3.3 address2line

address2line在ndk中,如:

E:SDKandroid-ndk-r20toolchainsaarch64-linux-android-4.9prebuiltwindows-x86_64binaarch64-linux-android-addr2line.exe

使用步骤:

# cd到address2line所在目录
# NDK r20 
cd E:SDKandroid-ndk-r20toolchainsaarch64-linux-android-4.9prebuiltwindows-x86_64bin
aarch64-linux-android-addr2line.exe -e E:repositorybreakpad-demooutlibbreakpad.so 0x58458

# 输出
E:/repository/breakpad-demo/BreakpadDemo/breakpad/src/main/cpp/breakpad.cpp:48

可以看到使用addr2line和前面得到的是一致的。到此,breakpad编译,接入,解析dump一整个流程已经完成。但是解析dump使用起来还是比较复杂,可以写一个 linux 的 shell 脚本简化工作。

3.4 使用脚本解析dump

整个流程相对复杂,手工 *** 作比较浪费时间,程序员不应该把时间浪费在重复的工作上。这时候脚本就派上用场,可以写一个脚本,把整个流程抽象为一个脚本,脚本输入是dump文件的路径和输出的解析后的文件路径。只要拷贝这个脚本,修改breakpad和带符号表的so的路径即可快速地实现dump解析。甚至可以部署一个http服务,用户上传dump文件和so,然后返回解析的dump文件。测试可以使用这种方法,快速定位奔溃位置。

#!/bin/sh
# 在linux环境下执行,如在windows,可装一个Linux子系统
# 接收两个参数:
# $1=dump文件
# $2=输出的文件
# path/to/dump.sh be8144d6-9733-4d78-1841a6aa-e70a16f7.dmp CrashInfo.txt

# TODO1 修改指你的so目录,注意是debug的
lib_path=/path/to/your/so
# TODO2 修改指向dump_syms的所在目录
dump_syms=/path/to/your/dump_syms
# TODO3 修改指向minidump_stackwalk的所在目录
minidump=/path/to/your/minidump_stackwalk
echo pwd=$(pwd)
echo so path=$lib_path
echo dump_syms=$dump_syms
echo minidump_stackwalk=$minidump

# 定义一个函数,用来解析符号表
symbolFun() {
    echo "parameter 1 is $1"
	libsym=$1.sym
	echo $libsym
	$dump_syms $lib_path/$1 > $libsym
	libsymDir=$(head -n1 $libsym)
	# 截取目录名称
	echo $libsymDir
	libsymDir2=${libsymDir#*"MODULE Linux arm "}
	echo $libsymDir2
	libsymDir3=${libsymDir2% $1}
	echo $libsymDir3
	mkdir -p ./symbol/$1/$libsymDir3
	mv $libsym ./symbol/$1/$libsymDir3/
}
symbolFun libxyz1.so
symbolFun libxyz2.so
symbolFun libxyz3.so
...

# 开始解析dump
$minidump $1  ./symbol > $2

四、另一种解析dump的方法

Android studo安装目录自带了一份minidump_stackwalk自带的minidump_stackwalk。本机地址为:
C:ProgramFilesandroid-studiopluginsandroid-ndkresourceslldbbinminidump_stackwalk.exe

C:ProgramFilesandroid-studiopluginsandroid-ndkresourceslldbbinminidump_stackwalk.exe E:repositorybreakpad-demodumpbe8144d6-9733-4d78-1841a6aa-e70a16f7.dmp > E:repositorybreakpad-demodumpnative_crashinfo.txt

同样可以得到堆栈信息,由于没有使用符号表,所以使用addr2line继续定位到代码行

五、总结

不管使用何种方法,都需要带符号表的so,这个需要在编译库的时候保存下来。这就需要每个放行的apk都要保留一份带符号的so。记住每个步骤,每个工具,是一件复杂的事情,脚本可以将复杂问题简单化,只需要一次编写就可以避免记住那么多工具、指令,相对于学习脚本的这点付出,是非常值得的。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5504808.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-13
下一篇 2022-12-13

发表评论

登录后才能评论

评论列表(0条)

保存