Version 2.19.0-70.0.dev

Merge commit 'f2f4b6df49531dbce7ea72c437ac8f520fa9881d' into 'dev'
diff --git a/pkg/front_end/test/crashing_test_case_minimizer.dart b/pkg/front_end/test/crashing_test_case_minimizer.dart
index 55c2b69..e63fe77 100644
--- a/pkg/front_end/test/crashing_test_case_minimizer.dart
+++ b/pkg/front_end/test/crashing_test_case_minimizer.dart
@@ -50,12 +50,12 @@
           }
         } else if (arg.startsWith("--widgetTransformation")) {
           settings.widgetTransformation = true;
-        } else if (arg.startsWith("--target=VM")) {
-          settings.targetString = "VM";
+        } else if (arg.startsWith("--target=vm")) {
+          settings.targetString = "vm";
         } else if (arg.startsWith("--target=flutter")) {
           settings.targetString = "flutter";
-        } else if (arg.startsWith("--target=ddc")) {
-          settings.targetString = "ddc";
+        } else if (arg.startsWith("--target=dartdevc")) {
+          settings.targetString = "dartdevc";
         } else if (arg.startsWith("--target=dart2js")) {
           settings.targetString = "dart2js";
         } else if (arg == "--noTryToDeleteEmptyFilesUpFront") {
diff --git a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
index 7bca147..3e6e11d 100644
--- a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
+++ b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
@@ -735,7 +735,7 @@
 type: newworld""");
     if (_settings.widgetTransformation) {
       print("trackWidgetCreation: true");
-      print("target: DDC # basically needed for widget creation to be run");
+      print("target: dartdevc # needed for widget creation to be run");
     }
     print("""
 worlds:
@@ -1939,13 +1939,13 @@
         trackWidgetCreation: _settings.widgetTransformation);
     Target target;
     switch (_settings.targetString) {
-      case "VM":
+      case "vm":
         target = new VmTarget(targetFlags);
         break;
       case "flutter":
         target = new FlutterTarget(targetFlags);
         break;
-      case "ddc":
+      case "dartdevc":
         target = new DevCompilerTarget(targetFlags);
         break;
       case "dart2js":
diff --git a/pkg/front_end/test/incremental_suite.dart b/pkg/front_end/test/incremental_suite.dart
index f6c4e9e..006b93a 100644
--- a/pkg/front_end/test/incremental_suite.dart
+++ b/pkg/front_end/test/incremental_suite.dart
@@ -169,15 +169,15 @@
   static const Property<String?> nnbdMode =
       Property.optional('nnbdMode', StringValue(options: {nnbdMode_strong}));
 
-  static const String target_none = 'None';
-  static const String target_ddc = 'DDC';
+  static const String target_none = 'none';
+  static const String target_dartdevc = 'dartdevc';
   static const String target_dart2js = 'dart2js';
-  static const String target_vm = 'VM';
+  static const String target_vm = 'vm';
 
   static const Property<String?> target = Property.optional(
       'target',
       StringValue(
-          options: {target_none, target_ddc, target_dart2js, target_vm}));
+          options: {target_none, target_dartdevc, target_dart2js, target_vm}));
 }
 
 /// Yaml properties for a [World] within a [NewWorldTest].
@@ -1073,7 +1073,7 @@
     if (targetName != null) {
       if (targetName == NewWorldTestProperties.target_none) {
         target = new NoneTarget(targetFlags);
-      } else if (targetName == NewWorldTestProperties.target_ddc) {
+      } else if (targetName == NewWorldTestProperties.target_dartdevc) {
         target = new DevCompilerTarget(targetFlags);
       } else if (targetName == NewWorldTestProperties.target_dart2js) {
         target = new Dart2jsTarget("dart2js", targetFlags);
diff --git a/pkg/front_end/testcases/incremental/changing_modules_13.yaml b/pkg/front_end/testcases/incremental/changing_modules_13.yaml
index 050087a..fb2ea73 100644
--- a/pkg/front_end/testcases/incremental/changing_modules_13.yaml
+++ b/pkg/front_end/testcases/incremental/changing_modules_13.yaml
@@ -5,7 +5,7 @@
 # Reproduction of https://github.com/flutter/flutter/issues/40966.
 
 type: newworld
-target: None
+target: none
 modules:
   module:
     module/a.dart: |
diff --git a/pkg/front_end/testcases/incremental/changing_modules_14.yaml b/pkg/front_end/testcases/incremental/changing_modules_14.yaml
index d3973fe..9f7e7cf 100644
--- a/pkg/front_end/testcases/incremental/changing_modules_14.yaml
+++ b/pkg/front_end/testcases/incremental/changing_modules_14.yaml
@@ -8,7 +8,7 @@
 
 type: newworld
 # Set to DDC for compiling modules as outline.
-target: DDC
+target: dartdevc
 modules:
   moduleC:
     moduleC/lib.dart: |
diff --git a/pkg/front_end/testcases/incremental/changing_modules_15.yaml b/pkg/front_end/testcases/incremental/changing_modules_15.yaml
index ee0493c..23d322a 100644
--- a/pkg/front_end/testcases/incremental/changing_modules_15.yaml
+++ b/pkg/front_end/testcases/incremental/changing_modules_15.yaml
@@ -8,7 +8,7 @@
 
 type: newworld
 # Set to DDC for compiling modules as outline.
-target: DDC
+target: dartdevc
 modules:
   moduleC:
     moduleC/lib.dart: |
diff --git a/pkg/front_end/testcases/incremental/changing_modules_16.yaml b/pkg/front_end/testcases/incremental/changing_modules_16.yaml
index 69ad3b9..3552cd5 100644
--- a/pkg/front_end/testcases/incremental/changing_modules_16.yaml
+++ b/pkg/front_end/testcases/incremental/changing_modules_16.yaml
@@ -8,7 +8,7 @@
 # This is essentially equivalent to not loading a needed component.
 
 type: newworld
-target: DDC
+target: dartdevc
 modules:
   moduleA:
     moduleA/x/lib.dart: |
diff --git a/pkg/front_end/testcases/incremental/constructor_change.yaml b/pkg/front_end/testcases/incremental/constructor_change.yaml
index 08eb555..ed39afdf 100644
--- a/pkg/front_end/testcases/incremental/constructor_change.yaml
+++ b/pkg/front_end/testcases/incremental/constructor_change.yaml
@@ -6,7 +6,7 @@
 # Try to mess up the hierarchy.
 
 type: newworld
-target: DDC
+target: dartdevc
 worlds:
   - entry: main.dart
     experiments: alternative-invalidation-strategy
diff --git a/pkg/front_end/testcases/incremental/crash_01.yaml b/pkg/front_end/testcases/incremental/crash_01.yaml
index d8c9c08..6cc3879 100644
--- a/pkg/front_end/testcases/incremental/crash_01.yaml
+++ b/pkg/front_end/testcases/incremental/crash_01.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: DDC # basically needed for widget creation to be run
+target: dartdevc # basically needed for widget creation to be run
 worlds:
   - entry: app/main.dart
     sources:
diff --git a/pkg/front_end/testcases/incremental/crash_02.yaml b/pkg/front_end/testcases/incremental/crash_02.yaml
index 7a10c94..6182857 100644
--- a/pkg/front_end/testcases/incremental/crash_02.yaml
+++ b/pkg/front_end/testcases/incremental/crash_02.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: DDC # basically needed for widget creation to be run
+target: dartdevc # basically needed for widget creation to be run
 worlds:
   - entry: app/main.dart
     sources:
diff --git a/pkg/front_end/testcases/incremental/crash_03.yaml b/pkg/front_end/testcases/incremental/crash_03.yaml
index 4d1be72..109f87a 100644
--- a/pkg/front_end/testcases/incremental/crash_03.yaml
+++ b/pkg/front_end/testcases/incremental/crash_03.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: DDC # basically needed for widget creation to be run
+target: dartdevc # basically needed for widget creation to be run
 worlds:
   - entry: app/main.dart
     sources:
diff --git a/pkg/front_end/testcases/incremental/crash_04.yaml b/pkg/front_end/testcases/incremental/crash_04.yaml
index 7a10c94..6182857 100644
--- a/pkg/front_end/testcases/incremental/crash_04.yaml
+++ b/pkg/front_end/testcases/incremental/crash_04.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: DDC # basically needed for widget creation to be run
+target: dartdevc # basically needed for widget creation to be run
 worlds:
   - entry: app/main.dart
     sources:
diff --git a/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change.yaml b/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change.yaml
index 38de9ca..a2938ad 100644
--- a/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change.yaml
+++ b/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: VM
+target: vm
 worlds:
   - entry: main.dart
     sources:
diff --git a/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change_02.yaml b/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change_02.yaml
index fa61ced..fd5d892 100644
--- a/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change_02.yaml
+++ b/pkg/front_end/testcases/incremental/error_on_recompile_with_no_change_02.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: VM
+target: vm
 worlds:
   - entry: main.dart
     sources:
diff --git a/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml b/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml
index 1322120..079b1a3 100644
--- a/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml
+++ b/pkg/front_end/testcases/incremental/flutter_issue_66122.yaml
@@ -6,7 +6,7 @@
 # https://github.com/flutter/flutter/issues/66122
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml b/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml
index dd756a9..979ff19 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml
index 95b124a..6e31982 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_const.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml b/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml
index 6bb2b2b..a2b05ff 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transform_nnbd.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml b/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml
index 1853f91..84da5a7 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transformer_43371.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml b/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml
index 0c8de3b..63ecfb5 100644
--- a/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml
+++ b/pkg/front_end/testcases/incremental/flutter_widget_transformer_non_const.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/front_end/testcases/incremental/mixin_application_declares.yaml b/pkg/front_end/testcases/incremental/mixin_application_declares.yaml
index a7ec07e..4c0219b 100644
--- a/pkg/front_end/testcases/incremental/mixin_application_declares.yaml
+++ b/pkg/front_end/testcases/incremental/mixin_application_declares.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: None
+target: none
 worlds:
   - entry: main.dart
     experiments: alternative-invalidation-strategy
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml b/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml
index 5977f3e..7ce6402 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml
+++ b/pkg/front_end/testcases/incremental/no_outline_change_44_flutter.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: DDC # basically needed for widget creation to be run
+target: dartdevc # basically needed for widget creation to be run
 worlds:
   - entry: flutter_gallery/lib/main.dart
     experiments: alternative-invalidation-strategy
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_45_flutter.yaml b/pkg/front_end/testcases/incremental/no_outline_change_45_flutter.yaml
index 004729a..27f769a 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_45_flutter.yaml
+++ b/pkg/front_end/testcases/incremental/no_outline_change_45_flutter.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: VM
+target: vm
 worlds:
   - entry: main.dart
     experiments: alternative-invalidation-strategy
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_45_flutter_prime_1.yaml b/pkg/front_end/testcases/incremental/no_outline_change_45_flutter_prime_1.yaml
index 8e05100..5de6466 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_45_flutter_prime_1.yaml
+++ b/pkg/front_end/testcases/incremental/no_outline_change_45_flutter_prime_1.yaml
@@ -6,7 +6,7 @@
 
 type: newworld
 trackWidgetCreation: true
-target: VM
+target: vm
 worlds:
   - entry: main.dart
     experiments: alternative-invalidation-strategy
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_46.yaml b/pkg/front_end/testcases/incremental/no_outline_change_46.yaml
index 5917122..3fc668c 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_46.yaml
+++ b/pkg/front_end/testcases/incremental/no_outline_change_46.yaml
@@ -5,7 +5,7 @@
 # Reproduce a crash.
 
 type: newworld
-target: VM
+target: vm
 worlds:
   - entry: main.dart
     experiments: alternative-invalidation-strategy
diff --git a/pkg/front_end/testcases/incremental/super_key.yaml b/pkg/front_end/testcases/incremental/super_key.yaml
index df78096..2acc66e 100644
--- a/pkg/front_end/testcases/incremental/super_key.yaml
+++ b/pkg/front_end/testcases/incremental/super_key.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 type: newworld
-target: DDC
+target: dartdevc
 trackWidgetCreation: true
 worlds:
   - entry: main.dart
diff --git a/pkg/native_stack_traces/CHANGELOG.md b/pkg/native_stack_traces/CHANGELOG.md
index a1b47ce..92ccfee 100644
--- a/pkg/native_stack_traces/CHANGELOG.md
+++ b/pkg/native_stack_traces/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.5.1
+
+- Parse new OS and architecture information from non-symbolic stack
+  trace headers and store that information in PCOffsets when available.
+
 ## 0.5.0
 
 - Require Dart >= 2.17 (enhanced enum support)
diff --git a/pkg/native_stack_traces/bin/decode.dart b/pkg/native_stack_traces/bin/decode.dart
index cb44a02..841cd8b 100644
--- a/pkg/native_stack_traces/bin/decode.dart
+++ b/pkg/native_stack_traces/bin/decode.dart
@@ -200,7 +200,8 @@
   }
 
   PCOffset? convertAddress(StackTraceHeader header, String s) {
-    final parsedOffset = tryParseSymbolOffset(s, forceHexadecimal);
+    final parsedOffset =
+        tryParseSymbolOffset(s, forceHexadecimal: forceHexadecimal);
     if (parsedOffset != null) return parsedOffset;
 
     final address = tryParseIntAddress(s);
@@ -236,7 +237,7 @@
     isolateStart = address;
   }
 
-  final header = StackTraceHeader(isolateStart, vmStart);
+  final header = StackTraceHeader.fromStarts(isolateStart, vmStart);
 
   final locations = <PCOffset>[];
   for (final String s in [
diff --git a/pkg/native_stack_traces/lib/src/convert.dart b/pkg/native_stack_traces/lib/src/convert.dart
index 0bc8f24..ebcdffd 100644
--- a/pkg/native_stack_traces/lib/src/convert.dart
+++ b/pkg/native_stack_traces/lib/src/convert.dart
@@ -11,45 +11,99 @@
 String _stackTracePiece(CallInfo call, int depth) =>
     '#${depth.toString().padRight(6)} $call';
 
-// A pattern matching the last line of the non-symbolic stack trace header.
-//
-// Currently, this happens to include the only pieces of information from the
-// stack trace header we need: the absolute addresses during program
-// execution of the start of the isolate and VM instructions.
+// The initial header line in a non-symbolic stack trace.
+const _headerStartLine =
+    '*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***';
+
+// A pattern matching the os/arch line of the non-symbolic stack trace header.
 //
 // This RegExp has been adjusted to parse the header line found in
 // non-symbolic stack traces and the modified version in signal handler stack
 // traces.
-final _headerEndRE = RegExp(r'isolate_instructions(?:=|: )([\da-f]+),? '
-    r'vm_instructions(?:=|: )([\da-f]+)');
+final _osArchLineRE = RegExp(r'os(?:=|: )(\S+?),? '
+    r'arch(?:=|: )(\S+?),? comp(?:=|: )(yes|no),? sim(?:=|: )(yes|no)');
 
-// Parses instructions section information into a new [StackTraceHeader].
+// A pattern matching the last line of the non-symbolic stack trace header.
 //
-// Returns a new [StackTraceHeader] if [line] contains the needed header
-// information, otherwise returns `null`.
-StackTraceHeader? _parseInstructionsLine(String line) {
-  final match = _headerEndRE.firstMatch(line);
-  if (match == null) return null;
-  final isolateAddr = int.parse(match[1]!, radix: 16);
-  final vmAddr = int.parse(match[2]!, radix: 16);
-  return StackTraceHeader(isolateAddr, vmAddr);
-}
+// This RegExp has been adjusted to parse the header line found in
+// non-symbolic stack traces and the modified version in signal handler stack
+// traces.
+final _instructionsLineRE = RegExp(r'isolate_instructions(?:=|: )([\da-f]+),? '
+    r'vm_instructions(?:=|: )([\da-f]+)');
 
 /// Header information for a non-symbolic Dart stack trace.
 class StackTraceHeader {
-  final int _isolateStart;
-  final int _vmStart;
+  String? _os;
+  String? _arch;
+  bool? _compressed;
+  bool? _simulated;
+  int? _isolateStart;
+  int? _vmStart;
 
-  StackTraceHeader(this._isolateStart, this._vmStart);
+  String? get os => _os;
+  String? get architecture => _arch;
+  bool? get compressedPointers => _compressed;
+  bool? get usingSimulator => _simulated;
+
+  static StackTraceHeader fromStarts(int isolateStart, int vmStart) =>
+      StackTraceHeader()
+        .._isolateStart = isolateStart
+        .._vmStart = vmStart;
+
+  /// Try and parse the given line as one of the recognized lines in the
+  /// header of a non-symbolic stack trace.
+  ///
+  /// Returns whether the line was recognized and parsed successfully.
+  bool tryParseHeaderLine(String line) {
+    if (line.contains(_headerStartLine)) {
+      // This is the start of a new non-symbolic stack trace, so reset all the
+      // stored information to be parsed anew.
+      _os = null;
+      _arch = null;
+      _compressed = null;
+      _simulated = null;
+      _isolateStart = null;
+      _vmStart = null;
+      return true;
+    }
+    RegExpMatch? match = _osArchLineRE.firstMatch(line);
+    if (match != null) {
+      _os = match[1]!;
+      _arch = match[2]!;
+      _compressed = match[3]! == "yes";
+      _simulated = match[4]! == "yes";
+      // The architecture line always proceeds the instructions section line,
+      // so reset these to null just in case we missed the header line.
+      _isolateStart = null;
+      _vmStart = null;
+      return true;
+    }
+    match = _instructionsLineRE.firstMatch(line);
+    if (match != null) {
+      _isolateStart = int.parse(match[1]!, radix: 16);
+      _vmStart = int.parse(match[2]!, radix: 16);
+      return true;
+    }
+    return false;
+  }
 
   /// The [PCOffset] for the given absolute program counter address.
-  PCOffset offsetOf(int address) {
-    final isolateOffset = address - _isolateStart;
-    var vmOffset = address - _vmStart;
+  PCOffset? offsetOf(int address) {
+    if (_isolateStart == null || _vmStart == null) return null;
+    final isolateOffset = address - _isolateStart!;
+    var vmOffset = address - _vmStart!;
     if (vmOffset > 0 && vmOffset == min(vmOffset, isolateOffset)) {
-      return PCOffset(vmOffset, InstructionsSection.vm);
+      return PCOffset(vmOffset, InstructionsSection.vm,
+          os: _os,
+          architecture: _arch,
+          compressedPointers: _compressed,
+          usingSimulator: _simulated);
     } else {
-      return PCOffset(isolateOffset, InstructionsSection.isolate);
+      return PCOffset(isolateOffset, InstructionsSection.isolate,
+          os: _os,
+          architecture: _arch,
+          compressedPointers: _compressed,
+          usingSimulator: _simulated);
     }
   }
 }
@@ -81,7 +135,8 @@
 /// any hexdecimal digits will be parsed as decimal.
 ///
 /// Returns null if the string is not of the expected format.
-PCOffset? tryParseSymbolOffset(String s, [bool forceHexadecimal = false]) {
+PCOffset? tryParseSymbolOffset(String s,
+    {bool forceHexadecimal = false, StackTraceHeader? header}) {
   final match = _symbolOffsetRE.firstMatch(s);
   if (match == null) return null;
   final symbolString = match.namedGroup('symbol')!;
@@ -99,31 +154,38 @@
   if (offset == null) return null;
   switch (symbolString) {
     case constants.vmSymbolName:
-      return PCOffset(offset, InstructionsSection.vm);
+      return PCOffset(offset, InstructionsSection.vm,
+          os: header?.os,
+          architecture: header?.architecture,
+          compressedPointers: header?.compressedPointers,
+          usingSimulator: header?.usingSimulator);
     case constants.isolateSymbolName:
-      return PCOffset(offset, InstructionsSection.isolate);
+      return PCOffset(offset, InstructionsSection.isolate,
+          os: header?.os,
+          architecture: header?.architecture,
+          compressedPointers: header?.compressedPointers,
+          usingSimulator: header?.usingSimulator);
     default:
       break;
   }
   return null;
 }
 
-PCOffset? _retrievePCOffset(StackTraceHeader? header, RegExpMatch? match) {
+PCOffset? _retrievePCOffset(StackTraceHeader header, RegExpMatch? match) {
   if (match == null) return null;
   final restString = match.namedGroup('rest')!;
   // Try checking for symbol information first, since we don't need the header
   // information to translate it.
   if (restString.isNotEmpty) {
-    final offset = tryParseSymbolOffset(restString);
+    final offset = tryParseSymbolOffset(restString, header: header);
     if (offset != null) return offset;
   }
   // If we're parsing the absolute address, we can only convert it into
   // a PCOffset if we saw the instructions line of the stack trace header.
-  if (header != null) {
-    final addressString = match.namedGroup('absolute')!;
-    final address = int.parse(addressString, radix: 16);
-    return header.offsetOf(address);
-  }
+  final addressString = match.namedGroup('absolute')!;
+  final address = int.parse(addressString, radix: 16);
+  final pcOffset = header.offsetOf(address);
+  if (pcOffset != null) return pcOffset;
   // If all other cases failed, check for a virtual address. Until this package
   // depends on a version of Dart which only prints virtual addresses when the
   // virtual addresses in the snapshot are the same as in separately saved
@@ -131,18 +193,20 @@
   final virtualString = match.namedGroup('virtual');
   if (virtualString != null) {
     final address = int.parse(virtualString, radix: 16);
-    return PCOffset(address, InstructionsSection.none);
+    return PCOffset(address, InstructionsSection.none,
+        os: header.os,
+        architecture: header.architecture,
+        compressedPointers: header.compressedPointers,
+        usingSimulator: header.usingSimulator);
   }
   return null;
 }
 
 /// The [PCOffset]s for frames of the non-symbolic stack traces in [lines].
 Iterable<PCOffset> collectPCOffsets(Iterable<String> lines) sync* {
-  StackTraceHeader? header;
+  final header = StackTraceHeader();
   for (var line in lines) {
-    final parsedHeader = _parseInstructionsLine(line);
-    if (parsedHeader != null) {
-      header = parsedHeader;
+    if (header.tryParseHeaderLine(line)) {
       continue;
     }
     final match = _traceLineRE.firstMatch(line);
@@ -185,11 +249,10 @@
   @override
   Stream<String> bind(Stream<String> stream) async* {
     var depth = 0;
-    StackTraceHeader? header;
+    final header = StackTraceHeader();
     await for (final line in stream) {
-      final parsedHeader = _parseInstructionsLine(line);
-      if (parsedHeader != null) {
-        header = parsedHeader;
+      // If we successfully parse a header line, then we reset the depth to 0.
+      if (header.tryParseHeaderLine(line)) {
         depth = 0;
         yield line;
         continue;
diff --git a/pkg/native_stack_traces/lib/src/dwarf.dart b/pkg/native_stack_traces/lib/src/dwarf.dart
index 9944f2d..13fac70 100644
--- a/pkg/native_stack_traces/lib/src/dwarf.dart
+++ b/pkg/native_stack_traces/lib/src/dwarf.dart
@@ -1451,12 +1451,34 @@
 enum InstructionsSection { none, vm, isolate }
 
 /// A program counter address viewed as an offset into the appropriate
-/// instructions section of a Dart snapshot.
+/// instructions section of a Dart snapshot. Includes other information
+/// parsed from the corresponding stack trace header when possible.
 class PCOffset {
+  /// The offset into the corresponding instructions section.
   final int offset;
+
+  /// The instructions section into which this is an offset.
   final InstructionsSection section;
 
-  PCOffset(this.offset, this.section);
+  /// The operating system on which the stack trace was generated, when
+  /// available.
+  final String? os;
+
+  /// The architecture on which the stack trace was generated, when
+  /// available.
+  final String? architecture;
+
+  /// Whether compressed pointers were enabled, when available.
+  final bool? compressedPointers;
+
+  /// Whether the architecture was being simulated, when available.
+  final bool? usingSimulator;
+
+  PCOffset(this.offset, this.section,
+      {this.os,
+      this.architecture,
+      this.compressedPointers,
+      this.usingSimulator});
 
   /// The virtual address for this [PCOffset] in [dwarf].
   int virtualAddressIn(Dwarf dwarf) => dwarf.virtualAddressOf(this);
@@ -1469,7 +1491,7 @@
   /// to user or library code is returned.
   Iterable<CallInfo>? callInfoFrom(Dwarf dwarf,
           {bool includeInternalFrames = false}) =>
-      dwarf.callInfoFor(dwarf.virtualAddressOf(this),
+      dwarf.callInfoForPCOffset(this,
           includeInternalFrames: includeInternalFrames);
 
   @override
@@ -1477,10 +1499,38 @@
 
   @override
   bool operator ==(Object other) =>
-      other is PCOffset && offset == other.offset && section == other.section;
+      other is PCOffset &&
+      offset == other.offset &&
+      section == other.section &&
+      os == other.os &&
+      architecture == other.architecture &&
+      compressedPointers == other.compressedPointers &&
+      usingSimulator == other.usingSimulator;
 
   @override
-  String toString() => 'PCOffset($section, 0x${offset.toRadixString(16)})';
+  String toString() {
+    final buffer = StringBuffer();
+    buffer
+      ..write('PCOffset(')
+      ..write(section)
+      ..write(', 0x')
+      ..write(offset.toRadixString(16));
+    if (os != null) {
+      buffer
+        ..write(', ')
+        ..write(os!);
+    }
+    if (architecture != null) {
+      if (usingSimulator ?? false) {
+        buffer.write('SIM');
+      }
+      buffer.write(architecture!.toUpperCase());
+      if (compressedPointers ?? false) {
+        buffer.write('C');
+      }
+    }
+    return buffer.toString();
+  }
 }
 
 /// The DWARF debugging information for a Dart snapshot.
@@ -1583,6 +1633,19 @@
     return calls;
   }
 
+  /// The call information for the given [PCOffset]. There may be multiple
+  /// [CallInfo] objects returned for a single [PCOffset] when code has been
+  /// inlined.
+  ///
+  /// Returns null if the given address is invalid for the DWARF information.
+  ///
+  /// If [includeInternalFrames] is false, then only information corresponding
+  /// to user or library code is returned.
+  Iterable<CallInfo>? callInfoForPCOffset(PCOffset pcOffset,
+          {bool includeInternalFrames = false}) =>
+      callInfoFor(virtualAddressOf(pcOffset),
+          includeInternalFrames: includeInternalFrames);
+
   /// The virtual address in this DWARF information for the given [PCOffset].
   int virtualAddressOf(PCOffset pcOffset) {
     switch (pcOffset.section) {
diff --git a/pkg/native_stack_traces/pubspec.yaml b/pkg/native_stack_traces/pubspec.yaml
index 09ed948..2497e11 100644
--- a/pkg/native_stack_traces/pubspec.yaml
+++ b/pkg/native_stack_traces/pubspec.yaml
@@ -1,5 +1,5 @@
 name: native_stack_traces
-version: 0.5.0
+version: 0.5.1
 description: Utilities for working with non-symbolic stack traces.
 repository: https://github.com/dart-lang/sdk/tree/main/pkg/native_stack_traces
 
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 2241e87..e26d9fb 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -321,7 +321,7 @@
 class MigrationResolutionHooksImpl
     with ResolutionUtils
     implements MigrationResolutionHooks {
-  FixBuilder? _fixBuilder;
+  late final FixBuilder _fixBuilder;
 
   final Expando<List<CollectionElement>> _collectionElements = Expando();
 
@@ -340,7 +340,7 @@
 
   final Map<Expression, DartType?> _contextTypes = {};
 
-  TypeProvider get typeProvider => _fixBuilder!.typeProvider;
+  TypeProvider get typeProvider => _fixBuilder.typeProvider;
 
   @override
   void freshTypeParameterCreated(TypeParameterElement newTypeParameter,
@@ -352,7 +352,7 @@
   @override
   List<InterfaceType> getClassInterfaces(AbstractClassElementImpl element) {
     return _wrapExceptions(
-        _fixBuilder!.unit,
+        _fixBuilder.unit,
         () => element.interfacesInternal,
         () => [
               for (var interface in element.interfacesInternal)
@@ -364,8 +364,8 @@
   bool? getConditionalKnownValue(AstNode node) =>
       _wrapExceptions(node, () => null, () {
         // TODO(paulberry): handle conditional expressions.
-        var conditionalDiscard = _fixBuilder!._variables!
-            .getConditionalDiscard(_fixBuilder!.source, node);
+        var conditionalDiscard = _fixBuilder._variables!
+            .getConditionalDiscard(_fixBuilder.source, node);
         if (conditionalDiscard == null) {
           return null;
         } else {
@@ -373,12 +373,12 @@
             return null;
           }
           var conditionValue = conditionalDiscard.keepTrue;
-          (_fixBuilder!._getChange(node) as NodeChangeForConditional)
+          (_fixBuilder._getChange(node) as NodeChangeForConditional)
             ..conditionValue = conditionValue
             ..conditionReason = conditionalDiscard.reason;
           // If we're just issuing warnings, instruct the resolver to go ahead
           // and visit both branches of the conditional.
-          return _fixBuilder!.warnOnWeakCode! ? null : conditionValue;
+          return _fixBuilder.warnOnWeakCode! ? null : conditionValue;
         }
       });
 
@@ -401,8 +401,8 @@
 
   @override
   FunctionType getExecutableType(ElementImplWithFunctionType element) =>
-      _wrapExceptions(_fixBuilder!.unit, () => element.typeInternal, () {
-        var type = _fixBuilder!._computeMigratedType(element);
+      _wrapExceptions(_fixBuilder.unit, () => element.typeInternal, () {
+        var type = _fixBuilder._computeMigratedType(element);
         Element baseElement = element;
         if (baseElement is Member) {
           type = baseElement.substitution.substituteType(type);
@@ -413,17 +413,17 @@
   @override
   DartType getExtendedType(ExtensionElementImpl element) {
     return _wrapExceptions(
-        _fixBuilder!.unit,
+        _fixBuilder.unit,
         () => element.extendedTypeInternal,
-        () => _fixBuilder!._variables!.toFinalType(
-            _fixBuilder!._variables!.decoratedElementType(element)));
+        () => _fixBuilder._variables!.toFinalType(
+            _fixBuilder._variables!.decoratedElementType(element)));
   }
 
   @override
   DartType getFieldType(PropertyInducingElementImpl element) =>
-      _wrapExceptions(_fixBuilder!.unit, () => element.typeInternal, () {
+      _wrapExceptions(_fixBuilder.unit, () => element.typeInternal, () {
         assert(!element.isSynthetic);
-        return _fixBuilder!._computeMigratedType(element);
+        return _fixBuilder._computeMigratedType(element);
       });
 
   @override
@@ -443,10 +443,10 @@
 
   @override
   DartType? getTypeParameterBound(TypeParameterElementImpl element) {
-    var decoratedBound = _fixBuilder!._variables!
+    var decoratedBound = _fixBuilder._variables!
         .decoratedTypeParameterBound(element, allowNullUnparentedBounds: true);
     if (decoratedBound == null) return element.boundInternal;
-    var bound = _fixBuilder!._variables!.toFinalType(decoratedBound);
+    var bound = _fixBuilder._variables!.toFinalType(decoratedBound);
     if (bound.isDynamic) {
       return null;
     } else if (bound.isDartCoreObject &&
@@ -459,7 +459,7 @@
 
   @override
   DartType getVariableType(VariableElementImpl variable) =>
-      _wrapExceptions(_fixBuilder!.unit, () => variable.typeInternal, () {
+      _wrapExceptions(_fixBuilder.unit, () => variable.typeInternal, () {
         if (variable.library == null) {
           // This is a synthetic variable created during resolution (e.g. a
           // parameter of a function type), so the type it currently has is the
@@ -472,10 +472,10 @@
               enclosingElement.isSynthetic) {
             // This is the parameter of a synthetic getter, so it has the same
             // type as the corresponding variable.
-            return _fixBuilder!._computeMigratedType(enclosingElement.variable);
+            return _fixBuilder._computeMigratedType(enclosingElement.variable);
           }
         }
-        return _fixBuilder!._computeMigratedType(variable);
+        return _fixBuilder._computeMigratedType(variable);
       });
 
   @override
@@ -487,15 +487,14 @@
 
   @override
   bool isLibraryNonNullableByDefault(LibraryElementImpl element) {
-    return _fixBuilder!._graph.isBeingMigrated(element.source) ||
+    return _fixBuilder._graph.isBeingMigrated(element.source) ||
         element.isNonNullableByDefaultInternal;
   }
 
   @override
   bool isMethodInvocationNullAware(MethodInvocation node) {
     return node.isNullAware &&
-        (_shouldStayNullAware[node] ??=
-            _fixBuilder!._shouldStayNullAware(node));
+        (_shouldStayNullAware[node] ??= _fixBuilder._shouldStayNullAware(node));
   }
 
   /// Indicates whether the given [element] is a member of an extension on a
@@ -505,7 +504,7 @@
     if (element != null) {
       var enclosingElement = element.enclosingElement3;
       if (enclosingElement is ExtensionElement) {
-        return _fixBuilder!._typeSystem
+        return _fixBuilder._typeSystem
             .isPotentiallyNullable(enclosingElement.extendedType);
       }
     }
@@ -515,8 +514,7 @@
   @override
   bool isPropertyAccessNullAware(PropertyAccess node) {
     return node.isNullAware &&
-        (_shouldStayNullAware[node] ??=
-            _fixBuilder!._shouldStayNullAware(node));
+        (_shouldStayNullAware[node] ??= _fixBuilder._shouldStayNullAware(node));
   }
 
   @override
@@ -555,7 +553,7 @@
     var postMigrationType = parameter.type;
     if (postMigrationType != type) {
       // TODO(paulberry): test field formal parameters.
-      _fixBuilder!._addedParameterTypes[parameter] = postMigrationType;
+      _fixBuilder._addedParameterTypes[parameter] = postMigrationType;
       return postMigrationType;
     }
     return type;
@@ -579,13 +577,13 @@
       var handler = _PrefixExpressionHandler(node);
       _assignmentLikeExpressionHandlers[node] = handler;
       handler.handleLValueType(this, node.readType, node.writeType!);
-      handler.handleAssignmentRhs(this, _fixBuilder!.typeProvider.intType);
+      handler.handleAssignmentRhs(this, _fixBuilder.typeProvider.intType);
     } else if (node is PostfixExpression) {
       assert(_isIncrementOrDecrementOperator(node.operator.type));
       var handler = _PostfixExpressionHandler(node);
       _assignmentLikeExpressionHandlers[node] = handler;
       handler.handleLValueType(this, node.readType, node.writeType!);
-      handler.handleAssignmentRhs(this, _fixBuilder!.typeProvider.intType);
+      handler.handleAssignmentRhs(this, _fixBuilder.typeProvider.intType);
     } else {
       throw StateError('(${node.runtimeType}) $node');
     }
@@ -601,10 +599,10 @@
   DartType _addCastOrNullCheck(
       Expression node, DartType expressionType, DartType contextType) {
     var checks =
-        _fixBuilder!._variables!.expressionChecks(_fixBuilder!.source, node);
+        _fixBuilder._variables!.expressionChecks(_fixBuilder.source, node);
     var change = _createExpressionChange(node, expressionType, contextType);
     var info = AtomicEditInfo(change.description, checks?.edges ?? {});
-    (_fixBuilder!._getChange(node) as NodeChangeForExpression)
+    (_fixBuilder._getChange(node) as NodeChangeForExpression)
         .addExpressionChange(change, info);
     return change.resultType;
   }
@@ -613,8 +611,8 @@
   /// called [extensionName] from `package:collection/collection.dart`, and that
   /// the pubspec will be appropriately updated (if necessary).
   void _addCollectionPackageExtension(String extensionName) {
-    _fixBuilder!.neededCollectionPackageExtensions.add(extensionName);
-    _fixBuilder!._neededPackages['collection'] =
+    _fixBuilder.neededCollectionPackageExtensions.add(extensionName);
+    _fixBuilder._neededPackages['collection'] =
         Version.parse('1.15.0-nullsafety.4');
   }
 
@@ -622,10 +620,10 @@
       {AtomicEditInfo? info, HintComment? hint}) {
     var change = _createNullCheckChange(node, type, hint: hint);
     var checks =
-        _fixBuilder!._variables!.expressionChecks(_fixBuilder!.source, node);
+        _fixBuilder._variables!.expressionChecks(_fixBuilder.source, node);
     info ??= AtomicEditInfo(change.description, checks?.edges ?? {});
     var nodeChangeForExpression =
-        _fixBuilder!._getChange(node) as NodeChangeForExpression;
+        _fixBuilder._getChange(node) as NodeChangeForExpression;
     nodeChangeForExpression.addExpressionChange(change, info);
     return change.resultType;
   }
@@ -643,21 +641,20 @@
     }
     // Either a cast or a null check is needed.  We prefer to do a null
     // check if we can.
-    var nonNullType = _fixBuilder!._typeSystem.promoteToNonNull(expressionType);
-    if (_fixBuilder!._typeSystem.isSubtypeOf(nonNullType, contextType)) {
+    var nonNullType = _fixBuilder._typeSystem.promoteToNonNull(expressionType);
+    if (_fixBuilder._typeSystem.isSubtypeOf(nonNullType, contextType)) {
       return _createNullCheckChange(node, expressionType);
     } else {
       _flowAnalysis!.asExpression_end(node, contextType);
       return IntroduceAsChange(contextType,
-          isDowncast: _fixBuilder!._typeSystem
-              .isSubtypeOf(contextType, expressionType));
+          isDowncast:
+              _fixBuilder._typeSystem.isSubtypeOf(contextType, expressionType));
     }
   }
 
   ExpressionChange _createNullCheckChange(Expression node, DartType type,
       {HintComment? hint}) {
-    var resultType =
-        _fixBuilder!._typeSystem.promoteToNonNull(type as TypeImpl);
+    var resultType = _fixBuilder._typeSystem.promoteToNonNull(type as TypeImpl);
     _flowAnalysis!.nonNullAssert_end(node);
     return type.isDartCoreNull && hint == null
         ? NoValidMigrationChange(resultType)
@@ -679,9 +676,9 @@
 
   InterfaceType _getClassInterface(
       ClassElement class_, InterfaceElement superclass) {
-    var decoratedSupertype = _fixBuilder!._decoratedClassHierarchy!
+    var decoratedSupertype = _fixBuilder._decoratedClassHierarchy!
         .getDecoratedSupertype(class_, superclass);
-    var finalType = _fixBuilder!._variables!.toFinalType(decoratedSupertype);
+    var finalType = _fixBuilder._variables!.toFinalType(decoratedSupertype);
     return finalType as InterfaceType;
   }
 
@@ -696,16 +693,15 @@
   }
 
   bool _isSubtypeOrCoercible(DartType type, DartType context) {
-    var fixBuilder = _fixBuilder!;
-    var typeSystem = fixBuilder._typeSystem;
+    var typeSystem = _fixBuilder._typeSystem;
     if (typeSystem.isSubtypeOf(type, context)) {
       return true;
     }
     if (context is FunctionType && type is InterfaceType) {
-      var callMethod =
-          type.lookUpMethod2('call', fixBuilder.unit!.declaredElement!.library);
+      var callMethod = type.lookUpMethod2(
+          'call', _fixBuilder.unit!.declaredElement!.library);
       if (callMethod != null) {
-        var variables = fixBuilder._variables!;
+        var variables = _fixBuilder._variables!;
         var callMethodType = variables.toFinalType(
             variables.decoratedElementType(callMethod.declaration));
         if (callMethod is MethodMember) {
@@ -729,7 +725,7 @@
       }
     }
     var hint =
-        _fixBuilder!._variables!.getNullCheckHint(_fixBuilder!.source, node);
+        _fixBuilder._variables!.getNullCheckHint(_fixBuilder.source, node);
     if (hint != null) {
       type = _addNullCheck(node, type,
           info: AtomicEditInfo(
@@ -753,7 +749,7 @@
       // transform `.where`.
       type = _tryTransformWhere(node, type) ?? type;
     }
-    if (!_fixBuilder!._typeSystem.isNullable(type)) return type;
+    if (!_fixBuilder._typeSystem.isNullable(type)) return type;
     if (_needsNullCheckDueToStructure(ancestor)) {
       return _addNullCheck(node, type);
     }
@@ -822,8 +818,8 @@
 
   CollectionElement? _transformCollectionElement(CollectionElement? node) {
     while (node is IfElement) {
-      var conditionalDiscard = _fixBuilder!._variables!
-          .getConditionalDiscard(_fixBuilder!.source, node);
+      var conditionalDiscard = _fixBuilder._variables!
+          .getConditionalDiscard(_fixBuilder.source, node);
       if (conditionalDiscard == null ||
           conditionalDiscard.keepTrue && conditionalDiscard.keepFalse) {
         return node;
@@ -849,7 +845,7 @@
   /// considered); otherwise returns `null`.
   DartType? _tryTransformOrElse(Expression node, DartType type) {
     var transformationInfo =
-        _fixBuilder!._whereOrNullTransformer.tryTransformOrElseArgument(node);
+        _fixBuilder._whereOrNullTransformer.tryTransformOrElseArgument(node);
     if (transformationInfo != null) {
       // We can fix this by dropping the node and changing the method call.
       _addCollectionPackageExtension('IterableExtension');
@@ -858,14 +854,14 @@
               transformationInfo.originalName,
               transformationInfo.replacementName),
           {});
-      (_fixBuilder!._getChange(transformationInfo.methodInvocation.methodName)
+      (_fixBuilder._getChange(transformationInfo.methodInvocation.methodName)
               as NodeChangeForMethodName)
           .replaceWith(transformationInfo.replacementName, info);
-      (_fixBuilder!._getChange(transformationInfo.methodInvocation.argumentList)
+      (_fixBuilder._getChange(transformationInfo.methodInvocation.argumentList)
               as NodeChangeForArgumentList)
           .dropArgument(transformationInfo.orElseArgument, info);
       _deferredMethodInvocationProcessing[transformationInfo.methodInvocation] =
-          (methodInvocationType) => _fixBuilder!._typeSystem
+          (methodInvocationType) => _fixBuilder._typeSystem
               .makeNullable(methodInvocationType as TypeImpl);
       return type;
     }
@@ -877,8 +873,8 @@
   /// indicates to the caller that no further transformations to this expression
   /// need to be considered); otherwise returns `null`.
   DartType? _tryTransformWhere(Expression node, DartType type) {
-    var transformationInfo = _fixBuilder!._whereNotNullTransformer
-        .tryTransformMethodInvocation(node);
+    var transformationInfo =
+        _fixBuilder._whereNotNullTransformer.tryTransformMethodInvocation(node);
     if (transformationInfo != null) {
       // We can fix this by dropping the method call's argument and changing the
       // call.
@@ -888,13 +884,13 @@
               transformationInfo.originalName,
               transformationInfo.replacementName),
           {});
-      (_fixBuilder!._getChange(transformationInfo.methodInvocation.methodName)
+      (_fixBuilder._getChange(transformationInfo.methodInvocation.methodName)
               as NodeChangeForMethodName)
           .replaceWith(transformationInfo.replacementName, info);
-      (_fixBuilder!._getChange(transformationInfo.methodInvocation.argumentList)
+      (_fixBuilder._getChange(transformationInfo.methodInvocation.argumentList)
               as NodeChangeForArgumentList)
           .dropArgument(transformationInfo.argument, info);
-      return _fixBuilder!._whereNotNullTransformer
+      return _fixBuilder._whereNotNullTransformer
           .transformPostMigrationInvocationType(type);
     }
     return null;
@@ -906,12 +902,12 @@
   /// exception is propagated normally.
   T _wrapExceptions<T>(
       AstNode? node, T Function() fallback, T Function() compute) {
-    if (_fixBuilder!.listener == null) return compute();
+    if (_fixBuilder.listener == null) return compute();
     try {
       return compute();
     } catch (exception, stackTrace) {
-      _fixBuilder!.listener!
-          .reportException(_fixBuilder!.source, node, exception, stackTrace);
+      _fixBuilder.listener!
+          .reportException(_fixBuilder.source, node, exception, stackTrace);
       return fallback();
     }
   }
@@ -976,7 +972,7 @@
       MigrationResolutionHooksImpl hooks, DartType rhsType) {
     MethodElement? combiner = this.combiner;
     if (combiner != null) {
-      var fixBuilder = hooks._fixBuilder!;
+      var fixBuilder = hooks._fixBuilder;
       var combinerReturnType =
           fixBuilder._typeSystem.refineBinaryExpressionType(
         readType!,
@@ -1011,13 +1007,13 @@
       assert(readType!.nullabilitySuffix != NullabilitySuffix.star);
       if (combinerType == TokenType.QUESTION_QUESTION_EQ) {
         rhsContextType = writeTypeToSet;
-        if (fixBuilder!._typeSystem.isNonNullable(readType!)) {
+        if (fixBuilder._typeSystem.isNonNullable(readType!)) {
           (fixBuilder._getChange(node) as NodeChangeForAssignment)
               .isWeakNullAware = true;
         }
       } else {
         if (!readType!.isDynamic &&
-            fixBuilder!._typeSystem.isPotentiallyNullable(readType!)) {
+            fixBuilder._typeSystem.isPotentiallyNullable(readType!)) {
           (fixBuilder._getChange(node) as NodeChangeForAssignmentLike)
               .hasNullableSource = true;
         }
diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h
index 4b5bb50..24fadff 100644
--- a/runtime/bin/platform.h
+++ b/runtime/bin/platform.h
@@ -29,7 +29,7 @@
   // Returns a string representing the operating system ("linux",
   // "macos", "windows", or "android"). The returned string should not be
   // deallocated by the caller.
-  static const char* OperatingSystem();
+  static const char* OperatingSystem() { return kHostOperatingSystemName; }
 
   // Returns a string representing the version of the operating system. The
   // format of the string is determined by the platform. The returned string
@@ -38,23 +38,7 @@
 
   // Returns the architecture name of the processor the VM is running on
   // (ia32, x64, arm, or arm64).
-  static const char* HostArchitecture() {
-#if defined(HOST_ARCH_ARM)
-    return "arm";
-#elif defined(HOST_ARCH_ARM64)
-    return "arm64";
-#elif defined(HOST_ARCH_IA32)
-    return "ia32";
-#elif defined(HOST_ARCH_X64)
-    return "x64";
-#elif defined(HOST_ARCH_RISCV32)
-    return "riscv32";
-#elif defined(HOST_ARCH_RISCV64)
-    return "riscv64";
-#else
-#error Architecture detection failed.
-#endif
-  }
+  static const char* HostArchitecture() { return kHostArchitectureName; }
 
   static const char* LibraryPrefix();
 
diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc
index dbbae40..ab084ba 100644
--- a/runtime/bin/platform_android.cc
+++ b/runtime/bin/platform_android.cc
@@ -92,10 +92,6 @@
   return sysconf(_SC_NPROCESSORS_ONLN);
 }
 
-const char* Platform::OperatingSystem() {
-  return "android";
-}
-
 const char* Platform::OperatingSystemVersion() {
   char os_version[PROP_VALUE_MAX + 1];
   int os_version_length =
diff --git a/runtime/bin/platform_fuchsia.cc b/runtime/bin/platform_fuchsia.cc
index 2c12818..6c0934f 100644
--- a/runtime/bin/platform_fuchsia.cc
+++ b/runtime/bin/platform_fuchsia.cc
@@ -34,10 +34,6 @@
   return sysconf(_SC_NPROCESSORS_CONF);
 }
 
-const char* Platform::OperatingSystem() {
-  return "fuchsia";
-}
-
 const char* Platform::OperatingSystemVersion() {
   struct utsname info;
   int ret = uname(&info);
diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc
index 84cf46c..e758d2c 100644
--- a/runtime/bin/platform_linux.cc
+++ b/runtime/bin/platform_linux.cc
@@ -91,10 +91,6 @@
   return sysconf(_SC_NPROCESSORS_ONLN);
 }
 
-const char* Platform::OperatingSystem() {
-  return "linux";
-}
-
 const char* Platform::OperatingSystemVersion() {
   struct utsname info;
   int ret = uname(&info);
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 498df50..f8e87fb 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -110,14 +110,6 @@
   }
 }
 
-const char* Platform::OperatingSystem() {
-#if DART_HOST_OS_IOS
-  return "ios";
-#else
-  return "macos";
-#endif
-}
-
 const char* Platform::OperatingSystemVersion() {
   std::string version(NSProcessInfoOperatingSystemVersionString());
   return DartUtils::ScopedCopyCString(version.c_str());
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index b407cd2..8e100a1 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -113,10 +113,6 @@
   return info.dwNumberOfProcessors;
 }
 
-const char* Platform::OperatingSystem() {
-  return "windows";
-}
-
 // We pull the version number, and other version information out of the
 // registry because GetVersionEx() and friends lie about the OS version after
 // Windows 8.1. See:
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index d71457b..98e15ed 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -734,6 +734,74 @@
 #endif
 #endif
 
+#if defined(DART_HOST_OS_ANDROID)
+#define kHostOperatingSystemName "android"
+#elif defined(DART_HOST_OS_FUCHSIA)
+#define kHostOperatingSystemName "fuchsia"
+#elif defined(DART_HOST_OS_IOS)
+#define kHostOperatingSystemName "ios"
+#elif defined(DART_HOST_OS_LINUX)
+#define kHostOperatingSystemName "linux"
+#elif defined(DART_HOST_OS_MACOS)
+#define kHostOperatingSystemName "macos"
+#elif defined(DART_HOST_OS_WINDOWS)
+#define kHostOperatingSystemName "windows"
+#else
+#error Host operating system detection failed.
+#endif
+
+#if defined(HOST_ARCH_ARM)
+#define kHostArchitectureName "arm"
+#elif defined(HOST_ARCH_ARM64)
+#define kHostArchitectureName "arm64"
+#elif defined(HOST_ARCH_IA32)
+#define kHostArchitectureName "ia32"
+#elif defined(HOST_ARCH_RISCV32)
+#define kHostArchitectureName "riscv32"
+#elif defined(HOST_ARCH_RISCV64)
+#define kHostArchitectureName "riscv64"
+#elif defined(HOST_ARCH_X64)
+#define kHostArchitectureName "x64"
+#else
+#error Host architecture detection failed.
+#endif
+
+#if defined(TARGET_ARCH_ARM)
+#define kTargetArchitectureName "arm"
+#elif defined(TARGET_ARCH_ARM64)
+#define kTargetArchitectureName "arm64"
+#elif defined(TARGET_ARCH_IA32)
+#define kTargetArchitectureName "ia32"
+#elif defined(TARGET_ARCH_RISCV32)
+#define kTargetArchitectureName "riscv32"
+#elif defined(TARGET_ARCH_RISCV64)
+#define kTargetArchitectureName "riscv64"
+#elif defined(TARGET_ARCH_X64)
+#define kTargetArchitectureName "x64"
+#else
+#error Target architecture detection failed.
+#endif
+
+// The ordering between DART_TARGET_OS_MACOS_IOS and DART_TARGET_OS_MACOS
+// below is important, since the latter is sometimes defined when the former
+// is, and sometimes not (e.g., ffi tests), so we need to test the former
+// before the latter.
+#if defined(DART_TARGET_OS_ANDROID)
+#define kTargetOperatingSystemName "android"
+#elif defined(DART_TARGET_OS_FUCHSIA)
+#define kTargetOperatingSystemName "fuchsia"
+#elif defined(DART_TARGET_OS_LINUX)
+#define kTargetOperatingSystemName "linux"
+#elif defined(DART_TARGET_OS_MACOS_IOS)
+#define kTargetOperatingSystemName "ios"
+#elif defined(DART_TARGET_OS_MACOS)
+#define kTargetOperatingSystemName "macos"
+#elif defined(DART_TARGET_OS_WINDOWS)
+#define kTargetOperatingSystemName "windows"
+#else
+#error Target operating system detection failed.
+#endif
+
 }  // namespace dart
 
 #endif  // RUNTIME_PLATFORM_GLOBALS_H_
diff --git a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
index f8598a4..3bc5dba 100644
--- a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
@@ -179,6 +179,25 @@
   final tracePCOffsets2 = collectPCOffsets(output2.trace);
   Expect.deepEquals(tracePCOffsets1, tracePCOffsets2);
 
+  if (tracePCOffsets1.isNotEmpty) {
+    final exampleOffset = tracePCOffsets1.first;
+
+    // We run the test program on the same host OS as the test, so any of the
+    // PCOffsets above should have this information.
+    Expect.isNotNull(exampleOffset.os);
+    Expect.isNotNull(exampleOffset.architecture);
+    Expect.isNotNull(exampleOffset.usingSimulator);
+    Expect.isNotNull(exampleOffset.compressedPointers);
+
+    Expect.equals(exampleOffset.os, Platform.operatingSystem);
+    final archString = '${exampleOffset.usingSimulator! ? 'SIM' : ''}'
+        '${exampleOffset.architecture!.toUpperCase()}'
+        '${exampleOffset.compressedPointers! ? 'C' : ''}';
+    final baseBuildDir = path.basename(buildDir);
+    Expect.isTrue(baseBuildDir.endsWith(archString),
+        'Expected $baseBuildDir to end with $archString');
+  }
+
   // Check that translating the DWARF stack trace (without internal frames)
   // matches the symbolic stack trace.
   print("Reading DWARF info from ${dwarfPath}");
@@ -216,16 +235,11 @@
   print('Offset of first stub address is $allocateObjectPCOffset1');
   print('Offset of second stub address is $allocateObjectPCOffset2');
 
-  final allocateObjectRelocatedAddress1 =
-      dwarf.virtualAddressOf(allocateObjectPCOffset1);
-  final allocateObjectRelocatedAddress2 =
-      dwarf.virtualAddressOf(allocateObjectPCOffset2);
-
-  final allocateObjectCallInfo1 = dwarf.callInfoFor(
-      allocateObjectRelocatedAddress1,
+  final allocateObjectCallInfo1 = dwarf.callInfoForPCOffset(
+      allocateObjectPCOffset1,
       includeInternalFrames: true);
-  final allocateObjectCallInfo2 = dwarf.callInfoFor(
-      allocateObjectRelocatedAddress2,
+  final allocateObjectCallInfo2 = dwarf.callInfoForPCOffset(
+      allocateObjectPCOffset2,
       includeInternalFrames: true);
 
   Expect.isNotNull(allocateObjectCallInfo1);
diff --git a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
index 7b2737e..5c479d1 100644
--- a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
@@ -181,6 +181,25 @@
   final tracePCOffsets2 = collectPCOffsets(output2.trace);
   Expect.deepEquals(tracePCOffsets1, tracePCOffsets2);
 
+  if (tracePCOffsets1.isNotEmpty) {
+    final exampleOffset = tracePCOffsets1.first;
+
+    // We run the test program on the same host OS as the test, so any of the
+    // PCOffsets above should have this information.
+    Expect.isNotNull(exampleOffset.os);
+    Expect.isNotNull(exampleOffset.architecture);
+    Expect.isNotNull(exampleOffset.usingSimulator);
+    Expect.isNotNull(exampleOffset.compressedPointers);
+
+    Expect.equals(exampleOffset.os, Platform.operatingSystem);
+    final archString = '${exampleOffset.usingSimulator ? 'SIM' : ''}'
+        '${exampleOffset.architecture.toUpperCase()}'
+        '${exampleOffset.compressedPointers ? 'C' : ''}';
+    final baseBuildDir = path.basename(buildDir);
+    Expect.isTrue(baseBuildDir.endsWith(archString),
+        'Expected $baseBuildDir to end with $archString');
+  }
+
   // Check that translating the DWARF stack trace (without internal frames)
   // matches the symbolic stack trace.
   print("Reading DWARF info from ${dwarfPath}");
@@ -218,16 +237,11 @@
   print('Offset of first stub address is $allocateObjectPCOffset1');
   print('Offset of second stub address is $allocateObjectPCOffset2');
 
-  final allocateObjectRelocatedAddress1 =
-      dwarf.virtualAddressOf(allocateObjectPCOffset1);
-  final allocateObjectRelocatedAddress2 =
-      dwarf.virtualAddressOf(allocateObjectPCOffset2);
-
-  final allocateObjectCallInfo1 = dwarf.callInfoFor(
-      allocateObjectRelocatedAddress1,
+  final allocateObjectCallInfo1 = dwarf.callInfoForPCOffset(
+      allocateObjectPCOffset1,
       includeInternalFrames: true);
-  final allocateObjectCallInfo2 = dwarf.callInfoFor(
-      allocateObjectRelocatedAddress2,
+  final allocateObjectCallInfo2 = dwarf.callInfoForPCOffset(
+      allocateObjectPCOffset2,
       includeInternalFrames: true);
 
   Expect.isNotNull(allocateObjectCallInfo1);
diff --git a/runtime/vm/compiler/ffi/abi.cc b/runtime/vm/compiler/ffi/abi.cc
index 01cf0ca..66fa5a8 100644
--- a/runtime/vm/compiler/ffi/abi.cc
+++ b/runtime/vm/compiler/ffi/abi.cc
@@ -4,6 +4,7 @@
 
 #include "vm/compiler/ffi/abi.h"
 
+#include "platform/globals.h"
 #include "vm/constants.h"
 
 namespace dart {
@@ -48,46 +49,34 @@
 
 #if defined(DART_TARGET_OS_ANDROID)
 #define DART_TARGET_OS_NAME Android
-#define DART_TARGET_OS_NAME_LC android
 #elif defined(DART_TARGET_OS_FUCHSIA)
 #define DART_TARGET_OS_NAME Fuchsia
-#define DART_TARGET_OS_NAME_LC fuchsia
 #elif defined(DART_TARGET_OS_LINUX)
 #define DART_TARGET_OS_NAME Linux
-#define DART_TARGET_OS_NAME_LC linux
 #elif defined(DART_TARGET_OS_MACOS)
 #if DART_TARGET_OS_MACOS_IOS
 #define DART_TARGET_OS_NAME IOS
-#define DART_TARGET_OS_NAME_LC ios
 #else
 #define DART_TARGET_OS_NAME MacOS
-#define DART_TARGET_OS_NAME_LC macos
 #endif
 #elif defined(DART_TARGET_OS_WINDOWS)
 #define DART_TARGET_OS_NAME Windows
-#define DART_TARGET_OS_NAME_LC windows
 #else
 #error Unknown OS
 #endif
 
 #if defined(TARGET_ARCH_IA32)
 #define TARGET_ARCH_NAME IA32
-#define TARGET_ARCH_NAME_LC ia32
 #elif defined(TARGET_ARCH_X64)
 #define TARGET_ARCH_NAME X64
-#define TARGET_ARCH_NAME_LC x64
 #elif defined(TARGET_ARCH_ARM)
 #define TARGET_ARCH_NAME Arm
-#define TARGET_ARCH_NAME_LC arm
 #elif defined(TARGET_ARCH_ARM64)
 #define TARGET_ARCH_NAME Arm64
-#define TARGET_ARCH_NAME_LC arm64
 #elif defined(TARGET_ARCH_RISCV32)
 #define TARGET_ARCH_NAME Riscv32
-#define TARGET_ARCH_NAME_LC riscv32
 #elif defined(TARGET_ARCH_RISCV64)
 #define TARGET_ARCH_NAME Riscv64
-#define TARGET_ARCH_NAME_LC riscv64
 #else
 #error Unknown arch
 #endif
@@ -100,11 +89,8 @@
   return Abi::ABI_ENUM_VALUE3;
 }
 
-#define STRINGIFY2(s) STRINGIFY(s)
-#define STRINGIFY(s) #s
-
 const char* target_abi_name =
-    STRINGIFY2(DART_TARGET_OS_NAME_LC) "_" STRINGIFY2(TARGET_ARCH_NAME_LC);
+    kTargetOperatingSystemName "_" kTargetArchitectureName;
 
 }  // namespace ffi
 
diff --git a/runtime/vm/compiler/ffi/native_calling_convention_test.cc b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
index 3c12a8f..d040fb1 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention_test.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention_test.cc
@@ -29,7 +29,7 @@
   char expectation_file_path[kFilePathLength];
   Utils::SNPrint(expectation_file_path, kFilePathLength,
                  "runtime/vm/compiler/ffi/unit_tests/%s/%s_%s.expect", name,
-                 kArch, kOs);
+                 kTargetArchitectureName, kOs);
 
   if (TestCaseBase::update_expectations) {
     Syslog::Print("Updating %s\n", expectation_file_path);
diff --git a/runtime/vm/compiler/ffi/native_type_test.cc b/runtime/vm/compiler/ffi/native_type_test.cc
index d132b91..d0a87a1 100644
--- a/runtime/vm/compiler/ffi/native_type_test.cc
+++ b/runtime/vm/compiler/ffi/native_type_test.cc
@@ -25,7 +25,7 @@
   char expectation_file_path[kFilePathLength];
   Utils::SNPrint(expectation_file_path, kFilePathLength,
                  "runtime/vm/compiler/ffi/unit_tests/%s/%s_%s.expect", name,
-                 kArch, kOs);
+                 kTargetArchitectureName, kOs);
 
   if (TestCaseBase::update_expectations) {
     Syslog::Print("Updating %s\n", expectation_file_path);
diff --git a/runtime/vm/compiler/ffi/unit_test.cc b/runtime/vm/compiler/ffi/unit_test.cc
index 138fe36..eb8211d 100644
--- a/runtime/vm/compiler/ffi/unit_test.cc
+++ b/runtime/vm/compiler/ffi/unit_test.cc
@@ -5,35 +5,16 @@
 #include "vm/compiler/ffi/unit_test.h"
 
 #include "platform/syslog.h"
+#include "vm/globals.h"
 
 namespace dart {
 namespace compiler {
 namespace ffi {
 
-#if defined(TARGET_ARCH_ARM)
-const char* kArch = "arm";
-#elif defined(TARGET_ARCH_ARM64)
-const char* kArch = "arm64";
-#elif defined(TARGET_ARCH_IA32)
-const char* kArch = "ia32";
-#elif defined(TARGET_ARCH_X64)
-const char* kArch = "x64";
-#elif defined(TARGET_ARCH_RISCV32)
-const char* kArch = "riscv32";
-#elif defined(TARGET_ARCH_RISCV64)
-const char* kArch = "riscv64";
-#endif
-
-#if defined(DART_TARGET_OS_ANDROID)
-const char* kOs = "android";
-#elif defined(DART_TARGET_OS_MACOS_IOS)
-const char* kOs = "ios";
-#elif defined(DART_TARGET_OS_LINUX)
-const char* kOs = "linux";
-#elif defined(DART_TARGET_OS_MACOS)
-const char* kOs = "macos";
-#elif defined(DART_TARGET_OS_WINDOWS)
+#if defined(DART_TARGET_OS_WINDOWS)
 const char* kOs = "win";
+#else
+const char* kOs = kTargetOperatingSystemName;
 #endif
 
 void WriteToFile(char* path, const char* contents) {
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a12f853..df8e064 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -1134,35 +1134,28 @@
     }
 
 // Generated code must match the host architecture and ABI.
+    buffer.Printf(" %s", kTargetArchitectureName);
 #if defined(TARGET_ARCH_ARM)
 #if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_MACOS_IOS)
-    buffer.AddString(" arm-ios");
+    buffer.AddString("-ios");
 #else
-    buffer.AddString(" arm-eabi");
+    buffer.AddString("-eabi");
 #endif
     buffer.AddString(TargetCPUFeatures::hardfp_supported() ? " hardfp"
                                                            : " softfp");
 #elif defined(TARGET_ARCH_ARM64)
 #if defined(DART_TARGET_OS_FUCHSIA)
     // See signal handler cheat in Assembler::EnterFrame.
-    buffer.AddString(" arm64-fuchsia");
+    buffer.AddString("-fuchsia");
 #else
-    buffer.AddString(" arm64-sysv");
+    buffer.AddString("-sysv");
 #endif
-#elif defined(TARGET_ARCH_IA32)
-    buffer.AddString(" ia32");
 #elif defined(TARGET_ARCH_X64)
 #if defined(DART_TARGET_OS_WINDOWS)
-    buffer.AddString(" x64-win");
+    buffer.AddString("-win");
 #else
-    buffer.AddString(" x64-sysv");
+    buffer.AddString("-sysv");
 #endif
-#elif defined(TARGET_ARCH_RISCV32)
-    buffer.AddString(" riscv32");
-#elif defined(TARGET_ARCH_RISCV64)
-    buffer.AddString(" riscv64");
-#else
-#error What architecture?
 #endif
 #if defined(DART_COMPRESSED_POINTERS)
     buffer.AddString(" compressed-pointers");
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e7c7b72..bb764d4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -25955,6 +25955,19 @@
     OSThread* thread = OSThread::Current();
     buffer.Printf("pid: %" Pd ", tid: %" Pd ", name %s\n", OS::ProcessId(),
                   OSThread::ThreadIdToIntPtr(thread->id()), thread->name());
+#if defined(DART_COMPRESSED_POINTERS)
+    const char kCompressedPointers[] = "yes";
+#else
+    const char kCompressedPointers[] = "no";
+#endif
+#if defined(USING_SIMULATOR)
+    const char kUsingSimulator[] = "yes";
+#else
+    const char kUsingSimulator[] = "no";
+#endif
+    buffer.Printf("os: %s arch: %s comp: %s sim: %s\n",
+                  kHostOperatingSystemName, kTargetArchitectureName,
+                  kCompressedPointers, kUsingSimulator);
     if (auto const build_id = isolate_instructions_image.build_id()) {
       const intptr_t length = isolate_instructions_image.build_id_length();
       buffer.Printf("build_id: '");
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index d0f9e4c..c774254 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -19,7 +19,7 @@
 class OS {
  public:
   // Returns the name of the given OS. For example "linux".
-  static const char* Name();
+  static const char* Name() { return kHostOperatingSystemName; }
 
   // Returns the current process id.
   static intptr_t ProcessId();
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 08af326..6ee9cd4 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -91,10 +91,6 @@
 
 #endif  // !PRODUCT
 
-const char* OS::Name() {
-  return "android";
-}
-
 intptr_t OS::ProcessId() {
   return static_cast<intptr_t>(getpid());
 }
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index 07150b3..74191ef 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -346,10 +346,6 @@
 
 #endif  // !PRODUCT
 
-const char* OS::Name() {
-  return "fuchsia";
-}
-
 intptr_t OS::ProcessId() {
   return static_cast<intptr_t>(getpid());
 }
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 411871a..8cb55b7 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -410,10 +410,6 @@
 
 #endif  // !PRODUCT
 
-const char* OS::Name() {
-  return "linux";
-}
-
 intptr_t OS::ProcessId() {
   return static_cast<intptr_t>(getpid());
 }
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index a4f58f6..390805d 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -26,14 +26,6 @@
 
 namespace dart {
 
-const char* OS::Name() {
-#if DART_HOST_OS_IOS
-  return "ios";
-#else
-  return "macos";
-#endif
-}
-
 intptr_t OS::ProcessId() {
   return static_cast<intptr_t>(getpid());
 }
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index a19fb63..b6fed58 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -22,10 +22,6 @@
 // Defined in vm/os_thread_win.cc
 extern bool private_flag_windows_run_tls_destructors;
 
-const char* OS::Name() {
-  return "windows";
-}
-
 intptr_t OS::ProcessId() {
   return static_cast<intptr_t>(GetCurrentProcessId());
 }
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index fb9bb9d..4ad80c5 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -477,6 +477,18 @@
                ", isolate_group=%s(%p), isolate=%s(%p)\n",
                static_cast<intptr_t>(OS::ProcessId()), thread_id,
                isolate_group_name, isolate_group, isolate_name, isolate);
+#if defined(DART_COMPRESSED_POINTERS)
+  const char kCompressedPointers[] = "yes";
+#else
+  const char kCompressedPointers[] = "no";
+#endif
+#if defined(USING_SIMULATOR)
+  const char kUsingSimulator[] = "yes";
+#else
+  const char kUsingSimulator[] = "no";
+#endif
+  OS::PrintErr("os=%s, arch=%s, comp=%s, sim=%s\n", kHostOperatingSystemName,
+               kTargetArchitectureName, kCompressedPointers, kUsingSimulator);
   OS::PrintErr("isolate_instructions=%" Px ", vm_instructions=%" Px "\n",
                source == nullptr
                    ? 0
diff --git a/runtime/vm/version_in.cc b/runtime/vm/version_in.cc
index ef8274c..7aee151 100644
--- a/runtime/vm/version_in.cc
+++ b/runtime/vm/version_in.cc
@@ -27,44 +27,12 @@
 const char* Version::snapshot_hash_ = "{{SNAPSHOT_HASH}}";
 const char* Version::str_ =
     "{{VERSION_STR}} ({{CHANNEL}}) ({{COMMIT_TIME}})"
-    " on \""
-#if defined(DART_HOST_OS_ANDROID)
-    "android"
-#elif defined(DART_HOST_OS_FUCHSIA)
-    "fuchsia"
-#elif defined(DART_HOST_OS_LINUX)
-    "linux"
-#elif defined(DART_HOST_OS_MACOS)
-#if DART_HOST_OS_IOS
-    "ios"
-#else
-    "macos"
-#endif
-#elif defined(DART_HOST_OS_WINDOWS)
-    "windows"
-#else
-#error Unknown OS
-#endif
+    " on \"" kHostOperatingSystemName
     "_"
 #if defined(USING_SIMULATOR)
     "sim"
 #endif
-#if defined(TARGET_ARCH_IA32)
-    "ia32"
-#elif defined(TARGET_ARCH_X64)
-    "x64"
-#elif defined(TARGET_ARCH_ARM)
-    "arm"
-#elif defined(TARGET_ARCH_ARM64)
-    "arm64"
-#elif defined(TARGET_ARCH_RISCV32)
-    "riscv32"
-#elif defined(TARGET_ARCH_RISCV64)
-    "riscv64"
-#else
-#error Unknown arch
-#endif
-    "\"";
+    kTargetArchitectureName "\"";
 const char* Version::commit_ = "{{VERSION_STR}}";
 const char* Version::git_short_hash_ = "{{GIT_HASH}}";
 
diff --git a/tools/VERSION b/tools/VERSION
index 9ea184b..adb3629 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 69
+PRERELEASE 70
 PRERELEASE_PATCH 0
\ No newline at end of file