本文是学习使用breakpad的一个总结,在这过程中看了很多博客,但是相对有用的有以下几篇:
- Android使用Google Breakpad进行崩溃日志管理
- breakpad的正确编译和常规用法
- Google Breakpad 学习笔记
环境:win10 linux 子系统,ubuntu 20,android-ndk-r20
一、源码编译先到github下载google/breakpad的源码,在ubuntu下编译。
总共遇到了三个问题(实际算两个问题),基本没什么大问题即可编译成功。
用windows的git clone代码有这个文件结尾的问题,导致各种失败。直接在ubuntu中clone代码可以避免这种麻烦。
1.2 找不到文件:third_party/lss/linux_syscall_support.hfatal 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 编译结果- client: /src/client/linux/libbreakpad_client.a,此文件可以编译进android 的app,完成native crash的捕捉和生成minidump文件;
- dump_syms: /src/tools/linux/dump_syms,用于提取so库的sym符号文件;
- minidump_stackwalk: /src/processor/minidump_stackwalk,用于将.dmp minudump文件和.sym文件合成可读的堆栈信息;
可参考Android使用Google Breakpad进行崩溃日志管理
三、解析dumplinux 环境下进行
3.1 准备工作将以下文件拷贝到一个目录(如果不拷贝到同一个目录则需要在不同的目录执行):
- /src/tools/linux/dump_syms/dump_syms
- /src/processor/minidump_stackwalk
- 准备带符号表的so(buildintermediatesCXXdebug)
- 准备收集到的奔溃堆栈文件(如:fde85952-3123-497b-83708b84-58dd1e16.dmp)
假设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 = 0x00000076d29d94003.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。记住每个步骤,每个工具,是一件复杂的事情,脚本可以将复杂问题简单化,只需要一次编写就可以避免记住那么多工具、指令,相对于学习脚本的这点付出,是非常值得的。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)