Index: llvm/include/llvm/ObjectYAML/yaml2obj.h =================================================================== --- llvm/include/llvm/ObjectYAML/yaml2obj.h +++ llvm/include/llvm/ObjectYAML/yaml2obj.h @@ -11,8 +11,18 @@ #ifndef LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H #define LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include + namespace llvm { class raw_ostream; +template class SmallVectorImpl; +template class Expected; + +namespace object { +class ObjectFile; +} namespace COFFYAML { struct Object; @@ -33,13 +43,20 @@ namespace yaml { class Input; struct YamlObjectFile; -} -} -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); -int yaml2minidump(llvm::MinidumpYAML::Object &Doc, llvm::raw_ostream &Out); -int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::raw_ostream &Out); +int yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out); +int yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out); +int yaml2macho(YamlObjectFile &Doc, raw_ostream &Out); +int yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out); +int yaml2wasm(WasmYAML::Object &Doc, raw_ostream &Out); + +Error convertYAML(Input &YIn, raw_ostream &Out, unsigned DocNum = 1); + +/// Convenience function for tests. +Expected> +yaml2ObjectFile(SmallVectorImpl &Storage, StringRef Yaml); + +} // namespace yaml +} // namespace llvm #endif Index: llvm/lib/ObjectYAML/CMakeLists.txt =================================================================== --- llvm/lib/ObjectYAML/CMakeLists.txt +++ llvm/lib/ObjectYAML/CMakeLists.txt @@ -1,17 +1,33 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoCodeView + MC + Object + Support + ) + add_llvm_library(LLVMObjectYAML CodeViewYAMLDebugSections.cpp CodeViewYAMLSymbols.cpp CodeViewYAMLTypeHashing.cpp CodeViewYAMLTypes.cpp + COFFEmitter.cpp COFFYAML.cpp DWARFEmitter.cpp DWARFVisitor.cpp DWARFYAML.cpp + ELFEmitter.cpp ELFYAML.cpp + MachOEmitter.cpp MachOYAML.cpp ObjectYAML.cpp + MinidumpEmitter.cpp MinidumpYAML.cpp + WasmEmitter.cpp WasmYAML.cpp XCOFFYAML.cpp YAML.cpp + yaml2obj.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjectYAML ) Index: llvm/lib/ObjectYAML/COFFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/COFFEmitter.cpp +++ llvm/lib/ObjectYAML/COFFEmitter.cpp @@ -11,7 +11,6 @@ /// //===----------------------------------------------------------------------===// -#include "yaml2obj.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" @@ -20,6 +19,7 @@ #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" #include "llvm/Object/COFF.h" #include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" @@ -29,6 +29,8 @@ using namespace llvm; +namespace { + /// This parses a yaml stream that represents a COFF object file. /// See docs/yaml2obj for the yaml scheema. struct COFFParser { @@ -64,7 +66,8 @@ bool parseSections() { for (std::vector::iterator i = Obj.Sections.begin(), - e = Obj.Sections.end(); i != e; ++i) { + e = Obj.Sections.end(); + i != e; ++i) { COFFYAML::Section &Sec = *i; // If the name is less than 8 bytes, store it in place, otherwise @@ -102,7 +105,8 @@ bool parseSymbols() { for (std::vector::iterator i = Obj.Symbols.begin(), - e = Obj.Symbols.end(); i != e; ++i) { + e = Obj.Symbols.end(); + i != e; ++i) { COFFYAML::Symbol &Sym = *i; // If the name is less than 8 bytes, store it in place, otherwise @@ -113,8 +117,8 @@ } else { // Add string to the string table and format the index for output. unsigned Index = getStringIndex(Name); - *reinterpret_cast( - Sym.Header.Name + 4) = Index; + *reinterpret_cast(Sym.Header.Name + 4) = + Index; } Sym.Header.Type = Sym.SimpleType; @@ -153,6 +157,10 @@ uint32_t SectionTableSize; }; +enum { DOSStubSize = 128 }; + +} // end anonymous namespace + // Take a CP and assign addresses and sizes to everything. Returns false if the // layout is not valid to do. static bool layoutOptionalHeader(COFFParser &CP) { @@ -166,10 +174,6 @@ return true; } -namespace { -enum { DOSStubSize = 128 }; -} - static yaml::BinaryRef toDebugS(ArrayRef Subsections, const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator) { @@ -271,7 +275,7 @@ uint32_t NumberOfSymbols = 0; for (std::vector::iterator i = CP.Obj.Symbols.begin(), e = CP.Obj.Symbols.end(); - i != e; ++i) { + i != e; ++i) { uint32_t NumberOfAuxSymbols = 0; if (i->FunctionDefinition) NumberOfAuxSymbols += 1; @@ -298,24 +302,23 @@ else CP.Obj.Header.PointerToSymbolTable = 0; - *reinterpret_cast(&CP.StringTable[0]) - = CP.StringTable.size(); + *reinterpret_cast(&CP.StringTable[0]) = + CP.StringTable.size(); return true; } -template -struct binary_le_impl { +template struct binary_le_impl { value_type Value; binary_le_impl(value_type V) : Value(V) {} }; template -raw_ostream &operator <<( raw_ostream &OS - , const binary_le_impl &BLE) { +raw_ostream &operator<<(raw_ostream &OS, + const binary_le_impl &BLE) { char Buffer[sizeof(BLE.Value)]; support::endian::write( - Buffer, BLE.Value); + Buffer, BLE.Value); OS.write(Buffer, sizeof(BLE.Value)); return OS; } @@ -335,13 +338,13 @@ return OS; } -template -zeros_impl zeros(const T &) { +template zeros_impl zeros(const T &) { return zeros_impl(); } template -static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Header) { +static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, + T Header) { memset(Header, 0, sizeof(*Header)); Header->Magic = Magic; Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment; @@ -376,10 +379,8 @@ CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion; Header->MinorOperatingSystemVersion = CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion; - Header->MajorImageVersion = - CP.Obj.OptionalHeader->Header.MajorImageVersion; - Header->MinorImageVersion = - CP.Obj.OptionalHeader->Header.MinorImageVersion; + Header->MajorImageVersion = CP.Obj.OptionalHeader->Header.MajorImageVersion; + Header->MinorImageVersion = CP.Obj.OptionalHeader->Header.MinorImageVersion; Header->MajorSubsystemVersion = CP.Obj.OptionalHeader->Header.MajorSubsystemVersion; Header->MinorSubsystemVersion = @@ -423,15 +424,13 @@ if (CP.useBigObj()) { OS << binary_le(static_cast(COFF::IMAGE_FILE_MACHINE_UNKNOWN)) << binary_le(static_cast(0xffff)) - << binary_le(static_cast(COFF::BigObjHeader::MinBigObjectVersion)) + << binary_le( + static_cast(COFF::BigObjHeader::MinBigObjectVersion)) << binary_le(CP.Obj.Header.Machine) << binary_le(CP.Obj.Header.TimeDateStamp); OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic)); - OS << zeros(uint32_t(0)) - << zeros(uint32_t(0)) - << zeros(uint32_t(0)) - << zeros(uint32_t(0)) - << binary_le(CP.Obj.Header.NumberOfSections) + OS << zeros(uint32_t(0)) << zeros(uint32_t(0)) << zeros(uint32_t(0)) + << zeros(uint32_t(0)) << binary_le(CP.Obj.Header.NumberOfSections) << binary_le(CP.Obj.Header.PointerToSymbolTable) << binary_le(CP.Obj.Header.NumberOfSymbols); } else { @@ -450,7 +449,8 @@ OS.write(reinterpret_cast(&PEH), sizeof(PEH)); } else { object::pe32_header PEH; - uint32_t BaseOfData = initializeOptionalHeader(CP, COFF::PE32Header::PE32, &PEH); + uint32_t BaseOfData = + initializeOptionalHeader(CP, COFF::PE32Header::PE32, &PEH); PEH.BaseOfData = BaseOfData; OS.write(reinterpret_cast(&PEH), sizeof(PEH)); } @@ -472,7 +472,7 @@ // Output section table. for (std::vector::iterator i = CP.Obj.Sections.begin(), e = CP.Obj.Sections.end(); - i != e; ++i) { + i != e; ++i) { OS.write(i->Header.Name, COFF::NameSize); OS << binary_le(i->Header.VirtualSize) << binary_le(i->Header.VirtualAddress) @@ -514,8 +514,7 @@ } else { SymbolTableIndex = SymbolTableIndexMap[R.SymbolName]; } - OS << binary_le(R.VirtualAddress) - << binary_le(SymbolTableIndex) + OS << binary_le(R.VirtualAddress) << binary_le(SymbolTableIndex) << binary_le(R.Type); } } @@ -524,15 +523,14 @@ for (std::vector::const_iterator i = CP.Obj.Symbols.begin(), e = CP.Obj.Symbols.end(); - i != e; ++i) { + i != e; ++i) { OS.write(i->Header.Name, COFF::NameSize); OS << binary_le(i->Header.Value); if (CP.useBigObj()) - OS << binary_le(i->Header.SectionNumber); + OS << binary_le(i->Header.SectionNumber); else - OS << binary_le(static_cast(i->Header.SectionNumber)); - OS << binary_le(i->Header.Type) - << binary_le(i->Header.StorageClass) + OS << binary_le(static_cast(i->Header.SectionNumber)); + OS << binary_le(i->Header.Type) << binary_le(i->Header.StorageClass) << binary_le(i->Header.NumberOfAuxSymbols); if (i->FunctionDefinition) { @@ -578,8 +576,7 @@ OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size); } if (i->CLRToken) { - OS << binary_le(i->CLRToken->AuxType) - << zeros(i->CLRToken->unused1) + OS << binary_le(i->CLRToken->AuxType) << zeros(i->CLRToken->unused1) << binary_le(i->CLRToken->SymbolTableIndex) << zeros(i->CLRToken->unused2); OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size); @@ -592,6 +589,9 @@ return true; } +namespace llvm { +namespace yaml { + int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) { COFFParser CP(Doc); if (!CP.parse()) { @@ -614,3 +614,6 @@ } return 0; } + +} // namespace yaml +} // namespace llvm Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -11,13 +11,13 @@ /// //===----------------------------------------------------------------------===// -#include "yaml2obj.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/ObjectYAML/ELFYAML.h" -#include "llvm/ADT/StringSet.h" +#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/WithColor.h" @@ -55,11 +55,9 @@ } void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } }; -} // end anonymous namespace // Used to keep track of section and symbol names, so that in the YAML file // sections and symbols can be referenced by name instead of by index. -namespace { class NameToIdxMap { StringMap Map; @@ -86,29 +84,11 @@ } unsigned size() const { return Map.size(); } }; -} // end anonymous namespace - -template -static size_t arrayDataSize(ArrayRef A) { - return A.size() * sizeof(T); -} -template -static void writeArrayData(raw_ostream &OS, ArrayRef A) { - OS.write((const char *)A.data(), arrayDataSize(A)); -} - -template -static void zero(T &Obj) { - memset(&Obj, 0, sizeof(Obj)); -} - -namespace { /// "Single point of truth" for the ELF file construction. /// TODO: This class still has a ways to go before it is truly a "single /// point of truth". -template -class ELFState { +template class ELFState { typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; typedef typename ELFT::Shdr Elf_Shdr; @@ -185,8 +165,17 @@ }; } // end anonymous namespace -template -ELFState::ELFState(ELFYAML::Object &D) : Doc(D) { +template static size_t arrayDataSize(ArrayRef A) { + return A.size() * sizeof(T); +} + +template static void writeArrayData(raw_ostream &OS, ArrayRef A) { + OS.write((const char *)A.data(), arrayDataSize(A)); +} + +template static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); } + +template ELFState::ELFState(ELFYAML::Object &D) : Doc(D) { StringSet<> DocSections; for (std::unique_ptr &D : Doc.Sections) if (!D->Name.empty()) @@ -197,7 +186,7 @@ Doc.Sections.insert( Doc.Sections.begin(), llvm::make_unique( - ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true)); + ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true)); std::vector ImplicitSections = {".symtab", ".strtab", ".shstrtab"}; if (!Doc.DynamicSymbols.empty()) @@ -216,8 +205,7 @@ } } -template -void ELFState::initELFHeader(Elf_Ehdr &Header) { +template void ELFState::initELFHeader(Elf_Ehdr &Header) { using namespace llvm::ELF; zero(Header); Header.e_ident[EI_MAG0] = 0x7f; @@ -700,10 +688,9 @@ } template -bool -ELFState::writeSectionContent(Elf_Shdr &SHeader, - const ELFYAML::RelocationSection &Section, - ContiguousBlobAccumulator &CBA) { +bool ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::RelocationSection &Section, + ContiguousBlobAccumulator &CBA) { assert((Section.Type == llvm::ELF::SHT_REL || Section.Type == llvm::ELF::SHT_RELA) && "Section type is not SHT_REL nor SHT_RELA"); @@ -949,7 +936,8 @@ else SHeader.sh_entsize = sizeof(Elf_Dyn); - raw_ostream &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + raw_ostream &OS = + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); for (const ELFYAML::DynamicEntry &DE : Section.Entries) { support::endian::write(OS, DE.Tag, ELFT::TargetEndianness); support::endian::write(OS, DE.Val, ELFT::TargetEndianness); @@ -1075,6 +1063,9 @@ return 0; } +namespace llvm { +namespace yaml { + int yaml2elf(llvm::ELFYAML::Object &Doc, raw_ostream &Out) { bool IsLE = Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); bool Is64Bit = Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); @@ -1087,3 +1078,6 @@ return ELFState::writeELF(Out, Doc); return ELFState::writeELF(Out, Doc); } + +} // namespace yaml +} // namespace llvm Index: llvm/lib/ObjectYAML/MachOEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/MachOEmitter.cpp +++ llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -11,10 +11,10 @@ /// //===----------------------------------------------------------------------===// -#include "yaml2obj.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/Error.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/YAMLTraits.h" @@ -263,8 +263,7 @@ } static bool isVirtualSection(uint8_t type) { - return (type == MachO::S_ZEROFILL || - type == MachO::S_GB_ZEROFILL || + return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL || type == MachO::S_THREAD_LOCAL_ZEROFILL); } @@ -276,7 +275,8 @@ case MachO::LC_SEGMENT_64: uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff : LC.Data.segment_command_data.fileoff; - if (0 == strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) { + if (0 == + strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) { FoundLinkEditSeg = true; if (auto Err = writeLinkEditData(OS)) return Err; @@ -592,7 +592,10 @@ } // end anonymous namespace -int yaml2macho(yaml::YamlObjectFile &Doc, raw_ostream &Out) { +namespace llvm { +namespace yaml { + +int yaml2macho(YamlObjectFile &Doc, raw_ostream &Out) { UniversalWriter Writer(Doc); if (auto Err = Writer.writeMachO(Out)) { errs() << toString(std::move(Err)); @@ -600,3 +603,6 @@ } return 0; } + +} // namespace yaml +} // namespace llvm Index: llvm/lib/ObjectYAML/MinidumpEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/MinidumpEmitter.cpp +++ llvm/lib/ObjectYAML/MinidumpEmitter.cpp @@ -6,13 +6,19 @@ // //===----------------------------------------------------------------------===// -#include "yaml2obj.h" #include "llvm/ObjectYAML/MinidumpYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; +namespace llvm { +namespace yaml { + int yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out) { writeAsBinary(Doc, Out); return 0; } + +} // namespace yaml +} // namespace llvm Index: llvm/lib/ObjectYAML/WasmEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/WasmEmitter.cpp +++ llvm/lib/ObjectYAML/WasmEmitter.cpp @@ -14,11 +14,13 @@ #include "llvm/Object/Wasm.h" #include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/Endian.h" #include "llvm/Support/LEB128.h" using namespace llvm; +namespace { /// This parses a yaml stream that represents a Wasm object file. /// See docs/yaml2obj for the yaml scheema. class WasmWriter { @@ -58,6 +60,26 @@ uint32_t NumImportedEvents = 0; }; +class SubSectionWriter { + raw_ostream &OS; + std::string OutString; + raw_string_ostream StringStream; + +public: + SubSectionWriter(raw_ostream &OS) : OS(OS), StringStream(OutString) {} + + void done() { + StringStream.flush(); + encodeULEB128(OutString.size(), OS); + OS << OutString; + OutString.clear(); + } + + raw_ostream &getStream() { return StringStream; } +}; + +} // end anonymous namespace + static int writeUint64(raw_ostream &OS, uint64_t Value) { char Data[sizeof(Value)]; support::endian::write64le(Data, Value); @@ -119,24 +141,6 @@ return 0; } -class SubSectionWriter { - raw_ostream &OS; - std::string OutString; - raw_string_ostream StringStream; - -public: - SubSectionWriter(raw_ostream &OS) : OS(OS), StringStream(OutString) {} - - void done() { - StringStream.flush(); - encodeULEB128(OutString.size(), OS); - OS << OutString; - OutString.clear(); - } - - raw_ostream &getStream() { return StringStream; } -}; - int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::DylinkSection &Section) { writeStringRef(Section.Name, OS); @@ -651,8 +655,14 @@ return 0; } -int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) { +namespace llvm { +namespace yaml { + +int yaml2wasm(WasmYAML::Object &Doc, raw_ostream &Out) { WasmWriter Writer(Doc); return Writer.writeWasm(Out); } + +} // namespace yaml +} // namespace llvm Index: llvm/lib/ObjectYAML/yaml2obj.cpp =================================================================== --- /dev/null +++ llvm/lib/ObjectYAML/yaml2obj.cpp @@ -0,0 +1,68 @@ +//===-- yaml2obj.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace yaml { + +Error convertYAML(yaml::Input &YIn, raw_ostream &Out, unsigned DocNum) { + // TODO: make yaml2* functions return Error instead of int. + auto IntToErr = [](int Ret) -> Error { + if (Ret) + return createStringError(errc::invalid_argument, "yaml2obj failed"); + return Error::success(); + }; + + unsigned CurDocNum = 0; + do { + if (++CurDocNum == DocNum) { + yaml::YamlObjectFile Doc; + YIn >> Doc; + if (std::error_code EC = YIn.error()) + return createStringError(EC, "Failed to parse YAML input!"); + if (Doc.Elf) + return IntToErr(yaml2elf(*Doc.Elf, Out)); + if (Doc.Coff) + return IntToErr(yaml2coff(*Doc.Coff, Out)); + if (Doc.MachO || Doc.FatMachO) + return IntToErr(yaml2macho(Doc, Out)); + if (Doc.Minidump) + return IntToErr(yaml2minidump(*Doc.Minidump, Out)); + if (Doc.Wasm) + return IntToErr(yaml2wasm(*Doc.Wasm, Out)); + return createStringError(errc::invalid_argument, + "Unknown document type!"); + } + } while (YIn.nextDocument()); + + return createStringError(errc::invalid_argument, + "Cannot find the %u%s document", DocNum, + getOrdinalSuffix(DocNum).data()); +} + +Expected> +yaml2ObjectFile(SmallVectorImpl &Storage, StringRef Yaml) { + Storage.clear(); + raw_svector_ostream OS(Storage); + + yaml::Input YIn(Yaml); + if (Error E = convertYAML(YIn, OS)) + return std::move(E); + + return object::ObjectFile::createObjectFile( + MemoryBufferRef(OS.str(), "YamlObject")); +} + +} // namespace yaml +} // namespace llvm Index: llvm/test/tools/yaml2obj/empty-or-invalid-doc.yaml =================================================================== --- llvm/test/tools/yaml2obj/empty-or-invalid-doc.yaml +++ llvm/test/tools/yaml2obj/empty-or-invalid-doc.yaml @@ -2,7 +2,7 @@ # RUN: echo -n "" | not yaml2obj 2>&1 | FileCheck %s # RUN: echo " " | not yaml2obj 2>&1 | FileCheck %s # RUN: echo " " | not yaml2obj 2>&1 | FileCheck %s -# CHECK: yaml2obj: Unknown document type! +# CHECK: yaml2obj: error: Unknown document type! # RUN: echo -e -n "\xff" | not yaml2obj 2>&1 | FileCheck %s --check-prefix=INVALID -# INVALID: yaml2obj: Failed to parse YAML file! +# INVALID: yaml2obj: error: Failed to parse YAML input! Index: llvm/test/tools/yaml2obj/invalid-docnum.test =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/invalid-docnum.test @@ -0,0 +1,22 @@ +## Test that an error is reported when a docnum is specified, which is +## greater than the number of YAML inputs in the file. + +# RUN: not yaml2obj %s --docnum=3 2>&1 | FileCheck %s +# CHECK: yaml2obj: error: Cannot find the 3rd document + +# RUN: not yaml2obj %s --docnum=76768677 2>&1 | FileCheck %s --check-prefix=TWO +# TWO: yaml2obj: error: Cannot find the 76768677th document + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 Index: llvm/test/tools/yaml2obj/missing_document_tag.yaml =================================================================== --- llvm/test/tools/yaml2obj/missing_document_tag.yaml +++ llvm/test/tools/yaml2obj/missing_document_tag.yaml @@ -6,4 +6,4 @@ ... # CHECK: YAML:4:1: error: YAML Object File missing document type tag! -# CHECK: yaml2obj: Failed to parse YAML file! +# CHECK: yaml2obj: error: Failed to parse YAML input! Index: llvm/tools/yaml2obj/CMakeLists.txt =================================================================== --- llvm/tools/yaml2obj/CMakeLists.txt +++ llvm/tools/yaml2obj/CMakeLists.txt @@ -8,9 +8,4 @@ add_llvm_tool(yaml2obj yaml2obj.cpp - yaml2coff.cpp - yaml2elf.cpp - yaml2macho.cpp - yaml2minidump.cpp - yaml2wasm.cpp ) Index: llvm/tools/yaml2obj/yaml2obj.cpp =================================================================== --- llvm/tools/yaml2obj/yaml2obj.cpp +++ llvm/tools/yaml2obj/yaml2obj.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "yaml2obj.h" +#include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/CommandLine.h" @@ -21,6 +21,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include @@ -42,32 +43,6 @@ exit(1); } -static int convertYAML(yaml::Input &YIn, raw_ostream &Out) { - unsigned CurDocNum = 0; - do { - if (++CurDocNum == DocNum) { - yaml::YamlObjectFile Doc; - YIn >> Doc; - if (YIn.error()) - error("yaml2obj: Failed to parse YAML file!"); - 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); - if (Doc.Minidump) - return yaml2minidump(*Doc.Minidump, Out); - if (Doc.Wasm) - return yaml2wasm(*Doc.Wasm, Out); - error("yaml2obj: Unknown document type!"); - } - } while (YIn.nextDocument()); - - error("yaml2obj: Cannot find the " + Twine(DocNum) + - llvm::getOrdinalSuffix(DocNum) + " document"); -} - int main(int argc, char **argv) { InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv); @@ -87,10 +62,12 @@ return 1; yaml::Input YIn(Buf.get()->getBuffer()); - int Res = convertYAML(YIn, Out->os()); - if (Res == 0) - Out->keep(); + if (Error E = convertYAML(YIn, Out->os(), DocNum)) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); + return 1; + } + Out->keep(); Out->os().flush(); - return Res; + return 0; } Index: llvm/unittests/ObjectYAML/CMakeLists.txt =================================================================== --- llvm/unittests/ObjectYAML/CMakeLists.txt +++ llvm/unittests/ObjectYAML/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_unittest(ObjectYAMLTests MinidumpYAMLTest.cpp + YAML2ObjTest.cpp YAMLTest.cpp ) Index: llvm/unittests/ObjectYAML/YAML2ObjTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/ObjectYAML/YAML2ObjTest.cpp @@ -0,0 +1,36 @@ +//===- YAML2ObjTest.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace object; +using namespace yaml; + +TEST(yaml2ObjectFile, ELF) { + SmallString<0> Storage; + Expected> ErrOrObj = yaml2ObjectFile(Storage, R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64)"); + + ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded()); + + std::unique_ptr ObjFile = std::move(ErrOrObj.get()); + + ASSERT_TRUE(ObjFile->isELF()); + ASSERT_TRUE(ObjFile->isRelocatableObject()); +}