版权申明:未经允许请勿转载。转载前请先联系作者(hello@yeshen.org)

背景是上一篇博客遇到了问题。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 oouttest.o: test.cc test.h    g++ -c test.ccmain.o : main.cc test.h    g++ -c main.cclibtest : test.o    g++ -shared -o libtest.so test.oout: main.o libtest.so    g++ -o out main.o libtest.soclean:    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_Resume0000000100000f00 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_v00000000100000000 T __mh_execute_header0000000100000db0 T _main                 U _printf                 U dyld_stub_binder

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

strip out

在看一下

                 U __Unwind_Resume                 U std::terminate()                 U ___cxa_begin_catch                 U ___gxx_personality_v00000000100000000 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 <<

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

********** Crash dump: **********Build fingerprint: 'generic/google_sdk/generic/:2.2/FRF91/43546:eng/test-keys'pid: 351, tid: 351  >>> /data/local/ndk-tests/crasher <<

用法

要使用 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 输出时查找第一行星号。例如:

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

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. tcping测试服务器TCP端口
  3. Android(安卓)Fragment 基本了解
  4. Android(安卓)设置全屏和无标题模式
  5. Android关机和重启的调用代码
  6. Android(安卓)自定义弹性ListView控件实例代码(三种方法)
  7. [Android1.5]DigitalClock自定义日期输出格式
  8. 使用AIDL实现进程间的通信
  9. Android(安卓)Device Monitor官方替代工具

随机推荐

  1. 八个问题帮你快速了解Docker
  2. 针对Docker容器的监控指标
  3. 将要改变IT世界的的docker技术是什么?
  4. 应对 Docker 网络功能难题的挑战与思考
  5. 如何实现 Docker 与分布式数据库结合
  6. docker 使用入门
  7. mysql新增纪录中某设有默认值的字段为nul
  8. 用 Docker 无脑备份数据库
  9. HBase 入门笔记-数据落地篇
  10. Docker 常用命令梳理