Closed jan-auer closed 1 year ago
/cc @sstrickl
I've added a --resolve-dwarf-paths
flag in CL 196491, submitted as 6730b12edc, that does most of this. I'm not sure how feasible it is to set DW_AT_comp_dir
appropriately, because I'm not sure if enough information is provided via the embedder interface to do so.
@sstrickl thanks, where do I pass the --resolve-dwarf-paths
parameter?
flutter build apk --split-debug-info=symbols --obfuscate --resolve-dwarf-paths
does not work.
Thanks for doing this btw (Flutter 3.0.1).
@sstrickl I've tried adding the --resolve-dwarf-paths
to the flutter tool and am getting the following errors while compiling a flutter app (for android first):
../../third_party/dart/runtime/vm/dwarf.cc: 898: error: cannot convert resolved URI org-dartlang-sdk:///third_party/dart/sdk/timeStamp/_internal/vm_shared/timeStamp/bigint_patch.dart
version=2.19.0-374.0.dev (dev) (Fri Nov 4 12:40:18 2022 -0700) on "macos_arm"
pid=42698, thread=-1, isolate_group=isolate(0x7fa964809a00), isolate=isolate(0x7fa96581ec00)
os=macos, arch=arm, comp=no, sim=no
isolate_instructions=0, vm_instructions=0
pc 0x00000001027bea25 fp 0x00000003098472c0 dart::Profiler::DumpStackTrace(void*)+0x85
pc 0x00000001026423d4 fp 0x00000003098473a0 dart::Assert::Fail(char const*, ...) const+0x84
pc 0x00000001026ebb8a fp 0x0000000309847400 std::_LIBCPP_ABI_NAMESPACE::__function::__func<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1::operator()() const::'lambda'(), std::_LIBCPP_ABI_NAMESPACE::allocator<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1::operator()() const::'lambda'()>, void ()>::operator()()+0x37a
pc 0x00000001026f42a8 fp 0x0000000309847440 dart::DwarfElfStream::WritePrefixedLength(char const*, std::_LIBCPP_ABI_NAMESPACE::function<void ()>)+0x58
pc 0x00000001026eb439 fp 0x00000003098474f0 std::_LIBCPP_ABI_NAMESPACE::__function::__func<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1, std::_LIBCPP_ABI_NAMESPACE::allocator<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1>, void ()>::operator()()+0x69
pc 0x00000001026f42a8 fp 0x0000000309847530 dart::DwarfElfStream::WritePrefixedLength(char const*, std::_LIBCPP_ABI_NAMESPACE::function<void ()>)+0x58
pc 0x00000001026e9ce0 fp 0x0000000309847590 dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)+0x50
pc 0x00000001026edc33 fp 0x0000000309847650 dart::Elf::FinalizeDwarfSections()+0x453
pc 0x00000001026eed7f fp 0x00000003098476e0 dart::Elf::Finalize()+0x3f
pc 0x0000000102ad529a fp 0x0000000309847a60 dart::CreateAppAOTSnapshot(void (*)(void*, unsigned char const*, long), void*, bool, bool, void*, dart::GrowableArray<dart::LoadingUnitSerializationData*>*, dart::LoadingUnitSerializationData*, unsigned int)+0x4ba
pc 0x0000000102ad5eec fp 0x0000000309847b40 Dart_CreateAppAOTSnapshotAsElf+0x13c
pc 0x000000010263a6ce fp 0x0000000309847cd0 dart::bin::main(int, char**)+0x10ee
pc 0x000000020315e52e fp 0x0000000309847de0 Unknown symbol
-- End of DumpStackTrace
Dart snapshot generator failed with exit code -6
../../third_party/dart/runtime/vm/dwarf.cc: 898: error: cannot convert resolved URI org-dartlang-sdk:///third_party/dart/sdk/timeStamp/internal/cast.dart
version=2.19.0-374.0.dev (dev) (Fri Nov 4 12:40:18 2022 -0700) on "macos_simarm64"
pid=42699, thread=-1, isolate_group=isolate(0x7f8c67808200), isolate=isolate(0x7f8c6780d800)
os=macos, arch=arm64, comp=yes, sim=yes
isolate_instructions=0, vm_instructions=0
pc 0x000000010477b8f5 fp 0x000000030d5d62e0 dart::Profiler::DumpStackTrace(void*)+0x85
pc 0x00000001045f03d4 fp 0x000000030d5d63c0 dart::Assert::Fail(char const*, ...) const+0x84
pc 0x000000010469e37a fp 0x000000030d5d6420 std::_LIBCPP_ABI_NAMESPACE::__function::__func<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1::operator()() const::'lambda'(), std::_LIBCPP_ABI_NAMESPACE::allocator<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1::operator()() const::'lambda'()>, void ()>::operator()()+0x39a
pc 0x00000001046a6a78 fp 0x000000030d5d6460 dart::DwarfElfStream::WritePrefixedLength(char const*, std::_LIBCPP_ABI_NAMESPACE::function<void ()>)+0x58
pc 0x000000010469dbdd fp 0x000000030d5d6520 std::_LIBCPP_ABI_NAMESPACE::__function::__func<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1, std::_LIBCPP_ABI_NAMESPACE::allocator<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1>, void ()>::operator()()+0x6d
pc 0x00000001046a6a78 fp 0x000000030d5d6560 dart::DwarfElfStream::WritePrefixedLength(char const*, std::_LIBCPP_ABI_NAMESPACE::function<void ()>)+0x58
pc 0x000000010469c430 fp 0x000000030d5d65c0 dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)+0x50
pc 0x00000001046a0423 fp 0x000000030d5d6680 dart::Elf::FinalizeDwarfSections()+0x453
pc 0x00000001046a156f fp 0x000000030d5d6710 dart::Elf::Finalize()+0x3f
pc 0x0000000104aa5baa fp 0x000000030d5d6a90 dart::CreateAppAOTSnapshot(void (*)(void*, unsigned char const*, long), void*, bool, bool, void*, dart::GrowableArray<dart::LoadingUnitSerializationData*>*, dart::LoadingUnitSerializationData*, unsigned int)+0x4ba
pc 0x0000000104aa67ac fp 0x000000030d5d6b70 Dart_CreateAppAOTSnapshotAsElf+0x13c
pc 0x00000001045e86ce fp 0x000000030d5d6d00 dart::bin::main(int, char**)+0x10ee
pc 0x0000000204f3f52e fp 0x000000030d5d6e10 Unknown symbol
-- End of DumpStackTrace
Dart snapshot generator failed with exit code -6
../../third_party/dart/runtime/vm/dwarf.cc: 898: error: cannot convert resolved URI org-dartlang-sdk:///third_party/dart/sdk/timeStamp/_internal/vm_shared/timeStamp/bigint_patch.dart
version=2.19.0-374.0.dev (dev) (Fri Nov 4 12:40:18 2022 -0700) on "macos_x64"
pid=42700, thread=-1, isolate_group=isolate(0x7fb8c6814400), isolate=isolate(0x7fb8c6820600)
os=macos, arch=x64, comp=yes, sim=no
isolate_instructions=0, vm_instructions=0
pc 0x0000000100730825 fp 0x00000003058732f0 dart::Profiler::DumpStackTrace(void*)+0x85
pc 0x00000001005a53d4 fp 0x00000003058733d0 dart::Assert::Fail(char const*, ...) const+0x84
pc 0x000000010065384a fp 0x0000000305873430 std::_LIBCPP_ABI_NAMESPACE::__function::__func<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1::operator()() const::'lambda'(), std::_LIBCPP_ABI_NAMESPACE::allocator<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1::operator()() const::'lambda'()>, void ()>::operator()()+0x39a
pc 0x000000010065bf28 fp 0x0000000305873470 dart::DwarfElfStream::WritePrefixedLength(char const*, std::_LIBCPP_ABI_NAMESPACE::function<void ()>)+0x58
pc 0x00000001006530ad fp 0x0000000305873530 std::_LIBCPP_ABI_NAMESPACE::__function::__func<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1, std::_LIBCPP_ABI_NAMESPACE::allocator<dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)::$_1>, void ()>::operator()()+0x6d
pc 0x000000010065bf28 fp 0x0000000305873570 dart::DwarfElfStream::WritePrefixedLength(char const*, std::_LIBCPP_ABI_NAMESPACE::function<void ()>)+0x58
pc 0x0000000100651900 fp 0x00000003058735d0 dart::Dwarf::WriteLineNumberProgram(dart::DwarfWriteStream*)+0x50
pc 0x00000001006558d3 fp 0x0000000305873690 dart::Elf::FinalizeDwarfSections()+0x453
pc 0x0000000100656a1f fp 0x0000000305873720 dart::Elf::Finalize()+0x3f
The issue is, AFAIK that these prefixes are different when specified in dwarf.cc in the Dart SDK but when integrated in Flutter, they're at a different path as seen here:
// 'dart:ui' maps to /flutter/lib/ui
final String flutterRoot = fileSystem.path.join(flutterSdkRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui');
orgDartlangSdkMappings[flutterRoot] = Uri.parse('org-dartlang-sdk:///flutter/lib/ui');
// The rest of the Dart SDK maps to /third_party/dart/sdk
final String dartRoot = fileSystem.path.join(flutterSdkRoot, 'bin', 'cache', 'pkg', 'sky_engine');
orgDartlangSdkMappings[dartRoot] = Uri.parse('org-dartlang-sdk:///third_party/dart/sdk');
What do you think would be the best way to get this working?
If we'd be looking for the above 'org-dartlang-sdk:///...'
prefixes in the resolved URIs, that's not too bad, we'd just need to change ConvertResolvedURI
in runtime/vm/dwarf.cc
to strip off the prefixes appropriately. (That is, it'll then be a relative path, and then you'll just need your source paths approrpiately set in your debugger of choice.)
In fact, an easier fix is probably to just literally strip off the 'org-dartlang-sdk:///'
prefix of any path that has it, since the only path where that function does so now ('org-dartlang-sdk:///sdk/...'
) just strips off that prefix and leaves 'sdk/...'
. So in your case, you'd just end up with 'third_party/dart/sdk/...'
and 'flutter/lib/ui/...'
. I think I just didn't want to liberally strip that prefix off before, but now I think it'll probably just be the right thing to do.
Ah, but wait, I suppose we'd need to strip 'org-dartlang-sdk:///flutter/'
as a prefix for the 'dart:ui'
case above, so it'll still need a special case where we strip 'org-dartlang-sdk:///flutter/'
completely first if that's found, and if not, then we strip off the 'org-dartlang-sdk:///'
prefix instead.
268762
for reference, the public link is: https://dart-review.googlesource.com/c/sdk/+/268762
Thanks, @sstrickl, great responsiveness as always!
Now that the flutter engine rolled to the SDK with your change merged, I've checked the output. Looks pretty good, see the following stack trace from flutter symbolize
(android):
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: async throws
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 32440, tid: 32479, name 1.ui
os: android arch: arm64 comp: yes sim: no
build_id: '9f14422b5cf396e95395d77ee820e784'
isolate_dso_base: 7a39aca000, vm_dso_base: 7a39aca000
isolate_instructions: 7a39bdf8c0, vm_instructions: 7a39bda000
#0 asyncThrows (/Users/ivan/dev/sentry-dart/flutter/example/lib/main.dart:412:3)
#1 MainScaffold.build.<anonymous closure> (/Users/ivan/dev/sentry-dart/flutter/example/lib/main.dart:153:38)
#2 _InkResponseState.handleTap (/Users/ivan/dev/flutter/packages/flutter/lib/src/material/ink_well.dart:1077:21)
#3 _InkResponseState.handleTap (/Users/ivan/dev/flutter/packages/flutter/lib/src/material/ink_well.dart:1069:3)
#4 GestureRecognizer.invokeCallback (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/recognizer.dart:253:24)
#5 TapGestureRecognizer.handleTapUp (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/tap.dart:627:11)
#6 BaseTapGestureRecognizer._checkUp (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/tap.dart:306:5)
#7 BaseTapGestureRecognizer.acceptGesture (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/tap.dart:276:7)
#8 GestureArenaManager.sweep (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/arena.dart:163:27)
#9 GestureBinding.handleEvent (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:464:20)
#10 GestureBinding.dispatchEvent (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:440:22)
#11 RendererBinding.dispatchEvent (/Users/ivan/dev/flutter/packages/flutter/lib/src/rendering/binding.dart:336:11)
#12 GestureBinding._handlePointerEventImmediately (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:395:7)
#13 GestureBinding.handlePointerEvent (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:357:5)
#14 GestureBinding._flushPointerEventQueue (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:314:7)
#15 GestureBinding._handlePointerDataPacket (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:295:7)
#16 GestureBinding._handlePointerDataPacket (/Users/ivan/dev/flutter/packages/flutter/lib/src/gestures/binding.dart:290:3)
#17 _invoke1 (lib/object8/hooks.dart:164:13)
#18 PlatformDispatcher._dispatchPointerDataPacket (lib/object8/platform_dispatcher.dart:361:7)
#19 _dispatchPointerDataPacket (lib/object8/hooks.dart:91:31)
1
I'm wondering about a few things though:
flutter build
was run is /Users/ivan/dev/sentry-dart/flutter/example/
, thou maybe it's different than the working-directory when gen_snapshot is launched - would that cause the paths to be absolute?/Users/ivan/dev/flutter/bin/cache/pkg/sky_engine/lib/ui/platform_dispatcher.dart
. No idea where "object8" comes fromfile:///
URLs, which only strip off the first two backslashes, since those URIs are absolute.org-dartlang-sdk:///lib/object8/...
or org-dartlang-sdk:///flutter/lib/object8/...
. In either case, though, the fact that there are additional non-filesystem components to the original resolved URI is unfortunate, and I'm wondering why.object8
and dispose
in the stacktrace above were variable names that somehow ended up in the dwarf... I've built today after grabbing latest flutter master and these changed, see the following output from dwarfdump. Notice the tlradius
, which is another variable name...
I've uploaded the built app including dSYMs: https://drive.google.com/file/d/1AL5z4X06UNip5Z6IfE3amAHv35SH5mWq/view?usp=share_link
@sstrickl do you think this issue (whatever is copying unrelated memory to the symbol path) could be in the Dart SDK or in Flutter?
@sstrickl I think the issue with paths containing nonsense components has to do with obfuscation - when I disable it, the paths are resolved correctly. The test code that should cover this functionality doesn't do so with obfuscation enabled: https://github.com/dart-lang/sdk/commit/6730b12edc9393566f5a3edee145c17c93ebf85e#diff-a1ba10025c42333799717c9da7b384e5d309691d5e5381a33f1e38a434abe1e6
BTW I've tried to dig into this and add it myself but I wasn't able to figure out how exactly to launch that specific test case, even after going through https://github.com/dart-lang/sdk/wiki/Testing 🤕
Looking into this starting today. First plan to change the vm/dart{,_2}/use_resolve_dwarf_paths_flag
tests to add test runs with the --obfuscate
flag and see if this issue is duplicated by doing so. If so, then resolving the issue will hopefully be quick.
My initial hypothesis looking at Ivan's example is that the deobfuscation code I've written in the DWARF subsystem is incorrectly substituting inside already-expanded parts of the string, e.g., in https://github.com/dart-lang/sdk/issues/44325#issuecomment-1315193581, I imagine that tlRadius
was obfuscated as lib
, and so we're replacing .../packages/flutter/lib/src/...
with .../packages/flutter/tlRadius/src/...
.
Good news, everyone, changing the test to add --obfuscate
to some runs does show the issue Ivan was seeing, so I think my hypothesis is correct and this should be a quick fix.
... though looking at the code, that's a bit confusing, as we don't do an in-place deobfuscation, so there's no reason we'd be inspecting part of the expanded string, unless we're deobfuscating a string that was already deobfuscated, or attempting to deobfuscate one that was never obfuscated. Not sure which is happening, looking into that now.
It's the latter, the compiler is attempting to deobfuscate a string that was not previously obfuscated.
Looking at the obfuscation code, we never obfuscate the resolved_url
field of a Script
, so we shouldn't be trying to deobfuscate it. That will fix the issue we're seeing here.
Going ahead and closing this now that the CL fixing the deobfuscation issue has been landed, but do reopen if you find any other issues.
I can confirm the fix works e2e in Flutter. Thanks again @sstrickl
I'm reporting this here since I've seen symbolication being discussed in this issue tracker.
DWARF debugging information generated for Android builds contains logical file paths, either prefixed by
dart:
orpackage:
, followed by the package and finally the source path. For example, this is extracted usingdwarfdump
from an example app:This way of representing files makes sense to a developer, as it clearly states where the file belongs to and how it can be located. However, it is hard for a general-purpose debugger to locate these files, as it usually has no concept of "packages".
Usually, paths like the one referred to by
DW_AT_decl_file
are relative to a location called the "compilation directory". This is the location in which the compiler was invoked, and is often also considered the "project root". It is defined on the compilation unit, which in our case looks like this:It would be great to follow DWARF conventions and allow debuggers to locate source files by emitting absolute file paths. This would allow to step through code while debugging, and crash reporting tools like Sentry could attach source code to their crash reports. A possible approach to this would be:
DW_AT_comp_dir
to the project's root folderdebug_info
anddebug_lines
relative to the compilation dir if they are in the directoryIt is still possible to retain custom paths by adding an extension to DWARF line programs after
DW_LNCT_MD5
. Please let me know if I should elaborate on this point.