android native crash日志解析

版权申明:未经允许请勿转载。转载前请先联系作者([email protected])

背景是上一篇博客遇到了问题。crashlytics的解析符号没解析出来,./gradlew crashlyticsUploadSymbolsRelease 执行了也没起什么作用。

嗯,这个问题先从 so 库的一些背景知识说起。

什么是 so

http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

so 就是share-library。先看怎么build出so吧。

Makefile

all : test.o main.o out libtest oout

test.o: test.cc test.h
    g++ -c test.cc

main.o : main.cc test.h
    g++ -c main.cc

libtest : test.o
    g++ -shared -o libtest.so test.o

out: main.o libtest.so
    g++ -o out main.o libtest.so

clean:
    rm -f *.o *.so out oout

main.cc

#include 
#include "test.h"

int main(int argc, const char *argv[])
{
  test t(22);
  t.increase();
  printf("Received: %i", t.getFlag());
}

test.cc

#include 
#include "test.h"

test::test(unsigned int flag)
    : _flag(flag)
{
}

test::~test()
{
}

unsigned int test::getFlag() const
{
  return _flag;
}

void test::increase()
{
  _flag += 1;
}

test.h

#ifndef TEST_H
#define TEST_H

#include 

class test
{
private:
  unsigned int _flag;

public:
  test(unsigned int flag);
  ~test();
  void increase();
  unsigned int getFlag() const;
};

#endif

关键的代码编译代码就只有一行

g++ -shared -o libtest.so test.o

也就是它把多个o文件合并成一个。

什么是 symbols

crash日志中,最重要的是符号,是代码的行数和对应的记录。
可以怎么看呢?

make 
nm -C out

执行之后,就可以看到具体的函数信息了。

0000000100000f68 s GCC_except_table0
                 U __Unwind_Resume
0000000100000f00 T test::increase()
0000000100000e90 T test::test(unsigned int)
0000000100000e70 T test::test(unsigned int)
0000000100000ed0 T test::~test()
0000000100000ec0 T test::~test()
0000000100000ef0 T test::getFlag() const
                 U std::terminate()
0000000100000e60 t ___clang_call_terminate
                 U ___cxa_begin_catch
                 U ___gxx_personality_v0
0000000100000000 T __mh_execute_header
0000000100000db0 T _main
                 U _printf
                 U dyld_stub_binder

当然我们对外的时候,不能把symbols都打进包里,所以这个时候,会

strip out

在看一下

                 U __Unwind_Resume
                 U std::terminate()
                 U ___cxa_begin_catch
                 U ___gxx_personality_v0
0000000100000000 T __mh_execute_header
                 U _printf
                 U dyld_stub_binder

可以看到,很多信息都被strip掉了。

在android平台上,不是直接用上面的 g++、strip。因为具体手机平台和PC的平台的环境是不同的,要用交叉编译。也就是用对应平台的gcc去编译。android的话,在 android/sdk/ndk-bundle/toolchains 下面。

adb logcat 日志的解析方法

参考: https://developer.android.com/ndk/guides/ndk-stack?hl=zh-CN

借助 ndk-stack 工具,您可以使用符号来表示来自 adb logcat 的堆栈轨迹或 /data/tombstones/ 中的 tombstone。该工具会将共享库内的任何地址替换为源代码中对应的 :,从而简化调试流程。

例如,它可将下面的代码:

I/DEBUG   (   31): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG   (   31): Build fingerprint: 'generic/google_sdk/generic/:2.2/FRF91/43546:eng/test-keys'
I/DEBUG   (   31): pid: 351, tid: 351  >>> /data/local/ndk-tests/crasher <<<
I/DEBUG   (   31): signal 11 (SIGSEGV), fault addr 0d9f00d8
I/DEBUG   (   31):  r0 0000af88  r1 0000a008  r2 baadf00d  r3 0d9f00d8
I/DEBUG   (   31):  r4 00000004  r5 0000a008  r6 0000af88  r7 00013c44
I/DEBUG   (   31):  r8 00000000  r9 00000000  10 00000000  fp 00000000
I/DEBUG   (   31):  ip 0000959c  sp be956cc8  lr 00008403  pc 0000841e  cpsr 60000030
I/DEBUG   (   31):          #00  pc 0000841e  /data/local/ndk-tests/crasher
I/DEBUG   (   31):          #01  pc 000083fe  /data/local/ndk-tests/crasher
I/DEBUG   (   31):          #02  pc 000083f6  /data/local/ndk-tests/crasher
I/DEBUG   (   31):          #03  pc 000191ac  /system/lib/libc.so
I/DEBUG   (   31):          #04  pc 000083ea  /data/local/ndk-tests/crasher
I/DEBUG   (   31):          #05  pc 00008458  /data/local/ndk-tests/crasher
I/DEBUG   (   31):          #06  pc 0000d362  /system/lib/libc.so
I/DEBUG   (   31):

转换为更具可读性的代码:

********** Crash dump: **********
Build fingerprint: 'generic/google_sdk/generic/:2.2/FRF91/43546:eng/test-keys'
pid: 351, tid: 351  >>> /data/local/ndk-tests/crasher <<<
signal 11 (SIGSEGV), fault addr 0d9f00d8
Stack frame #00  pc 0000841e  /data/local/ndk-tests/crasher : Routine zoo in /tmp/foo/crasher/jni/zoo.c:13
Stack frame #01  pc 000083fe  /data/local/ndk-tests/crasher : Routine bar in /tmp/foo/crasher/jni/bar.c:5
Stack frame #02  pc 000083f6  /data/local/ndk-tests/crasher : Routine my_comparison in /tmp/foo/crasher/jni/foo.c:9
Stack frame #03  pc 000191ac  /system/lib/libc.so
Stack frame #04  pc 000083ea  /data/local/ndk-tests/crasher : Routine foo in /tmp/foo/crasher/jni/foo.c:14
Stack frame #05  pc 00008458  /data/local/ndk-tests/crasher : Routine main in /tmp/foo/crasher/jni/main.c:19
Stack frame #06  pc 0000d362  /system/lib/libc.so

用法

要使用 ndk-stack,您首先要有一个包含未剥离版应用共享库的目录。如果您使用 ndk-build,则可在 $PROJECT_PATH/obj/local/ 中找到这些未剥离版共享库,其中 是您设备的 ABI。

使用此工具的方式有两种。您可以将 logcat 文本作为直接输入馈送到程序。例如:

adb logcat | $NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi-v7a

您也可以使用 -dump 选项将 logcat 指定为输入文件。例如:

adb logcat > /tmp/foo.txt
$NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi-v7a -dump foo.txt

该工具会在开始解析 logcat 输出时查找第一行星号。例如:

    *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

你可能感兴趣的:(Android)