Version 2.17.0-182.0.dev

Merge commit '5f0afa0ac45f5c3c3e691803dd2e95d40d91a6a0' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 1350c46..12ae415 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -703,8 +703,9 @@
 
   @override
   void applyFileRemoved(String file) {
-    sendAnalysisNotificationFlushResults(analysisServer, [file]);
-    filesToFlush.remove(file);
+    if (filesToFlush.remove(file)) {
+      sendAnalysisNotificationFlushResults(analysisServer, [file]);
+    }
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/utilities/mocks.dart b/pkg/analysis_server/lib/src/utilities/mocks.dart
index bef5102..6ad7371 100644
--- a/pkg/analysis_server/lib/src/utilities/mocks.dart
+++ b/pkg/analysis_server/lib/src/utilities/mocks.dart
@@ -23,7 +23,7 @@
   StreamController<Response> responseController =
       StreamController<Response>.broadcast();
   StreamController<Notification> notificationController =
-      StreamController<Notification>(sync: true);
+      StreamController<Notification>.broadcast(sync: true);
   Completer<Response>? errorCompleter;
 
   List<Response> responsesReceived = [];
@@ -35,6 +35,11 @@
 
   MockServerChannel();
 
+  /// Return the broadcast stream of notifications.
+  Stream<Notification> get notifications {
+    return notificationController.stream;
+  }
+
   @override
   Stream<Request> get requests => requestController.stream;
 
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 3045889..df45776 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -202,11 +202,7 @@
     server = createAnalysisServer();
     server.pluginManager = pluginManager;
     handler = analysisHandler;
-    // listen for notifications
-    var notificationStream = serverChannel.notificationController.stream;
-    notificationStream.listen((Notification notification) {
-      processNotification(notification);
-    });
+    serverChannel.notifications.listen(processNotification);
   }
 
   @mustCallSuper
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 3546ca2..9ac113c 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -135,10 +135,10 @@
 
     // Track diagnostics that arrive.
     final errorsByFile = <String, List<AnalysisError>>{};
-    channel.notificationController.stream
+    channel.notifications
         .where((notification) => notification.event == 'analysis.errors')
-        .listen((notificaton) {
-      final params = AnalysisErrorsParams.fromNotification(notificaton);
+        .listen((notification) {
+      final params = AnalysisErrorsParams.fromNotification(notification);
       errorsByFile[params.file] = params.errors;
     });
 
diff --git a/pkg/analysis_server/test/client/impl/completion_driver.dart b/pkg/analysis_server/test/client/impl/completion_driver.dart
index 63d8ec0..095db29 100644
--- a/pkg/analysis_server/test/client/impl/completion_driver.dart
+++ b/pkg/analysis_server/test/client/impl/completion_driver.dart
@@ -84,10 +84,7 @@
     required this.supportsAvailableSuggestions,
     required this.server,
   }) {
-    server.serverChannel.notificationController.stream
-        .listen((Notification notification) {
-      processNotification(notification);
-    });
+    server.serverChannel.notifications.listen(processNotification);
   }
 
   void addTestFile(String content, {int? offset}) {
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index fe0da92..21b79b3 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -25,6 +25,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'analysis_abstract.dart';
+import 'domain_completion_test.dart';
 import 'mocks.dart';
 
 void main() {
@@ -44,8 +45,6 @@
 
   String get myPackageTestFilePath => '$myPackageLibPath/test.dart';
 
-  String get workspaceRootPath => '/workspace';
-
   @override
   void setUp() {
     super.setUp();
@@ -347,15 +346,8 @@
 
 @reflectiveTest
 class AnalysisDomainPubTest extends _AnalysisDomainTest {
-  String get testFilePath => '$testPackageLibPath/test.dart';
-
-  String get testPackageLibPath => '$testPackageRootPath/lib';
-
-  String get testPackageRootPath => '$workspaceRootPath/test';
-
-  String get workspaceRootPath => '/home';
-
   Future<void> test_fileSystem_addFile_analysisOptions() async {
+    deleteTestPackageAnalysisOptionsFile();
     var a_path = '$testPackageLibPath/a.dart';
     var b_path = '$testPackageLibPath/b.dart';
 
@@ -389,6 +381,7 @@
   }
 
   Future<void> test_fileSystem_addFile_analysisOptions_analysis() async {
+    deleteTestPackageAnalysisOptionsFile();
     var a_path = '$testPackageLibPath/a.dart';
     var options_path = '$testPackageRootPath/analysis_options.yaml';
 
@@ -460,16 +453,15 @@
   }
 
   Future<void> test_fileSystem_addFile_dart_dotFolder() async {
-    var a_path = '$projectPath/lib/.foo/a.dart';
-    var b_path = '$projectPath/lib/b.dart';
+    var a_path = '$testPackageLibPath/.foo/a.dart';
+    var b_path = '$testPackageLibPath/b.dart';
 
     newFile(b_path, content: r'''
 import '.foo/a.dart';
 void f(A a) {}
 ''');
 
-    await createProject();
-    await pumpEventQueue();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We don't have a.dart, so the import cannot be resolved.
@@ -489,10 +481,10 @@
   }
 
   Future<void> test_fileSystem_addFile_dart_excluded() async {
-    var a_path = '$projectPath/lib/a.dart';
-    var b_path = '$projectPath/lib/b.dart';
+    var a_path = '$testPackageLibPath/a.dart';
+    var b_path = '$testPackageLibPath/b.dart';
 
-    newAnalysisOptionsYamlFile(projectPath, content: r'''
+    newAnalysisOptionsYamlFile(testPackageRootPath, content: r'''
 analyzer:
   exclude:
     - "**/a.dart"
@@ -503,8 +495,7 @@
 void f(A a) {}
 ''');
 
-    await createProject();
-    await pumpEventQueue();
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We don't have a.dart, so the import cannot be resolved.
@@ -524,6 +515,7 @@
   }
 
   Future<void> test_fileSystem_addFile_dotPackagesFile() async {
+    deleteTestPackageConfigJsonFile();
     var aaaLibPath = '/packages/aaa/lib';
     var a_path = '$aaaLibPath/a.dart';
 
@@ -562,12 +554,6 @@
 
     newFile('$testPackageLibPath/a.dart', content: '');
 
-    // Make sure that it is a package.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder(),
-    );
-
     await setRoots(included: [workspaceRootPath], excluded: []);
 
     // No `fix_data.yaml` to analyze yet.
@@ -605,9 +591,9 @@
     assertHasErrors(testFilePath);
 
     // Write `package_config.json`, recreate analysis contexts.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder()..add(name: 'aaa', rootPath: aaaRootPath),
+    writeTestPackageConfig(
+      config: PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: aaaRootPath),
     );
 
     await pumpEventQueue();
@@ -857,6 +843,7 @@
   }
 
   Future<void> test_fileSystem_changeFile_dotPackagesFile() async {
+    deleteTestPackageConfigJsonFile();
     var aaaLibPath = '/packages/aaa/lib';
     var a_path = '$aaaLibPath/a.dart';
 
@@ -898,12 +885,6 @@
 
     newFile('$testPackageLibPath/a.dart', content: '');
 
-    // Make sure that it is a package.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder(),
-    );
-
     // This file has an error.
     newFile(path, content: '0: 1');
 
@@ -935,12 +916,6 @@
 class A {}
 ''');
 
-    // Write the empty file, without `package:aaa`.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder(),
-    );
-
     newFile(testFilePath, content: '''
 import 'package:aaa/a.dart';
 void f(A a) {}
@@ -949,13 +924,14 @@
     await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
+    // The default `package_config.json` is without `package:aaa`.
     // We cannot resolve `package:aaa/a.dart`
     assertHasErrors(testFilePath);
 
     // Write `package_config.json`, recreate analysis contexts.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder()..add(name: 'aaa', rootPath: aaaRootPath),
+    writeTestPackageConfig(
+      config: PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: aaaRootPath),
     );
 
     await pumpEventQueue();
@@ -1090,6 +1066,7 @@
   }
 
   Future<void> test_fileSystem_deleteFile_dotPackagesFile() async {
+    deleteTestPackageConfigJsonFile();
     var aaaLibPath = '/packages/aaa/lib';
     var a_path = '$aaaLibPath/a.dart';
 
@@ -1130,12 +1107,6 @@
 
     newFile('$testPackageLibPath/a.dart', content: '');
 
-    // Make sure that it is a package.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder(),
-    );
-
     // This file has an error.
     newFile(path, content: '0: 1');
 
@@ -1161,9 +1132,9 @@
 ''');
 
     // Write the empty file, without `package:aaa`.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder()..add(name: 'aaa', rootPath: aaaRootPath),
+    writeTestPackageConfig(
+      config: PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: aaaRootPath),
     );
 
     newFile(testFilePath, content: '''
@@ -1193,6 +1164,7 @@
   }
 
   Future<void> test_setRoots_dotPackagesFile() async {
+    deleteTestPackageConfigJsonFile();
     var aaaLibPath = '/packages/aaa/lib';
     var a_path = '$aaaLibPath/a.dart';
 
@@ -1373,13 +1345,7 @@
   Future<void> test_setRoots_notDartFile_fixDataYaml() async {
     var path = '$testPackageLibPath/fix_data.yaml';
 
-    // Make sure that it is a package.
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder(),
-    );
-
-    // So, `lib/fix_data.yaml` will be analyzed.
+    // `lib/fix_data.yaml` will be analyzed.
     newFile(path, content: '0: 1');
 
     await setRoots(included: [workspaceRootPath], excluded: []);
@@ -1395,9 +1361,9 @@
 class A {}
 ''');
 
-    writePackageConfig(
-      '$testPackageRootPath/.dart_tool/package_config.json',
-      PackageConfigFileBuilder()..add(name: 'aaa', rootPath: aaaRootPath),
+    writeTestPackageConfig(
+      config: PackageConfigFileBuilder()
+        ..add(name: 'aaa', rootPath: aaaRootPath),
     );
 
     newFile(testFilePath, content: '''
@@ -1454,8 +1420,7 @@
         InstrumentationService.NULL_SERVICE);
     handler = AnalysisDomainHandler(server);
     // listen for notifications
-    var notificationStream = serverChannel.notificationController.stream;
-    notificationStream.listen((Notification notification) {
+    serverChannel.notifications.listen((Notification notification) {
       if (notification.event == ANALYSIS_NOTIFICATION_ERRORS) {
         var decoded = AnalysisErrorsParams.fromNotification(notification);
         filesErrors[decoded.file] = decoded.errors;
@@ -1763,7 +1728,7 @@
   }
 }
 
-class _AnalysisDomainTest extends AbstractAnalysisTest {
+class _AnalysisDomainTest extends PubPackageAnalysisServerTest {
   final Map<String, List<AnalysisError>> filesErrors = {};
 
   /// The files for which `analysis.flushResults` was received.
@@ -1801,10 +1766,6 @@
     }
   }
 
-  void writePackageConfig(String path, PackageConfigFileBuilder config) {
-    newFile(path, content: config.toContent(toUriStr: toUriStr));
-  }
-
   void _assertAnalyzedFiles({
     required List<String> hasErrors,
     List<String> noErrors = const [],
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 0ecd2f7..37bf033 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -2951,10 +2951,20 @@
 
   String get workspaceRootPath => '/home';
 
+  void deleteTestPackageAnalysisOptionsFile() {
+    deleteAnalysisOptionsYamlFile(testPackageRootPath);
+  }
+
+  void deleteTestPackageConfigJsonFile() {
+    deletePackageConfigJsonFile(testPackageRootPath);
+  }
+
   Future<Response> handleRequest(Request request) async {
     return await serverChannel.sendRequest(request);
   }
 
+  void processNotification(Notification notification) {}
+
   Future<void> setRoots({
     required List<String> included,
     required List<String> excluded,
@@ -2988,6 +2998,8 @@
       ),
     );
 
+    serverChannel.notifications.listen(processNotification);
+
     server = AnalysisServer(
       serverChannel,
       resourceProvider,
diff --git a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
index c082771..867272e 100644
--- a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
+++ b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
@@ -14,6 +14,11 @@
 
   String convertPath(String path) => resourceProvider.convertPath(path);
 
+  void deleteAnalysisOptionsYamlFile(String directoryPath) {
+    var path = join(directoryPath, file_paths.analysisOptionsYaml);
+    deleteFile(path);
+  }
+
   void deleteFile(String path) {
     String convertedPath = convertPath(path);
     resourceProvider.deleteFile(convertedPath);
@@ -24,6 +29,15 @@
     resourceProvider.deleteFolder(convertedPath);
   }
 
+  void deletePackageConfigJsonFile(String directoryPath) {
+    var path = join(
+      directoryPath,
+      file_paths.dotDartTool,
+      file_paths.packageConfigJson,
+    );
+    deleteFile(path);
+  }
+
   File getFile(String path) {
     String convertedPath = convertPath(path);
     return resourceProvider.getFile(convertedPath);
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index a37565a..3c65323 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -1195,7 +1195,8 @@
 //   R2 : arguments array.
 //   R3 : current thread.
 void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
-  READS_RETURN_ADDRESS_FROM_LR(__ Push(LR));  // Marker for the profiler.
+  // Marker for the profiler.
+  NOT_IN_PRODUCT(READS_RETURN_ADDRESS_FROM_LR(__ Push(LR)));
   SPILLS_LR_TO_FRAME(__ EnterFrame((1 << FP) | (1 << LR), 0));
 
   // Push code object to PC marker slot.
@@ -1318,7 +1319,7 @@
 
   // Restore the frame pointer and return.
   RESTORES_LR_FROM_FRAME(__ LeaveFrame((1 << FP) | (1 << LR)));
-  __ Drop(1);
+  NOT_IN_PRODUCT(__ Drop(1));  // Drop profiler marker.
   __ Ret();
 }
 
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 6dc4dbe..e32707b 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -1365,7 +1365,8 @@
   // from over-writing Dart frames.
   __ mov(SP, CSP);
   __ SetupCSPFromThread(R3);
-  READS_RETURN_ADDRESS_FROM_LR(__ Push(LR));  // Marker for the profiler.
+  // Marker for the profiler.
+  NOT_IN_PRODUCT(READS_RETURN_ADDRESS_FROM_LR(__ Push(LR)));
   __ EnterFrame(0);
 
   // Push code object to PC marker slot.
@@ -1488,7 +1489,7 @@
 
   // Restore the frame pointer and C stack pointer and return.
   __ LeaveFrame();
-  __ Drop(1);
+  NOT_IN_PRODUCT(__ Drop(1));  // Drop profiler marker.
   __ RestoreCSP();
   __ ret();
 }
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 68b3b4c..52f6ed0 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -969,7 +969,7 @@
   const intptr_t kArgumentsOffset = 5 * target::kWordSize;
   const intptr_t kThreadOffset = 6 * target::kWordSize;
 
-  __ pushl(Address(ESP, 0));  // Marker for the profiler.
+  NOT_IN_PRODUCT(__ pushl(Address(ESP, 0)));  // Marker for the profiler.
   __ EnterFrame(0);
 
   // Push code object to PC marker slot.
@@ -1084,7 +1084,7 @@
 
   // Restore the frame pointer.
   __ LeaveFrame();
-  __ popl(ECX);
+  NOT_IN_PRODUCT(__ popl(ECX));  // Drop profiler marker.
 
   __ ret();
 }
diff --git a/runtime/vm/compiler/stub_code_compiler_riscv.cc b/runtime/vm/compiler/stub_code_compiler_riscv.cc
index 14dd9f3..f4a17da 100644
--- a/runtime/vm/compiler/stub_code_compiler_riscv.cc
+++ b/runtime/vm/compiler/stub_code_compiler_riscv.cc
@@ -1276,7 +1276,7 @@
 void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
   __ Comment("InvokeDartCodeStub");
 
-  __ PushRegister(RA);  // Marker for the profiler.
+  NOT_IN_PRODUCT(__ PushRegister(RA));  // Marker for the profiler.
   __ EnterFrame(0);
 
   // Push code object to PC marker slot.
@@ -1396,7 +1396,7 @@
 
   // Restore the frame pointer and C stack pointer and return.
   __ LeaveFrame();
-  __ Drop(1);
+  __ NOT_IN_PRODUCT(__ Drop(1));  // Drop profiler marker.
   __ ret();
 }
 
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index de42236..0268696 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -1375,7 +1375,7 @@
 //   RDX : arguments array.
 //   RCX : current thread.
 void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
-  __ pushq(Address(RSP, 0));  // Marker for the profiler.
+  NOT_IN_PRODUCT(__ pushq(Address(RSP, 0)));  // Marker for the profiler.
   __ EnterFrame(0);
 
   const Register kTargetReg = CallingConventions::kArg1Reg;
@@ -1518,7 +1518,7 @@
 
   // Restore the frame pointer.
   __ LeaveFrame();
-  __ popq(RCX);
+  NOT_IN_PRODUCT(__ popq(RCX));  // Drop profiler marker.
 
   __ ret();
 }
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 77d6949..7f87db9 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -1373,7 +1373,7 @@
 
   // Multiplier which will be used to scale operands of DW_CFA_offset and
   // DW_CFA_val_offset.
-  const intptr_t kDataAlignment = compiler::target::kWordSize;
+  const intptr_t kDataAlignment = -compiler::target::kWordSize;
 
   static const uint8_t DW_EH_PE_pcrel = 0x10;
   static const uint8_t DW_EH_PE_sdata4 = 0x0b;
@@ -1395,12 +1395,20 @@
         ConcreteRegister(LINK_REGISTER));  // Return address register
     dwarf_stream.uleb128(1);               // Augmentation size
     dwarf_stream.u1(DW_EH_PE_pcrel | DW_EH_PE_sdata4);  // FDE encoding.
-    // CFA is FP+0
+    // CFA is caller's SP (FP+kCallerSpSlotFromFp*kWordSize)
     dwarf_stream.u1(Dwarf::DW_CFA_def_cfa);
     dwarf_stream.uleb128(FP);
-    dwarf_stream.uleb128(0);
+    dwarf_stream.uleb128(kCallerSpSlotFromFp * compiler::target::kWordSize);
   });
 
+  // Emit rule defining that |reg| value is stored at CFA+offset.
+  const auto cfa_offset = [&](Register reg, intptr_t offset) {
+    const intptr_t scaled_offset = offset / kDataAlignment;
+    RELEASE_ASSERT(scaled_offset >= 0);
+    dwarf_stream.u1(Dwarf::DW_CFA_offset | reg);
+    dwarf_stream.uleb128(scaled_offset);
+  };
+
   // Emit an FDE covering each .text section.
   for (const auto& portion : text_section->portions()) {
     ASSERT(portion.symbol_name != nullptr);  // Needed for relocations.
@@ -1413,27 +1421,17 @@
       dwarf_stream.u4(portion.size);           // Size.
       dwarf_stream.u1(0);                      // Augmentation Data length.
 
-      // FP at FP+kSavedCallerPcSlotFromFp*kWordSize
-      COMPILE_ASSERT(kSavedCallerFpSlotFromFp >= 0);
-      dwarf_stream.u1(Dwarf::DW_CFA_offset | FP);
-      dwarf_stream.uleb128(kSavedCallerFpSlotFromFp);
+      // Caller FP at FP+kSavedCallerPcSlotFromFp*kWordSize,
+      // where FP is CFA - kCallerSpSlotFromFp*kWordSize.
+      COMPILE_ASSERT((kSavedCallerFpSlotFromFp - kCallerSpSlotFromFp) <= 0);
+      cfa_offset(FP,
+                 (kSavedCallerFpSlotFromFp - kCallerSpSlotFromFp) * kWordSize);
 
-      // LR at FP+kSavedCallerPcSlotFromFp*kWordSize
-      COMPILE_ASSERT(kSavedCallerPcSlotFromFp >= 0);
-      dwarf_stream.u1(Dwarf::DW_CFA_offset | ConcreteRegister(LINK_REGISTER));
-      dwarf_stream.uleb128(kSavedCallerPcSlotFromFp);
-
-      // SP is FP+kCallerSpSlotFromFp*kWordSize
-      COMPILE_ASSERT(kCallerSpSlotFromFp >= 0);
-      dwarf_stream.u1(Dwarf::DW_CFA_val_offset);
-#if defined(TARGET_ARCH_ARM64)
-      dwarf_stream.uleb128(ConcreteRegister(CSP));
-#elif defined(TARGET_ARCH_ARM)
-      dwarf_stream.uleb128(SP);
-#else
-#error "Unsupported .eh_frame architecture"
-#endif
-      dwarf_stream.uleb128(kCallerSpSlotFromFp);
+      // Caller LR at FP+kSavedCallerPcSlotFromFp*kWordSize,
+      // where FP is CFA - kCallerSpSlotFromFp*kWordSize
+      COMPILE_ASSERT((kSavedCallerPcSlotFromFp - kCallerSpSlotFromFp) <= 0);
+      cfa_offset(ConcreteRegister(LINK_REGISTER),
+                 (kSavedCallerPcSlotFromFp - kCallerSpSlotFromFp) * kWordSize);
     });
   }
 
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 3661d07..4528f28 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -1294,97 +1294,31 @@
   // CFA = Canonical frame address
   assembly_stream_->WriteString(".cfi_startproc\n");
 
-#if defined(TARGET_ARCH_X64)
-  assembly_stream_->WriteString(".cfi_def_cfa rbp, 0\n");  // CFA is fp+0
-  assembly_stream_->WriteString(
-      ".cfi_offset rbp, 0\n");  // saved fp is *(CFA+0)
-  assembly_stream_->WriteString(
-      ".cfi_offset rip, 8\n");  // saved pc is *(CFA+8)
-  // saved sp is CFA+16
-  // Would prefer to use ".cfi_value_offset sp, 16", but this requires gcc
-  // newer than late 2016. Can't emit .cfi_value_offset using .cfi_scape
-  // because DW_CFA_val_offset uses scaled operand and we don't know what
-  // data alignment factor will be choosen by the assembler when emitting CIE.
-  // DW_CFA_expression          0x10
-  // uleb128 register (rsp)        7   (DWARF register number)
-  // uleb128 size of operation     2
-  // DW_OP_plus_uconst          0x23
-  // uleb128 addend               16
-  assembly_stream_->WriteString(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
+  // Below .cfi_def_cfa defines CFA as caller's SP, while .cfi_offset R, offs
+  // tells unwinder that caller's value of register R is stored at address
+  // CFA+offs.
 
+#if defined(TARGET_ARCH_X64)
+  assembly_stream_->WriteString(".cfi_def_cfa rbp, 16\n");
+  assembly_stream_->WriteString(".cfi_offset rbp, -16\n");
+  assembly_stream_->WriteString(".cfi_offset rip, -8\n");
 #elif defined(TARGET_ARCH_ARM64)
   COMPILE_ASSERT(R29 == FP);
   COMPILE_ASSERT(R30 == LINK_REGISTER);
-  assembly_stream_->WriteString(".cfi_def_cfa x29, 0\n");  // CFA is fp+0
-  assembly_stream_->WriteString(
-      ".cfi_offset x29, 0\n");  // saved fp is *(CFA+0)
-  assembly_stream_->WriteString(
-      ".cfi_offset x30, 8\n");  // saved pc is *(CFA+8)
-  // saved sp is CFA+16
-  // Would prefer to use ".cfi_value_offset sp, 16", but this requires gcc
-  // newer than late 2016. Can't emit .cfi_value_offset using .cfi_scape
-  // because DW_CFA_val_offset uses scaled operand and we don't know what
-  // data alignment factor will be choosen by the assembler when emitting CIE.
-#if defined(DART_TARGET_OS_ANDROID)
-  // On Android libunwindstack has a bug (b/191113792): it does not push
-  // CFA value to the expression stack before evaluating expression given
-  // to DW_CFA_expression. We have to workaround this bug by manually pushing
-  // CFA (R11) to the stack using DW_OP_breg29 0.
-  // DW_CFA_expression          0x10
-  // uleb128 register (x31)       31
-  // uleb128 size of operation     4
-  // DW_OP_breg11               0x8d (0x70 + 29)
-  // sleb128 offset                0
-  // DW_OP_plus_uconst          0x23
-  // uleb128 addend               16
-  assembly_stream_->WriteString(".cfi_escape 0x10, 31, 4, 0x8d, 0, 0x23, 16\n");
-#else
-  // DW_CFA_expression          0x10
-  // uleb128 register (x31)       31
-  // uleb128 size of operation     2
-  // DW_OP_plus_uconst          0x23
-  // uleb128 addend               16
-  assembly_stream_->WriteString(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
-#endif
-
+  assembly_stream_->WriteString(".cfi_def_cfa x29, 16\n");
+  assembly_stream_->WriteString(".cfi_offset x29, -16\n");
+  assembly_stream_->WriteString(".cfi_offset x30, -8\n");
 #elif defined(TARGET_ARCH_ARM)
 #if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_MACOS_IOS)
   COMPILE_ASSERT(FP == R7);
-  assembly_stream_->WriteString(".cfi_def_cfa r7, 0\n");  // CFA is fp+0
-  assembly_stream_->WriteString(".cfi_offset r7, 0\n");  // saved fp is *(CFA+0)
+  assembly_stream_->WriteString(".cfi_def_cfa r7, 8\n");
+  assembly_stream_->WriteString(".cfi_offset r7, -8\n");
 #else
   COMPILE_ASSERT(FP == R11);
-  assembly_stream_->WriteString(".cfi_def_cfa r11, 0\n");  // CFA is fp+0
-  assembly_stream_->WriteString(
-      ".cfi_offset r11, 0\n");  // saved fp is *(CFA+0)
+  assembly_stream_->WriteString(".cfi_def_cfa r11, 8\n");
+  assembly_stream_->WriteString(".cfi_offset r11, -8\n");
 #endif
-  assembly_stream_->WriteString(".cfi_offset lr, 4\n");  // saved pc is *(CFA+4)
-  // saved sp is CFA+8
-  // Would prefer to use ".cfi_value_offset sp, 16", but this requires gcc
-  // newer than late 2016. Can't emit .cfi_value_offset using .cfi_scape
-  // because DW_CFA_val_offset uses scaled operand and we don't know what
-  // data alignment factor will be choosen by the assembler when emitting CIE.
-#if defined(DART_TARGET_OS_ANDROID)
-  // On Android libunwindstack has a bug (b/191113792): it does not push
-  // CFA value to the expression stack before evaluating expression given
-  // to DW_CFA_expression. We have to workaround this bug by manually pushing
-  // CFA (R11) to the stack using DW_OP_breg11 0.
-  // DW_CFA_expression          0x10
-  // uleb128 register (sp)        13
-  // uleb128 size of operation     4
-  // DW_OP_breg11               0x7b (0x70 + 11)
-  // sleb128 offset                0
-  // DW_OP_plus_uconst          0x23
-  // uleb128 addend                8
-  assembly_stream_->WriteString(".cfi_escape 0x10, 31, 4, 0x7b, 0, 0x23, 16\n");
-#else
-  // DW_CFA_expression          0x10
-  // uleb128 register (sp)        13
-  // uleb128 size of operation     2
-  // DW_OP_plus_uconst          0x23
-  // uleb128 addend                8
-  assembly_stream_->WriteString(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
-#endif
+  assembly_stream_->WriteString(".cfi_offset lr, -4\n");
 
 // libunwind on ARM may use .ARM.exidx instead of .debug_frame
 #if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
diff --git a/tools/VERSION b/tools/VERSION
index 96ecaf9..81d0e2a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 181
+PRERELEASE 182
 PRERELEASE_PATCH 0
\ No newline at end of file