1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

[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.

llvm-svn: 273719
This commit is contained in:
Chris Bieneman 2016-06-24 20:42:28 +00:00
parent 51f5dc0174
commit c9778ed077
8 changed files with 328 additions and 11 deletions

View File

@ -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 =

View File

@ -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);
};

View File

@ -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(

View File

@ -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: ...

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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;