Search code examples
androidflutterndk-stack

How to symbolicate libapp.so stack trace in Flutter?


In Google Play console, sometimes I see crash reports like this:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.blackoutage.game <<<

backtrace:
  #00  pc 00000000003080f0  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc 0000000000306ad4  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc 000000000065ebc4  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc 000000000051e4a8  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libapp.so (offset 0x1000)
  #00  pc 0000000000565c9c  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libapp.so (offset 0x1000)
  #00  pc 000000000063925c  /data/app/~~X6gyE3SkREkb9PZZqeHzjA==/com.blackoutage.game-7OdYWe4UMLRMee8enANExA==/split_config.arm64_v8a.apk!lib/arm64-v8a/libflutter.so (offset 0xafa000)
  #00  pc b4000071fdfd5200  <unknown>

It is pretty easy to symbolicate stack traces from libflutter.so (https://github.com/flutter/flutter/wiki/Crashes). Based on the log above I can say that something in flutter crashes, but to fix those bugs I need to also symbolicate traces from libapp.so, how can I do that?


Solution

  • Firstly, if you can, try to use an integrated solution, such as Sentry (https://pub.dev/packages/sentry_flutter). It automatically captures stack traces and tries to symbolize them. If your app is stripped, you can also upload the symbol files to their server and they will symbolize them.

    Secondly, if you want to do it manually, here are some insights. I have struggled with such symbolization before, and there does not seem to be enough information on the Internet (so let me add a bit of information to the Internet ;) ).

    The libapp.so, interestingly, is a normal .so file (dynamic linked library). It is not a special home-made specific-to-Flutter format. On the contrary, it is the same ELF format even when you write down a C/C++ program and compile it. With this knowledge, you will immediately realize that, symbolizing Flutter stack traces is no difference than symbolizing normal C/C++/... code.

    Therefore, you may need to learn a bit about the traditional world of C/C++. For example, I suggest to read the "Linker" chapter of the classical CSAPP textbook, which explains everything quite well. Then you will fully understand what is a .so file, how to symbolize a C/C++ .so file's stack trace, etc.

    Then you should have no problem doing Flutter's symbolization. But here I also write down what to do step by step: Firstly, when you build the apk without containing debug info inside it, you use the split-debug-info flag and get the debug info file separately. This debug info file will be needed in symbolization. Then, use traditional tools manipulating traditional .so files, such as addr2line, to get the source code line number given the pc. Of course, higher-level tools such as ndk-stack can also be helpful. Or you can write down your own script calling addr2line and so on.