[ package:vm_service ] Migrate Observatory service tests (o* - r*)

Also:
 - added some missing RPC error kinds to `RPCErrorKind`
 - started making use of `update_line_numbers.dart` to automatically fix
   line numbers in service tests. Will go back through the existing
   tests to update them to use this script in a future CL.
Change-Id: I99a443ca59429eec829e5f289c0f396562cde89b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333980
Reviewed-by: Derek Xu <derekx@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 07ada22..9d8038e 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 13.1.0-dev
+- Add the following error codes to `RPCErrorKind`:
+  - `kVmMustBePaused`
+  - `kCannotAddBreakpoint`
+  - `kIsolateMustBeRunnable`
+  - `kIsolateCannotBeResumed`
+  - `kIsolateIsReloading`
+  - `kIsolateCannotReload`
+  - `kIsolateNoReloadChangesApplied`
+  - `kInvalidTimelineRequest`
+
 ## 13.0.0
 - Add Dart IO extension methods:
   - `isSocketProfilingAvailable`
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index bb4898b..c688ad9 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -1934,15 +1934,40 @@
   /// The requested feature is disabled.
   kFeatureDisabled(code: 100, message: 'Feature is disabled'),
 
+  /// The VM must be paused when performing this operation.
+  kVmMustBePaused(code: 101, message: 'The VM must be paused'),
+
+  /// Unable to add a breakpoint at the specified line or function.
+  kCannotAddBreakpoint(
+      code: 102,
+      message: 'Unable to add breakpoint at specified line or function'),
+
   /// The stream has already been subscribed to.
   kStreamAlreadySubscribed(code: 103, message: 'Stream already subscribed'),
 
   /// The stream has not been subscribed to.
   kStreamNotSubscribed(code: 104, message: 'Stream not subscribed'),
 
+  /// Isolate must first be runnable.
+  kIsolateMustBeRunnable(code: 105, message: 'Isolate must be runnable'),
+
   /// Isolate must first be paused.
   kIsolateMustBePaused(code: 106, message: 'Isolate must be paused'),
 
+  /// The isolate could not be resumed.
+  kIsolateCannotBeResumed(
+      code: 107, message: 'The isolate could not be resumed'),
+
+  /// The isolate is currently reloading.
+  kIsolateIsReloading(code: 108, message: 'The isolate is currently reloading'),
+
+  /// The isolate could not be reloaded due to an unhandled exception.
+  kIsolateCannotReload(code: 109, message: 'The isolate could not be reloaded'),
+
+  /// The isolate reload resulted in no changes being applied.
+  kIsolateNoReloadChangesApplied(
+      code: 110, message: 'No reload changes applied'),
+
   /// The service has already been registered.
   kServiceAlreadyRegistered(code: 111, message: 'Service already registered'),
 
@@ -1953,6 +1978,12 @@
   kExpressionCompilationError(
       code: 113, message: 'Expression compilation error'),
 
+  /// The timeline related request could not be completed due to the current configuration.
+  kInvalidTimelineRequest(
+      code: 114,
+      message:
+          'Invalid timeline request for the current timeline configuration'),
+
   /// The custom stream does not exist.
   kCustomStreamDoesNotExist(code: 130, message: 'Custom stream does not exist'),
 
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 44f31c9..9b3b084 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -21,6 +21,7 @@
   markdown: any
   path: any
   pub_semver: any
+  stack_trace: any
   test_package: any
   test: any
   vm_service_protos: any
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
index fce4fce..13e75a9 100644
--- a/pkg/vm_service/test/common/service_test_common.dart
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -5,6 +5,7 @@
 library service_test_common;
 
 import 'dart:async';
+import 'dart:typed_data';
 
 import 'package:path/path.dart';
 import 'package:test/test.dart';
@@ -528,6 +529,34 @@
   }
 }
 
+Future<HeapSnapshotGraph> fetchHeapSnapshot(
+  VmService service,
+  IsolateRef isolateRef,
+) async {
+  final isolateId = isolateRef.id!;
+  final completer = Completer<void>();
+  late final StreamSubscription sub;
+  final data = <ByteData>[];
+  sub = service.onHeapSnapshotEvent.listen((event) async {
+    data.add(event.data!);
+    if (event.last == true) {
+      sub.cancel();
+      await service.streamCancel(EventStreams.kHeapSnapshot);
+      completer.complete();
+    }
+  });
+  await service.streamListen(EventStreams.kHeapSnapshot);
+  await service.requestHeapSnapshot(isolateId);
+  await completer.future;
+  return HeapSnapshotGraph.fromChunks(data);
+}
+
+IsolateTest reloadSources({bool pause = false}) {
+  return (VmService service, IsolateRef isolateRef) async {
+    await service.reloadSources(isolateRef.id!, pause: pause);
+  };
+}
+
 IsolateTest hasLocalVarInTopStackFrame(String varName) {
   return (VmService service, IsolateRef isolateRef) async {
     print("Checking we have variable '$varName' in the top frame");
diff --git a/pkg/vm_service/test/object_graph_identity_hash_test.dart b/pkg/vm_service/test/object_graph_identity_hash_test.dart
index 9ada6aa..c5ecdb1 100644
--- a/pkg/vm_service/test/object_graph_identity_hash_test.dart
+++ b/pkg/vm_service/test/object_graph_identity_hash_test.dart
@@ -1,64 +1,65 @@
-// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:collection';
-
-import 'package:test/test.dart';
 import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
 
+import 'common/service_test_common.dart';
 import 'common/test_helper.dart';
 
+@pragma('vm:entry-point') // Prevent obfuscation
 class Foo {}
 
+@pragma('vm:entry-point') // Prevent obfuscation
 class Bar {}
 
 class Container1 {
-  @pragma("vm:entry-point")
-  Foo foo = Foo();
-  @pragma("vm:entry-point")
-  Bar bar = Bar();
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final foo = Foo();
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final bar = Bar();
 }
 
 class Container2 {
   Container2(this.foo);
 
-  @pragma("vm:entry-point")
-  Foo foo;
-  @pragma("vm:entry-point")
-  Bar bar = Bar();
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final Foo foo;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final bar = Bar();
 }
 
 class Container3 {
-  @pragma("vm:entry-point")
-  int number = 42;
-  @pragma("vm:entry-point")
-  double doub = 3.14;
-  @pragma("vm:entry-point")
-  String foo = 'foobar';
-  @pragma("vm:entry-point")
-  bool bar = false;
-  @pragma("vm:entry-point")
-  late Map baz;
-  @pragma("vm:entry-point")
-  late LinkedHashMap linkedBaz;
-  @pragma("vm:entry-point")
-  late List list;
-  @pragma("vm:entry-point")
-  late List unmodifiableList;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final number = 42;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final doub = 3.14;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final foo = 'foobar';
+  @pragma('vm:entry-point') // Prevent obfuscation
+  final bar = false;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  late final Map<String, String> baz;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  late final List<int> list;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  late final List<void> unmodifiableList;
 
   Container3() {
     baz = {
       'a': 'b',
     };
-    linkedBaz = LinkedHashMap.from(baz);
     list = [1, 2, 3];
-    unmodifiableList = List.empty();
+    unmodifiableList = List<void>.empty();
   }
 }
 
+@pragma('vm:entry-point') // Prevent obfuscation
 late Container1 c1;
+@pragma('vm:entry-point') // Prevent obfuscation
 late Container2 c2;
+@pragma('vm:entry-point') // Prevent obfuscation
 late Container3 c3;
 
 void script() {
@@ -78,16 +79,19 @@
 late HeapSnapshotGraph snapshot3;
 
 final tests = <IsolateTest>[
-  (VmService service, IsolateRef isolate) async {
-    snapshot1 = await HeapSnapshotGraph.getSnapshot(service, isolate);
+  (VmService service, IsolateRef isolateRef) async {
+    snapshot1 = await fetchHeapSnapshot(service, isolateRef);
 
-    Iterable<HeapSnapshotObject> container1s = snapshot1.objects.where(
-      (HeapSnapshotObject obj) => obj.klass.name == 'Container1',
+    final container1s = snapshot1.objects.where(
+      (obj) => obj.klass.name == 'Container1',
     );
     expect(container1s.length, 1);
 
     final c1Obj = container1s.first;
 
+    c1Obj.successors.forEach((element) {
+      print(element.klass.name);
+    });
     snapshot1Foo = c1Obj.successors.firstWhere(
       (element) => element.klass.name == 'Foo',
     );
@@ -104,11 +108,10 @@
       true,
     );
   },
-  (VmService service, IsolateRef isolate) async {
-    snapshot2 = await HeapSnapshotGraph.getSnapshot(service, isolate);
-    ;
-    Iterable<HeapSnapshotObject> container2s = snapshot2.objects.where(
-      (HeapSnapshotObject obj) => obj.klass.name == 'Container2',
+  (VmService service, IsolateRef isolateRef) async {
+    snapshot2 = await fetchHeapSnapshot(service, isolateRef);
+    final container2s = snapshot2.objects.where(
+      (obj) => obj.klass.name == 'Container2',
     );
     expect(container2s.length, 1);
 
@@ -138,10 +141,10 @@
       true,
     );
   },
-  (VmService service, IsolateRef isolate) async {
-    snapshot3 = await HeapSnapshotGraph.getSnapshot(service, isolate);
-    Iterable<HeapSnapshotObject> container3s = snapshot3.objects.where(
-      (HeapSnapshotObject obj) => obj.klass.name == 'Container3',
+  (VmService service, IsolateRef isolateRef) async {
+    snapshot3 = await fetchHeapSnapshot(service, isolateRef);
+    final container3s = snapshot3.objects.where(
+      (obj) => obj.klass.name == 'Container3',
     );
     expect(container3s.length, 1);
     final c3Obj = container3s.first;
@@ -151,7 +154,7 @@
   },
 ];
 
-main([args = const <String>[]]) => runIsolateTests(
+void main([args = const <String>[]]) => runIsolateTests(
       args,
       tests,
       'object_graph_identity_hash_test.dart',
diff --git a/pkg/vm_service/test/parameters_in_scope_at_entry_test.dart b/pkg/vm_service/test/parameters_in_scope_at_entry_test.dart
new file mode 100644
index 0000000..cd90fe6
--- /dev/null
+++ b/pkg/vm_service/test/parameters_in_scope_at_entry_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--verbose_debug
+
+import 'dart:developer';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+const LINE_A = 32;
+const LINE_B = LINE_A + 1;
+const LINE_C = LINE_B + 3;
+const LINE_D = LINE_C + 1;
+
+String foo(String param) {
+  return param;
+}
+
+String Function(String) fooClosure() {
+  String theClosureFunction(String param) {
+    return param;
+  }
+
+  return theClosureFunction;
+}
+
+void testMain() {
+  debugger(); // LINE_A
+  foo('in-scope'); // LINE_B
+
+  final f = fooClosure();
+  debugger(); // LINE_C
+  f('in-scope'); // LINE_D
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  stepInto,
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.frames!, isNotEmpty);
+    final top = stack.frames!.first;
+    expect(top.function!.name, 'foo');
+    expect(top.vars!.length, equals(1));
+    final param = top.vars![0];
+    expect(param.name, 'param');
+    expect(param.value.valueAsString, 'in-scope');
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D),
+  stepInto,
+  hasStoppedAtBreakpoint,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.frames!, isNotEmpty);
+    final top = stack.frames!.first;
+    expect(top.function!.name, 'theClosureFunction');
+    expect(top.vars!.length, equals(1));
+    final param = top.vars![0];
+    expect(param.name, 'param');
+    expect(param.value.valueAsString, 'in-scope');
+  },
+  resumeIsolate,
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'parameters_in_scope_at_entry_test.dart',
+      testeeConcurrent: testMain,
+    );
diff --git a/pkg/vm_service/test/pause_idle_isolate_test.dart b/pkg/vm_service/test/pause_idle_isolate_test.dart
new file mode 100644
index 0000000..1a54b3d
--- /dev/null
+++ b/pkg/vm_service/test/pause_idle_isolate_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+import 'dart:isolate' show ReceivePort;
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 20;
+
+late final ReceivePort receivePort;
+
+void testMain() {
+  receivePort = ReceivePort();
+  debugger(); // LINE_A
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  resumeIsolate,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    // Wait for the isolate to become idle.  We detect this by querying
+    // the stack until it becomes empty.
+    int frameCount;
+    do {
+      final stack = await service.getStack(isolateId);
+      frameCount = stack.frames!.length;
+      print('Frames: $frameCount');
+      await Future.delayed(const Duration(milliseconds: 10));
+    } while (frameCount > 0);
+    print('Isolate is idle.');
+    final isolate = await service.getIsolate(isolateId);
+    expect(isolate.pauseEvent!.kind, EventKind.kResume);
+
+    // Make sure that the isolate receives an interrupt even when it is
+    // idle. (https://github.com/dart-lang/sdk/issues/24349)
+    final interruptFuture = hasPausedFor(
+      service,
+      isolate,
+      EventKind.kPauseInterrupted,
+    );
+    print('Pausing...');
+    await service.pause(isolateId);
+    await interruptFuture;
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_idle_isolate_test.dart',
+      testeeConcurrent: testMain,
+      verbose_vm: true,
+      extraArgs: ['--trace-service', '--trace-service-verbose'],
+    );
diff --git a/pkg/vm_service/test/pause_on_exception_from_slow_path_test.dart b/pkg/vm_service/test/pause_on_exception_from_slow_path_test.dart
new file mode 100644
index 0000000..26c30e4
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_exception_from_slow_path_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--deterministic --optimization-counter-threshold=1000
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+class X {
+  late String _y;
+
+  @pragma('vm:never-inline')
+  String get y => _y;
+}
+
+void testeeMain() async {
+  final x = X();
+  x._y = '';
+  for (int i = 0; i < 2000; i++) x.y;
+
+  X().y;
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_exception_from_slow_path_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: testeeMain,
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/pause_on_start_and_exit_test.dart b/pkg/vm_service/test/pause_on_start_and_exit_test.dart
new file mode 100644
index 0000000..f7faf25
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_start_and_exit_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+void testMain() {
+  print('Hello');
+}
+
+final tests = <IsolateTest>[
+  hasPausedAtStart,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    // Grab the timestamp.
+    final pausetime1 = isolate.pauseEvent!.timestamp;
+    expect(pausetime1, isNotNull);
+
+    // Reload the isolate.
+    final reloaded = await service.getIsolate(isolateId);
+    // Verify that it is the same.
+    expect(pausetime1, reloaded.pauseEvent!.timestamp);
+  },
+  resumeIsolate,
+  hasStoppedAtExit,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    // Grab the timestamp.
+    final pausetime1 = isolate.pauseEvent!.timestamp;
+    expect(pausetime1, isNotNull);
+
+    // Reload the isolate.
+    final reloaded = await service.getIsolate(isolateId);
+    // Verify that it is the same.
+    expect(pausetime1, reloaded.pauseEvent!.timestamp);
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_start_and_exit_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_start: true,
+      pause_on_exit: true,
+      verbose_vm: true,
+      extraArgs: ['--trace-service', '--trace-service-verbose'],
+    );
diff --git a/pkg/vm_service/test/pause_on_start_then_step_test.dart b/pkg/vm_service/test/pause_on_start_then_step_test.dart
new file mode 100644
index 0000000..c2aee63
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_start_then_step_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 21;
+
+void testMain() {
+  print('Hello');
+}
+
+final tests = <IsolateTest>[
+  hasPausedAtStart,
+  stepInto,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+];
+
+void main([args = const <String>[]]) /* LINE_A */ => runIsolateTests(
+      args,
+      tests,
+      'pause_on_start_then_step_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_start: true,
+      pause_on_exit: true,
+      verbose_vm: true,
+      extraArgs: ['--trace-service', '--trace-service-verbose'],
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_async_exceptions2_test.dart b/pkg/vm_service/test/pause_on_unhandled_async_exceptions2_test.dart
new file mode 100644
index 0000000..bbc9fe9
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_async_exceptions2_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=
+// VMOptions=--optimization-counter-threshold=90
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 42;
+// AUTOGENERATED END
+
+class Foo {}
+
+Never doThrow() {
+  throw 'TheException';
+}
+
+Future<Never> asyncThrower() async {
+  await 0; // force async gap
+  doThrow();
+}
+
+Future<void> testeeMain() async {
+  // Trigger optimization via OSR.
+  int s = 0;
+  for (int i = 0; i < 100; i++) {
+    s += i;
+  }
+  print(s);
+  // No try ... catch.
+  await asyncThrower(); // LINE_A
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.asyncCausalFrames, isNotNull);
+    final asyncStack = stack.asyncCausalFrames!;
+    expect(asyncStack.length, greaterThanOrEqualTo(4));
+    expect(asyncStack[0].function!.name, 'doThrow');
+    expect(asyncStack[1].function!.name, 'asyncThrower');
+    expect(asyncStack[2].kind, FrameKind.kAsyncSuspensionMarker);
+    expect(asyncStack[3].kind, FrameKind.kAsyncCausal);
+    expect(asyncStack[3].function!.name, 'testeeMain');
+    expect(asyncStack[3].location!.line, LINE_A);
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_unhandled_async_exceptions2_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: testeeMain,
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_async_exceptions3_test.dart b/pkg/vm_service/test/pause_on_unhandled_async_exceptions3_test.dart
new file mode 100644
index 0000000..3684b45
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_async_exceptions3_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that debugger can stop on an unhandled exception thrown from async
+// function. Regression test for https://dartbug.com/38697.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 26;
+const LINE_B = 31;
+const LINE_C = 34;
+// AUTOGENERATED END
+
+throwException() async {
+  throw 'exception'; // LINE_A
+}
+
+testeeMain() async {
+  try {
+    await throwException(); // LINE_B
+  } finally {
+    try {
+      await throwException(); // LINE_C
+    } finally {}
+  }
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.frames, isNotEmpty);
+    expect(stack.frames![0].function!.name, 'throwException');
+    expect(stack.frames![0].location!.line, LINE_A);
+  },
+  resumeIsolate,
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.frames, isNotEmpty);
+    // await in testeeMain
+    expect(stack.frames![0].location!.line, LINE_B);
+  },
+  resumeIsolate,
+  hasStoppedWithUnhandledException,
+  stoppedAtLine(LINE_A),
+  resumeIsolate,
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.frames, isNotEmpty);
+    expect(stack.frames![0].location!.line, LINE_C);
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_unhandled_async_exceptions3_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: testeeMain,
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_async_exceptions4_test.dart b/pkg/vm_service/test/pause_on_unhandled_async_exceptions4_test.dart
new file mode 100644
index 0000000..e74e907
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_async_exceptions4_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verifies that execution can be stopped on an unhandled exception
+// in async method which is not awaited.
+// Regression test for https://github.com/dart-lang/sdk/issues/51175.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+Future<Never> doThrow() async {
+  await null; // force async gap
+  throw 'TheException';
+}
+
+Future<void> testeeMain() async {
+  doThrow();
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.asyncCausalFrames, isNotNull);
+    final asyncStack = stack.asyncCausalFrames!;
+    expect(asyncStack.length, greaterThanOrEqualTo(2));
+    expect(asyncStack[0].function!.name, 'doThrow');
+    expect(asyncStack[1].kind, FrameKind.kAsyncSuspensionMarker);
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_unhandled_async_exceptions4_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: testeeMain,
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_async_exceptions_test.dart b/pkg/vm_service/test/pause_on_unhandled_async_exceptions_test.dart
new file mode 100644
index 0000000..318eec5
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_async_exceptions_test.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore_for_file: unused_catch_clause
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 62;
+// AUTOGENERATED END
+
+class Foo {}
+
+String doThrow() {
+  throw 'TheException';
+  // ignore: dead_code
+  return 'end of doThrow';
+}
+
+Future<void> asyncThrower() async {
+  await 0; // force async gap
+  doThrow();
+}
+
+void testeeMain() async {
+  try {
+    // This is a regression case for https://dartbug.com/53334:
+    // we should recognize `then(..., onError: ...)` as a catch
+    // all exception handler.
+    await asyncThrower().then((v) => v, onError: (e, st) {
+      // Caught and ignored.
+    });
+
+    await asyncThrower().onError((error, stackTrace) {
+      // Caught and ignored.
+    });
+
+    try {
+      await asyncThrower();
+    } on String catch (e) {
+      // Caught and ignored.
+    }
+
+    try {
+      await asyncThrower();
+    } catch (e) {
+      // Caught and ignored.
+    }
+
+    // This does not catch the exception.
+    try {
+      await asyncThrower(); // LINE_A
+    } on double catch (e) {}
+  } on Foo catch (e) {}
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.asyncCausalFrames, isNotNull);
+    final asyncStack = stack.asyncCausalFrames!;
+    expect(asyncStack.length, greaterThanOrEqualTo(4));
+    expect(asyncStack[0].function!.name, 'doThrow');
+    expect(asyncStack[1].function!.name, 'asyncThrower');
+    expect(asyncStack[2].kind, FrameKind.kAsyncSuspensionMarker);
+    expect(asyncStack[3].kind, FrameKind.kAsyncCausal);
+    expect(asyncStack[3].function!.name, 'testeeMain');
+    expect(asyncStack[3].location!.line, LINE_A);
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_unhandled_async_exceptions_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: testeeMain,
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_async_exceptions_zones_test.dart b/pkg/vm_service/test/pause_on_unhandled_async_exceptions_zones_test.dart
new file mode 100644
index 0000000..1948b2a
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_async_exceptions_zones_test.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:stack_trace/stack_trace.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 61;
+// AUTOGENERATED END
+
+class Foo {}
+
+String doThrow() {
+  throw 'TheException';
+  // ignore: dead_code
+  return 'end of doThrow';
+}
+
+Future<void> asyncThrower() async {
+  await 0; // force async gap
+  doThrow();
+}
+
+Future<void> testeeMain() async {
+  try {
+    // This is a regression case for https://dartbug.com/53334:
+    // we should recognize `then(..., onError: ...)` as a catch
+    // all exception handler.
+    await asyncThrower().then((v) => v, onError: (e, st) {
+      // Caught and ignored.
+    });
+
+    await asyncThrower().onError((error, stackTrace) {
+      // Caught and ignored.
+    });
+
+    try {
+      await asyncThrower();
+    } on String {
+      // Caught and ignored.
+    }
+
+    try {
+      await asyncThrower();
+    } catch (e) {
+      // Caught and ignored.
+    }
+
+    // This does not catch the exception.
+    try {
+      await asyncThrower(); // LINE_A.
+    } on double {}
+  } on Foo {}
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.asyncCausalFrames, isNotNull);
+    final asyncStack = stack.asyncCausalFrames!;
+    expect(asyncStack.length, greaterThanOrEqualTo(4));
+    expect(asyncStack[0].function!.name, 'doThrow');
+    expect(asyncStack[1].function!.name, 'asyncThrower');
+    expect(asyncStack[2].kind, FrameKind.kAsyncSuspensionMarker);
+    expect(asyncStack[3].kind, FrameKind.kAsyncCausal);
+    expect(asyncStack[3].function!.name, 'testeeMain');
+    expect(asyncStack[3].location!.line, LINE_A);
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_unhandled_async_exceptions_zones_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: () => Chain.capture(testeeMain),
+      extraArgs: extraDebuggingArgs,
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_exceptions_catcherror_test.dart b/pkg/vm_service/test/pause_on_unhandled_exceptions_catcherror_test.dart
new file mode 100644
index 0000000..68076e4
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_exceptions_catcherror_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression: https://github.com/dart-lang/sdk/issues/37953
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+Future<void> throwAsync() async {
+  await Future.delayed(const Duration(milliseconds: 10));
+  throw 'Throw from throwAsync!';
+}
+
+Future<void> nestedThrowAsync() async {
+  await Future.delayed(const Duration(milliseconds: 10));
+  await throwAsync();
+}
+
+Future<void> testeeMain() async {
+  await throwAsync().then((v) {
+    print('Hello from then()!');
+  }).catchError((e, st) {
+    print('Caught in catchError: $e!');
+  });
+  // Make sure we can chain through off-stack awaiters as well.
+  try {
+    await nestedThrowAsync();
+  } catch (e) {
+    print('Caught in catch: $e!');
+  }
+}
+
+final tests = <IsolateTest>[
+  // We shouldn't get any debugger breaks before exit as all exceptions are
+  // caught (via `Future.catchError()`).
+  hasStoppedAtExit,
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'pause_on_unhandled_exceptions_catcherror_test.dart',
+      pause_on_unhandled_exceptions: true,
+      pause_on_exit: true,
+      testeeConcurrent: testeeMain,
+    );
diff --git a/pkg/vm_service/test/pause_on_unhandled_exceptions_test.dart b/pkg/vm_service/test/pause_on_unhandled_exceptions_test.dart
new file mode 100644
index 0000000..21571e8
--- /dev/null
+++ b/pkg/vm_service/test/pause_on_unhandled_exceptions_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+Never doThrow() {
+  throw 'TheException';
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    expect(stack.frames, isNotEmpty);
+    expect(stack.frames![0].function!.name, 'doThrow');
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTestsSynchronous(
+      args,
+      tests,
+      'pause_on_unhandled_exceptions_test.dart',
+      pause_on_unhandled_exceptions: true,
+      testeeConcurrent: doThrow,
+    );
diff --git a/pkg/vm_service/test/positive_token_pos_test.dart b/pkg/vm_service/test/positive_token_pos_test.dart
new file mode 100644
index 0000000..7875d87
--- /dev/null
+++ b/pkg/vm_service/test/positive_token_pos_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--verbose_debug
+
+import 'dart:developer';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_C = 29;
+const LINE_A = 33;
+const LINE_B = 34;
+// AUTOGENERATED END
+
+const LINE_B_COL = 3;
+const LINE_C_COL = 1;
+
+Future<void> helper() async {
+  // LINE_C
+}
+
+void testMain() {
+  debugger(); // LINE_A
+  helper(); // LINE_B
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  stepInto,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final stack = await service.getStack(isolateId);
+    final frames = stack.frames!;
+    expect(frames.length, greaterThan(2));
+
+    // We used to return a negative token position for this frame.
+    // See issue #27128.
+    var frame = frames[0];
+    expect(frame.function!.name, 'helper');
+    expect(await frame.location!.line, LINE_C + 1);
+    expect(await frame.location!.column, LINE_C_COL);
+
+    frame = frames[1];
+    expect(frame.function!.name, 'testMain');
+    expect(await frame.location!.line, LINE_B);
+    expect(await frame.location!.column, LINE_B_COL);
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'positive_token_pos_test.dart',
+      testeeConcurrent: testMain,
+    );
diff --git a/pkg/vm_service/test/private_rpcs/reachable_size_test.dart b/pkg/vm_service/test/private_rpcs/reachable_size_test.dart
new file mode 100644
index 0000000..c41a4d0
--- /dev/null
+++ b/pkg/vm_service/test/private_rpcs/reachable_size_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import '../common/test_helper.dart';
+
+class Pair {
+  // Make sure these fields are not removed by the tree shaker.
+  @pragma('vm:entry-point') // Prevent obfuscation
+  dynamic x;
+  @pragma('vm:entry-point') // Prevent obfuscation
+  dynamic y;
+}
+
+@pragma('vm:entry-point') // Prevent obfuscation
+dynamic p1;
+@pragma('vm:entry-point') // Prevent obfuscation
+dynamic p2;
+
+buildGraph() {
+  p1 = Pair();
+  p2 = Pair();
+
+  // Adds to both reachable and retained size.
+  p1.x = <dynamic>[];
+  p2.x = <dynamic>[];
+
+  // Adds to reachable size only.
+  p1.y = p2.y = <dynamic>[];
+}
+
+extension on VmService {
+  Future<int> getReachableSize(String isolateId, String targetId) async {
+    final result = await callMethod(
+      '_getReachableSize',
+      isolateId: isolateId,
+      args: {
+        'targetId': targetId,
+      },
+    ) as InstanceRef;
+
+    return int.parse(result.valueAsString!);
+  }
+
+  Future<int> getRetainedSize(String isolateId, String targetId) async {
+    final result = await callMethod(
+      '_getRetainedSize',
+      isolateId: isolateId,
+      args: {
+        'targetId': targetId,
+      },
+    ) as InstanceRef;
+
+    return int.parse(result.valueAsString!);
+  }
+}
+
+final tests = <IsolateTest>[
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+
+    final p1Ref = await service.evaluate(
+      isolateId,
+      rootLibId,
+      'p1',
+    ) as InstanceRef;
+    final p1 = await service.getObject(isolateId, p1Ref.id!) as Instance;
+
+    final p2Ref = await service.evaluate(
+      isolateId,
+      rootLibId,
+      'p2',
+    ) as InstanceRef;
+    final p2 = await service.getObject(isolateId, p2Ref.id!) as Instance;
+
+    // In general, shallow <= retained <= reachable. In this program,
+    // 0 < shallow < retained < reachable.
+
+    final p1_shallow = p1.size!;
+    final p1_retained = await service.getRetainedSize(isolateId, p1.id!);
+    final p1_reachable = await service.getReachableSize(isolateId, p1.id!);
+
+    expect(0, lessThan(p1_shallow));
+    expect(p1_shallow, lessThan(p1_retained));
+    expect(p1_retained, lessThan(p1_reachable));
+
+    final p2_shallow = p2.size!;
+    final p2_retained = await service.getRetainedSize(isolateId, p2.id!);
+    final p2_reachable = await service.getReachableSize(isolateId, p2.id!);
+
+    expect(0, lessThan(p2_shallow));
+    expect(p2_shallow, lessThan(p2_retained));
+    expect(p2_retained, lessThan(p2_reachable));
+
+    expect(p1_shallow, p2_shallow);
+    expect(p1_retained, p2_retained);
+    expect(p1_reachable, p2_reachable);
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'reachable_size_test.dart',
+      testeeBefore: buildGraph,
+    );
diff --git a/pkg/vm_service/test/regexp_function_test.dart b/pkg/vm_service/test/regexp_function_test.dart
new file mode 100644
index 0000000..a3fdfe5
--- /dev/null
+++ b/pkg/vm_service/test/regexp_function_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=
+// VMOptions=--interpret_irregexp
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/expect.dart';
+import 'common/test_helper.dart';
+
+// Make sure these variables are not removed by the tree shaker.
+@pragma('vm:entry-point')
+late RegExp regex0;
+@pragma('vm:entry-point')
+late RegExp regex;
+
+void script() {
+  // Check the internal NUL doesn't trip up the name scrubbing in the vm.
+  regex0 = RegExp('with internal \u{0} NUL');
+  regex = RegExp(r'(\w+)');
+  final str = 'Parse my string';
+  final matches = regex.allMatches(str); // Run to generate bytecode.
+  Expect.equals(matches.length, 3);
+}
+
+final tests = <IsolateTest>[
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLib = await service.getObject(
+      isolateId,
+      isolate.rootLib!.id!,
+    ) as Library;
+
+    final variables = rootLib.variables!;
+
+    final fieldRef = variables.singleWhere((v) => v.name == 'regex');
+    final field = await service.getObject(
+      isolateId,
+      fieldRef.id!,
+    ) as Field;
+
+    final regexRef = field.staticValue as InstanceRef;
+    expect(regexRef.kind, InstanceKind.kRegExp);
+
+    final regex = await service.getObject(
+      isolateId,
+      regexRef.id!,
+    ) as Instance;
+
+    final regexJson = regex.json!;
+    if (regexJson
+        case {
+          '_oneByteBytecode': {'kind': InstanceKind.kUint8List},
+          // No two-byte string subject was used.
+          '_twoByteBytecode': {'kind': InstanceKind.kNull},
+        } when !regexJson.containsKey('_oneByteFunction')) {
+      // Running with interpreted regexp.
+    } else if (regexJson
+        case {
+          '_oneByteFunction': {'type': '@Function'},
+          '_twoByteFunction': {'type': '@Function'},
+          '_externalOneByteFunction': {'type': '@Function'},
+          '_externalTwoByteFunction': {'type': '@Function'},
+        }) {
+      // Running with compiled regexp.
+    } else {
+      fail('Unexpected JSON structure: ${regex.json!}');
+    }
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regexp_function_test.dart',
+      testeeBefore: script,
+    );
diff --git a/pkg/vm_service/test/regress_28443_test.dart b/pkg/vm_service/test/regress_28443_test.dart
new file mode 100644
index 0000000..760321f
--- /dev/null
+++ b/pkg/vm_service/test/regress_28443_test.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 36;
+const LINE_B = 41;
+const LINE_C = 45;
+// AUTOGENERATED END
+
+class VMServiceClient {
+  VMServiceClient(this.x);
+  Future<void> close() => Future.microtask(() => print('close'));
+  final String x;
+}
+
+Future<void> collect() async {
+  final uri = 'abc';
+  late VMServiceClient vmService;
+  await Future.microtask(() async {
+    try {
+      vmService = VMServiceClient(uri);
+      await Future.microtask(() => throw new TimeoutException('here'));
+    } on Object {
+      vmService.close();
+      rethrow; // LINE_A
+    }
+  });
+}
+
+Future<void> test_code() async /* LINE_B */ {
+  try {
+    await collect();
+  } on TimeoutException {
+    print('ok'); // LINE_C
+  }
+}
+
+final tests = <IsolateTest>[
+  hasPausedAtStart,
+  markDartColonLibrariesDebuggable,
+  setBreakpointAtLine(LINE_B),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  setBreakpointAtLine(LINE_A),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  setBreakpointAtLine(LINE_C),
+  stepOut,
+  resumeIsolate,
+  stoppedAtLine(LINE_C),
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regress_28443_test.dart',
+      testeeConcurrent: test_code,
+      pause_on_start: true,
+      pause_on_exit: false,
+    );
diff --git a/pkg/vm_service/test/regress_28980_test.dart b/pkg/vm_service/test/regress_28980_test.dart
new file mode 100644
index 0000000..b2539c4
--- /dev/null
+++ b/pkg/vm_service/test/regress_28980_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 26;
+const LINE_B = 44;
+// AUTOGENERATED END
+
+late A _lock;
+bool _lockEnabled = true;
+
+String flutterRoot = 'abc';
+
+A foo(String a, String b, String c, String d) {
+  return A(); // LINE_A
+}
+
+class A {
+  Future lock() => Future.microtask(() => print('lock'));
+  final path = 'path';
+}
+
+class FileSystemException {}
+
+Future<void> test_code() async {
+  if (!_lockEnabled) return null;
+  _lock = foo(flutterRoot, 'bin', 'cache', 'lockfile');
+  bool locked = false;
+  bool printed = false;
+  while (!locked) {
+    try {
+      await _lock.lock();
+      locked = true; // LINE_B
+    } on FileSystemException {
+      if (!printed) {
+        print('Print path: ${_lock.path}');
+        print('Just another line...');
+        printed = true;
+      }
+      await Future<Null>.delayed(const Duration(milliseconds: 50));
+    }
+  }
+}
+
+final tests = <IsolateTest>[
+  hasPausedAtStart,
+  markDartColonLibrariesDebuggable,
+  setBreakpointAtLine(LINE_A),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  setBreakpointAtLine(LINE_B),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stepInto,
+  stepInto,
+  stepInto,
+  resumeIsolate,
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regress_28980_test.dart',
+      testeeConcurrent: test_code,
+      pause_on_start: true,
+      pause_on_exit: false,
+    );
diff --git a/pkg/vm_service/test/regress_34841_lib.dart b/pkg/vm_service/test/regress_34841_lib.dart
new file mode 100644
index 0000000..b4c4283
--- /dev/null
+++ b/pkg/vm_service/test/regress_34841_lib.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+mixin Foo {
+  String baz() => StackTrace.current.toString();
+  final String foo = () {
+    return StackTrace.current.toString();
+  }();
+}
diff --git a/pkg/vm_service/test/regress_34841_test.dart b/pkg/vm_service/test/regress_34841_test.dart
new file mode 100644
index 0000000..9addd77
--- /dev/null
+++ b/pkg/vm_service/test/regress_34841_test.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// While it's not (currently) necessary, add some noise here to push down token
+// positions in this file compared to the file regress_34841_lib.dart.
+// This is to ensure that any possible tokens in that file are just comments
+// (i.e. not actual) positions in this file.
+
+import 'dart:developer';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+import 'regress_34841_lib.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 34;
+// AUTOGENERATED END
+
+class Bar extends Object with Foo {}
+
+void testFunction() {
+  final bar = Bar();
+  print(bar.foo);
+  print(bar.baz());
+  debugger(); // LINE_A
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLib = await service.getObject(
+      isolateId,
+      isolate.rootLib!.id!,
+    ) as Library;
+    final script = await service.getObject(
+      isolateId,
+      rootLib.scripts!.first.id!,
+    ) as Script;
+
+    final report = await service.getSourceReport(
+      isolateId,
+      [SourceReportKind.kCoverage],
+      scriptId: script.id!,
+      forceCompile: true,
+    );
+
+    final ranges = report.ranges!;
+    final coveragePlaces = <int>[];
+    for (final range in ranges) {
+      final coverage = range.coverage!;
+      for (int i in coverage.hits!) {
+        coveragePlaces.add(i);
+      }
+      for (int i in coverage.misses!) {
+        coveragePlaces.add(i);
+      }
+    }
+    expect(ranges, isNotEmpty);
+
+    // Make sure we can translate it all.
+    for (int place in coveragePlaces) {
+      int? line = script.getLineNumberFromTokenPos(place);
+      int? column = script.getColumnNumberFromTokenPos(place);
+      if (line == null || column == null) {
+        throw 'Token $place translated to $line:$column';
+      }
+    }
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regress_34841_test.dart',
+      testeeConcurrent: testFunction,
+    );
diff --git a/pkg/vm_service/test/regress_45684_test.dart b/pkg/vm_service/test/regress_45684_test.dart
new file mode 100644
index 0000000..8734d05
--- /dev/null
+++ b/pkg/vm_service/test/regress_45684_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=--verbose_debug
+
+// Check that a try/finally is not treated as a try/catch:
+// http://dartbug.com/45684.
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 32;
+// AUTOGENERATED END
+
+void tryFinally(Function() code) {
+  // There is a synthetic try/catch inside try/finally but it is not authored
+  // by the user, so debugger should not consider that this try/catch is
+  // going to handle the exception.
+  try {
+    code();
+  } finally {}
+}
+
+Never syncThrow() {
+  throw 'Hello from syncThrow!'; // LINE_A
+}
+
+void testMain() {
+  tryFinally(syncThrow);
+}
+
+final tests = <IsolateTest>[
+  hasStoppedWithUnhandledException,
+  stoppedAtLine(LINE_A),
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regress_45684_test.dart',
+      testeeConcurrent: testMain,
+      pause_on_unhandled_exceptions: true,
+    );
diff --git a/pkg/vm_service/test/regress_46419_test.dart b/pkg/vm_service/test/regress_46419_test.dart
new file mode 100644
index 0000000..304d5fa
--- /dev/null
+++ b/pkg/vm_service/test/regress_46419_test.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--verbose-debug
+
+import 'dart:async';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 31;
+const LINE_B = 34;
+const LINE_C = 41;
+const LINE_D = 48;
+// AUTOGENERATED END
+
+// DO NOT REORDER BEYOND THIS POINT
+bool testing = false;
+void printSync() {
+  print('sync');
+  if (testing) {
+    // LINE_A
+    // We'll never reach this code, but setting a breakpoint here will result in
+    // the breakpoint being resolved below at line LINE_C.
+    print('unreachable'); // LINE_B
+  }
+}
+
+printSyncStar() sync* {
+  // We'll end up resolving breakpoint 1 to this location instead of at LINE_A
+  // if #46419 regresses.
+  print('sync*'); // LINE_C
+}
+
+testeeDo() {
+  printSync();
+  final iterator = printSyncStar();
+
+  print('middle'); // LINE_D
+
+  iterator.toList();
+}
+// END DO NOT REORDER SECTION
+
+late Breakpoint bp1;
+late Breakpoint bp2;
+
+final tests = <IsolateTest>[
+  hasPausedAtStart,
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLib = await service.getObject(
+      isolateId,
+      isolate.rootLib!.id!,
+    ) as Library;
+    final scriptId = rootLib.scripts!.first.id!;
+
+    bp1 = await service.addBreakpoint(isolateId, scriptId, LINE_B);
+    print('BP1 - $bp1');
+    bp2 = await service.addBreakpoint(isolateId, scriptId, LINE_D);
+    print('BP2 - $bp2');
+
+    final done = Completer<void>();
+    late final StreamSubscription sub;
+    sub = service.onDebugEvent.listen((event) async {
+      if (event.kind == EventKind.kPauseBreakpoint) {
+        expect(event.pauseBreakpoints!.length, 1);
+        final bp = event.pauseBreakpoints!.first;
+        print('Hit $bp');
+        expect(bp, bp2);
+        sub.cancel();
+        await service.streamCancel(EventStreams.kDebug);
+        await service.resume(isolateId);
+        done.complete();
+      }
+    });
+    await service.streamListen(EventStreams.kDebug);
+    await service.resume(isolateId);
+    await done.future;
+  }
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'regress_46419_test.dart',
+      testeeConcurrent: testeeDo,
+      pause_on_start: true,
+    );
diff --git a/pkg/vm_service/test/reload_sources_test.dart b/pkg/vm_service/test/reload_sources_test.dart
new file mode 100644
index 0000000..e873c03
--- /dev/null
+++ b/pkg/vm_service/test/reload_sources_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'common/test_helper.dart';
+import 'common/service_test_common.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_A = 23;
+// AUTOGENERATED END
+
+void testMain() {
+  debugger(); // LINE_A.
+  print('1');
+  while (true) {}
+}
+
+Future<void> isolateIsRunning(VmService service, IsolateRef isolateRef) async {
+  final isolate = await service.getIsolate(isolateRef.id!);
+  final pauseEvent = isolate.pauseEvent;
+  final isPaused = pauseEvent == null
+      ? false
+      : isolate.pauseEvent!.kind != EventKind.kResume;
+  final topFrame = pauseEvent?.topFrame;
+  expect(!isPaused && topFrame != null, true);
+}
+
+final tests = <IsolateTest>[
+  // Stopped at 'debugger' statement.
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  // Reload sources and request to pause post reload. The pause request will be
+  // ignored because we are already paused at a breakpoint.
+  reloadSources(pause: true),
+  // Ensure that we are still stopped at a breakpoint.
+  hasStoppedAtBreakpoint,
+  // Resume the isolate into the while loop.
+  resumeIsolate,
+  // Reload sources and request to pause post reload. The pause request will
+  // be respected because we are not already paused.
+  reloadSources(pause: true),
+  // Ensure that we are paused post reload request.
+  hasStoppedPostRequest,
+  // Resume the isolate.
+  resumeIsolate,
+  // Verify that it is running.
+  isolateIsRunning,
+  // Reload sources and do not request to pause post reload.
+  reloadSources(),
+  // Verify that it is running.
+  isolateIsRunning,
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'reload_sources_test.dart',
+      testeeConcurrent: testMain,
+    );
diff --git a/pkg/vm_service/test/resume_shutdown_race_test.dart b/pkg/vm_service/test/resume_shutdown_race_test.dart
new file mode 100644
index 0000000..1f6addf7
--- /dev/null
+++ b/pkg/vm_service/test/resume_shutdown_race_test.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--pause-isolates-on-exit --enable-vm-service=0 --disable-service-auth-codes
+
+// See b/271314180.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:developer';
+import 'dart:io';
+import 'dart:isolate';
+
+const childCount = 4;
+
+void child(i) {
+  print('Child $i');
+  // Paused-at-exit.
+}
+
+void main() {
+  for (int i = 0; i < childCount; i++) {
+    Isolate.spawn(child, i);
+  }
+  Isolate.spawn(resumer, null);
+  print('Parent');
+  // Paused-at-exit.
+}
+
+Future<Map<String, dynamic>> get(
+  String method,
+  Map<String, dynamic> arguments,
+) async {
+  final info = await Service.getInfo();
+  final uri = info.serverUri!.replace(path: method, queryParameters: arguments);
+  final client = HttpClient();
+  try {
+    final request = await client.getUrl(uri);
+    final response = await request.close();
+    final string = await response.transform(utf8.decoder).join();
+    return jsonDecode(string);
+  } finally {
+    client.close();
+  }
+}
+
+Future<Never> resumer(_) async {
+  try {
+    // Wait for the main isolate and children to all be paused at exit.
+    final paused = <String>[];
+    do {
+      paused.clear();
+      final vm = (await get('getVM', {}))['result'];
+      for (Map<String, dynamic> isolate in vm['isolates']) {
+        final id = isolate['id'];
+        isolate = (await get('getIsolate', {'isolateId': id}))['result'];
+        if ((isolate['pauseEvent'] != null) &&
+            (isolate['pauseEvent']['kind'] == 'PauseExit')) {
+          paused.add(id);
+        }
+      }
+    } while (paused.length != childCount + 1);
+
+    // Resume the main isolate and children. When the main isolate resumes, it
+    // will exit and trigger VM shutdown. The VM shutdown will send the OOB kill
+    // message to children and so race with the resume message. No matter how
+    // the race resolves, the children should exit and the VM shutdown should
+    // not hang with
+    //    Attempt:138 waiting for isolate child to check in
+    //    ...
+    for (final id in paused) {
+      await get('resume', {'isolateId': id}).then((v) => print(v));
+    }
+  } catch (e, st) {
+    print(e);
+    print(st);
+    rethrow;
+  }
+
+  // This isolate itself will be paused-at-exit with no resume message coming,
+  // but should exit because of the VM shutdown.
+  throw StateError('Unreachable');
+}
diff --git a/pkg/vm_service/test/rewind_optimized_out_test.dart b/pkg/vm_service/test/rewind_optimized_out_test.dart
new file mode 100644
index 0000000..0b3e814
--- /dev/null
+++ b/pkg/vm_service/test/rewind_optimized_out_test.dart
@@ -0,0 +1,102 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_0 = 39;
+const LINE_A = 41;
+const LINE_B = 46;
+const LINE_C = 49;
+const LINE_D = 53;
+// AUTOGENERATED END
+
+int global = 0;
+
+@pragma('vm:never-inline')
+int b3(int x) {
+  int sum = 0;
+  try {
+    for (int i = 0; i < x; i++) {
+      sum += x;
+    }
+  } catch (e) {
+    print('caught $e');
+  }
+  if (global >= 100) {
+    debugger(); // LINE_0.
+  }
+  global = global + 1; // LINE_A.
+  return sum;
+}
+
+@pragma('vm:prefer-inline')
+int b2(x) => b3(x); // LINE_B.
+
+@pragma('vm:prefer-inline')
+int b1(x) => b2(x); // LINE_C.
+
+void test() {
+  while (true) {
+    b1(10000); // LINE_D.
+  }
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_0),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+
+    // We are at our breakpoint with global=100.
+    final result = await service.evaluate(
+        isolateId, isolate.rootLib!.id!, 'global') as InstanceRef;
+    expect(result.valueAsString, '100');
+
+    // Rewind the top stack frame.
+    bool caughtException = false;
+    try {
+      await service.resume(isolateId, step: StepOption.kRewind);
+      fail('Unreachable');
+    } on RPCError catch (e) {
+      caughtException = true;
+      expect(e.code, RPCErrorKind.kIsolateCannotBeResumed.code);
+      expect(
+          e.details,
+          startsWith('Cannot rewind to frame 1 due to conflicting compiler '
+              'optimizations. Run the vm with --no-prune-dead-locals '
+              'to disallow these optimizations. Next valid rewind '
+              'frame is '));
+    }
+    expect(caughtException, true);
+  },
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'rewind_optimized_out_test.dart',
+      testeeConcurrent: test,
+      extraArgs: [
+        '--trace-rewind',
+        '--prune-dead-locals',
+        '--no-background-compilation',
+        '--optimization-counter-threshold=10',
+      ],
+    );
diff --git a/pkg/vm_service/test/rewind_test.dart b/pkg/vm_service/test/rewind_test.dart
new file mode 100644
index 0000000..e2df063
--- /dev/null
+++ b/pkg/vm_service/test/rewind_test.dart
@@ -0,0 +1,194 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:developer';
+
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+// AUTOGENERATED START
+//
+// Update these constants by running:
+//
+// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
+//
+const LINE_0 = 39;
+const LINE_A = 41;
+const LINE_B = 46;
+const LINE_C = 49;
+const LINE_D = 53;
+// AUTOGENERATED END
+
+int global = 0;
+
+@pragma('vm:never-inline')
+int b3(int x) {
+  int sum = 0;
+  try {
+    for (int i = 0; i < x; i++) {
+      sum += x;
+    }
+  } catch (e) {
+    print('caught $e');
+  }
+  if (global >= 100) {
+    debugger(); // LINE_0.
+  }
+  global = global + 1; // LINE_A.
+  return sum;
+}
+
+@pragma('vm:prefer-inline')
+int b2(x) => b3(x); // LINE_B.
+
+@pragma('vm:prefer-inline')
+int b1(x) => b2(x); // LINE_C.
+
+void test() {
+  while (true) {
+    b1(10000); // LINE_D.
+  }
+}
+
+final tests = <IsolateTest>[
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_0),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    // We are not able to rewind frame 0.
+    bool caughtException = false;
+    try {
+      await service.resume(
+        isolateId,
+        step: StepOption.kRewind,
+        frameIndex: 0,
+      );
+      fail('Unreachable');
+    } on RPCError catch (e) {
+      caughtException = true;
+      expect(e.code, RPCErrorKind.kIsolateCannotBeResumed.code);
+      expect(e.details, 'Frame must be in bounds [1..8]: saw 0');
+    }
+    expect(caughtException, true);
+  },
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    // We are not able to rewind frame 13.
+    bool caughtException = false;
+    try {
+      await service.resume(
+        isolateId,
+        step: StepOption.kRewind,
+        frameIndex: 13,
+      );
+      fail('Unreachable');
+    } on RPCError catch (e) {
+      caughtException = true;
+      expect(e.code, RPCErrorKind.kIsolateCannotBeResumed.code);
+      expect(e.details, 'Frame must be in bounds [1..8]: saw 13');
+    }
+    expect(caughtException, true);
+  },
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+
+    // We are at our breakpoint with global=100.
+    final result = await service.evaluate(
+      isolateId,
+      rootLibId,
+      'global',
+    ) as InstanceRef;
+    print('global is $result');
+    expect(result.valueAsString, '100');
+
+    // Rewind the top stack frame.
+    await service.resume(isolateId, step: StepOption.kRewind, frameIndex: 1);
+  },
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_B),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_0),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+
+    // global still is equal to 100.  We did not execute 'global++'.
+    final result = await service.evaluate(
+      isolateId,
+      rootLibId,
+      'global',
+    ) as InstanceRef;
+    print('global is $result');
+    expect(result.valueAsString, '100');
+
+    // Rewind up to 'test'/
+    await service.resume(isolateId, step: StepOption.kRewind, frameIndex: 3);
+  },
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+
+    // Reset global to 0 and start again.
+    final result = await service.evaluate(
+      isolateId,
+      rootLibId,
+      'global = 0',
+    ) as InstanceRef;
+    expect(result.valueAsString, '0');
+  },
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_0),
+  stepOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id!;
+    final isolate = await service.getIsolate(isolateId);
+    final rootLibId = isolate.rootLib!.id!;
+
+    // We are at our breakpoint with global=100.
+    final result = await service.evaluate(
+      isolateId,
+      rootLibId,
+      'global',
+    ) as InstanceRef;
+    print('global is $result');
+    expect(result.valueAsString, '100');
+
+    // Rewind the top 2 stack frames.
+    await service.resume(isolateId, step: StepOption.kRewind, frameIndex: 2);
+  },
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+];
+
+void main([args = const <String>[]]) => runIsolateTests(
+      args,
+      tests,
+      'rewind_test.dart',
+      testeeConcurrent: test,
+      extraArgs: [
+        '--trace-rewind',
+        '--no-prune-dead-locals',
+        '--no-background-compilation',
+        '--optimization-counter-threshold=10',
+      ],
+    );
diff --git a/pkg/vm_service/test/update_line_numbers.dart b/pkg/vm_service/test/update_line_numbers.dart
new file mode 100644
index 0000000..fce70d1
--- /dev/null
+++ b/pkg/vm_service/test/update_line_numbers.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+// This script updates LINE_* constants in the given test.
+void main(List<String> args) {
+  if (args.length != 1 || !args[0].endsWith('.dart')) {
+    print('Usage: ${Platform.executable} ${Platform.script} <test-file>');
+    exit(1);
+  }
+
+  final inputFile = File(args[0]);
+
+  final content = inputFile.readAsLinesSync();
+
+  const autogeneratedStart = '// AUTOGENERATED START';
+  const autogeneratedEnd = '// AUTOGENERATED END';
+
+  final lineConstantPattern = RegExp(r'^const( int)? LINE_\w+ = \d+;$');
+
+  final prefix = content
+      .takeWhile((line) =>
+          !lineConstantPattern.hasMatch(line) && autogeneratedStart != line)
+      .toList();
+
+  final suffix = content
+      .skip(prefix.length)
+      .skipWhile(
+          (line) => line.startsWith('//') || lineConstantPattern.hasMatch(line))
+      .toList();
+
+  final lineCommentPattern =
+      RegExp(r' // (LINE_\w+)\.?$|/\*\s*(LINE_\w+)\s*\*/');
+  final mapping = <String, int>{};
+  for (var i = 0; i < suffix.length; i++) {
+    final line = suffix[i];
+    final m = lineCommentPattern.firstMatch(line);
+    if (m != null) {
+      mapping[(m[1] ?? m[2])!] = i;
+    }
+  }
+
+  final header = [
+    ...prefix,
+    autogeneratedStart,
+    '//',
+    '// Update these constants by running:',
+    '//',
+    '// dart pkg/vm_service/test/update_line_numbers.dart '
+        '<test.dart>',
+    '//',
+  ];
+
+  // Mapping currently contains 0 based indices into suffix.
+  // Convert them into 1 based line numbers taking into account that we will
+  // generate a header + one line for each LINE_* constant plus
+  // autogeneratedEnd marker.
+  mapping
+      .updateAll((_, value) => 1 + header.length + mapping.length + 1 + value);
+
+  inputFile.writeAsString([
+    ...header,
+    for (var entry in mapping.entries) 'const ${entry.key} = ${entry.value};',
+    autogeneratedEnd,
+    ...suffix,
+    '',
+  ].join('\n'));
+  print('Updated ${inputFile}');
+}
diff --git a/pkg/vm_service/tool/dart/generate_dart_client.dart b/pkg/vm_service/tool/dart/generate_dart_client.dart
index cf0cdfa..d4fa532 100644
--- a/pkg/vm_service/tool/dart/generate_dart_client.dart
+++ b/pkg/vm_service/tool/dart/generate_dart_client.dart
@@ -265,15 +265,37 @@
   /// The requested feature is disabled.
   kFeatureDisabled(code: 100, message: 'Feature is disabled'),
 
+  /// The VM must be paused when performing this operation.
+  kVmMustBePaused(code: 101, message: 'The VM must be paused'),
+
+  /// Unable to add a breakpoint at the specified line or function.
+  kCannotAddBreakpoint(code: 102,
+    message: 'Unable to add breakpoint at specified line or function'),
+
   /// The stream has already been subscribed to.
   kStreamAlreadySubscribed(code: 103, message: 'Stream already subscribed'),
 
   /// The stream has not been subscribed to.
   kStreamNotSubscribed(code: 104, message: 'Stream not subscribed'),
 
+  /// Isolate must first be runnable.
+  kIsolateMustBeRunnable(code: 105, message: 'Isolate must be runnable'),
+
   /// Isolate must first be paused.
   kIsolateMustBePaused(code: 106, message: 'Isolate must be paused'),
 
+  /// The isolate could not be resumed.
+  kIsolateCannotBeResumed(code: 107, message: 'The isolate could not be resumed'),
+
+  /// The isolate is currently reloading.
+  kIsolateIsReloading(code: 108, message: 'The isolate is currently reloading'),
+
+  /// The isolate could not be reloaded due to an unhandled exception.
+  kIsolateCannotReload(code: 109, message: 'The isolate could not be reloaded'),
+
+  /// The isolate reload resulted in no changes being applied.
+  kIsolateNoReloadChangesApplied(code: 110, message: 'No reload changes applied'),
+
   /// The service has already been registered.
   kServiceAlreadyRegistered(code: 111, message: 'Service already registered'),
 
@@ -284,6 +306,10 @@
   kExpressionCompilationError(
       code: 113, message: 'Expression compilation error'),
 
+  /// The timeline related request could not be completed due to the current configuration.
+  kInvalidTimelineRequest(code: 114,
+      message: 'Invalid timeline request for the current timeline configuration'),
+
   /// The custom stream does not exist.
   kCustomStreamDoesNotExist(code: 130, message: 'Custom stream does not exist'),
 
diff --git a/pkg/vm_service/tool/dart/generate_dart_interface.dart b/pkg/vm_service/tool/dart/generate_dart_interface.dart
index 2053f9f..c0c2fc7 100644
--- a/pkg/vm_service/tool/dart/generate_dart_interface.dart
+++ b/pkg/vm_service/tool/dart/generate_dart_interface.dart
@@ -19,7 +19,7 @@
 
 import 'dart:async';
 
-import 'package:vm_service/vm_service.dart' hide ServiceExtensionRegistry, VmServerConnection, VmServiceInterface;
+import 'package:vm_service/vm_service.dart';
 
 import 'service_extension_registry.dart';