Convert JavaScript uncaught exception stack traces to Dart stacks (#1603)
* Convert JavaScript uncaught exception stack traces to Dart stacks
Fixes https://github.com/dart-lang/webdev/issues/1265
Fixes https://github.com/flutter/flutter/issues/101888
* Built
diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md
index 3fe3115..f5a9ad6 100644
--- a/dwds/CHANGELOG.md
+++ b/dwds/CHANGELOG.md
@@ -1,6 +1,7 @@
## 14.0.3-dev
- Make data types null safe
- Update `package:vm_service` to 8.3.0.
+- Convert JavaScript stack traces in uncaught exceptions to Dart stack traces.
## 14.0.2
- Update the min SDK constraint to 2.17.0.
diff --git a/dwds/lib/src/debugging/debugger.dart b/dwds/lib/src/debugging/debugger.dart
index b761879..dd9e024 100644
--- a/dwds/lib/src/debugging/debugger.dart
+++ b/dwds/lib/src/debugging/debugger.dart
@@ -558,8 +558,10 @@
if (isNativeJsObject(exception)) {
if (obj.description != null) {
// Create a string exception object.
- exception = await inspector.instanceHelper
- .instanceRefFor(obj.description);
+ var description =
+ await inspector.mapExceptionStackTrace(obj.description);
+ exception =
+ await inspector.instanceHelper.instanceRefFor(description);
} else {
exception = null;
}
diff --git a/dwds/lib/src/debugging/inspector.dart b/dwds/lib/src/debugging/inspector.dart
index 44e2b89..24d1972 100644
--- a/dwds/lib/src/debugging/inspector.dart
+++ b/dwds/lib/src/debugging/inspector.dart
@@ -67,6 +67,12 @@
final String _root;
final SdkConfiguration _sdkConfiguration;
+ /// JavaScript expression that evaluates to the Dart stack trace mapper.
+ static const stackTraceMapperExpression = '\$dartStackTraceUtility.mapper';
+
+ /// Regex used to extract the message from an exception description.
+ static final exceptionMessageRegex = RegExp(r'^.*$', multiLine: true);
+
AppInspector._(
this.appConnection,
this.isolate,
@@ -223,7 +229,7 @@
/// [evalExpression] should be a JS function definition that can accept
/// [arguments].
Future<RemoteObject> _jsCallFunction(
- String evalExpression, List<RemoteObject> arguments,
+ String evalExpression, List<Object> arguments,
{bool returnByValue = false}) async {
var jsArguments = arguments.map(callArgumentFor).toList();
var result =
@@ -550,4 +556,23 @@
handleErrorIfPresent(extensionsResult, evalContents: expression);
return List.from(extensionsResult.result['result']['value'] as List);
}
+
+ /// Convert a JS exception description into a description containing
+ /// a Dart stack trace.
+ Future<String> mapExceptionStackTrace(String description) async {
+ RemoteObject mapperResult;
+ try {
+ mapperResult = await _jsCallFunction(
+ stackTraceMapperExpression, <Object>[description]);
+ } catch (_) {
+ return description;
+ }
+ var mappedStack = mapperResult?.value?.toString();
+ if (mappedStack == null || mappedStack.isEmpty) {
+ return description;
+ }
+ var message = exceptionMessageRegex.firstMatch(description)?.group(0);
+ message = (message != null) ? '$message\n' : '';
+ return '$message$mappedStack';
+ }
}
diff --git a/dwds/lib/src/injected/client.js b/dwds/lib/src/injected/client.js
index 483470f..c7c3faa 100644
--- a/dwds/lib/src/injected/client.js
+++ b/dwds/lib/src/injected/client.js
@@ -1,4 +1,4 @@
-// Generated by dart2js (NullSafetyMode.unsound, csp), the Dart to JavaScript compiler version: 2.18.0-106.0.dev.
+// Generated by dart2js (NullSafetyMode.unsound, csp), the Dart to JavaScript compiler version: 2.18.0-109.0.dev.
// The code supports the following hooks:
// dartPrint(message):
// if this function is defined it is called instead of the Dart [print]
@@ -4244,30 +4244,6 @@
this.$function = t1;
this.$ti = t2;
},
- _RunNullaryZoneFunction: function _RunNullaryZoneFunction(t0, t1) {
- this.zone = t0;
- this.$function = t1;
- },
- _RunUnaryZoneFunction: function _RunUnaryZoneFunction(t0, t1) {
- this.zone = t0;
- this.$function = t1;
- },
- _RunBinaryZoneFunction: function _RunBinaryZoneFunction(t0, t1) {
- this.zone = t0;
- this.$function = t1;
- },
- _RegisterNullaryZoneFunction: function _RegisterNullaryZoneFunction(t0, t1) {
- this.zone = t0;
- this.$function = t1;
- },
- _RegisterUnaryZoneFunction: function _RegisterUnaryZoneFunction(t0, t1) {
- this.zone = t0;
- this.$function = t1;
- },
- _RegisterBinaryZoneFunction: function _RegisterBinaryZoneFunction(t0, t1) {
- this.zone = t0;
- this.$function = t1;
- },
_ZoneSpecification: function _ZoneSpecification(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) {
var _ = this;
_.handleUncaughtError = t0;
@@ -12856,12 +12832,6 @@
}
};
A._ZoneFunction.prototype = {};
- A._RunNullaryZoneFunction.prototype = {};
- A._RunUnaryZoneFunction.prototype = {};
- A._RunBinaryZoneFunction.prototype = {};
- A._RegisterNullaryZoneFunction.prototype = {};
- A._RegisterUnaryZoneFunction.prototype = {};
- A._RegisterBinaryZoneFunction.prototype = {};
A._ZoneSpecification.prototype = {$isZoneSpecification: 1};
A._ZoneDelegate.prototype = {$isZoneDelegate: 1};
A._Zone.prototype = {
@@ -13127,22 +13097,22 @@
};
A._RootZone.prototype = {
get$_run() {
- return B._RunNullaryZoneFunction__RootZone__rootRun;
+ return B._ZoneFunction__RootZone__rootRun;
},
get$_runUnary() {
- return B._RunUnaryZoneFunction__RootZone__rootRunUnary;
+ return B._ZoneFunction__RootZone__rootRunUnary;
},
get$_runBinary() {
- return B._RunBinaryZoneFunction__RootZone__rootRunBinary;
+ return B._ZoneFunction__RootZone__rootRunBinary;
},
get$_registerCallback() {
- return B._RegisterNullaryZoneFunction__RootZone__rootRegisterCallback;
+ return B._ZoneFunction__RootZone__rootRegisterCallback;
},
get$_registerUnaryCallback() {
- return B._RegisterUnaryZoneFunction_Bqo;
+ return B._ZoneFunction_Eeh;
},
get$_registerBinaryCallback() {
- return B._RegisterBinaryZoneFunction_kGu;
+ return B._ZoneFunction_7G2;
},
get$_errorCallback() {
return B._ZoneFunction__RootZone__rootErrorCallback;
@@ -25394,7 +25364,7 @@
_inherit = hunkHelpers.inherit,
_inheritMany = hunkHelpers.inheritMany;
_inherit(A.Object, null);
- _inheritMany(A.Object, [A.JS_CONST, J.Interceptor, J.ArrayIterator, A.Iterable, A.CastIterator, A.Closure, A.MapMixin, A.Error, A.SentinelValue, A.ListIterator, A.Iterator, A.EmptyIterator, A.FixedLengthListMixin, A.UnmodifiableListMixin, A._ListBase_Object_ListMixin, A.Symbol, A.MapView, A.ConstantMap, A.JSInvocationMirror, A.TypeErrorDecoder, A.NullThrownFromJavaScriptException, A.ExceptionAndStackTrace, A._StackTrace, A._Required, A.LinkedHashMapCell, A.LinkedHashMapKeyIterator, A.JSSyntaxRegExp, A._MatchImplementation, A._AllMatchesIterator, A.StringMatch, A._StringAllMatchesIterator, A._Cell, A.Rti, A._FunctionParameters, A._Type, A._TimerImpl, A._AsyncAwaitCompleter, A.AsyncError, A._Completer, A._FutureListener, A._Future, A._AsyncCallbackEntry, A.Stream, A.StreamSubscription, A.StreamTransformerBase, A._StreamController, A._SyncStreamControllerDispatch, A._AsyncStreamControllerDispatch, A._BufferingStreamSubscription, A._StreamSinkWrapper, A._DelayedEvent, A._DelayedDone, A._PendingEvents, A._StreamIterator, A._ZoneFunction, A._RunNullaryZoneFunction, A._RunUnaryZoneFunction, A._RunBinaryZoneFunction, A._RegisterNullaryZoneFunction, A._RegisterUnaryZoneFunction, A._RegisterBinaryZoneFunction, A._ZoneSpecification, A._ZoneDelegate, A._Zone, A._HashMapKeyIterator, A.__SetBase_Object_SetMixin, A._HashSetIterator, A._LinkedHashSetCell, A._LinkedHashSetIterator, A.IterableMixin, A.ListMixin, A._UnmodifiableMapMixin, A._ListQueueIterator, A.SetMixin, A._SplayTreeNode, A._SplayTree, A._SplayTreeIterator, A.Codec, A._JsonStringifier, A._Utf8Encoder, A._BigIntImpl, A.DateTime, A.Duration, A.OutOfMemoryError, A.StackOverflowError, A._Exception, A.FormatException, A.IntegerDivisionByZeroException, A.Null, A._StringStackTrace, A.StringBuffer, A._Uri, A.UriData, A._SimpleUri, A.Expando, A.CssStyleDeclarationBase, A.EventStreamProvider, A._Html5NodeValidator, A.ImmutableListMixin, A.NodeValidatorBuilder, A._SimpleNodeValidator, A._SvgNodeValidator, A.FixedSizeListIterator, A._DOMWindowCrossFrame, A._SameOriginUriPolicy, A._ValidatingTreeSanitizer, A._StructuredClone, A._AcceptStructuredClone, A.JsObject, A.NullRejectionException, A._JSRandom, A._Random, A.AsyncMemoizer, A.DelegatingStreamSink, A.ErrorResult, A.ValueResult, A.StreamQueue, A._NextRequest, A._HasNextRequest, A.CopyOnWriteList, A.BuiltList, A.ListBuilder, A.BuiltListMultimap, A.ListMultimapBuilder, A.BuiltMap, A.MapBuilder, A.BuiltSet, A.SetBuilder, A.BuiltSetMultimap, A.SetMultimapBuilder, A.EnumClass, A.IndentingBuiltValueToStringHelper, A.JsonObject, A.FullType, A.BigIntSerializer, A.BoolSerializer, A.BuiltJsonSerializers, A.BuiltJsonSerializersBuilder, A.BuiltListMultimapSerializer, A.BuiltListSerializer, A.BuiltMapSerializer, A.BuiltSetMultimapSerializer, A.BuiltSetSerializer, A.DateTimeSerializer, A.DoubleSerializer, A.DurationSerializer, A.Int64Serializer, A.IntSerializer, A.JsonObjectSerializer, A.NullSerializer, A.NumSerializer, A.RegExpSerializer, A.StringSerializer, A.UriSerializer, A.DefaultEquality, A.IterableEquality, A.ListEquality, A._UnorderedEquality, A._MapEntry, A.MapEquality, A.DeepCollectionEquality, A._QueueList_Object_ListMixin, A.BuildResult, A._$BuildStatusSerializer, A._$BuildResultSerializer, A.BuildResultBuilder, A.ConnectRequest, A._$ConnectRequestSerializer, A.ConnectRequestBuilder, A.DebugEvent, A.BatchedDebugEvents, A._$DebugEventSerializer, A._$BatchedDebugEventsSerializer, A.DebugEventBuilder, A.BatchedDebugEventsBuilder, A.DevToolsRequest, A.DevToolsResponse, A._$DevToolsRequestSerializer, A._$DevToolsResponseSerializer, A.DevToolsRequestBuilder, A.DevToolsResponseBuilder, A.ErrorResponse, A._$ErrorResponseSerializer, A.ErrorResponseBuilder, A.ExtensionRequest, A.ExtensionResponse, A.ExtensionEvent, A.BatchedEvents, A._$ExtensionRequestSerializer, A._$ExtensionResponseSerializer, A._$ExtensionEventSerializer, A._$BatchedEventsSerializer, A.ExtensionRequestBuilder, A.ExtensionResponseBuilder, A.ExtensionEventBuilder, A.BatchedEventsBuilder, A.IsolateExit, A.IsolateStart, A._$IsolateExitSerializer, A._$IsolateStartSerializer, A.IsolateExitBuilder, A.IsolateStartBuilder, A.RegisterEvent, A._$RegisterEventSerializer, A.RegisterEventBuilder, A.RunRequest, A._$RunRequestSerializer, A.SocketClient, A.Int64, A.Level, A.LogRecord, A.Logger, A.Pool, A.PoolResource, A.StreamChannelMixin, A._GuaranteeSink, A.StreamChannelController, A.Uuid, A.WebSocketChannelException, A.BatchedStreamController, A.LegacyRestarter, A.ReloadingManager, A.HotReloadFailedException, A.RequireRestarter]);
+ _inheritMany(A.Object, [A.JS_CONST, J.Interceptor, J.ArrayIterator, A.Iterable, A.CastIterator, A.Closure, A.MapMixin, A.Error, A.SentinelValue, A.ListIterator, A.Iterator, A.EmptyIterator, A.FixedLengthListMixin, A.UnmodifiableListMixin, A._ListBase_Object_ListMixin, A.Symbol, A.MapView, A.ConstantMap, A.JSInvocationMirror, A.TypeErrorDecoder, A.NullThrownFromJavaScriptException, A.ExceptionAndStackTrace, A._StackTrace, A._Required, A.LinkedHashMapCell, A.LinkedHashMapKeyIterator, A.JSSyntaxRegExp, A._MatchImplementation, A._AllMatchesIterator, A.StringMatch, A._StringAllMatchesIterator, A._Cell, A.Rti, A._FunctionParameters, A._Type, A._TimerImpl, A._AsyncAwaitCompleter, A.AsyncError, A._Completer, A._FutureListener, A._Future, A._AsyncCallbackEntry, A.Stream, A.StreamSubscription, A.StreamTransformerBase, A._StreamController, A._SyncStreamControllerDispatch, A._AsyncStreamControllerDispatch, A._BufferingStreamSubscription, A._StreamSinkWrapper, A._DelayedEvent, A._DelayedDone, A._PendingEvents, A._StreamIterator, A._ZoneFunction, A._ZoneSpecification, A._ZoneDelegate, A._Zone, A._HashMapKeyIterator, A.__SetBase_Object_SetMixin, A._HashSetIterator, A._LinkedHashSetCell, A._LinkedHashSetIterator, A.IterableMixin, A.ListMixin, A._UnmodifiableMapMixin, A._ListQueueIterator, A.SetMixin, A._SplayTreeNode, A._SplayTree, A._SplayTreeIterator, A.Codec, A._JsonStringifier, A._Utf8Encoder, A._BigIntImpl, A.DateTime, A.Duration, A.OutOfMemoryError, A.StackOverflowError, A._Exception, A.FormatException, A.IntegerDivisionByZeroException, A.Null, A._StringStackTrace, A.StringBuffer, A._Uri, A.UriData, A._SimpleUri, A.Expando, A.CssStyleDeclarationBase, A.EventStreamProvider, A._Html5NodeValidator, A.ImmutableListMixin, A.NodeValidatorBuilder, A._SimpleNodeValidator, A._SvgNodeValidator, A.FixedSizeListIterator, A._DOMWindowCrossFrame, A._SameOriginUriPolicy, A._ValidatingTreeSanitizer, A._StructuredClone, A._AcceptStructuredClone, A.JsObject, A.NullRejectionException, A._JSRandom, A._Random, A.AsyncMemoizer, A.DelegatingStreamSink, A.ErrorResult, A.ValueResult, A.StreamQueue, A._NextRequest, A._HasNextRequest, A.CopyOnWriteList, A.BuiltList, A.ListBuilder, A.BuiltListMultimap, A.ListMultimapBuilder, A.BuiltMap, A.MapBuilder, A.BuiltSet, A.SetBuilder, A.BuiltSetMultimap, A.SetMultimapBuilder, A.EnumClass, A.IndentingBuiltValueToStringHelper, A.JsonObject, A.FullType, A.BigIntSerializer, A.BoolSerializer, A.BuiltJsonSerializers, A.BuiltJsonSerializersBuilder, A.BuiltListMultimapSerializer, A.BuiltListSerializer, A.BuiltMapSerializer, A.BuiltSetMultimapSerializer, A.BuiltSetSerializer, A.DateTimeSerializer, A.DoubleSerializer, A.DurationSerializer, A.Int64Serializer, A.IntSerializer, A.JsonObjectSerializer, A.NullSerializer, A.NumSerializer, A.RegExpSerializer, A.StringSerializer, A.UriSerializer, A.DefaultEquality, A.IterableEquality, A.ListEquality, A._UnorderedEquality, A._MapEntry, A.MapEquality, A.DeepCollectionEquality, A._QueueList_Object_ListMixin, A.BuildResult, A._$BuildStatusSerializer, A._$BuildResultSerializer, A.BuildResultBuilder, A.ConnectRequest, A._$ConnectRequestSerializer, A.ConnectRequestBuilder, A.DebugEvent, A.BatchedDebugEvents, A._$DebugEventSerializer, A._$BatchedDebugEventsSerializer, A.DebugEventBuilder, A.BatchedDebugEventsBuilder, A.DevToolsRequest, A.DevToolsResponse, A._$DevToolsRequestSerializer, A._$DevToolsResponseSerializer, A.DevToolsRequestBuilder, A.DevToolsResponseBuilder, A.ErrorResponse, A._$ErrorResponseSerializer, A.ErrorResponseBuilder, A.ExtensionRequest, A.ExtensionResponse, A.ExtensionEvent, A.BatchedEvents, A._$ExtensionRequestSerializer, A._$ExtensionResponseSerializer, A._$ExtensionEventSerializer, A._$BatchedEventsSerializer, A.ExtensionRequestBuilder, A.ExtensionResponseBuilder, A.ExtensionEventBuilder, A.BatchedEventsBuilder, A.IsolateExit, A.IsolateStart, A._$IsolateExitSerializer, A._$IsolateStartSerializer, A.IsolateExitBuilder, A.IsolateStartBuilder, A.RegisterEvent, A._$RegisterEventSerializer, A.RegisterEventBuilder, A.RunRequest, A._$RunRequestSerializer, A.SocketClient, A.Int64, A.Level, A.LogRecord, A.Logger, A.Pool, A.PoolResource, A.StreamChannelMixin, A._GuaranteeSink, A.StreamChannelController, A.Uuid, A.WebSocketChannelException, A.BatchedStreamController, A.LegacyRestarter, A.ReloadingManager, A.HotReloadFailedException, A.RequireRestarter]);
_inheritMany(J.Interceptor, [J.JSBool, J.JSNull, J.JavaScriptObject, J.JSArray, J.JSNumber, J.JSString, A.NativeByteBuffer, A.NativeTypedData]);
_inheritMany(J.JavaScriptObject, [J.LegacyJavaScriptObject, A.EventTarget, A.AccessibleNodeList, A.Blob, A.Event, A.CssTransformComponent, A.CssRule, A._CssStyleDeclaration_JavaScriptObject_CssStyleDeclarationBase, A.CssStyleValue, A.DataTransferItemList, A.DomException, A.DomImplementation, A._DomRectList_JavaScriptObject_ListMixin, A.DomRectReadOnly, A._DomStringList_JavaScriptObject_ListMixin, A.DomTokenList, A._FileList_JavaScriptObject_ListMixin, A.Gamepad, A.History, A._HtmlCollection_JavaScriptObject_ListMixin, A.ImageData, A.Location, A.MediaList, A._MidiInputMap_JavaScriptObject_MapMixin, A._MidiOutputMap_JavaScriptObject_MapMixin, A.MimeType, A._MimeTypeArray_JavaScriptObject_ListMixin, A._NodeList_JavaScriptObject_ListMixin, A.Plugin, A._PluginArray_JavaScriptObject_ListMixin, A._RtcStatsReport_JavaScriptObject_MapMixin, A.SpeechGrammar, A._SpeechGrammarList_JavaScriptObject_ListMixin, A.SpeechRecognitionResult, A._Storage_JavaScriptObject_MapMixin, A.StyleSheet, A._TextTrackCueList_JavaScriptObject_ListMixin, A.TimeRanges, A.Touch, A._TouchList_JavaScriptObject_ListMixin, A.TrackDefaultList, A.Url, A.__CssRuleList_JavaScriptObject_ListMixin, A.__GamepadList_JavaScriptObject_ListMixin, A.__NamedNodeMap_JavaScriptObject_ListMixin, A.__SpeechRecognitionResultList_JavaScriptObject_ListMixin, A.__StyleSheetList_JavaScriptObject_ListMixin, A.KeyRange, A.Length, A._LengthList_JavaScriptObject_ListMixin, A.Number, A._NumberList_JavaScriptObject_ListMixin, A.PointList, A._StringList_JavaScriptObject_ListMixin, A.Transform, A._TransformList_JavaScriptObject_ListMixin, A.AudioBuffer, A._AudioParamMap_JavaScriptObject_MapMixin]);
_inheritMany(J.LegacyJavaScriptObject, [J.PlainJavaScriptObject, J.UnknownJavaScriptObject, J.JavaScriptFunction, A.Promise, A.RequireLoader, A.JsError, A.JsMap]);
@@ -26190,19 +26160,19 @@
B.Type_Uri_EFX = A.typeLiteral("Uri");
B.Type_double_K1J = A.typeLiteral("double");
B.Type_num_cv7 = A.typeLiteral("num");
- B._RegisterBinaryZoneFunction_kGu = new A._RegisterBinaryZoneFunction(B.C__RootZone, A.async___rootRegisterBinaryCallback$closure());
- B._RegisterNullaryZoneFunction__RootZone__rootRegisterCallback = new A._RegisterNullaryZoneFunction(B.C__RootZone, A.async___rootRegisterCallback$closure());
- B._RegisterUnaryZoneFunction_Bqo = new A._RegisterUnaryZoneFunction(B.C__RootZone, A.async___rootRegisterUnaryCallback$closure());
- B._RunBinaryZoneFunction__RootZone__rootRunBinary = new A._RunBinaryZoneFunction(B.C__RootZone, A.async___rootRunBinary$closure());
- B._RunNullaryZoneFunction__RootZone__rootRun = new A._RunNullaryZoneFunction(B.C__RootZone, A.async___rootRun$closure());
- B._RunUnaryZoneFunction__RootZone__rootRunUnary = new A._RunUnaryZoneFunction(B.C__RootZone, A.async___rootRunUnary$closure());
B._StringStackTrace_3uE = new A._StringStackTrace("");
B._ZoneFunction_3bB = new A._ZoneFunction(B.C__RootZone, A.async___rootCreatePeriodicTimer$closure(), A.findType("_ZoneFunction<Timer*(Zone*,ZoneDelegate*,Zone*,Duration*,~(Timer*)*)*>"));
+ B._ZoneFunction_7G2 = new A._ZoneFunction(B.C__RootZone, A.async___rootRegisterBinaryCallback$closure(), A.findType("_ZoneFunction<0^*(1^*,2^*)*(Zone*,ZoneDelegate*,Zone*,0^*(1^*,2^*)*)<Object?Object?Object?>*>"));
+ B._ZoneFunction_Eeh = new A._ZoneFunction(B.C__RootZone, A.async___rootRegisterUnaryCallback$closure(), A.findType("_ZoneFunction<0^*(1^*)*(Zone*,ZoneDelegate*,Zone*,0^*(1^*)*)<Object?Object?>*>"));
B._ZoneFunction_NMc = new A._ZoneFunction(B.C__RootZone, A.async___rootHandleUncaughtError$closure(), A.findType("_ZoneFunction<~(Zone*,ZoneDelegate*,Zone*,Object*,StackTrace*)*>"));
B._ZoneFunction__RootZone__rootCreateTimer = new A._ZoneFunction(B.C__RootZone, A.async___rootCreateTimer$closure(), A.findType("_ZoneFunction<Timer*(Zone*,ZoneDelegate*,Zone*,Duration*,~()*)*>"));
B._ZoneFunction__RootZone__rootErrorCallback = new A._ZoneFunction(B.C__RootZone, A.async___rootErrorCallback$closure(), A.findType("_ZoneFunction<AsyncError?(Zone*,ZoneDelegate*,Zone*,Object*,StackTrace?)*>"));
B._ZoneFunction__RootZone__rootFork = new A._ZoneFunction(B.C__RootZone, A.async___rootFork$closure(), A.findType("_ZoneFunction<Zone*(Zone*,ZoneDelegate*,Zone*,ZoneSpecification?,Map<Object?,Object?>?)*>"));
B._ZoneFunction__RootZone__rootPrint = new A._ZoneFunction(B.C__RootZone, A.async___rootPrint$closure(), A.findType("_ZoneFunction<~(Zone*,ZoneDelegate*,Zone*,String*)*>"));
+ B._ZoneFunction__RootZone__rootRegisterCallback = new A._ZoneFunction(B.C__RootZone, A.async___rootRegisterCallback$closure(), A.findType("_ZoneFunction<0^*()*(Zone*,ZoneDelegate*,Zone*,0^*()*)<Object?>*>"));
+ B._ZoneFunction__RootZone__rootRun = new A._ZoneFunction(B.C__RootZone, A.async___rootRun$closure(), A.findType("_ZoneFunction<0^*(Zone*,ZoneDelegate*,Zone*,0^*()*)<Object?>*>"));
+ B._ZoneFunction__RootZone__rootRunBinary = new A._ZoneFunction(B.C__RootZone, A.async___rootRunBinary$closure(), A.findType("_ZoneFunction<0^*(Zone*,ZoneDelegate*,Zone*,0^*(1^*,2^*)*,1^*,2^*)<Object?Object?Object?>*>"));
+ B._ZoneFunction__RootZone__rootRunUnary = new A._ZoneFunction(B.C__RootZone, A.async___rootRunUnary$closure(), A.findType("_ZoneFunction<0^*(Zone*,ZoneDelegate*,Zone*,0^*(1^*)*,1^*)<Object?Object?>*>"));
B._ZoneFunction__RootZone__rootScheduleMicrotask = new A._ZoneFunction(B.C__RootZone, A.async___rootScheduleMicrotask$closure(), A.findType("_ZoneFunction<~(Zone*,ZoneDelegate*,Zone*,~()*)*>"));
B._ZoneSpecification_ALf = new A._ZoneSpecification(null, null, null, null, null, null, null, null, null, null, null, null, null);
})();
diff --git a/dwds/lib/src/services/chrome_proxy_service.dart b/dwds/lib/src/services/chrome_proxy_service.dart
index 3b396ba..196419e 100644
--- a/dwds/lib/src/services/chrome_proxy_service.dart
+++ b/dwds/lib/src/services/chrome_proxy_service.dart
@@ -842,15 +842,19 @@
..timestamp = e.timestamp.toInt());
});
if (includeExceptions) {
- exceptionsSubscription = remoteDebugger.onExceptionThrown.listen((e) {
+ exceptionsSubscription =
+ remoteDebugger.onExceptionThrown.listen((e) async {
var isolate = _inspector?.isolate;
if (isolate == null) return;
+ var description = e.exceptionDetails.exception.description;
+ if (description != null) {
+ description = await _inspector.mapExceptionStackTrace(description);
+ }
controller.add(Event(
kind: EventKind.kWriteEvent,
timestamp: DateTime.now().millisecondsSinceEpoch,
isolate: _inspector.isolateRef)
- ..bytes = base64.encode(
- utf8.encode(e.exceptionDetails.exception.description ?? '')));
+ ..bytes = base64.encode(utf8.encode(description ?? '')));
});
}
});
diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart
index 46bebc6..92fe072 100644
--- a/dwds/test/chrome_proxy_service_test.dart
+++ b/dwds/test/chrome_proxy_service_test.dart
@@ -1129,6 +1129,8 @@
var event = await stream
.firstWhere((event) => event.kind == EventKind.kPauseException);
expect(event.exception, isNotNull);
+ // Check that the exception stack trace has been mapped to Dart source files.
+ expect(event.exception.valueAsString, contains('main.dart'));
var stack = await service.getStack(isolateId);
expect(stack, isNotNull);
@@ -1660,6 +1662,18 @@
await tabConnection.runtime.evaluate('console.error("Error");');
});
+ test('exception stack trace mapper', () async {
+ expect(service.streamListen('Stderr'), completion(_isSuccess));
+ var stderrStream = service.onEvent('Stderr');
+ expect(
+ stderrStream,
+ emitsThrough(predicate((Event event) =>
+ event.kind == EventKind.kWriteEvent &&
+ String.fromCharCodes(base64.decode(event.bytes))
+ .contains('main.dart'))));
+ await tabConnection.runtime.evaluate('throwUncaughtException();');
+ });
+
test('VM', () async {
var status = await service.streamListen('VM');
expect(status, _isSuccess);
diff --git a/fixtures/_test/example/hello_world/main.dart b/fixtures/_test/example/hello_world/main.dart
index da0bd5a..f36903c 100644
--- a/fixtures/_test/example/hello_world/main.dart
+++ b/fixtures/_test/example/hello_world/main.dart
@@ -55,6 +55,10 @@
log(message, name: 'testLogCategory');
};
+ context['throwUncaughtException'] = () {
+ scheduleMicrotask(() => throw Exception('UncaughtException'));
+ };
+
Timer.periodic(const Duration(seconds: 1), (_) {
printCount(); // Breakpoint: callPrintCount
});
diff --git a/fixtures/_testSound/example/hello_world/main.dart b/fixtures/_testSound/example/hello_world/main.dart
index 6618118..d21af3f 100644
--- a/fixtures/_testSound/example/hello_world/main.dart
+++ b/fixtures/_testSound/example/hello_world/main.dart
@@ -55,6 +55,10 @@
log(message, name: 'testLogCategory');
};
+ context['throwUncaughtException'] = () {
+ scheduleMicrotask(() => throw Exception('UncaughtException'));
+ };
+
Timer.periodic(const Duration(seconds: 1), (_) {
printCount(); // Breakpoint: callPrintCount
});