Index: include/llvm/ObjectYAML/MachOYAML.h =================================================================== --- include/llvm/ObjectYAML/MachOYAML.h +++ include/llvm/ObjectYAML/MachOYAML.h @@ -129,12 +129,6 @@ std::vector Slices; }; -struct MachFile { - bool isFat; - UniversalBinary FatFile; - Object ThinFile; -}; - } // namespace llvm::MachOYAML } // namespace llvm @@ -174,10 +168,6 @@ static void mapping(IO &IO, MachOYAML::UniversalBinary &UniversalBinary); }; -template <> struct MappingTraits { - static void mapping(IO &IO, MachOYAML::MachFile &MachFile); -}; - template <> struct MappingTraits { static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand); }; Index: include/llvm/ObjectYAML/ObjectYAML.h =================================================================== --- /dev/null +++ include/llvm/ObjectYAML/ObjectYAML.h @@ -0,0 +1,35 @@ +//===- ObjectYAML.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_OBJECTYAML_H +#define LLVM_OBJECTYAML_OBJECTYAML_H + +#include "llvm/Support/YAMLTraits.h" +#include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ObjectYAML/COFFYAML.h" +#include "llvm/ObjectYAML/MachOYAML.h" + +namespace llvm { +namespace yaml { + +struct YamlObjectFile { + std::unique_ptr Elf; + std::unique_ptr Coff; + std::unique_ptr MachO; + std::unique_ptr FatMachO; +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, YamlObjectFile &ObjectFile); +}; + +} // namespace yaml +} // namespace llvm + +#endif Index: lib/ObjectYAML/CMakeLists.txt =================================================================== --- lib/ObjectYAML/CMakeLists.txt +++ lib/ObjectYAML/CMakeLists.txt @@ -3,4 +3,5 @@ COFFYAML.cpp ELFYAML.cpp MachOYAML.cpp + ObjectYAML.cpp ) Index: lib/ObjectYAML/COFFYAML.cpp =================================================================== --- lib/ObjectYAML/COFFYAML.cpp +++ lib/ObjectYAML/COFFYAML.cpp @@ -493,6 +493,7 @@ } void MappingTraits::mapping(IO &IO, COFFYAML::Object &Obj) { + IO.mapTag("!COFF", true); IO.mapOptional("OptionalHeader", Obj.OptionalHeader); IO.mapRequired("header", Obj.Header); IO.mapRequired("sections", Obj.Sections); Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -820,6 +820,7 @@ void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { assert(!IO.getContext() && "The IO context is initialized already"); IO.setContext(&Object); + IO.mapTag("!ELF", true); IO.mapRequired("FileHeader", Object.Header); IO.mapOptional("Sections", Object.Sections); IO.mapOptional("Symbols", Object.Symbols); Index: lib/ObjectYAML/MachOYAML.cpp =================================================================== --- lib/ObjectYAML/MachOYAML.cpp +++ lib/ObjectYAML/MachOYAML.cpp @@ -132,34 +132,6 @@ IO.setContext(nullptr); } -void MappingTraits::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::mapping(IO, MachFile.FatFile); - } else { - IO.mapTag("!mach-o", true); - MappingTraits::mapping(IO, MachFile.ThinFile); - } - } else { - if (IO.mapTag("!fat-mach-o")) { - MachFile.isFat = true; - MappingTraits::mapping(IO, MachFile.FatFile); - } else if (IO.mapTag("!mach-o")) { - MachFile.isFat = false; - MappingTraits::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::mapping( IO &IO, MachOYAML::LinkEditData &LinkEditData) { IO.mapOptional("RebaseOpcodes", LinkEditData.RebaseOpcodes); Index: lib/ObjectYAML/ObjectYAML.cpp =================================================================== --- /dev/null +++ lib/ObjectYAML/ObjectYAML.cpp @@ -0,0 +1,48 @@ +//===- ObjectYAML.cpp - YAML utilities for object files -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a wrapper class for handling tagged YAML input +// +//===----------------------------------------------------------------------===// + +#include "llvm/ObjectYAML/YAML.h" +#include "llvm/ObjectYAML/ObjectYAML.h" + +using namespace llvm; +using namespace yaml; + +void MappingTraits::mapping(IO &IO, + YamlObjectFile &ObjectFile) { + if (IO.outputting()) { + if (ObjectFile.Elf) + MappingTraits::mapping(IO, *ObjectFile.Elf); + if (ObjectFile.Coff) + MappingTraits::mapping(IO, *ObjectFile.Coff); + if (ObjectFile.MachO) + MappingTraits::mapping(IO, *ObjectFile.MachO); + if (ObjectFile.FatMachO) + MappingTraits::mapping(IO, + *ObjectFile.FatMachO); + } else { + if (IO.mapTag("!ELF")) { + ObjectFile.Elf.reset(new ELFYAML::Object()); + MappingTraits::mapping(IO, *ObjectFile.Elf); + } else if (IO.mapTag("!COFF")) { + ObjectFile.Coff.reset(new COFFYAML::Object()); + MappingTraits::mapping(IO, *ObjectFile.Coff); + } else if (IO.mapTag("!mach-o")) { + ObjectFile.MachO.reset(new MachOYAML::Object()); + MappingTraits::mapping(IO, *ObjectFile.MachO); + } else if (IO.mapTag("!fat-mach-o")) { + ObjectFile.FatMachO.reset(new MachOYAML::UniversalBinary()); + MappingTraits::mapping(IO, + *ObjectFile.FatMachO); + } + } +} Index: tools/obj2yaml/macho2yaml.cpp =================================================================== --- tools/obj2yaml/macho2yaml.cpp +++ tools/obj2yaml/macho2yaml.cpp @@ -10,7 +10,7 @@ #include "Error.h" #include "obj2yaml.h" #include "llvm/Object/MachOUniversal.h" -#include "llvm/ObjectYAML/MachOYAML.h" +#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" @@ -467,15 +467,18 @@ if (!YAML) return YAML.takeError(); + yaml::YamlObjectFile YAMLFile; + YAMLFile.MachO = std::move(YAML.get()); + yaml::Output Yout(Out); - Yout << *(YAML.get()); + Yout << YAMLFile; return Error::success(); } Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) { - MachOYAML::MachFile YAMLFile; - YAMLFile.isFat = true; - MachOYAML::UniversalBinary &YAML = YAMLFile.FatFile; + yaml::YamlObjectFile YAMLFile; + YAMLFile.FatMachO.reset(new MachOYAML::UniversalBinary()); + MachOYAML::UniversalBinary &YAML = *YAMLFile.FatMachO; YAML.Header.magic = Obj.getMagic(); YAML.Header.nfat_arch = Obj.getNumberOfObjects(); Index: tools/yaml2obj/yaml2coff.cpp =================================================================== --- tools/yaml2obj/yaml2coff.cpp +++ tools/yaml2obj/yaml2coff.cpp @@ -18,7 +18,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/COFF.h" -#include "llvm/ObjectYAML/COFFYAML.h" +#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" @@ -532,14 +532,7 @@ return true; } -int yaml2coff(yaml::Input &YIn, raw_ostream &Out) { - COFFYAML::Object Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - +int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) { COFFParser CP(Doc); if (!CP.parse()) { errs() << "yaml2obj: Failed to parse YAML file!\n"; Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -558,13 +558,7 @@ return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); } -int yaml2elf(yaml::Input &YIn, raw_ostream &Out) { - ELFYAML::Object Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } +int yaml2elf(llvm::ELFYAML::Object &Doc, raw_ostream &Out) { using object::ELFType; typedef ELFType LE64; typedef ELFType BE64; Index: tools/yaml2obj/yaml2macho.cpp =================================================================== --- tools/yaml2obj/yaml2macho.cpp +++ tools/yaml2obj/yaml2macho.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "yaml2obj.h" -#include "llvm/ObjectYAML/MachOYAML.h" +#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/Error.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MachO.h" @@ -426,8 +426,8 @@ class UniversalWriter { public: - UniversalWriter(MachOYAML::MachFile &MachFile) - : MachFile(MachFile), fileStart(0) {} + UniversalWriter(yaml::YamlObjectFile &ObjectFile) + : ObjectFile(ObjectFile), fileStart(0) {} Error writeMachO(raw_ostream &OS); @@ -437,21 +437,21 @@ void ZeroToOffset(raw_ostream &OS, size_t offset); - MachOYAML::MachFile &MachFile; + yaml::YamlObjectFile &ObjectFile; uint64_t fileStart; }; Error UniversalWriter::writeMachO(raw_ostream &OS) { fileStart = OS.tell(); - if (!MachFile.isFat) { - MachOWriter Writer(MachFile.ThinFile); + if (ObjectFile.MachO) { + MachOWriter Writer(*ObjectFile.MachO); return Writer.writeMachO(OS); } if (auto Err = writeFatHeader(OS)) return Err; if (auto Err = writeFatArchs(OS)) return Err; - auto &FatFile = MachFile.FatFile; + auto &FatFile = *ObjectFile.FatMachO; assert(FatFile.FatArchs.size() == FatFile.Slices.size()); for (size_t i = 0; i < FatFile.Slices.size(); i++) { ZeroToOffset(OS, FatFile.FatArchs[i].offset); @@ -465,7 +465,7 @@ } Error UniversalWriter::writeFatHeader(raw_ostream &OS) { - auto &FatFile = MachFile.FatFile; + auto &FatFile = *ObjectFile.FatMachO; MachO::fat_header header; header.magic = FatFile.Header.magic; header.nfat_arch = FatFile.Header.nfat_arch; @@ -509,7 +509,7 @@ } Error UniversalWriter::writeFatArchs(raw_ostream &OS) { - auto &FatFile = MachFile.FatFile; + auto &FatFile = *ObjectFile.FatMachO; bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64; for (auto Arch : FatFile.FatArchs) { if (is64Bit) @@ -529,14 +529,7 @@ } // end anonymous namespace -int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { - MachOYAML::MachFile Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - +int yaml2macho(yaml::YamlObjectFile &Doc, raw_ostream &Out) { UniversalWriter Writer(Doc); if (auto Err = Writer.writeMachO(Out)) { errs() << toString(std::move(Err)); Index: tools/yaml2obj/yaml2obj.h =================================================================== --- tools/yaml2obj/yaml2obj.h +++ tools/yaml2obj/yaml2obj.h @@ -14,12 +14,23 @@ namespace llvm { class raw_ostream; + +namespace COFFYAML { +struct Object; +} + +namespace ELFYAML { +struct Object; +} + namespace yaml { class Input; +struct YamlObjectFile; } } -int yaml2coff(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); -int yaml2elf(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); -int yaml2macho(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); + +int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out); +int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out); +int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out); #endif Index: tools/yaml2obj/yaml2obj.cpp =================================================================== --- tools/yaml2obj/yaml2obj.cpp +++ tools/yaml2obj/yaml2obj.cpp @@ -16,6 +16,7 @@ #include "yaml2obj.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -32,29 +33,6 @@ static cl::opt Input(cl::Positional, cl::desc(""), cl::init("-")); -// TODO: The "right" way to tell what kind of object file a given YAML file -// corresponds to is to look at YAML "tags" (e.g. `!Foo`). Then, different -// tags (`!ELF`, `!COFF`, etc.) would be used to discriminate between them. -// Interpreting the tags is needed eventually for when writing test cases, -// so that we can e.g. have `!Archive` contain a sequence of `!ELF`, and -// just Do The Right Thing. However, interpreting these tags and acting on -// them appropriately requires some work in the YAML parser and the YAMLIO -// library. -enum YAMLObjectFormat { - YOF_COFF, - YOF_ELF, - YOF_MACHO -}; - -cl::opt Format( - "format", - cl::desc("Interpret input as this type of object file"), - cl::values( - clEnumValN(YOF_COFF, "coff", "COFF object file format"), - clEnumValN(YOF_ELF, "elf", "ELF object file format"), - clEnumValN(YOF_MACHO, "macho", "Mach-O object file format"), - clEnumValEnd)); - cl::opt DocNum("docnum", cl::init(1), cl::desc("Read specified document from input (default = 1)")); @@ -62,14 +40,26 @@ static cl::opt OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); -typedef int (*ConvertFuncPtr)(yaml::Input & YIn, raw_ostream &Out); - -static int convertYAML(yaml::Input &YIn, raw_ostream &Out, - ConvertFuncPtr Convert) { +static int convertYAML(yaml::Input &YIn, raw_ostream &Out) { unsigned CurDocNum = 0; do { - if (++CurDocNum == DocNum) - return Convert(YIn, Out); + if (++CurDocNum == DocNum) { + yaml::YamlObjectFile Doc; + YIn >> Doc; + if (YIn.error()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + + if (Doc.Elf) + return yaml2elf(*Doc.Elf, Out); + if (Doc.Coff) + return yaml2coff(*Doc.Coff, Out); + if (Doc.MachO || Doc.FatMachO) + return yaml2macho(Doc, Out); + errs() << "yaml2obj: Unknown document type!\n"; + return 1; + } } while (YIn.nextDocument()); errs() << "yaml2obj: Cannot find the " << DocNum @@ -99,21 +89,9 @@ if (!Buf) return 1; - ConvertFuncPtr Convert = nullptr; - if (Format == YOF_COFF) - Convert = yaml2coff; - else if (Format == YOF_ELF) - Convert = yaml2elf; - else if (Format == YOF_MACHO) - Convert = yaml2macho; - else { - errs() << "Not yet implemented\n"; - return 1; - } - yaml::Input YIn(Buf.get()->getBuffer()); - int Res = convertYAML(YIn, Out->os(), Convert); + int Res = convertYAML(YIn, Out->os()); if (Res == 0) Out->keep();