diff options
-rw-r--r-- | llvm/include/llvm/Object/MachOUniversal.h | 6 | ||||
-rw-r--r-- | llvm/include/llvm/ObjectYAML/MachOYAML.h | 44 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/MachOYAML.cpp | 63 | ||||
-rw-r--r-- | llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml | 72 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/macho2yaml.cpp | 39 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/obj2yaml.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/obj2yaml.h | 2 | ||||
-rw-r--r-- | llvm/tools/yaml2obj/yaml2macho.cpp | 107 |
8 files changed, 328 insertions, 11 deletions
diff --git a/llvm/include/llvm/Object/MachOUniversal.h b/llvm/include/llvm/Object/MachOUniversal.h index 8e6b204e728..f5acf90d446 100644 --- a/llvm/include/llvm/Object/MachOUniversal.h +++ b/llvm/include/llvm/Object/MachOUniversal.h @@ -84,6 +84,12 @@ public: else // Parent->getMagic() == MachO::FAT_MAGIC_64 return Header64.align; } + uint32_t getReserved() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return 0; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.align; + } std::string getArchTypeName() const { if (Parent->getMagic() == MachO::FAT_MAGIC) { Triple T = diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h index dee1bec3af3..e8565e24d91 100644 --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -109,6 +109,32 @@ struct Object { LinkEditData LinkEdit; }; +struct FatHeader { + llvm::yaml::Hex32 magic; + uint32_t nfat_arch; +}; + +struct FatArch { + llvm::yaml::Hex32 cputype; + llvm::yaml::Hex32 cpusubtype; + llvm::yaml::Hex64 offset; + uint64_t size; + uint32_t align; + llvm::yaml::Hex32 reserved; +}; + +struct UniversalBinary { + FatHeader Header; + std::vector<FatArch> FatArchs; + std::vector<Object> Slices; +}; + +struct MachFile { + bool isFat; + UniversalBinary FatFile; + Object ThinFile; +}; + } // namespace llvm::MachOYAML } // namespace llvm @@ -122,6 +148,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::BindOpcode) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::ExportEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch) namespace llvm { namespace yaml { @@ -134,6 +162,22 @@ template <> struct MappingTraits<MachOYAML::Object> { static void mapping(IO &IO, MachOYAML::Object &Object); }; +template <> struct MappingTraits<MachOYAML::FatHeader> { + static void mapping(IO &IO, MachOYAML::FatHeader &FatHeader); +}; + +template <> struct MappingTraits<MachOYAML::FatArch> { + static void mapping(IO &IO, MachOYAML::FatArch &FatArch); +}; + +template <> struct MappingTraits<MachOYAML::UniversalBinary> { + static void mapping(IO &IO, MachOYAML::UniversalBinary &UniversalBinary); +}; + +template <> struct MappingTraits<MachOYAML::MachFile> { + static void mapping(IO &IO, MachOYAML::MachFile &MachFile); +}; + template <> struct MappingTraits<MachOYAML::LoadCommand> { static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand); }; diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index 890bc039956..15ff4efb5c3 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -96,7 +96,68 @@ void MappingTraits<MachOYAML::Object>::mapping(IO &IO, IO.mapRequired("FileHeader", Object.Header); IO.mapOptional("LoadCommands", Object.LoadCommands); IO.mapOptional("LinkEditData", Object.LinkEdit); - IO.setContext(nullptr); + + if (IO.getContext() == &Object) + IO.setContext(nullptr); +} + +void MappingTraits<MachOYAML::FatHeader>::mapping( + IO &IO, MachOYAML::FatHeader &FatHeader) { + IO.mapRequired("magic", FatHeader.magic); + IO.mapRequired("nfat_arch", FatHeader.nfat_arch); +} + +void MappingTraits<MachOYAML::FatArch>::mapping(IO &IO, + MachOYAML::FatArch &FatArch) { + IO.mapRequired("cputype", FatArch.cputype); + IO.mapRequired("cpusubtype", FatArch.cpusubtype); + IO.mapRequired("offset", FatArch.offset); + IO.mapRequired("size", FatArch.size); + IO.mapRequired("align", FatArch.align); + IO.mapOptional("reserved", FatArch.reserved, + static_cast<llvm::yaml::Hex32>(0)); +} + +void MappingTraits<MachOYAML::UniversalBinary>::mapping( + IO &IO, MachOYAML::UniversalBinary &UniversalBinary) { + if (!IO.getContext()) { + IO.setContext(&UniversalBinary); + IO.mapTag("!fat-mach-o", true); + } + IO.mapRequired("FatHeader", UniversalBinary.Header); + IO.mapRequired("FatArchs", UniversalBinary.FatArchs); + IO.mapRequired("Slices", UniversalBinary.Slices); + + if (IO.getContext() == &UniversalBinary) + IO.setContext(nullptr); +} + +void MappingTraits<MachOYAML::MachFile>::mapping( + IO &IO, MachOYAML::MachFile &MachFile) { + if (!IO.getContext()) { + IO.setContext(&MachFile); + } + if (IO.outputting()) { + if (MachFile.isFat) { + IO.mapTag("!fat-mach-o", true); + MappingTraits<MachOYAML::UniversalBinary>::mapping(IO, MachFile.FatFile); + } else { + IO.mapTag("!mach-o", true); + MappingTraits<MachOYAML::Object>::mapping(IO, MachFile.ThinFile); + } + } else { + if (IO.mapTag("!fat-mach-o")) { + MachFile.isFat = true; + MappingTraits<MachOYAML::UniversalBinary>::mapping(IO, MachFile.FatFile); + } else if (IO.mapTag("!mach-o")) { + MachFile.isFat = false; + MappingTraits<MachOYAML::Object>::mapping(IO, MachFile.ThinFile); + } else { + assert(false && "No tag found in YAML, cannot identify file type!"); + } + } + if (IO.getContext() == &MachFile) + IO.setContext(nullptr); } void MappingTraits<MachOYAML::LinkEditData>::mapping( diff --git a/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml b/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml new file mode 100644 index 00000000000..edd3338f925 --- /dev/null +++ b/llvm/test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml @@ -0,0 +1,72 @@ +# RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s + +--- !fat-mach-o +FatHeader: + magic: 0xCAFEBABE + nfat_arch: 2 +FatArchs: + - cputype: 0x00000007 + cpusubtype: 0x00000003 + offset: 0x0000000000001000 + size: 15244 + align: 12 + - cputype: 0x01000007 + cpusubtype: 0x80000003 + offset: 0x0000000000005000 + size: 15380 + align: 12 +Slices: + - FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000002 + ncmds: 0 + sizeofcmds: 0 + flags: 0x01218085 + - FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x80000003 + filetype: 0x00000002 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00218085 + reserved: 0x00000000 +... + + +#CHECK: --- !fat-mach-o +#CHECK: FatHeader: +#CHECK: magic: 0xCAFEBABE +#CHECK: nfat_arch: 2 +#CHECK: FatArchs: +#CHECK: - cputype: 0x00000007 +#CHECK: cpusubtype: 0x00000003 +#CHECK: offset: 0x0000000000001000 +#CHECK: size: 15244 +#CHECK: align: 12 +#CHECK: - cputype: 0x01000007 +#CHECK: cpusubtype: 0x80000003 +#CHECK: offset: 0x0000000000005000 +#CHECK: size: 15380 +#CHECK: align: 12 +#CHECK: Slices: +#CHECK: - FileHeader: +#CHECK: magic: 0xFEEDFACE +#CHECK: cputype: 0x00000007 +#CHECK: cpusubtype: 0x00000003 +#CHECK: filetype: 0x00000002 +#CHECK: ncmds: 0 +#CHECK: sizeofcmds: 0 +#CHECK: flags: 0x01218085 +#CHECK: - FileHeader: +#CHECK: magic: 0xFEEDFACF +#CHECK: cputype: 0x01000007 +#CHECK: cpusubtype: 0x80000003 +#CHECK: filetype: 0x00000002 +#CHECK: ncmds: 0 +#CHECK: sizeofcmds: 0 +#CHECK: flags: 0x00218085 +#CHECK: reserved: 0x00000000 +#CHECK: ... diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index 24bd6a60da4..060a2b82726 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -473,23 +473,52 @@ Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { } Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) { - return make_error<Obj2YamlError>(obj2yaml_error::not_implemented); + MachOYAML::MachFile YAMLFile; + YAMLFile.isFat = true; + MachOYAML::UniversalBinary &YAML = YAMLFile.FatFile; + YAML.Header.magic = Obj.getMagic(); + YAML.Header.nfat_arch = Obj.getNumberOfObjects(); + + for (auto Slice : Obj.objects()) { + MachOYAML::FatArch arch; + arch.cputype = Slice.getCPUType(); + arch.cpusubtype = Slice.getCPUSubType(); + arch.offset = Slice.getOffset(); + arch.size = Slice.getSize(); + arch.align = Slice.getAlign(); + arch.reserved = Slice.getReserved(); + YAML.FatArchs.push_back(arch); + + auto SliceObj = Slice.getAsObjectFile(); + if (!SliceObj) + return SliceObj.takeError(); + + MachODumper Dumper(*SliceObj.get()); + Expected<std::unique_ptr<MachOYAML::Object>> YAMLObj = Dumper.dump(); + if (!YAMLObj) + return YAMLObj.takeError(); + YAML.Slices.push_back(*YAMLObj.get()); + } + + yaml::Output Yout(Out); + Yout << YAML; + return Error::success(); } -std::error_code macho2yaml(raw_ostream &Out, const object::ObjectFile &Obj) { - if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Obj)) { +std::error_code macho2yaml(raw_ostream &Out, const object::Binary &Binary) { + if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Binary)) { if (auto Err = macho2yaml(Out, *MachOObj)) { return errorToErrorCode(std::move(Err)); } return obj2yaml_error::success; } - if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) { + if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Binary)) { if (auto Err = macho2yaml(Out, *MachOObj)) { return errorToErrorCode(std::move(Err)); } return obj2yaml_error::success; } - + return obj2yaml_error::unsupported_obj_file_format; } diff --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp index e243f2d843a..3f9373ee17e 100644 --- a/llvm/tools/obj2yaml/obj2yaml.cpp +++ b/llvm/tools/obj2yaml/obj2yaml.cpp @@ -24,8 +24,6 @@ static std::error_code dumpObject(const ObjectFile &Obj) { return coff2yaml(outs(), cast<COFFObjectFile>(Obj)); if (Obj.isELF()) return elf2yaml(outs(), Obj); - if (Obj.isMachO() || Obj.isMachOUniversalBinary()) - return macho2yaml(outs(), Obj); return obj2yaml_error::unsupported_obj_file_format; } @@ -36,6 +34,10 @@ static std::error_code dumpInput(StringRef File) { return errorToErrorCode(BinaryOrErr.takeError()); Binary &Binary = *BinaryOrErr.get().getBinary(); + // Universal MachO is not a subclass of ObjectFile, so it needs to be handled + // here with the other binary types. + if (Binary.isMachO() || Binary.isMachOUniversalBinary()) + return macho2yaml(outs(), Binary); // TODO: If this is an archive, then burst it and dump each entry if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) return dumpObject(*Obj); diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h index c17b7d1642c..28c74751c0d 100644 --- a/llvm/tools/obj2yaml/obj2yaml.h +++ b/llvm/tools/obj2yaml/obj2yaml.h @@ -22,6 +22,6 @@ std::error_code coff2yaml(llvm::raw_ostream &Out, std::error_code elf2yaml(llvm::raw_ostream &Out, const llvm::object::ObjectFile &Obj); std::error_code macho2yaml(llvm::raw_ostream &Out, - const llvm::object::ObjectFile &Obj); + const llvm::object::Binary &Obj); #endif diff --git a/llvm/tools/yaml2obj/yaml2macho.cpp b/llvm/tools/yaml2obj/yaml2macho.cpp index 7821e63cf88..3d8be965209 100644 --- a/llvm/tools/yaml2obj/yaml2macho.cpp +++ b/llvm/tools/yaml2obj/yaml2macho.cpp @@ -424,17 +424,120 @@ Error MachOWriter::writeStringTable(raw_ostream &OS) { return Error::success(); } +class UniversalWriter { +public: + UniversalWriter(MachOYAML::MachFile &MachFile) + : MachFile(MachFile), fileStart(0) {} + + Error writeMachO(raw_ostream &OS); + +private: + Error writeFatHeader(raw_ostream &OS); + Error writeFatArchs(raw_ostream &OS); + + void ZeroToOffset(raw_ostream &OS, size_t offset); + + MachOYAML::MachFile &MachFile; + uint64_t fileStart; +}; + +Error UniversalWriter::writeMachO(raw_ostream &OS) { + fileStart = OS.tell(); + if (!MachFile.isFat) { + MachOWriter Writer(MachFile.ThinFile); + return Writer.writeMachO(OS); + } + if (auto Err = writeFatHeader(OS)) + return Err; + if (auto Err = writeFatArchs(OS)) + return Err; + auto &FatFile = MachFile.FatFile; + assert(FatFile.FatArchs.size() == FatFile.Slices.size()); + for (size_t i = 0; i < FatFile.Slices.size(); i++) { + ZeroToOffset(OS, FatFile.FatArchs[i].offset); + MachOWriter Writer(FatFile.Slices[i]); + if (auto Err = Writer.writeMachO(OS)) + return Err; + auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size; + ZeroToOffset(OS, SliceEnd); + } + return Error::success(); +} + +Error UniversalWriter::writeFatHeader(raw_ostream &OS) { + auto &FatFile = MachFile.FatFile; + MachO::fat_header header; + header.magic = FatFile.Header.magic; + header.nfat_arch = FatFile.Header.nfat_arch; + if (sys::IsLittleEndianHost) + swapStruct(header); + OS.write(reinterpret_cast<const char *>(&header), sizeof(MachO::fat_header)); + return Error::success(); +} + +template <typename FatArchType> +FatArchType constructFatArch(MachOYAML::FatArch &Arch) { + FatArchType FatArch; + FatArch.cputype = Arch.cputype; + FatArch.cpusubtype = Arch.cpusubtype; + FatArch.offset = Arch.offset; + FatArch.size = Arch.size; + FatArch.align = Arch.align; + return FatArch; +} + +template <typename StructType> +void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {} + +template <> +void writeFatArch<MachO::fat_arch>(MachOYAML::FatArch &Arch, raw_ostream &OS) { + auto FatArch = constructFatArch<MachO::fat_arch>(Arch); + if (sys::IsLittleEndianHost) + swapStruct(FatArch); + OS.write(reinterpret_cast<const char *>(&FatArch), sizeof(MachO::fat_arch)); +} + +template <> +void writeFatArch<MachO::fat_arch_64>(MachOYAML::FatArch &Arch, + raw_ostream &OS) { + auto FatArch = constructFatArch<MachO::fat_arch_64>(Arch); + FatArch.reserved = Arch.reserved; + if (sys::IsLittleEndianHost) + swapStruct(FatArch); + OS.write(reinterpret_cast<const char *>(&FatArch), + sizeof(MachO::fat_arch_64)); +} + +Error UniversalWriter::writeFatArchs(raw_ostream &OS) { + auto &FatFile = MachFile.FatFile; + bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64; + for (auto Arch : FatFile.FatArchs) { + if (is64Bit) + writeFatArch<MachO::fat_arch_64>(Arch, OS); + else + writeFatArch<MachO::fat_arch>(Arch, OS); + } + + return Error::success(); +} + +void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { + auto currOffset = OS.tell() - fileStart; + if (currOffset < Offset) + ZeroFillBytes(OS, Offset - currOffset); +} + } // end anonymous namespace int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { - MachOYAML::Object Doc; + MachOYAML::MachFile Doc; YIn >> Doc; if (YIn.error()) { errs() << "yaml2obj: Failed to parse YAML file!\n"; return 1; } - MachOWriter Writer(Doc); + UniversalWriter Writer(Doc); if (auto Err = Writer.writeMachO(Out)) { errs() << toString(std::move(Err)); return 1; |