2023年7月10日发(作者:)
breakpad的正确编译和常规⽤法⼀、breakpad简介breakpad ⽽是⼀个全平台的C/C++程序的崩溃⽇志收集⼯具,适配了Windows/MacOX/Linux,当然也⽀持了Android。breadpad的⼯作原理如下图所⽰:adpad 主要包含三个模块:client编译进⼊项⽬中,随项⽬⼀起编译发布,发布出去的so是strip掉debug信息的。当在⽤户⼿机上崩溃的时候,client就收集信息,写⼊特定格式的崩溃⽂件。⽂件最后被收集到服务端。Breakpad symbol dumper (dump_syms⼯具)当你在编译so的时候,除了编译strip后的so,还得保留strip前的so。dump_syms 就是⽤来从strip前的so 提取符号信息.sym⽂件如何获得保留strip信息的so?假如你是⽤gradle编译的话,strip前的so和strip后的so都是存在的,可以在特定⽬录查找,如下:└── transforms ├── mergeJniLibs │ └── debug │ ├── 0 │ │ └── lib │ │ └── arm64-v8a │ │ └── │ └── __content__.json └── stripDebugSymbol └── debug ├── 0 │ └── lib │ └── arm64-v8a │ └── └── __content__.jsonapp/build/intermediates/transforms/ ⽬录下,mergeJniLibs中的so是strip debug信息之前的so;stripDebugSymbol中的so是strip掉debug信息之后的so找到未strip的so之后,可以⽤以下命令提取出符号信息./dump_syms > dump processer(minidump_stackwalk⼯具)sym符号⽂件和.dmp minidump⽂件发送给Server端后,通过minidump_stackwalk指令,从.sym符号⽂件和包含崩溃信息的.dmp⽂件中提取出完整的奔溃时的堆栈信息。⼆、下载breakpad源码可以从breadpad-github,然后编译。很⼈反映从官⽹下载的breadpad源码编译会报错,需要补充缺失的⽂件。所以也可以直接feifei-123的github直接下载可以编译通过的版本。执⾏命令:git clone /feifei-123/breakpad三、编译breadpadbreakpad 是跨平台的,⽀持linux、window和Mac os系统,不同平台上的编译配置也是不同的。linux 平台编译出来的dump_syms 仅能再linux上运⾏,来解析linux上运⾏的so的符号信息macOS 平台编译出来的dump_syms 仅能再mac OS 上运⾏,来解析mac 上运⾏的so的符号信息。window 平台编译出来的dump_syms,仅能在Window上运⾏,并解析window上运⾏的dll的符号信息。因为我最终的应⽤场景时 捕捉Android上的natvie crash,然后解析奔溃时的堆栈,⽽Android 是属于Linux系统的。所以编译breadpad 也必须在Linux系统上进⾏。否则编译出来的dump_syms ⽆法解析android的minidump信息的。编译过程:清空上次build的临时⽂件 make clean
运⾏配置信息./configure
parallels@parallels-vm:~/Desktop/Parallels Shared Folders/Home/Desktop/TM/Github/orginal_breakpad/breakpad$ ./configure
checking build x86_64-pc-linux-gnuchecking host x86_64-pc-linux-gnuchecking for a /usr/bin/install -cchecking whether build environment yeschecking for a thread-safe mkdir -p... /bin/mkdir -pchecking nochecking mawkchecking whether make sets $(MAKE)... yeschecking whether make supports yeschecking whether UID '1000' is supported by yeschecking whether GID '1000' is supported by yeschecking how to create a ustar gnutarchecking whether to enable maintainer-specific portions nochecking for style of include used GNUchecking gccchecking whether the C yeschecking for C compiler default output cking for suffix
checking whether we are nochecking for suffix of ochecking whether we are using the GNU yeschecking whether gcc accepts -g... yeschecking for gcc option to accept none neededchecking whether gcc understands -c and - yeschecking dependency style gcc3checking archecking the archiver (ar) archecking dependency style gcc3checking (cached) gccchecking whether we are using the GNU (cached) yeschecking whether gcc accepts -g... (cached) yeschecking for gcc option to accept (cached) none neededchecking whether gcc understands -c and - (cached) yeschecking dependency style (cached) gcc3checking how to run the gcc -Echecking for g++... g++checking whether we are using the GNU C++ yeschecking whether g++ accepts -g... yeschecking dependency style of g++... gcc3checking ranlibchecking for grep that handles long lines and -e... /bin/grepchecking /bin/grep -Echecking for ANSI C yeschecking for special C compiler options needed for nochecking for _FILE_OFFSET_BITS value needed for nochecking for the pthreads library - nochecking whether pthreads work without nochecking whether pthreads work with - nochecking whether pthreads work with - nochecking for the pthreads library - nochecking whether pthreads work with - yeschecking for joinable PTHREAD_CREATE_JOINABLEchecking if more special flags are required nochecking for sys/ yeschecking for sys/ yeschecking for yeschecking for yeschecking for yeschecking for yeschecking for yeschecking for yeschecking for yeschecking . yeschecking . yeschecking for .h... yeschecking sys/random. nochecking sys/random. nochecking for sys/ nochecking nochecking nochecking whether g++ supports C++11 features nochecking whether g++ supports C++11 features with -std=c++11... yeschecking whether C++ compiler accepts - nochecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking whether C++ compiler accepts - yeschecking for O_CLOEXEC defined in yeschecking that generated files are newer doneconfigure: creating ./: creating : creating : creating : creating src/: src/config.h is : executing depfiles commands注意 checking build x86_64-pc-linux-gnu 表明我当前的编译环境是linuxmake 执⾏编译make编译完成后libbreakpad_client.a 位于/src/client/linux ⽬录下,此⽂件可以编译进android 的app,完成native crash的捕捉和⽣成minidump⽂件dump_syms ⽂件位于 /src/tools/linux/dump_syms ⽬录,⽤于提取so库的sym符号⽂件parallels@parallels-vm:~/Desktop/Parallels Shared Folders/Home/Desktop/TM/Github/orginal_breakpad/breakpad/src/tools/linux/dump_syms$ lsdump_syms dump_ src_tools_linux_dump_syms_dump_syms-dump_ump_stackwalk 位于/src/processor⽬录下,⽤于将.dmp minudump⽂件和.sym⽂件合成可读的堆栈信息parallels@parallels-vm:~/Desktop/Parallels Shared Folders/Home/Desktop/TM/Github/orginal_breakpad/breakpad/src/processor$ ls | grep minidump_stackwalkminidump_stackwalkminidump_dump_stackwalk_machine_readable_testminidump_ump_stackwalk_test三、解析minudump⽂件1、 dump_sym1、 dump_syms 提取特定so库的符号信息以为例:./dump_syms > 2、根据1中⽣成的⽣成特定的⽬录结构:⽣成特定的⽬录结构:├── symbol│ └── │ └── 57399AA1EE2607A34686D5DED7D43C310│ └── 命令如下:head -n1
MODULE Linux arm64 57399AA1EE2607A34686D5DED7D43C310 r -p ./symbol//57399AA1EE2607A34686D5DED7D43C310mv ./symbol//57399AA1EE2607A34686D5DED7D43C310/3、调⽤minidump_stackwalk命令,将dm命令,将dmp⽂件和sym⽂件合成可读的cp⽂件和sym⽂件合成可读的./minidump_stackwalk ./symbol > 部分内容如下:Operating system: Android 0.0.0 Linux 4.4.83 #2 SMP PREEMPT Sun Jan 12 10:48:20 CST 2020 aarch64CPU: arm64 4 CPUsGPU: UNKNOWNCrash reason: SIGSEGV /SEGV_MAPERRCrash address: 0x0Process uptime: not availableThread 32 (crashed) 0 !testCrash1() + 0x14 x0 = 0x0027 x1 = 0x00000078e60f5f30 x2 = 0x0005 x3 = 0x0003 x4 = 0x0401 x5 = 0xa800 x6 = 0x0000 x7 = 0x7f7f7f7f7f7f7f7f x8 = 0x0000 x9 = 0x0001 x10 = 0x00000078e60f60c0 x11 = 0x0018 x12 = 0x000b x13 = 0xffffffffffffffff x14 = 0xff00 x15 = 0xffffffffffffffff x16 = 0x00000078e82b7608 x17 = 0x00000078e823b454 x18 = 0x0008 x19 = 0x00000078e7e2fe00 x20 = 0xae7f20 x21 = 0x00000078e7e2fe00 x22 = 0x00000078e60f693c x23 = 0x00000078e8f1bc31 x24 = 0x0000 x25 = 0x00000078e60f7588 x26 = 0x00000078e7e2fea0 x27 = 0x0000 x28 = 0x0000 fp = 0x00000078e60f6650 lr = 0x00000078e823b4c8 sp = 0x00000078e60f6620 pc = 0x00000078e823b468 Found by: given as instruction pointer in context 1 !testCoffeCacher() + 0x4c x19 = 0x00000078e7e2fe00 x20 = 0xae7f20 x21 = 0x00000078e7e2fe00 x22 = 0x00000078e60f693c x23 = 0x00000078e8f1bc31 x24 = 0x0000 x25 = 0x00000078e60f7588 x26 = 0x00000078e7e2fea0 x27 = 0x0000 x28 = 0x0000 fp = 0x00000078e60f6650 sp = 0x00000078e60f6630 pc = 0x00000078e823b4c8 Found by: call frame info 2 !call_dangerous_function() + 0x14 x19 = 0x00000078e7e2fe00 x20 = 0xae7f20 x21 = 0x00000078e7e2fe00 x22 = 0x00000078e60f693c x23 = 0x00000078e8f1bc31 x24 = 0x0000 x25 = 0x00000078e60f7588 x26 = 0x00000078e7e2fea0 x27 = 0x0000 x28 = 0x0000 fp = 0x00000078e60f6670 sp = 0x00000078e60f6660 pc = 0x00000078e823b508 Found by: call frame info 3 !Java_com_sogou_translate_jni_BreakpadInit_go2crash + 0x14 x19 = 0x00000078e7e2fe00 x20 = 0xae7f20 x21 = 0x00000078e7e2fe00 x22 = 0x00000078e60f693c x23 = 0x00000078e8f1bc31 x24 = 0x0000 x25 = 0x00000078e60f7588 x26 = 0x00000078e7e2fea0 x27 = 0x0000 x28 = 0x0000 fp = 0x00000078e60f6690 sp = 0x00000078e60f6680 pc = 0x00000078e823b534 Found by: call frame info 4 + 0x111c0 x19 = 0x00000078e7e2fe00 x20 = 0xae7f20 x21 = 0x00000078e7e2fe00 x22 = 0x00000078e60f693c x23 = 0x00000078e8f1bc31 x24 = 0x0000 x25 = 0x00000078e60f7588 x26 = 0x00000078e7e2fea0 x27 = 0x0000 x28 = 0x0000 fp = 0x00000078e60f6768 sp = 0x00000078e60f66a0 pc = 0x00000078e8e261c4 Found by: call frame info四、⼀路踩的坑因为我⾃⼰的笔记本是mac pro,最初编译breakpad是在mac上编译的。执⾏./configure & make 成功编译之后 ./configure & make
feifeideMacBook-Pro:src feifei$ ./configure & make
[1] 45277make: *** No targets specified and no makefile found. deMacBook-Pro:src feifei$ checking build x86_64-apple-darwin18.5.0checking host x86_64-apple-darwin18.5.0在/src/client/linux中未⽣成 dump_syms⽂件,feifeideMacBook-Pro:dump_syms feifei$ pwd/Users/feifei/Desktop/tmp/breakpad/src/src/tools/linux/dump_symsfeifeideMacBook-Pro:dump_syms feifei$ lsdump_进⽽去/src/client/mac中 存在⼀个dump_roj⽂件。/Users/feifei/Desktop/tmp/breakpad/src/src/tools/mac/dump_symsfeifeideMacBook-Pro:dump_syms feifei$ lsdump_roj dump_syms_ macho_利⽤xcode 打开dump_roj编译通过得到dump_syms,利⽤该dump_syms 解析Android ⼯程中的 失败。feifeideMacBook-Pro:try feifei$ mac/dump_syms > : file is neither a fat binary file nor a Mach-O object file但是src/processor下的minidump_stackwalk 可以直接处理android 项⽬⽣成的dmp⽂件的.feifeideMacBook-Pro:processor feifei$ pwd/Users/feifei/Desktop/tmp/breakpad/src/processorfeifeideMacBook-Pro:processor feifei$ ls | grep minidump_stackwalkminidump_stackwalkminidump_dump_ump_stackwalk_machine_readable_testminidump_stackwalk_test/Users/feifei/Desktop/tmp/breakpad/src/processor/minidump_stackwalk > 最终解决办法:安装了⼀个ubuntn 虚拟机,在虚拟机中对breadpad 进⾏编译,搞定~五、breadpad 解析奔溃堆栈的另⼀种玩法1、minidump_stackwalk 直接将.dmp ⽂件解析成可读的信息,但是缺少堆栈的解析(奔溃点的函数符号和⾏号)Android studo安装⽬录⾃带了⼀份minidump_stackwalk⾃带的minidump_stackwalk可以在mac上直接运⾏ 解析dmp⽂件查找minidump_stackwalk位置find / -name minidump_stackwalk我mac上的⽬录为/Applications/Android /Contents/bin/lldb/bin/minidump_stackwalk也可以直接使⽤“四”步中mac 环境编译⽣成的 minidump_stackwalk,位置如下:breakpad/src/src/processor/minidump_stackwalkminidump_stackwalk 解析minidump⽂件/Users/feifei/Library/Android/sdk/lldb/3.1/bin/minidump_stackwalk > 内容:Operating system: Android 0.0.0 Linux 4.4.83 #2 SMP PREEMPT Sun Jan 12 10:48:20 CST 2020 aarch64CPU: arm64 4 CPUsGPU: UNKNOWNCrash reason: SIGSEGV /SEGV_MAPERRCrash address: 0x0Process uptime: not availableThread 32 (crashed) 0 + 0x28468 x0 = 0x0027 x1 = 0x00000078e6b82f30 x2 = 0x0005 x3 = 0x0003 x4 = 0x0401 x5 = 0xa800 x6 = 0x0000 x7 = 0x7f7f7f7f7f7f7f7f x8 = 0x0000 x9 = 0x0001 x10 = 0x00000078e6b830c0 x11 = 0x0018 x12 = 0x000b x13 = 0xffffffffffffffff x14 = 0xff00 x15 = 0xffffffffffffffff x16 = 0x00000078e86ec608 x17 = 0x00000078e8670454 x18 = 0x00000078e6b8166c x19 = 0x00000078fa1e8800 x20 = 0xae7f20 x21 = 0x00000078fa1e8800 x22 = 0x00000078e6b8393c x23 = 0x00000078e9018c31 x24 = 0x0000 x25 = 0x00000078e6b84588 x26 = 0x00000078fa1e88a0 x27 = 0x0000 x28 = 0x0000 fp = 0x00000078e6b83650 lr = 0x00000078e86704c8 sp = 0x00000078e6b83620 pc = 0x00000078e8670468 Found by: given as instruction pointer in context 1 + 0x284c4 fp = 0x00000078e6b83670 lr = 0x00000078e8670508 sp = 0x00000078e6b83660 pc = 0x00000078e86704c8 Found by: previous frame's frame pointer 2 + 0x28504 fp = 0x00000078e6b83690 lr = 0x00000078e8670534 sp = 0x00000078e6b83680 pc = 0x00000078e8670508 Found by: previous frame's frame pointer 3 + 0x28530由此可知程序 奔溃在了 的相对偏移位置 0x28468的地址调⽤的关系如下: + + + + 0x285302、利⽤addr2line 根据发⽣crash的so⽂件,以及偏移地址,得出产⽣carsh的⽅法、⾏数和调⽤堆栈关系。aarch64-linux-android-addr2line ⼯具也是在android sdk 安装⽬录下⾃带的,可以⾃⾏查找。feifeideMacBook-Pro:~ feifei$ find / -name aarch64-linux-android-addr2line我mac上aarch64-linux-android-addr2line的⽬录为/Users/feifei/Library/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line针对上⾯得出的调⽤堆栈,解析 的 0x28468、0x284c4、0x28504、0x28530分别对应哪个函数符号 + + + + 0x28530feifeideMacBook-Pro:try feifei$ /Users/feifei/Library/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-adtestCrash1():?testCoffeCacher():?call_dangerous_function():?Java_com_sogou_translate_jni_BreakpadInit_go2crash:?可以得出实际的⽅法调⽤栈为:testCrash1()testCoffeCacher()call_dangerous_function()Java_com_sogou_translate_jni_BreakpadInit_go2crasharm-linux-androideabi-addr2line 使⽤⽅法介绍:arm-linux-androideabi-addr2line -C -f -e ${SOPATH} ${Address}-C -f //打印错误⾏数所在的函数名称 -e //打印错误地址的对应路径及⾏数 ${SOPATH} //so库路径
${Address} //需要转换的堆栈错误信息地址,可以添加多个,但是中间要⽤空格隔开六、参考⽂献:
发布者:admin,转转请注明出处:http://www.yc00.com/web/1688987111a191927.html
评论列表(0条)