[vm] Output accompaning relocatable object for Mach-O snapshots.

In order to appropriately generate .dSYMs for a snapshot and allow
the strip tool to be used on the snapshot afterwards, add a mode that
not only outputs the snapshot (sans DWARF information) but also
an associated relocatable object file that contains the program's DWARF
information. That allows dsymutil to retrieve the DWARF information
from the relocatable object when run on the snapshot prior to stripping.

To specify that the relocatable object file should be output, use
the new --macho-object command line argument to gen_snapshot
to specify where the object file should be written.

This CL also adds an additional command line argument,
--macho-reduce-padding, which reduces the alignment used for segments
and the text/const sections in Mach-O outputs from 16KB to 64 bytes.
The larger padding is needed for some uses, like non-native loading
of Mach-O objects, but can be elided for other uses like Flutter builds.

TEST=vm/dart/use_dwarf_stack_traces_flag_test
     vm/dart/use_macho_reduce_padding_flag_test

Change-Id: I2bf4bacb70c41299b8b6fdb7635c2374acf7a07d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/457420
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Tess Strickland
2025-11-19 07:45:52 -08:00
committed by Commit Queue
parent 18e6ccadc3
commit bc021bbc01
16 changed files with 1602 additions and 324 deletions
+96 -20
View File
@@ -6616,7 +6616,7 @@ static constexpr intptr_t kAssemblyInitialSize = 512 * KB;
static constexpr intptr_t kInitialSize = 2 * MB;
static constexpr intptr_t kInitialDebugSize = 1 * MB;
static void CreateAppAOTSnapshot(
static void CreateAppAOTSnapshotHelper(
Dart_StreamingWriteCallback callback,
void* callback_data,
bool strip,
@@ -6626,7 +6626,8 @@ static void CreateAppAOTSnapshot(
LoadingUnitSerializationData* unit,
uint32_t program_hash,
const char* identifier,
const char* path) {
const char* path,
void* object_callback_data) {
Thread* T = Thread::Current();
NOT_IN_PRODUCT(TimelineBeginEndScope tbes2(T, Timeline::GetIsolateStream(),
@@ -6671,6 +6672,14 @@ static void CreateAppAOTSnapshot(
: kInitialSize,
callback, callback_data);
// Should not be directly used below as writing to it when
// [object_callback_data] is null causes a crash. Instead, use
// [object_stream], which is appropriately nullptr in this case.
StreamingWriteStream object_stream_value(kInitialSize, callback,
object_callback_data);
StreamingWriteStream* object_stream =
object_callback_data != nullptr ? &object_stream_value : nullptr;
auto const use_output_writer = [&](ImageWriter* image_writer) {
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
&isolate_snapshot_data, image_writer,
@@ -6693,9 +6702,15 @@ static void CreateAppAOTSnapshot(
so = new (Z)
ElfWriter(Z, &output_stream, SharedObjectWriter::Type::Snapshot, dwarf);
} else if (format == Dart_AotBinaryFormat_MachO_Dylib) {
MachOWriter* object_writer = nullptr;
if (object_stream != nullptr) {
object_writer = new (Z)
MachOWriter(Z, object_stream, SharedObjectWriter::Type::Object,
identifier, path, dwarf);
}
so = new (Z)
MachOWriter(Z, &output_stream, SharedObjectWriter::Type::Snapshot,
identifier, path, dwarf);
identifier, path, dwarf, object_writer);
}
if (format == Dart_AotBinaryFormat_Assembly) {
@@ -6704,13 +6719,44 @@ static void CreateAppAOTSnapshot(
strip, debug_so);
use_output_writer(&assembly_writer);
} else {
BlobImageWriter blob_writer(T, &vm_snapshot_instructions,
&isolate_snapshot_instructions,
deobfuscation_trie, debug_so, so);
BlobImageWriter blob_writer(
T, &vm_snapshot_instructions, &isolate_snapshot_instructions,
deobfuscation_trie, debug_so, so,
/*needs_unique_names=*/object_callback_data != nullptr);
use_output_writer(&blob_writer);
}
}
static void CreateAppAOTProgramSnapshot(Dart_StreamingWriteCallback callback,
void* callback_data,
bool strip,
Dart_AotBinaryFormat format,
void* debug_callback_data,
const char* identifier = nullptr,
const char* path = nullptr,
void* object_callback_data = nullptr) {
CreateAppAOTSnapshotHelper(
callback, callback_data, strip, format, debug_callback_data,
/*units=*/nullptr,
/*unit=*/nullptr,
/*program_hash=*/0, identifier, path, object_callback_data);
}
static void CreateAppAOTUnitSnapshot(
Dart_StreamingWriteCallback callback,
void* callback_data,
bool strip,
Dart_AotBinaryFormat format,
void* debug_callback_data,
GrowableArray<LoadingUnitSerializationData*>* units,
LoadingUnitSerializationData* unit,
uint32_t program_hash) {
CreateAppAOTSnapshotHelper(callback, callback_data, strip, format,
debug_callback_data, units, unit, program_hash,
/*identifier=*/nullptr, /*path=*/nullptr,
/*object_callback_data=*/nullptr);
}
static void Split(Dart_CreateLoadingUnitCallback next_callback,
void* next_callback_data,
bool strip,
@@ -6746,10 +6792,9 @@ static void Split(Dart_CreateLoadingUnitCallback next_callback,
next_callback(next_callback_data, id, &write_callback_data,
&write_debug_callback_data);
}
CreateAppAOTSnapshot(write_callback, write_callback_data, strip, format,
write_debug_callback_data, &data, data[id],
program_hash, /*identifier=*/nullptr,
/*path=*/nullptr);
CreateAppAOTUnitSnapshot(write_callback, write_callback_data, strip, format,
write_debug_callback_data, &data, data[id],
program_hash);
{
TransitionVMToNative transition(T);
close_callback(write_callback_data);
@@ -6779,10 +6824,9 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
// Mark as not split.
T->isolate_group()->object_store()->set_loading_units(Object::null_array());
CreateAppAOTSnapshot(callback, callback_data, strip,
Dart_AotBinaryFormat_Assembly, debug_callback_data,
nullptr, nullptr, 0, /*identifier=*/nullptr,
/*path=*/nullptr);
CreateAppAOTProgramSnapshot(callback, callback_data, strip,
Dart_AotBinaryFormat_Assembly,
debug_callback_data);
return Api::Success();
#endif
@@ -6858,9 +6902,8 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
// Mark as not split.
T->isolate_group()->object_store()->set_loading_units(Object::null_array());
CreateAppAOTSnapshot(callback, callback_data, strip, Dart_AotBinaryFormat_Elf,
debug_callback_data, nullptr, nullptr, 0,
/*identifier=*/nullptr, /*path=*/nullptr);
CreateAppAOTProgramSnapshot(callback, callback_data, strip,
Dart_AotBinaryFormat_Elf, debug_callback_data);
return Api::Success();
#endif
@@ -6912,9 +6955,42 @@ Dart_CreateAppAOTSnapshotAsBinary(Dart_AotBinaryFormat format,
// Mark as not split.
T->isolate_group()->object_store()->set_loading_units(Object::null_array());
CreateAppAOTSnapshot(callback, callback_data, strip, format,
debug_callback_data, nullptr, nullptr, 0, identifier,
path);
CreateAppAOTProgramSnapshot(callback, callback_data, strip, format,
debug_callback_data, identifier, path);
return Api::Success();
#endif
}
DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAndRelocatableObject(
Dart_AotBinaryFormat format,
Dart_StreamingWriteCallback callback,
void* snapshot_callback_data,
void* object_callback_data,
bool strip,
void* debug_callback_data,
const char* identifier,
const char* path) {
#if defined(TARGET_ARCH_IA32)
return Api::NewError("AOT compilation is not supported on IA32.");
#elif !defined(DART_PRECOMPILER)
return Api::NewError(
"This VM was built without support for AOT compilation.");
#else
if (format != Dart_AotBinaryFormat_MachO_Dylib) {
return Api::NewError(
"Relocatable objects are currently only supported for Mach-O output.");
}
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
CHECK_NULL(callback);
// Mark as not split.
T->isolate_group()->object_store()->set_loading_units(Object::null_array());
CreateAppAOTProgramSnapshot(callback, snapshot_callback_data, strip, format,
debug_callback_data, identifier, path,
object_callback_data);
return Api::Success();
#endif