Skip to content

Commit 83e9bd7

Browse files
sstricklCommit Queue
authored andcommitted
[vm] Additional Mach-O related command line options for gen_snapshot.
Adds the following command line options to gen_snapshot: * --macho-install-name: The name to use as the install name for the dynamic library (used in the LC_ID_DYLIB and LC_CODE_SIGNATURE load commands). If not provided, the output filename is used. * --[no-]macho-linker-signature: Whether or not gen_snapshot should generate an ad-hoc linker-signed signature. Defaults to true. The following command line option is macOS/iOS-specific: * --macho-rpath: Comma-delimited run paths that should be added at runtime to the current run path used for finding @rpath-prefixed dynamic libraries. Adds support to parsing rpath and dylib load commands to pkg/native_stack_traces's Mach-O parser in order to test the command line options appropriately. TEST=vm/dart/use_macho_options Issue: #60307 Change-Id: I17618578a7bff7851a88cdaf27f299f058f98dd3 Cq-Include-Trybots: luci.dart.try:vm-aot-mac-debug-x64-try,vm-aot-mac-debug-arm64-try,vm-aot-linux-debug-arm64-try,vm-aot-linux-debug-x64-try,pkg-mac-release-try,pkg-mac-release-arm64-try,pkg-linux-release-arm64-try,vm-aot-win-release-arm64-try,vm-aot-win-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/441920 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Tess Strickland <[email protected]>
1 parent 20f7737 commit 83e9bd7

File tree

6 files changed

+545
-164
lines changed

6 files changed

+545
-164
lines changed

pkg/native_stack_traces/lib/src/macho.dart

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,15 @@ class LoadCommand {
121121

122122
LoadCommand._(this.cmd, this.cmdsize);
123123

124+
static const LC_REQ_DYLD = 0x80000000;
125+
124126
static const LC_SEGMENT = 0x1;
125127
static const LC_SYMTAB = 0x2;
128+
static const LC_ID_DYLIB = 0xd;
126129
static const LC_SEGMENT_64 = 0x19;
127130
static const LC_UUID = 0x1b;
131+
static const LC_RPATH = 0x1c | LC_REQ_DYLD;
132+
static const LC_CODE_SIGNATURE = 0x1d; // Only used in vm/dart tests.
128133
static const LC_BUILD_VERSION = 0x32;
129134

130135
static LoadCommand fromReader(Reader reader) {
@@ -147,6 +152,10 @@ class LoadCommand {
147152
case LC_BUILD_VERSION:
148153
command = BuildVersionCommand.fromReader(reader, cmd, cmdsize);
149154
break;
155+
case LC_ID_DYLIB:
156+
command = DylibCommand.fromReader(reader, cmd, cmdsize);
157+
case LC_RPATH:
158+
command = RunPathCommand.fromReader(reader, cmd, cmdsize);
150159
default:
151160
break;
152161
}
@@ -355,6 +364,86 @@ class UuidCommand extends LoadCommand {
355364
}
356365
}
357366

367+
class DylibInfo {
368+
final String name;
369+
final int timestamp;
370+
final int currentVersion;
371+
final int compatibilityVersion;
372+
373+
const DylibInfo._(this.name, this.timestamp, this.currentVersion,
374+
this.compatibilityVersion);
375+
376+
static DylibInfo fromReader(Reader reader, int cmdsize) {
377+
final start = reader.offset - 8; // cmd + cmdsize
378+
final offset = _readMachOUint32(reader);
379+
final timestamp = _readMachOUint32(reader);
380+
final currentVersion = _readMachOUint32(reader);
381+
final compatibilityVersion = _readMachOUint32(reader);
382+
reader.seek(start + offset, absolute: true);
383+
final name = reader.readNullTerminatedString(maxSize: cmdsize - offset);
384+
return DylibInfo._(name, timestamp, currentVersion, compatibilityVersion);
385+
}
386+
387+
void writeToStringBuffer(StringBuffer buffer) {
388+
buffer
389+
..write(' Name: ')
390+
..writeln(name)
391+
..write(' Timestamp: ')
392+
..writeln(timestamp)
393+
..write(' Current version: ')
394+
..writeln(currentVersion)
395+
..write(' Compatibility version: ')
396+
..writeln(compatibilityVersion);
397+
}
398+
399+
@override
400+
String toString() {
401+
final buffer = StringBuffer();
402+
writeToStringBuffer(buffer);
403+
return buffer.toString();
404+
}
405+
}
406+
407+
class DylibCommand extends LoadCommand {
408+
final DylibInfo info;
409+
410+
DylibCommand._(super.cmd, super.cmdsize, this.info) : super._();
411+
412+
static DylibCommand fromReader(Reader reader, int cmd, int cmdsize) =>
413+
DylibCommand._(cmd, cmdsize, DylibInfo.fromReader(reader, cmdsize));
414+
415+
@override
416+
void writeToStringBuffer(StringBuffer buffer) {
417+
if (cmd == LoadCommand.LC_ID_DYLIB) {
418+
buffer.writeln('LC_ID_DYLIB:');
419+
info.writeToStringBuffer(buffer);
420+
} else {
421+
throw StateError("Unexpected command code $cmd");
422+
}
423+
}
424+
}
425+
426+
class RunPathCommand extends LoadCommand {
427+
String path;
428+
429+
RunPathCommand._(super.cmd, super.cmdsize, this.path) : super._();
430+
431+
static RunPathCommand fromReader(Reader reader, int cmd, int cmdsize) {
432+
final start = reader.offset - 8; // cmd + cmdsize
433+
final offset = _readMachOUint32(reader);
434+
reader.seek(start + offset, absolute: true);
435+
final path = reader.readNullTerminatedString(maxSize: cmdsize - offset);
436+
return RunPathCommand._(cmd, cmdsize, path);
437+
}
438+
439+
@override
440+
void writeToStringBuffer(StringBuffer buffer) {
441+
buffer
442+
..write('Run path: ')
443+
..write(path);
444+
}
445+
}
446+
358447
class Version {
359448
final int x;
360449
final int y;
@@ -688,6 +777,7 @@ class MachO extends DwarfContainer {
688777
Reader.fromTypedData(reader.bdata,
689778
wordSize: _header.wordSize, endian: _header.endian);
690779

780+
Iterable<LoadCommand> get commands => _commands;
691781
Iterable<T> commandsWhereType<T extends LoadCommand>() =>
692782
_commands.whereType<T>();
693783

runtime/platform/mach_o.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ struct load_command {
115115
// The description of the LC_* constants are followed by the name of
116116
// the specific C structure describing their contents in parentheses.
117117

118+
// Flag stored in high bit for LC_* constants that denotes sections
119+
// the dynamic linker must understand to properly load the library.
120+
static constexpr uint32_t LC_REQ_DYLD = 0x80000000;
121+
118122
// A portion of the file that is mapped into memory when the
119123
// object file is loaded. (segment_command)
120124
static constexpr uint32_t LC_SEGMENT = 0x1;
@@ -132,6 +136,7 @@ static constexpr uint32_t LC_ID_DYLIB = 0xd;
132136
static constexpr uint32_t LC_SEGMENT_64 = 0x19;
133137
// The UUID, used as a build identifier. (uuid_command)
134138
static constexpr uint32_t LC_UUID = 0x1b;
139+
static constexpr uint32_t LC_RPATH = (0x1c | LC_REQ_DYLD);
135140
// The code signature which protects the preceding portion of the object file.
136141
// Must be the last contents in the object file. (linkedit_data_command)
137142
static constexpr uint32_t LC_CODE_SIGNATURE = 0x1d;
@@ -452,6 +457,12 @@ struct linkedit_data_command {
452457
uint32_t datasize;
453458
};
454459

460+
struct rpath_command {
461+
uint32_t cmd; // LC_RPATH
462+
uint32_t cmdsize;
463+
lc_str path;
464+
};
465+
455466
// Magic numbers for code signature blobs.
456467

457468
static constexpr uint32_t CSMAGIC_CODEDIRECTORY = 0xfade0c02;

0 commit comments

Comments
 (0)