[go: nahoru, domu]

Skip to content

An example of collecting Dart stack trace using manual native stack unwinding

License

Notifications You must be signed in to change notification settings

mraleph/thread_collect_stack_example

Repository files navigation

thread_collect_stack_example

This code illustrates how you could get a stack trace of the Dart thread using native stack unwinding.

The core of the implementation is in the lib/collect_stack.dart and src/collect_stack.cc.

  • The target thread needs to proactively register itself by calling setCurrentThreadAsTarget. This only really works for isolates that don't jump between threads (e.g. main UI isolate in Flutter). User created isolates are backed by a thread pool so Dart code can migrate between different threads.
  • We assume that we can walk the stack by following frame links chain. This might not necessary work if execution is in the native code which is compiled without frame pointers. This will work if execution is in the Dart code.

The stack is collected as a sequence of raw PC values and needs to be symbolized later using debug information.

Running example:

$ flutter config --enable-native-assets
$ flutter build apk --release --split-debug-info=debug-info -t lib/main.dart
$ flutter run --no-build --use-application-binary=build/app/outputs/flutter-apk/app-release.apk
...
Installing build/app/outputs/flutter-apk/app-release.apk...         3.4s
I/flutter ( 8225): Frame(pc: 3396957692, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3396957536, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3397044152, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3397056056, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3397112352, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3396903540, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3397112352, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3397057696, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3397111684, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3396845236, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3396662844, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libapp.so, baseAddress: 3396415488))
I/flutter ( 8225): Frame(pc: 3410865893, module: Module(path: /data/app/com.example.thread_collect_stack_example-TBzzwMgiQJ7BUep7husHbA==/lib/arm/libflutter.so, baseAddress: 3404587008))
I/flutter ( 8225): Frame(pc: 3403509000)

Here we got a sequence of frames in the application libapp.so (Dart frames) a frame in libflutter.so and then an unknown frame (unwinding error possibly).

We can symbolize Dart frames by doing:

$ llvm-symbolizer --exe debug-info/app.android-arm.symbols --adjust-vma 3396415488 3396957692 3396957536 3397044152 3397056056 3397112352 3396903540 3397112352 3397057696 3397111684 3396845236 3396662844

Here:

  • --exe specifies in which file to look for symbols (debug-info folder was generated by --split-debug-info=debug-info passed to flutter build).
  • --adjust-vma specifies base address of the shared library
  • the rest of command line are frame PCs

The output of this command:

IndexError.check
third_party/dart/sdk/lib/core/errors.dart:479:24

_GeneratorIterable.elementAt
third_party/dart/sdk/lib/core/iterable.dart:0:0
ListIterable.reduce
third_party/dart/sdk/lib/internal/iterable.dart:194:30

new _GrowableList.generate
third_party/dart/sdk/lib/_internal/vm/lib/growable_array.dart:136:13
main.<anonymous closure>
/usr/local/google/home/vegorov/src/temp/thread_collect_stack_example/lib/main.dart:38:29
new _GrowableList.generate
third_party/dart/sdk/lib/_internal/vm/lib/growable_array.dart:136:28
main
/usr/local/google/home/vegorov/src/temp/thread_collect_stack_example/lib/main.dart:36:25

main
/usr/local/google/home/vegorov/src/temp/thread_collect_stack_example/lib/main.dart:11:1

_Closure.call
third_party/dart/sdk/lib/_internal/vm/lib/function.dart:0:0

_runMain.<anonymous closure>
lib/ui/hooks.dart:301:23

_Closure.call
third_party/dart/sdk/lib/_internal/vm/lib/function.dart:0:0

_delayEntrypointInvocation.<anonymous closure>
third_party/dart/sdk/lib/_internal/vm/lib/isolate_patch.dart:300:17

_Closure.call
third_party/dart/sdk/lib/_internal/vm/lib/function.dart:0:0

_RawReceivePort._handleMessage
third_party/dart/sdk/lib/_internal/vm/lib/isolate_patch.dart:185:5

stub InvokeDartCode
??:0:0

About

An example of collecting Dart stack trace using manual native stack unwinding

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published