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:
parent
51f5dc0174
commit
c9778ed077
@ -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 =
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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(
|
||||
|
72
test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml
Normal file
72
test/ObjectYAML/MachO/fat_macho_i386_x86_64.yaml
Normal 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: ...
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user