Dart Stack Symbolization
Version Notice: The applicable version of this document is based on its initial release. Some content may not have been fully synchronized with the latest changes and may contain inaccuracies. We plan to update this material in the 27.H1 release.
Overview
When a Flutter application freezes (AppFreeze) or crashes (CppCrash) in Release or Profile mode, the related logs usually contain the Dart-layer stack information (the libapp.so part). However, the stack addresses obtained are hexadecimal offsets, and you cannot directly see the specific Dart functions and line numbers. You need to use the flutter symbolize tool to convert the raw stack addresses into readable Dart source code locations.
Tool
- Tool:
flutter symbolize - Input: the stack file to be symbolized + the symbol file
- Output: the symbolized stack file
Command
flutter symbolize -i <stack-file> -d <symbol-file> -o <output-file>
Obtaining the Symbol File
The symbol file is generated during the packaging phase. When building the HAP package, append the --split-debug-info parameter (which strips debug info; you need to pass in a folder path), for example:
flutter build hap --release --split-debug-info=./debug-info
During packaging, the symbol information is separated from libapp.so and generated in the specified directory, for example: ./debug-info/app.ohos-arm64.symbols
Generating the Stack File
AppFreeze logs, CppCrash logs, or trace files captured by Hiprofiler usually contain the Dart-layer stack information (the libapp.so part), but it needs to be converted into a format recognized by the flutter symbolize tool.
Raw stack format (from the log):
#00 pc 0000000000171698 /data/storage/el1/bundle/libs/arm64/libapp.so(301f78813ec57f68e57e8d5453ab0d89)
#01 pc 00000000001537b4 /data/storage/el1/bundle/libs/arm64/libapp.so(301f78813ec57f68e57e8d5453ab0d89)
...
Converted stack format:
#00 abs 0000000000171698 virt 0000000000171698 libapp.so
#01 abs 00000000001537b4 virt 00000000001537b4 libapp.so
...
Notes:
#xx: the frame number in the call stackpc: program counter - represents the instruction pointer address0000000000xxxxxx: hexadecimal address/data/storage/.../libapp.so: shared library path(301f78813ec57f68e57e8d5453ab0d89): build fingerprint/hash
Example: AppFreeze Stack Symbolization
1. Prepare the Input File
Save the converted stack as input.txt:
#00 abs 0000000000171698 virt 0000000000171698 libapp.so
#01 abs 00000000001537b4 virt 00000000001537b4 libapp.so
#02 abs 0000000000281fe4 virt 0000000000281fe4 libapp.so
#03 abs 000000000023e2b4 virt 000000000023e2b4 libapp.so
#04 abs 000000000022ae88 virt 000000000022ae88 libapp.so
#05 abs 0000000000234b8c virt 0000000000234b8c libapp.so
#06 abs 0000000000237f2c virt 0000000000237f2c libapp.so
#07 abs 0000000000237cd0 virt 0000000000237cd0 libapp.so
#08 abs 0000000000278d3c virt 0000000000278d3c libapp.so
#09 abs 0000000000146204 virt 0000000000146204 libapp.so
#10 abs 000000000024df24 virt 000000000024df24 libapp.so
#11 abs 0000000000146190 virt 0000000000146190 libapp.so
#12 abs 00000000001460f8 virt 00000000001460f8 libapp.so
#13 abs 00000000001458d4 virt 00000000001458d4 libapp.so
#14 abs 000000000027d6a4 virt 000000000027d6a4 libapp.so
#15 abs 0000000000179014 virt 0000000000179014 libapp.so
#16 abs 0000000000178f54 virt 0000000000178f54 libapp.so
#17 abs 0000000000178a40 virt 0000000000178a40 libapp.so
#18 abs 000000000028dadc virt 000000000028dadc libapp.so
#19 abs 000000000025bd20 virt 000000000025bd20 libapp.so
#20 abs 00000000000dffc4 virt 00000000000dffc4 libapp.so
#21 abs 00000000000ec878 virt 00000000000ec878 libapp.so
#22 abs 00000000000ec808 virt 00000000000ec808 libapp.so
#23 abs 00000000000ed5d4 virt 00000000000ed5d4 libapp.so
#24 abs 00000000000dca20 virt 00000000000dca20 libapp.so
2. Run the Symbolization Command
flutter symbolize -i input.txt -d app.ohos-arm64.symbols -o symbols.txt
3. View the Symbolization Result
The content of symbols.txt is as follows:
#0 _MyHomePageState._dartFreeze (D:/Flutter/demo/flutter_dfx_sample/lib/main.dart:44:5)
#1 _MyHomePageState._dartFreeze (D:/Flutter/demo/flutter_dfx_sample/lib/main.dart:41:3)
#2 _InkResponseState.handleTap (D:/Flutter/flutter_flutter/packages/flutter/lib/src/material/ink_well.dart:1195:3)
#3 GestureRecognizer.invokeCallback (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/recognizer.dart:345:24)
#4 TapGestureRecognizer.handleTapUp (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/tap.dart:737:11)
#5 BaseTapGestureRecognizer._checkUp (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/tap.dart:362:5)
#6 BaseTapGestureRecognizer.handlePrimaryPointer (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/tap.dart:293:7)
#7 PrimaryPointerGestureRecognizer.handleEvent (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/recognizer.dart:706:9)
#8 PrimaryPointerGestureRecognizer.handleEvent (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/recognizer.dart:688:3)
#9 PointerRouter._dispatch (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/pointer_router.dart:97:12)
#10 PointerRouter._dispatchEventToRoutes.<anonymous closure> (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/pointer_router.dart:143:9)
#11 _LinkedHashMapMixin.forEach (third_party/dart/sdk/lib/_internal/vm_shared/lib/compact_hash.dart:764:13)
#12 PointerRouter._dispatchEventToRoutes (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/pointer_router.dart:141:18)
#13 PointerRouter.route (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/pointer_router.dart:131:7)
#14 GestureBinding.handleEvent (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:530:19)
#15 GestureBinding.dispatchEvent (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:499:22)
#16 RendererBinding.dispatchEvent (D:/Flutter/flutter/rendering/binding.dart:473:11)
#17 GestureBinding._handlePointerEventImmediately (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:437:7)
#18 GestureBinding.handlePointerEvent (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:394:5)
#19 GestureBinding._flushPointerEventQueue (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:341:7)
#20 GestureBinding._handlePointerDataPacket (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:308:9)
#21 GestureBinding._handlePointerDataPacket (D:/Flutter/flutter_flutter/packages/flutter/lib/src/gestures/binding.dart:300:3)
#22 _invoke1 (lib/ui/hooks.dart:347:13)
#23 PlatformDispatcher._dispatchPointerDataPacket (lib/ui/platform_dispatcher.dart:467:7)
#24 _dispatchPointerDataPacket (lib/ui/hooks.dart:282:31)
#25 _dispatchPointerDataPacket (lib/ui/hooks.dart:280:1)
#26 stub InvokeDartCode+0xd4
After symbolization, you can clearly see:
- The crash occurred in the
_MyHomePageState._dartFreezemethod inmain.dart - Specific line numbers: line 41 and line 44
- The complete call chain: from the Dart layer to the Flutter framework and then to the native layer
Impact of the split-debug-info Parameter
Size Reduction
With the --split-debug-info parameter, the symbol information is separated from app.so, slightly reducing the application size.
DevTools Cannot Connect
DevTools relies on the symbol file for debugging. Adding this parameter will cause DevTools to be unable to connect to the application. It is recommended to use it in Release mode.
No Performance Impact
Tests show that enabling or disabling this parameter has no significant impact on UI and Raster performance.
Related Links
- Flutter official documentation: https://docs.flutter.dev/reference/flutter-cli