From 24683da915867609b9b52bd2124e6fb603b9f160 Mon Sep 17 00:00:00 2001 From: Tess Strickland Date: Fri, 5 Aug 2022 11:53:37 +0000 Subject: [PATCH] [vm] Add OS and architecture to non-symbolic stack traces. Examples of the new line added to non-symbolic stack traces: os: linux arch: x64 comp: yes sim: no (Running on linux-x64c) os: macos arch: arm64 comp: no sim: yes (Running on mac-simarm64) This CL also abstracts out the separate hardcoded strings across the codebase for host and target OS and architecture into definitions in platform/globals.h to ensure that they stay in sync across different uses. TEST=vm/dart{,_2}/use_dwarf_stack_traces_flag Issue: https://github.com/flutter/flutter/pull/101586 Change-Id: Ifdfea5138dd1003f561da0174e89aebc165bf9b0 Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-dwarf-linux-product-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-mac-product-x64-try,vm-kernel-precomp-nnbd-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-release-simarm_x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-ffi-android-release-arm-try,vm-ffi-android-release-arm64c-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/253283 Reviewed-by: Ryan Macnak Commit-Queue: Tess Strickland Reviewed-by: Daco Harkes --- pkg/native_stack_traces/CHANGELOG.md | 5 + pkg/native_stack_traces/bin/decode.dart | 5 +- pkg/native_stack_traces/lib/src/convert.dart | 151 +++++++++++++----- pkg/native_stack_traces/lib/src/dwarf.dart | 73 ++++++++- pkg/native_stack_traces/pubspec.yaml | 2 +- runtime/bin/platform.h | 20 +-- runtime/bin/platform_android.cc | 4 - runtime/bin/platform_fuchsia.cc | 4 - runtime/bin/platform_linux.cc | 4 - runtime/bin/platform_macos.cc | 8 - runtime/bin/platform_win.cc | 4 - runtime/platform/globals.h | 68 ++++++++ .../use_dwarf_stack_traces_flag_test.dart | 32 ++-- .../use_dwarf_stack_traces_flag_test.dart | 32 ++-- runtime/vm/compiler/ffi/abi.cc | 18 +-- .../ffi/native_calling_convention_test.cc | 2 +- runtime/vm/compiler/ffi/native_type_test.cc | 2 +- runtime/vm/compiler/ffi/unit_test.cc | 27 +--- runtime/vm/dart.cc | 21 +-- runtime/vm/object.cc | 13 ++ runtime/vm/os.h | 2 +- runtime/vm/os_android.cc | 4 - runtime/vm/os_fuchsia.cc | 4 - runtime/vm/os_linux.cc | 4 - runtime/vm/os_macos.cc | 8 - runtime/vm/os_win.cc | 4 - runtime/vm/profiler.cc | 12 ++ runtime/vm/version_in.cc | 36 +---- 28 files changed, 343 insertions(+), 226 deletions(-) diff --git a/pkg/native_stack_traces/CHANGELOG.md b/pkg/native_stack_traces/CHANGELOG.md index a1b47ce3126d..92ccfee58d37 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 cb44a02d144a..841cd8b6c4e5 100644 --- a/pkg/native_stack_traces/bin/decode.dart +++ b/pkg/native_stack_traces/bin/decode.dart @@ -200,7 +200,8 @@ void find(ArgResults options) { } 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 @@ void find(ArgResults options) { isolateStart = address; } - final header = StackTraceHeader(isolateStart, vmStart); + final header = StackTraceHeader.fromStarts(isolateStart, vmStart); final locations = []; 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 0bc8f2470a96..ebcdffd45e55 100644 --- a/pkg/native_stack_traces/lib/src/convert.dart +++ b/pkg/native_stack_traces/lib/src/convert.dart @@ -11,45 +11,99 @@ import 'dwarf.dart'; 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; + + String? get os => _os; + String? get architecture => _arch; + bool? get compressedPointers => _compressed; + bool? get usingSimulator => _simulated; - StackTraceHeader(this._isolateStart, this._vmStart); + 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 @@ final _traceLineRE = RegExp( /// 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 @@ PCOffset? tryParseSymbolOffset(String s, [bool forceHexadecimal = false]) { 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 @@ PCOffset? _retrievePCOffset(StackTraceHeader? header, RegExpMatch? match) { 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 collectPCOffsets(Iterable 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 @@ class DwarfStackTraceDecoder extends StreamTransformerBase { @override Stream bind(Stream 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 9944f2d628df..13fac7065de0 100644 --- a/pkg/native_stack_traces/lib/src/dwarf.dart +++ b/pkg/native_stack_traces/lib/src/dwarf.dart @@ -1451,12 +1451,34 @@ class StubCallInfo extends CallInfo { 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 @@ class PCOffset { /// to user or library code is returned. Iterable? callInfoFrom(Dwarf dwarf, {bool includeInternalFrames = false}) => - dwarf.callInfoFor(dwarf.virtualAddressOf(this), + dwarf.callInfoForPCOffset(this, includeInternalFrames: includeInternalFrames); @override @@ -1477,10 +1499,38 @@ class PCOffset { @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 @@ class Dwarf { 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? 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 09ed948cabb6..2497e11cea00 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/runtime/bin/platform.h b/runtime/bin/platform.h index 4b5bb506438d..24fadff85e6f 100644 --- a/runtime/bin/platform.h +++ b/runtime/bin/platform.h @@ -29,7 +29,7 @@ class Platform { // 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 @@ class Platform { // 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 dbbae4057fa2..ab084babce76 100644 --- a/runtime/bin/platform_android.cc +++ b/runtime/bin/platform_android.cc @@ -92,10 +92,6 @@ int Platform::NumberOfProcessors() { 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 2c128189f625..6c0934f3349b 100644 --- a/runtime/bin/platform_fuchsia.cc +++ b/runtime/bin/platform_fuchsia.cc @@ -34,10 +34,6 @@ int Platform::NumberOfProcessors() { 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 84cf46ca8b13..e758d2cae608 100644 --- a/runtime/bin/platform_linux.cc +++ b/runtime/bin/platform_linux.cc @@ -91,10 +91,6 @@ int Platform::NumberOfProcessors() { 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 498df50625c7..f8e87fbbae76 100644 --- a/runtime/bin/platform_macos.cc +++ b/runtime/bin/platform_macos.cc @@ -110,14 +110,6 @@ int Platform::NumberOfProcessors() { } } -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 b407cd28db1b..8e100a104dd9 100644 --- a/runtime/bin/platform_win.cc +++ b/runtime/bin/platform_win.cc @@ -113,10 +113,6 @@ int Platform::NumberOfProcessors() { 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 d71457b27b7e..98e15edad739 100644 --- a/runtime/platform/globals.h +++ b/runtime/platform/globals.h @@ -734,6 +734,74 @@ DART_FORCE_INLINE D bit_copy(const S& source) { #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 f8598a4c2bdd..3bc5dba1a656 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 @@ Future compareTraces(List nonDwarfTrace, DwarfTestOutput output1, 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 @@ Future compareTraces(List nonDwarfTrace, DwarfTestOutput output1, 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 7b2737ea8761..5c479d1fe9c0 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 @@ Future compareTraces(List nonDwarfTrace, DwarfTestOutput output1, 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 @@ Future compareTraces(List nonDwarfTrace, DwarfTestOutput output1, 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 01cf0ca835a2..66fa5a8d564e 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 @@ static_assert(offsetof(AbiAlignmentUint64, i) == 8, #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 @@ Abi TargetAbi() { 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 3c12a8f491f6..d040fb10618e 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 @@ const NativeCallingConvention& RunSignatureTest( 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 d132b9159ccb..d0a87a137d49 100644 --- a/runtime/vm/compiler/ffi/native_type_test.cc +++ b/runtime/vm/compiler/ffi/native_type_test.cc @@ -25,7 +25,7 @@ const NativeCompoundType& RunStructTest(dart::Zone* zone, 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 138fe3693667..eb8211d4058a 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 a12f853e18c5..df8e06420271 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -1134,35 +1134,28 @@ char* Dart::FeaturesString(IsolateGroup* isolate_group, } // 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 e7c7b72130c2..bb764d49abde 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -25955,6 +25955,19 @@ const char* StackTrace::ToCString() const { 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 d0f9e4c70586..c77425412a65 100644 --- a/runtime/vm/os.h +++ b/runtime/vm/os.h @@ -19,7 +19,7 @@ class Zone; 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 08af326dafc8..6ee9cd4738af 100644 --- a/runtime/vm/os_android.cc +++ b/runtime/vm/os_android.cc @@ -91,10 +91,6 @@ class PerfCodeObserver : public CodeObserver { #endif // !PRODUCT -const char* OS::Name() { - return "android"; -} - intptr_t OS::ProcessId() { return static_cast(getpid()); } diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc index 07150b3c9313..74191efd2d33 100644 --- a/runtime/vm/os_fuchsia.cc +++ b/runtime/vm/os_fuchsia.cc @@ -346,10 +346,6 @@ DEFINE_FLAG(bool, #endif // !PRODUCT -const char* OS::Name() { - return "fuchsia"; -} - intptr_t OS::ProcessId() { return static_cast(getpid()); } diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc index 411871ae3399..8cb55b7c0cfa 100644 --- a/runtime/vm/os_linux.cc +++ b/runtime/vm/os_linux.cc @@ -410,10 +410,6 @@ class JitDumpCodeObserver : public CodeObserver { #endif // !PRODUCT -const char* OS::Name() { - return "linux"; -} - intptr_t OS::ProcessId() { return static_cast(getpid()); } diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc index a4f58f6438d1..390805d9f1db 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(getpid()); } diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc index a19fb6343853..b6fed58d9c9a 100644 --- a/runtime/vm/os_win.cc +++ b/runtime/vm/os_win.cc @@ -22,10 +22,6 @@ namespace dart { // 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(GetCurrentProcessId()); } diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc index fb9bb9d8dc51..4ad80c5e5a9a 100644 --- a/runtime/vm/profiler.cc +++ b/runtime/vm/profiler.cc @@ -477,6 +477,18 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) { ", isolate_group=%s(%p), isolate=%s(%p)\n", static_cast(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 ef8274cab73f..7aee151d8849 100644 --- a/runtime/vm/version_in.cc +++ b/runtime/vm/version_in.cc @@ -27,44 +27,12 @@ const char* Version::SdkHash() { 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}}";