Skip to content

Commit 38ef28a

Browse files
sstricklCommit Queue
authored andcommitted
[vm, gen_snapshot] Add app-aot-macho-dylib option for AOT snapshots.
This is the initial framework for creating snapshots as Mach-O dynamic libraries. Note that this framework is not 100% feature complete compared to generating Mach-O snapshots via assembly. In particular, the directly-compiled Mach-O dylib does not yet contain compact unwinding information. Other changes: * Adds UuidCommand to the native_stack_traces package's Mach-O reader, which now appropriately returns the UUID as the build ID for Mach-O shared objects. * Adds Utils::Basename(path) for portably retrieving the basename from a path. (Returns nullptr for all arguments where it is not currently implemented on Fuchsia or Windows.) * Adjusts vm/timeline.h to avoid pulling in <mach_o/loader.h> on MacOS, as that interferes with uses of the namespaced Mach-O definitions in platform/mach_o.h. * Only attempt to dlopen() a snapshot if ELF is the native format for the host platform or the snapshot is not an ELF shared object. If dlopen() is used, report the error message if it fails rather than attempting to manually load the snapshot as an ELF shared object. * Fix the magic number stored in DylibAppSnapshot for loaded non-ELF dynamic libraries. * Remove the detection of reverse-endian Mach-O magic numbers in DartUtils::SniffForMagicNumber(), since all our Mach-O related code assumes host-endian Mach-O files and so there's no point other than to give a slightly better error message when failing. TEST=vm/dart/exported_symbols_test vm/dart/unobfuscated_static_symbols_test vm/dart/use_dwarf_stack_traces_flag_test vm/cc/CanDetectMachOFiles Issue: #60307 Change-Id: Idf5b49d6c6d035ab033509613212b95520d65965 Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-mac-release-arm64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-dwarf-linux-product-x64-try,vm-linux-debug-x64-try,vm-mac-debug-arm64-try,vm-fuchsia-release-x64-try,vm-fuchsia-release-arm64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/415020 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Tess Strickland <[email protected]>
1 parent 6fa858c commit 38ef28a

37 files changed

+4046
-463
lines changed

pkg/native_stack_traces/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 0.6.1
2+
- Add handling for Mach-O UUID load commands.
3+
14
## 0.6.1-wip
25
- Update SDK constraint to `^3.5.0`.
36

pkg/native_stack_traces/lib/src/macho.dart

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class LoadCommand {
124124
static const LC_SEGMENT = 0x1;
125125
static const LC_SYMTAB = 0x2;
126126
static const LC_SEGMENT_64 = 0x19;
127+
static const LC_UUID = 0x1b;
127128

128129
static LoadCommand fromReader(Reader reader) {
129130
final start = reader.offset; // cmdsize includes size of cmd and cmdsize.
@@ -139,6 +140,9 @@ class LoadCommand {
139140
case LC_SYMTAB:
140141
command = SymbolTableCommand.fromReader(reader, cmd, cmdsize);
141142
break;
143+
case LC_UUID:
144+
command = UuidCommand.fromReader(reader, cmd, cmdsize);
145+
break;
142146
default:
143147
break;
144148
}
@@ -324,6 +328,29 @@ class SymbolTableCommand extends LoadCommand {
324328
}
325329
}
326330

331+
class UuidCommand extends LoadCommand {
332+
Uint8List uuid;
333+
334+
static const kUuidSize = 16;
335+
336+
UuidCommand._(super.cmd, super.cmdsize, this.uuid) : super._();
337+
338+
static UuidCommand fromReader(Reader reader, int cmd, int cmdsize) {
339+
final uuid = Uint8List.sublistView(
340+
reader.bytes, reader.offset, reader.offset + kUuidSize);
341+
return UuidCommand._(cmd, cmdsize, uuid);
342+
}
343+
344+
String get uuidString => uuid.map((i) => paddedHex(i, 1)).join();
345+
346+
@override
347+
void writeToStringBuffer(StringBuffer buffer) {
348+
buffer
349+
..write('UUID: ')
350+
..write(uuidString);
351+
}
352+
}
353+
327354
class MachOHeader {
328355
final int magic;
329356
final int cputype;
@@ -523,7 +550,8 @@ class MachO extends DwarfContainer {
523550
_symbolTable[constants.isolateSymbolName]?.value;
524551

525552
@override
526-
String? get buildId => null;
553+
String? get buildId =>
554+
_commands.whereType<UuidCommand>().firstOrNull?.uuidString;
527555

528556
@override
529557
DwarfContainerStringTable? get debugStringTable => _debugStringTable;

pkg/native_stack_traces/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: native_stack_traces
2-
version: 0.6.1-wip
2+
version: 0.6.1
33
description: Utilities for working with non-symbolic stack traces.
44
repository: https://github.com/dart-lang/sdk/tree/main/pkg/native_stack_traces
55

@@ -13,7 +13,7 @@ executables:
1313

1414
dependencies:
1515
args: ^2.0.0
16-
path: ^1.8.0
16+
path: ^1.9.0
1717

1818
# We use 'any' version constraints here as we get our package versions from
1919
# the dart-lang/sdk repo's DEPS file. Note that this is a special case; the

runtime/bin/dart_api_win.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,13 @@ typedef Dart_Handle (*Dart_CreateAppAOTSnapshotAsElfsType)(
424424
bool,
425425
Dart_StreamingWriteCallback,
426426
Dart_StreamingCloseCallback);
427+
typedef Dart_Handle (*Dart_CreateAppAOTSnapshotAsBinaryType)(
428+
Dart_AotBinaryFormat,
429+
Dart_StreamingWriteCallback,
430+
void*,
431+
bool,
432+
void*,
433+
const char*);
427434
typedef Dart_Handle (*Dart_CreateVMAOTSnapshotAsAssemblyType)(
428435
Dart_StreamingWriteCallback,
429436
void*);
@@ -724,6 +731,8 @@ static Dart_CreateAppAOTSnapshotAsElfType Dart_CreateAppAOTSnapshotAsElfFn =
724731
NULL;
725732
static Dart_CreateAppAOTSnapshotAsElfsType Dart_CreateAppAOTSnapshotAsElfsFn =
726733
NULL;
734+
static Dart_CreateAppAOTSnapshotAsBinaryType
735+
Dart_CreateAppAOTSnapshotAsBinaryFn = NULL;
727736
static Dart_CreateVMAOTSnapshotAsAssemblyType
728737
Dart_CreateVMAOTSnapshotAsAssemblyFn = NULL;
729738
static Dart_SortClassesType Dart_SortClassesFn = NULL;
@@ -1293,6 +1302,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
12931302
Dart_CreateAppAOTSnapshotAsElfsFn =
12941303
(Dart_CreateAppAOTSnapshotAsElfsType)GetProcAddress(
12951304
process, "Dart_CreateAppAOTSnapshotAsElfs");
1305+
Dart_CreateAppAOTSnapshotAsBinaryFn =
1306+
(Dart_CreateAppAOTSnapshotAsBinaryType)GetProcAddress(
1307+
process, "Dart_CreateAppAOTSnapshotAsBinary");
12961308
Dart_CreateVMAOTSnapshotAsAssemblyFn =
12971309
(Dart_CreateVMAOTSnapshotAsAssemblyType)GetProcAddress(
12981310
process, "Dart_CreateVMAOTSnapshotAsAssembly");
@@ -2551,6 +2563,18 @@ Dart_Handle Dart_CreateAppAOTSnapshotAsElfs(
25512563
close_callback);
25522564
}
25532565

2566+
Dart_Handle Dart_CreateAppAOTSnapshotAsBinary(
2567+
Dart_AotBinaryFormat format,
2568+
Dart_StreamingWriteCallback callback,
2569+
void* callback_data,
2570+
bool stripped,
2571+
void* debug_callback_data,
2572+
const char* identifier) {
2573+
return Dart_CreateAppAOTSnapshotAsBinaryFn(format, callback, callback_data,
2574+
stripped, debug_callback_data,
2575+
identifier);
2576+
}
2577+
25542578
Dart_Handle Dart_CreateVMAOTSnapshotAsAssembly(
25552579
Dart_StreamingWriteCallback callback,
25562580
void* callback_data) {

runtime/bin/dartutils.cc

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "include/dart_native_api.h"
1515
#include "platform/assert.h"
1616
#include "platform/globals.h"
17+
#include "platform/mach_o.h"
1718
#include "platform/utils.h"
1819

1920
// Return the error from the containing function if handle is in error handle.
@@ -34,9 +35,6 @@ dart::SimpleHashMap* DartUtils::environment_ = nullptr;
3435

3536
MagicNumberData appjit_magic_number = {8, {0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0}};
3637
MagicNumberData aotelf_magic_number = {4, {0x7F, 0x45, 0x4C, 0x46, 0x0}};
37-
MagicNumberData aotmacho32_magic_number = {4, {0xFE, 0xED, 0xFA, 0xCE}};
38-
MagicNumberData aotmacho64_magic_number = {4, {0xFE, 0xED, 0xFA, 0xCF}};
39-
MagicNumberData aotmacho64_arm64_magic_number = {4, {0xCF, 0xFA, 0xED, 0xFE}};
4038
MagicNumberData aotcoff_arm32_magic_number = {2, {0x01, 0xC0}};
4139
MagicNumberData aotcoff_arm64_magic_number = {2, {0xAA, 0x64}};
4240
MagicNumberData aotcoff_riscv32_magic_number = {2, {0x50, 0x32}};
@@ -404,9 +402,8 @@ DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const char* filename) {
404402
MagicNumber magic_number = DartUtils::kUnknownMagicNumber;
405403
ASSERT(kMaxMagicNumberSize == appjit_magic_number.length);
406404
ASSERT(aotelf_magic_number.length <= appjit_magic_number.length);
407-
ASSERT(aotmacho32_magic_number.length <= appjit_magic_number.length);
408-
ASSERT(aotmacho64_magic_number.length <= appjit_magic_number.length);
409-
ASSERT(aotmacho64_arm64_magic_number.length <= appjit_magic_number.length);
405+
ASSERT(static_cast<intptr_t>(sizeof(mach_o::mach_header::magic)) <=
406+
appjit_magic_number.length);
410407
ASSERT(aotcoff_arm32_magic_number.length <= appjit_magic_number.length);
411408
ASSERT(aotcoff_arm64_magic_number.length <= appjit_magic_number.length);
412409
ASSERT(aotcoff_riscv32_magic_number.length <= appjit_magic_number.length);
@@ -453,16 +450,19 @@ DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const uint8_t* buffer,
453450
return kAotELFMagicNumber;
454451
}
455452

456-
if (CheckMagicNumber(buffer, buffer_length, aotmacho32_magic_number)) {
457-
return kAotMachO32MagicNumber;
458-
}
459-
460-
if (CheckMagicNumber(buffer, buffer_length, aotmacho64_magic_number)) {
461-
return kAotMachO64MagicNumber;
462-
}
463-
464-
if (CheckMagicNumber(buffer, buffer_length, aotmacho64_arm64_magic_number)) {
465-
return kAotMachO64Arm64MagicNumber;
453+
// Mach-O magic numbers are reported by whether the endianness of the file
454+
// matches the endianness of the system. Here, we only bother looking for
455+
// host-endian magic numbers, as our Mach-O parsing code won't handle the
456+
// reverse endian case.
457+
if (static_cast<intptr_t>(sizeof(mach_o::mach_header::magic)) <=
458+
buffer_length) {
459+
const uint32_t magic =
460+
reinterpret_cast<const mach_o::mach_header*>(buffer)->magic;
461+
if (magic == mach_o::MH_MAGIC) {
462+
return kAotMachO32MagicNumber;
463+
} else if (magic == mach_o::MH_MAGIC_64) {
464+
return kAotMachO64MagicNumber;
465+
}
466466
}
467467

468468
if (CheckMagicNumber(buffer, buffer_length, aotcoff_arm32_magic_number)) {

runtime/bin/dartutils.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,10 @@ class DartUtils {
260260
kKernelListMagicNumber,
261261
kGzipMagicNumber,
262262
kAotELFMagicNumber,
263+
// Only the host-endian magic numbers are recognized, not the reverse-endian
264+
// ("cigam") ones, as we can't load a reverse-endian snapshot anyway.
263265
kAotMachO32MagicNumber,
264266
kAotMachO64MagicNumber,
265-
kAotMachO64Arm64MagicNumber,
266267
kAotCoffARM32MagicNumber,
267268
kAotCoffARM64MagicNumber,
268269
kAotCoffRISCV32MagicNumber,
@@ -278,7 +279,24 @@ class DartUtils {
278279
(number <= DartUtils::kAotCoffRISCV64MagicNumber);
279280
}
280281

281-
// Checks if the buffer is a script snapshot, kernel file, or gzip file.
282+
// Returns the bitsize corresponding to the magic number if the bitsize
283+
// is specified by the magic number, otherwise returns -1.
284+
static intptr_t MagicNumberBitSize(MagicNumber number) {
285+
if (number == DartUtils::kAotMachO32MagicNumber ||
286+
number == DartUtils::kAotCoffARM32MagicNumber ||
287+
number == DartUtils::kAotCoffRISCV32MagicNumber) {
288+
return 32;
289+
}
290+
if (number == DartUtils::kAotMachO64MagicNumber ||
291+
number == DartUtils::kAotCoffARM64MagicNumber ||
292+
number == DartUtils::kAotCoffRISCV64MagicNumber) {
293+
return 64;
294+
}
295+
return -1;
296+
}
297+
298+
// Checks if the file is a script snapshot, kernel file, or gzip file
299+
// by reading the first kMaxMagicNumberSize bytes of the file.
282300
static MagicNumber SniffForMagicNumber(const char* filename);
283301

284302
// Checks if the buffer is a script snapshot, kernel file, or gzip file.

0 commit comments

Comments
 (0)