llvm.org GIT mirror llvm / e92acf1
[obj2yaml] [yaml2obj] Support for MachO Universal binaries This patch adds round-trip support for MachO Universal binaries to obj2yaml and yaml2obj. Universal binaries have a header and list of architecture structures, followed by a the individual object files at specified offsets. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273719 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Bieneman 3 years ago
8 changed file(s) with 330 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
8383 else // Parent->getMagic() == MachO::FAT_MAGIC_64
8484 return Header64.align;
8585 }
86 uint32_t getReserved() const {
87 if (Parent->getMagic() == MachO::FAT_MAGIC)
88 return 0;
89 else // Parent->getMagic() == MachO::FAT_MAGIC_64
90 return Header64.align;
91 }
8692 std::string getArchTypeName() const {
8793 if (Parent->getMagic() == MachO::FAT_MAGIC) {
8894 Triple T =
108108 LinkEditData LinkEdit;
109109 };
110110
111 struct FatHeader {
112 llvm::yaml::Hex32 magic;
113 uint32_t nfat_arch;
114 };
115
116 struct FatArch {
117 llvm::yaml::Hex32 cputype;
118 llvm::yaml::Hex32 cpusubtype;
119 llvm::yaml::Hex64 offset;
120 uint64_t size;
121 uint32_t align;
122 llvm::yaml::Hex32 reserved;
123 };
124
125 struct UniversalBinary {
126 FatHeader Header;
127 std::vector FatArchs;
128 std::vector Slices;
129 };
130
131 struct MachFile {
132 bool isFat;
133 UniversalBinary FatFile;
134 Object ThinFile;
135 };
136
111137 } // namespace llvm::MachOYAML
112138 } // namespace llvm
113139
121147 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::ExportEntry)
122148 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry)
123149 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef)
150 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object)
151 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch)
124152
125153 namespace llvm {
126154 namespace yaml {
131159
132160 template <> struct MappingTraits {
133161 static void mapping(IO &IO, MachOYAML::Object &Object);
162 };
163
164 template <> struct MappingTraits {
165 static void mapping(IO &IO, MachOYAML::FatHeader &FatHeader);
166 };
167
168 template <> struct MappingTraits {
169 static void mapping(IO &IO, MachOYAML::FatArch &FatArch);
170 };
171
172 template <> struct MappingTraits {
173 static void mapping(IO &IO, MachOYAML::UniversalBinary &UniversalBinary);
174 };
175
176 template <> struct MappingTraits {
177 static void mapping(IO &IO, MachOYAML::MachFile &MachFile);
134178 };
135179
136180 template <> struct MappingTraits {
9595 IO.mapRequired("FileHeader", Object.Header);
9696 IO.mapOptional("LoadCommands", Object.LoadCommands);
9797 IO.mapOptional("LinkEditData", Object.LinkEdit);
98 IO.setContext(nullptr);
98
99 if (IO.getContext() == &Object)
100 IO.setContext(nullptr);
101 }
102
103 void MappingTraits::mapping(
104 IO &IO, MachOYAML::FatHeader &FatHeader) {
105 IO.mapRequired("magic", FatHeader.magic);
106 IO.mapRequired("nfat_arch", FatHeader.nfat_arch);
107 }
108
109 void MappingTraits::mapping(IO &IO,
110 MachOYAML::FatArch &FatArch) {
111 IO.mapRequired("cputype", FatArch.cputype);
112 IO.mapRequired("cpusubtype", FatArch.cpusubtype);
113 IO.mapRequired("offset", FatArch.offset);
114 IO.mapRequired("size", FatArch.size);
115 IO.mapRequired("align", FatArch.align);
116 IO.mapOptional("reserved", FatArch.reserved,
117 static_cast(0));
118 }
119
120 void MappingTraits::mapping(
121 IO &IO, MachOYAML::UniversalBinary &UniversalBinary) {
122 if (!IO.getContext()) {
123 IO.setContext(&UniversalBinary);
124 IO.mapTag("!fat-mach-o", true);
125 }
126 IO.mapRequired("FatHeader", UniversalBinary.Header);
127 IO.mapRequired("FatArchs", UniversalBinary.FatArchs);
128 IO.mapRequired("Slices", UniversalBinary.Slices);
129
130 if (IO.getContext() == &UniversalBinary)
131 IO.setContext(nullptr);
132 }
133
134 void MappingTraits::mapping(
135 IO &IO, MachOYAML::MachFile &MachFile) {
136 if (!IO.getContext()) {
137 IO.setContext(&MachFile);
138 }
139 if (IO.outputting()) {
140 if (MachFile.isFat) {
141 IO.mapTag("!fat-mach-o", true);
142 MappingTraits::mapping(IO, MachFile.FatFile);
143 } else {
144 IO.mapTag("!mach-o", true);
145 MappingTraits::mapping(IO, MachFile.ThinFile);
146 }
147 } else {
148 if (IO.mapTag("!fat-mach-o")) {
149 MachFile.isFat = true;
150 MappingTraits::mapping(IO, MachFile.FatFile);
151 } else if (IO.mapTag("!mach-o")) {
152 MachFile.isFat = false;
153 MappingTraits::mapping(IO, MachFile.ThinFile);
154 } else {
155 assert(false && "No tag found in YAML, cannot identify file type!");
156 }
157 }
158 if (IO.getContext() == &MachFile)
159 IO.setContext(nullptr);
99160 }
100161
101162 void MappingTraits::mapping(
0 # RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s
1
2 --- !fat-mach-o
3 FatHeader:
4 magic: 0xCAFEBABE
5 nfat_arch: 2
6 FatArchs:
7 - cputype: 0x00000007
8 cpusubtype: 0x00000003
9 offset: 0x0000000000001000
10 size: 15244
11 align: 12
12 - cputype: 0x01000007
13 cpusubtype: 0x80000003
14 offset: 0x0000000000005000
15 size: 15380
16 align: 12
17 Slices:
18 - FileHeader:
19 magic: 0xFEEDFACE
20 cputype: 0x00000007
21 cpusubtype: 0x00000003
22 filetype: 0x00000002
23 ncmds: 0
24 sizeofcmds: 0
25 flags: 0x01218085
26 - FileHeader:
27 magic: 0xFEEDFACF
28 cputype: 0x01000007
29 cpusubtype: 0x80000003
30 filetype: 0x00000002
31 ncmds: 0
32 sizeofcmds: 0
33 flags: 0x00218085
34 reserved: 0x00000000
35 ...
36
37
38 #CHECK: --- !fat-mach-o
39 #CHECK: FatHeader:
40 #CHECK: magic: 0xCAFEBABE
41 #CHECK: nfat_arch: 2
42 #CHECK: FatArchs:
43 #CHECK: - cputype: 0x00000007
44 #CHECK: cpusubtype: 0x00000003
45 #CHECK: offset: 0x0000000000001000
46 #CHECK: size: 15244
47 #CHECK: align: 12
48 #CHECK: - cputype: 0x01000007
49 #CHECK: cpusubtype: 0x80000003
50 #CHECK: offset: 0x0000000000005000
51 #CHECK: size: 15380
52 #CHECK: align: 12
53 #CHECK: Slices:
54 #CHECK: - FileHeader:
55 #CHECK: magic: 0xFEEDFACE
56 #CHECK: cputype: 0x00000007
57 #CHECK: cpusubtype: 0x00000003
58 #CHECK: filetype: 0x00000002
59 #CHECK: ncmds: 0
60 #CHECK: sizeofcmds: 0
61 #CHECK: flags: 0x01218085
62 #CHECK: - FileHeader:
63 #CHECK: magic: 0xFEEDFACF
64 #CHECK: cputype: 0x01000007
65 #CHECK: cpusubtype: 0x80000003
66 #CHECK: filetype: 0x00000002
67 #CHECK: ncmds: 0
68 #CHECK: sizeofcmds: 0
69 #CHECK: flags: 0x00218085
70 #CHECK: reserved: 0x00000000
71 #CHECK: ...
472472 }
473473
474474 Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) {
475 return make_error(obj2yaml_error::not_implemented);
476 }
477
478 std::error_code macho2yaml(raw_ostream &Out, const object::ObjectFile &Obj) {
479 if (const auto *MachOObj = dyn_cast(&Obj)) {
475 MachOYAML::MachFile YAMLFile;
476 YAMLFile.isFat = true;
477 MachOYAML::UniversalBinary &YAML = YAMLFile.FatFile;
478 YAML.Header.magic = Obj.getMagic();
479 YAML.Header.nfat_arch = Obj.getNumberOfObjects();
480
481 for (auto Slice : Obj.objects()) {
482 MachOYAML::FatArch arch;
483 arch.cputype = Slice.getCPUType();
484 arch.cpusubtype = Slice.getCPUSubType();
485 arch.offset = Slice.getOffset();
486 arch.size = Slice.getSize();
487 arch.align = Slice.getAlign();
488 arch.reserved = Slice.getReserved();
489 YAML.FatArchs.push_back(arch);
490
491 auto SliceObj = Slice.getAsObjectFile();
492 if (!SliceObj)
493 return SliceObj.takeError();
494
495 MachODumper Dumper(*SliceObj.get());
496 Expected> YAMLObj = Dumper.dump();
497 if (!YAMLObj)
498 return YAMLObj.takeError();
499 YAML.Slices.push_back(*YAMLObj.get());
500 }
501
502 yaml::Output Yout(Out);
503 Yout << YAML;
504 return Error::success();
505 }
506
507 std::error_code macho2yaml(raw_ostream &Out, const object::Binary &Binary) {
508 if (const auto *MachOObj = dyn_cast(&Binary)) {
480509 if (auto Err = macho2yaml(Out, *MachOObj)) {
481510 return errorToErrorCode(std::move(Err));
482511 }
483512 return obj2yaml_error::success;
484513 }
485514
486 if (const auto *MachOObj = dyn_cast(&Obj)) {
515 if (const auto *MachOObj = dyn_cast(&Binary)) {
487516 if (auto Err = macho2yaml(Out, *MachOObj)) {
488517 return errorToErrorCode(std::move(Err));
489518 }
490519 return obj2yaml_error::success;
491520 }
492
521
493522 return obj2yaml_error::unsupported_obj_file_format;
494523 }
2323 return coff2yaml(outs(), cast(Obj));
2424 if (Obj.isELF())
2525 return elf2yaml(outs(), Obj);
26 if (Obj.isMachO() || Obj.isMachOUniversalBinary())
27 return macho2yaml(outs(), Obj);
2826
2927 return obj2yaml_error::unsupported_obj_file_format;
3028 }
3533 return errorToErrorCode(BinaryOrErr.takeError());
3634
3735 Binary &Binary = *BinaryOrErr.get().getBinary();
36 // Universal MachO is not a subclass of ObjectFile, so it needs to be handled
37 // here with the other binary types.
38 if (Binary.isMachO() || Binary.isMachOUniversalBinary())
39 return macho2yaml(outs(), Binary);
3840 // TODO: If this is an archive, then burst it and dump each entry
3941 if (ObjectFile *Obj = dyn_cast(&Binary))
4042 return dumpObject(*Obj);
2121 std::error_code elf2yaml(llvm::raw_ostream &Out,
2222 const llvm::object::ObjectFile &Obj);
2323 std::error_code macho2yaml(llvm::raw_ostream &Out,
24 const llvm::object::ObjectFile &Obj);
24 const llvm::object::Binary &Obj);
2525
2626 #endif
423423 return Error::success();
424424 }
425425
426 class UniversalWriter {
427 public:
428 UniversalWriter(MachOYAML::MachFile &MachFile)
429 : MachFile(MachFile), fileStart(0) {}
430
431 Error writeMachO(raw_ostream &OS);
432
433 private:
434 Error writeFatHeader(raw_ostream &OS);
435 Error writeFatArchs(raw_ostream &OS);
436
437 void ZeroToOffset(raw_ostream &OS, size_t offset);
438
439 MachOYAML::MachFile &MachFile;
440 uint64_t fileStart;
441 };
442
443 Error UniversalWriter::writeMachO(raw_ostream &OS) {
444 fileStart = OS.tell();
445 if (!MachFile.isFat) {
446 MachOWriter Writer(MachFile.ThinFile);
447 return Writer.writeMachO(OS);
448 }
449 if (auto Err = writeFatHeader(OS))
450 return Err;
451 if (auto Err = writeFatArchs(OS))
452 return Err;
453 auto &FatFile = MachFile.FatFile;
454 assert(FatFile.FatArchs.size() == FatFile.Slices.size());
455 for (size_t i = 0; i < FatFile.Slices.size(); i++) {
456 ZeroToOffset(OS, FatFile.FatArchs[i].offset);
457 MachOWriter Writer(FatFile.Slices[i]);
458 if (auto Err = Writer.writeMachO(OS))
459 return Err;
460 auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size;
461 ZeroToOffset(OS, SliceEnd);
462 }
463 return Error::success();
464 }
465
466 Error UniversalWriter::writeFatHeader(raw_ostream &OS) {
467 auto &FatFile = MachFile.FatFile;
468 MachO::fat_header header;
469 header.magic = FatFile.Header.magic;
470 header.nfat_arch = FatFile.Header.nfat_arch;
471 if (sys::IsLittleEndianHost)
472 swapStruct(header);
473 OS.write(reinterpret_cast(&header), sizeof(MachO::fat_header));
474 return Error::success();
475 }
476
477 template
478 FatArchType constructFatArch(MachOYAML::FatArch &Arch) {
479 FatArchType FatArch;
480 FatArch.cputype = Arch.cputype;
481 FatArch.cpusubtype = Arch.cpusubtype;
482 FatArch.offset = Arch.offset;
483 FatArch.size = Arch.size;
484 FatArch.align = Arch.align;
485 return FatArch;
486 }
487
488 template
489 void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {}
490
491 template <>
492 void writeFatArch(MachOYAML::FatArch &Arch, raw_ostream &OS) {
493 auto FatArch = constructFatArch(Arch);
494 if (sys::IsLittleEndianHost)
495 swapStruct(FatArch);
496 OS.write(reinterpret_cast(&FatArch), sizeof(MachO::fat_arch));
497 }
498
499 template <>
500 void writeFatArch(MachOYAML::FatArch &Arch,
501 raw_ostream &OS) {
502 auto FatArch = constructFatArch(Arch);
503 FatArch.reserved = Arch.reserved;
504 if (sys::IsLittleEndianHost)
505 swapStruct(FatArch);
506 OS.write(reinterpret_cast(&FatArch),
507 sizeof(MachO::fat_arch_64));
508 }
509
510 Error UniversalWriter::writeFatArchs(raw_ostream &OS) {
511 auto &FatFile = MachFile.FatFile;
512 bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64;
513 for (auto Arch : FatFile.FatArchs) {
514 if (is64Bit)
515 writeFatArch(Arch, OS);
516 else
517 writeFatArch(Arch, OS);
518 }
519
520 return Error::success();
521 }
522
523 void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
524 auto currOffset = OS.tell() - fileStart;
525 if (currOffset < Offset)
526 ZeroFillBytes(OS, Offset - currOffset);
527 }
528
426529 } // end anonymous namespace
427530
428531 int yaml2macho(yaml::Input &YIn, raw_ostream &Out) {
429 MachOYAML::Object Doc;
532 MachOYAML::MachFile Doc;
430533 YIn >> Doc;
431534 if (YIn.error()) {
432535 errs() << "yaml2obj: Failed to parse YAML file!\n";
433536 return 1;
434537 }
435538
436 MachOWriter Writer(Doc);
539 UniversalWriter Writer(Doc);
437540 if (auto Err = Writer.writeMachO(Out)) {
438541 errs() << toString(std::move(Err));
439542 return 1;