[yaml2obj] Move core yaml2obj code into lib and include for use in unit tests

Reviewers: jhenderson, rupprecht, MaskRay, grimar, labath

Reviewed By: rupprecht

Subscribers: gribozavr, mgrang, seiya, mgorny, sbc100, hiraditya, aheejin, jakehehrlich, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D65255

llvm-svn: 368119
This commit is contained in:
Alex Brachet 2019-08-07 02:44:49 +00:00
parent 6cebeafac3
commit c22d9666fc
18 changed files with 292 additions and 151 deletions

View File

@ -11,8 +11,18 @@
#ifndef LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H #ifndef LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H
#define LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H #define LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <memory>
namespace llvm { namespace llvm {
class raw_ostream; class raw_ostream;
template <typename T> class SmallVectorImpl;
template <typename T> class Expected;
namespace object {
class ObjectFile;
}
namespace COFFYAML { namespace COFFYAML {
struct Object; struct Object;
@ -33,13 +43,20 @@ struct Object;
namespace yaml { namespace yaml {
class Input; class Input;
struct YamlObjectFile; struct YamlObjectFile;
}
}
int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out); int yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out);
int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out); int yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out);
int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out); int yaml2macho(YamlObjectFile &Doc, raw_ostream &Out);
int yaml2minidump(llvm::MinidumpYAML::Object &Doc, llvm::raw_ostream &Out); int yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out);
int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::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<std::unique_ptr<object::ObjectFile>>
yaml2ObjectFile(SmallVectorImpl<char> &Storage, StringRef Yaml);
} // namespace yaml
} // namespace llvm
#endif #endif

View File

@ -3,15 +3,24 @@ add_llvm_library(LLVMObjectYAML
CodeViewYAMLSymbols.cpp CodeViewYAMLSymbols.cpp
CodeViewYAMLTypeHashing.cpp CodeViewYAMLTypeHashing.cpp
CodeViewYAMLTypes.cpp CodeViewYAMLTypes.cpp
COFFEmitter.cpp
COFFYAML.cpp COFFYAML.cpp
DWARFEmitter.cpp DWARFEmitter.cpp
DWARFVisitor.cpp DWARFVisitor.cpp
DWARFYAML.cpp DWARFYAML.cpp
ELFEmitter.cpp
ELFYAML.cpp ELFYAML.cpp
MachOEmitter.cpp
MachOYAML.cpp MachOYAML.cpp
ObjectYAML.cpp ObjectYAML.cpp
MinidumpEmitter.cpp
MinidumpYAML.cpp MinidumpYAML.cpp
WasmEmitter.cpp
WasmYAML.cpp WasmYAML.cpp
XCOFFYAML.cpp XCOFFYAML.cpp
YAML.cpp YAML.cpp
yaml2obj.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjectYAML
) )

View File

@ -11,7 +11,6 @@
/// ///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "yaml2obj.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
@ -20,6 +19,7 @@
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
#include "llvm/Object/COFF.h" #include "llvm/Object/COFF.h"
#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/Endian.h" #include "llvm/Support/Endian.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SourceMgr.h"
@ -29,6 +29,8 @@
using namespace llvm; using namespace llvm;
namespace {
/// This parses a yaml stream that represents a COFF object file. /// This parses a yaml stream that represents a COFF object file.
/// See docs/yaml2obj for the yaml scheema. /// See docs/yaml2obj for the yaml scheema.
struct COFFParser { struct COFFParser {
@ -64,7 +66,8 @@ struct COFFParser {
bool parseSections() { bool parseSections() {
for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(), for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(),
e = Obj.Sections.end(); i != e; ++i) { e = Obj.Sections.end();
i != e; ++i) {
COFFYAML::Section &Sec = *i; COFFYAML::Section &Sec = *i;
// If the name is less than 8 bytes, store it in place, otherwise // If the name is less than 8 bytes, store it in place, otherwise
@ -102,7 +105,8 @@ struct COFFParser {
bool parseSymbols() { bool parseSymbols() {
for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(), for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(),
e = Obj.Symbols.end(); i != e; ++i) { e = Obj.Symbols.end();
i != e; ++i) {
COFFYAML::Symbol &Sym = *i; COFFYAML::Symbol &Sym = *i;
// If the name is less than 8 bytes, store it in place, otherwise // If the name is less than 8 bytes, store it in place, otherwise
@ -113,8 +117,8 @@ struct COFFParser {
} else { } else {
// Add string to the string table and format the index for output. // Add string to the string table and format the index for output.
unsigned Index = getStringIndex(Name); unsigned Index = getStringIndex(Name);
*reinterpret_cast<support::aligned_ulittle32_t*>( *reinterpret_cast<support::aligned_ulittle32_t *>(Sym.Header.Name + 4) =
Sym.Header.Name + 4) = Index; Index;
} }
Sym.Header.Type = Sym.SimpleType; Sym.Header.Type = Sym.SimpleType;
@ -153,6 +157,10 @@ struct COFFParser {
uint32_t SectionTableSize; uint32_t SectionTableSize;
}; };
enum { DOSStubSize = 128 };
} // end anonymous namespace
// Take a CP and assign addresses and sizes to everything. Returns false if the // Take a CP and assign addresses and sizes to everything. Returns false if the
// layout is not valid to do. // layout is not valid to do.
static bool layoutOptionalHeader(COFFParser &CP) { static bool layoutOptionalHeader(COFFParser &CP) {
@ -166,10 +174,6 @@ static bool layoutOptionalHeader(COFFParser &CP) {
return true; return true;
} }
namespace {
enum { DOSStubSize = 128 };
}
static yaml::BinaryRef static yaml::BinaryRef
toDebugS(ArrayRef<CodeViewYAML::YAMLDebugSubsection> Subsections, toDebugS(ArrayRef<CodeViewYAML::YAMLDebugSubsection> Subsections,
const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator) { const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator) {
@ -271,7 +275,7 @@ static bool layoutCOFF(COFFParser &CP) {
uint32_t NumberOfSymbols = 0; uint32_t NumberOfSymbols = 0;
for (std::vector<COFFYAML::Symbol>::iterator i = CP.Obj.Symbols.begin(), for (std::vector<COFFYAML::Symbol>::iterator i = CP.Obj.Symbols.begin(),
e = CP.Obj.Symbols.end(); e = CP.Obj.Symbols.end();
i != e; ++i) { i != e; ++i) {
uint32_t NumberOfAuxSymbols = 0; uint32_t NumberOfAuxSymbols = 0;
if (i->FunctionDefinition) if (i->FunctionDefinition)
NumberOfAuxSymbols += 1; NumberOfAuxSymbols += 1;
@ -298,24 +302,23 @@ static bool layoutCOFF(COFFParser &CP) {
else else
CP.Obj.Header.PointerToSymbolTable = 0; CP.Obj.Header.PointerToSymbolTable = 0;
*reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0]) *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0]) =
= CP.StringTable.size(); CP.StringTable.size();
return true; return true;
} }
template <typename value_type> template <typename value_type> struct binary_le_impl {
struct binary_le_impl {
value_type Value; value_type Value;
binary_le_impl(value_type V) : Value(V) {} binary_le_impl(value_type V) : Value(V) {}
}; };
template <typename value_type> template <typename value_type>
raw_ostream &operator <<( raw_ostream &OS raw_ostream &operator<<(raw_ostream &OS,
, const binary_le_impl<value_type> &BLE) { const binary_le_impl<value_type> &BLE) {
char Buffer[sizeof(BLE.Value)]; char Buffer[sizeof(BLE.Value)];
support::endian::write<value_type, support::little, support::unaligned>( support::endian::write<value_type, support::little, support::unaligned>(
Buffer, BLE.Value); Buffer, BLE.Value);
OS.write(Buffer, sizeof(BLE.Value)); OS.write(Buffer, sizeof(BLE.Value));
return OS; return OS;
} }
@ -335,13 +338,13 @@ raw_ostream &operator<<(raw_ostream &OS, const zeros_impl<NumBytes> &) {
return OS; return OS;
} }
template <typename T> template <typename T> zeros_impl<sizeof(T)> zeros(const T &) {
zeros_impl<sizeof(T)> zeros(const T &) {
return zeros_impl<sizeof(T)>(); return zeros_impl<sizeof(T)>();
} }
template <typename T> template <typename T>
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)); memset(Header, 0, sizeof(*Header));
Header->Magic = Magic; Header->Magic = Magic;
Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment; Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment;
@ -376,10 +379,8 @@ static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Heade
CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion; CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion;
Header->MinorOperatingSystemVersion = Header->MinorOperatingSystemVersion =
CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion; CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion;
Header->MajorImageVersion = Header->MajorImageVersion = CP.Obj.OptionalHeader->Header.MajorImageVersion;
CP.Obj.OptionalHeader->Header.MajorImageVersion; Header->MinorImageVersion = CP.Obj.OptionalHeader->Header.MinorImageVersion;
Header->MinorImageVersion =
CP.Obj.OptionalHeader->Header.MinorImageVersion;
Header->MajorSubsystemVersion = Header->MajorSubsystemVersion =
CP.Obj.OptionalHeader->Header.MajorSubsystemVersion; CP.Obj.OptionalHeader->Header.MajorSubsystemVersion;
Header->MinorSubsystemVersion = Header->MinorSubsystemVersion =
@ -423,15 +424,13 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
if (CP.useBigObj()) { if (CP.useBigObj()) {
OS << binary_le(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN)) OS << binary_le(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN))
<< binary_le(static_cast<uint16_t>(0xffff)) << binary_le(static_cast<uint16_t>(0xffff))
<< binary_le(static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion)) << binary_le(
static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion))
<< binary_le(CP.Obj.Header.Machine) << binary_le(CP.Obj.Header.Machine)
<< binary_le(CP.Obj.Header.TimeDateStamp); << binary_le(CP.Obj.Header.TimeDateStamp);
OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic)); OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
OS << zeros(uint32_t(0)) OS << zeros(uint32_t(0)) << zeros(uint32_t(0)) << zeros(uint32_t(0))
<< zeros(uint32_t(0)) << zeros(uint32_t(0)) << binary_le(CP.Obj.Header.NumberOfSections)
<< 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.PointerToSymbolTable)
<< binary_le(CP.Obj.Header.NumberOfSymbols); << binary_le(CP.Obj.Header.NumberOfSymbols);
} else { } else {
@ -450,7 +449,8 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH)); OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
} else { } else {
object::pe32_header PEH; 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; PEH.BaseOfData = BaseOfData;
OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH)); OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
} }
@ -472,7 +472,7 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
// Output section table. // Output section table.
for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(), for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
e = CP.Obj.Sections.end(); e = CP.Obj.Sections.end();
i != e; ++i) { i != e; ++i) {
OS.write(i->Header.Name, COFF::NameSize); OS.write(i->Header.Name, COFF::NameSize);
OS << binary_le(i->Header.VirtualSize) OS << binary_le(i->Header.VirtualSize)
<< binary_le(i->Header.VirtualAddress) << binary_le(i->Header.VirtualAddress)
@ -514,8 +514,7 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
} else { } else {
SymbolTableIndex = SymbolTableIndexMap[R.SymbolName]; SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
} }
OS << binary_le(R.VirtualAddress) OS << binary_le(R.VirtualAddress) << binary_le(SymbolTableIndex)
<< binary_le(SymbolTableIndex)
<< binary_le(R.Type); << binary_le(R.Type);
} }
} }
@ -524,15 +523,14 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(), for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(),
e = CP.Obj.Symbols.end(); e = CP.Obj.Symbols.end();
i != e; ++i) { i != e; ++i) {
OS.write(i->Header.Name, COFF::NameSize); OS.write(i->Header.Name, COFF::NameSize);
OS << binary_le(i->Header.Value); OS << binary_le(i->Header.Value);
if (CP.useBigObj()) if (CP.useBigObj())
OS << binary_le(i->Header.SectionNumber); OS << binary_le(i->Header.SectionNumber);
else else
OS << binary_le(static_cast<int16_t>(i->Header.SectionNumber)); OS << binary_le(static_cast<int16_t>(i->Header.SectionNumber));
OS << binary_le(i->Header.Type) OS << binary_le(i->Header.Type) << binary_le(i->Header.StorageClass)
<< binary_le(i->Header.StorageClass)
<< binary_le(i->Header.NumberOfAuxSymbols); << binary_le(i->Header.NumberOfAuxSymbols);
if (i->FunctionDefinition) { if (i->FunctionDefinition) {
@ -578,8 +576,7 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size); OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
} }
if (i->CLRToken) { if (i->CLRToken) {
OS << binary_le(i->CLRToken->AuxType) OS << binary_le(i->CLRToken->AuxType) << zeros(i->CLRToken->unused1)
<< zeros(i->CLRToken->unused1)
<< binary_le(i->CLRToken->SymbolTableIndex) << binary_le(i->CLRToken->SymbolTableIndex)
<< zeros(i->CLRToken->unused2); << zeros(i->CLRToken->unused2);
OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size); OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
@ -592,6 +589,9 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
return true; return true;
} }
namespace llvm {
namespace yaml {
int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) { int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) {
COFFParser CP(Doc); COFFParser CP(Doc);
if (!CP.parse()) { if (!CP.parse()) {
@ -614,3 +614,6 @@ int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) {
} }
return 0; return 0;
} }
} // namespace yaml
} // namespace llvm

View File

@ -11,13 +11,13 @@
/// ///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "yaml2obj.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/StringTableBuilder.h" #include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFObjectFile.h"
#include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/ELFYAML.h"
#include "llvm/ADT/StringSet.h" #include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/EndianStream.h" #include "llvm/Support/EndianStream.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/WithColor.h" #include "llvm/Support/WithColor.h"
@ -55,11 +55,9 @@ public:
} }
void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } 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 // 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. // sections and symbols can be referenced by name instead of by index.
namespace {
class NameToIdxMap { class NameToIdxMap {
StringMap<unsigned> Map; StringMap<unsigned> Map;
@ -86,29 +84,11 @@ public:
} }
unsigned size() const { return Map.size(); } unsigned size() const { return Map.size(); }
}; };
} // end anonymous namespace
template <class T>
static size_t arrayDataSize(ArrayRef<T> A) {
return A.size() * sizeof(T);
}
template <class T>
static void writeArrayData(raw_ostream &OS, ArrayRef<T> A) {
OS.write((const char *)A.data(), arrayDataSize(A));
}
template <class T>
static void zero(T &Obj) {
memset(&Obj, 0, sizeof(Obj));
}
namespace {
/// "Single point of truth" for the ELF file construction. /// "Single point of truth" for the ELF file construction.
/// TODO: This class still has a ways to go before it is truly a "single /// TODO: This class still has a ways to go before it is truly a "single
/// point of truth". /// point of truth".
template <class ELFT> template <class ELFT> class ELFState {
class ELFState {
typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Ehdr Elf_Ehdr;
typedef typename ELFT::Phdr Elf_Phdr; typedef typename ELFT::Phdr Elf_Phdr;
typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Shdr Elf_Shdr;
@ -185,8 +165,17 @@ private:
}; };
} // end anonymous namespace } // end anonymous namespace
template <class ELFT> template <class T> static size_t arrayDataSize(ArrayRef<T> A) {
ELFState<ELFT>::ELFState(ELFYAML::Object &D) : Doc(D) { return A.size() * sizeof(T);
}
template <class T> static void writeArrayData(raw_ostream &OS, ArrayRef<T> A) {
OS.write((const char *)A.data(), arrayDataSize(A));
}
template <class T> static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); }
template <class ELFT> ELFState<ELFT>::ELFState(ELFYAML::Object &D) : Doc(D) {
StringSet<> DocSections; StringSet<> DocSections;
for (std::unique_ptr<ELFYAML::Section> &D : Doc.Sections) for (std::unique_ptr<ELFYAML::Section> &D : Doc.Sections)
if (!D->Name.empty()) if (!D->Name.empty())
@ -197,7 +186,7 @@ ELFState<ELFT>::ELFState(ELFYAML::Object &D) : Doc(D) {
Doc.Sections.insert( Doc.Sections.insert(
Doc.Sections.begin(), Doc.Sections.begin(),
llvm::make_unique<ELFYAML::Section>( llvm::make_unique<ELFYAML::Section>(
ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true)); ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true));
std::vector<StringRef> ImplicitSections = {".symtab", ".strtab", ".shstrtab"}; std::vector<StringRef> ImplicitSections = {".symtab", ".strtab", ".shstrtab"};
if (!Doc.DynamicSymbols.empty()) if (!Doc.DynamicSymbols.empty())
@ -216,8 +205,7 @@ ELFState<ELFT>::ELFState(ELFYAML::Object &D) : Doc(D) {
} }
} }
template <class ELFT> template <class ELFT> void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
using namespace llvm::ELF; using namespace llvm::ELF;
zero(Header); zero(Header);
Header.e_ident[EI_MAG0] = 0x7f; Header.e_ident[EI_MAG0] = 0x7f;
@ -700,10 +688,9 @@ static bool isMips64EL(const ELFYAML::Object &Doc) {
} }
template <class ELFT> template <class ELFT>
bool bool ELFState<ELFT>::writeSectionContent(
ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader, Elf_Shdr &SHeader, const ELFYAML::RelocationSection &Section,
const ELFYAML::RelocationSection &Section, ContiguousBlobAccumulator &CBA) {
ContiguousBlobAccumulator &CBA) {
assert((Section.Type == llvm::ELF::SHT_REL || assert((Section.Type == llvm::ELF::SHT_REL ||
Section.Type == llvm::ELF::SHT_RELA) && Section.Type == llvm::ELF::SHT_RELA) &&
"Section type is not SHT_REL nor SHT_RELA"); "Section type is not SHT_REL nor SHT_RELA");
@ -949,7 +936,8 @@ bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
else else
SHeader.sh_entsize = sizeof(Elf_Dyn); 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) { for (const ELFYAML::DynamicEntry &DE : Section.Entries) {
support::endian::write<uintX_t>(OS, DE.Tag, ELFT::TargetEndianness); support::endian::write<uintX_t>(OS, DE.Tag, ELFT::TargetEndianness);
support::endian::write<uintX_t>(OS, DE.Val, ELFT::TargetEndianness); support::endian::write<uintX_t>(OS, DE.Val, ELFT::TargetEndianness);
@ -1075,6 +1063,9 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, ELFYAML::Object &Doc) {
return 0; return 0;
} }
namespace llvm {
namespace yaml {
int yaml2elf(llvm::ELFYAML::Object &Doc, raw_ostream &Out) { int yaml2elf(llvm::ELFYAML::Object &Doc, raw_ostream &Out) {
bool IsLE = Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); bool IsLE = Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB);
bool Is64Bit = Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); bool Is64Bit = Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64);
@ -1087,3 +1078,6 @@ int yaml2elf(llvm::ELFYAML::Object &Doc, raw_ostream &Out) {
return ELFState<object::ELF32LE>::writeELF(Out, Doc); return ELFState<object::ELF32LE>::writeELF(Out, Doc);
return ELFState<object::ELF32BE>::writeELF(Out, Doc); return ELFState<object::ELF32BE>::writeELF(Out, Doc);
} }
} // namespace yaml
} // namespace llvm

View File

@ -10,4 +10,4 @@
type = Library type = Library
name = ObjectYAML name = ObjectYAML
parent = Libraries parent = Libraries
required_libraries = Object Support DebugInfoCodeView required_libraries = Object Support DebugInfoCodeView MC

View File

@ -11,10 +11,10 @@
/// ///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "yaml2obj.h"
#include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/MachO.h"
#include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include "llvm/Support/LEB128.h" #include "llvm/Support/LEB128.h"
#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/YAMLTraits.h"
@ -263,8 +263,7 @@ Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
} }
static bool isVirtualSection(uint8_t type) { static bool isVirtualSection(uint8_t type) {
return (type == MachO::S_ZEROFILL || return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL ||
type == MachO::S_GB_ZEROFILL ||
type == MachO::S_THREAD_LOCAL_ZEROFILL); type == MachO::S_THREAD_LOCAL_ZEROFILL);
} }
@ -276,7 +275,8 @@ Error MachOWriter::writeSectionData(raw_ostream &OS) {
case MachO::LC_SEGMENT_64: case MachO::LC_SEGMENT_64:
uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
: LC.Data.segment_command_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; FoundLinkEditSeg = true;
if (auto Err = writeLinkEditData(OS)) if (auto Err = writeLinkEditData(OS))
return Err; return Err;
@ -592,7 +592,10 @@ void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
} // end anonymous namespace } // 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); UniversalWriter Writer(Doc);
if (auto Err = Writer.writeMachO(Out)) { if (auto Err = Writer.writeMachO(Out)) {
errs() << toString(std::move(Err)); errs() << toString(std::move(Err));
@ -600,3 +603,6 @@ int yaml2macho(yaml::YamlObjectFile &Doc, raw_ostream &Out) {
} }
return 0; return 0;
} }
} // namespace yaml
} // namespace llvm

View File

@ -6,13 +6,19 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "yaml2obj.h"
#include "llvm/ObjectYAML/MinidumpYAML.h" #include "llvm/ObjectYAML/MinidumpYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
using namespace llvm; using namespace llvm;
namespace llvm {
namespace yaml {
int yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out) { int yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out) {
writeAsBinary(Doc, Out); writeAsBinary(Doc, Out);
return 0; return 0;
} }
} // namespace yaml
} // namespace llvm

View File

@ -14,11 +14,13 @@
#include "llvm/Object/Wasm.h" #include "llvm/Object/Wasm.h"
#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/Endian.h" #include "llvm/Support/Endian.h"
#include "llvm/Support/LEB128.h" #include "llvm/Support/LEB128.h"
using namespace llvm; using namespace llvm;
namespace {
/// This parses a yaml stream that represents a Wasm object file. /// This parses a yaml stream that represents a Wasm object file.
/// See docs/yaml2obj for the yaml scheema. /// See docs/yaml2obj for the yaml scheema.
class WasmWriter { class WasmWriter {
@ -58,6 +60,26 @@ private:
uint32_t NumImportedEvents = 0; 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) { static int writeUint64(raw_ostream &OS, uint64_t Value) {
char Data[sizeof(Value)]; char Data[sizeof(Value)];
support::endian::write64le(Data, Value); support::endian::write64le(Data, Value);
@ -119,24 +141,6 @@ static int writeInitExpr(const wasm::WasmInitExpr &InitExpr, raw_ostream &OS) {
return 0; 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, int WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::DylinkSection &Section) { WasmYAML::DylinkSection &Section) {
writeStringRef(Section.Name, OS); writeStringRef(Section.Name, OS);
@ -651,8 +655,14 @@ int WasmWriter::writeWasm(raw_ostream &OS) {
return 0; 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); WasmWriter Writer(Doc);
return Writer.writeWasm(Out); return Writer.writeWasm(Out);
} }
} // namespace yaml
} // namespace llvm

View File

@ -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<std::unique_ptr<object::ObjectFile>>
yaml2ObjectFile(SmallVectorImpl<char> &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

View File

@ -2,7 +2,7 @@
# RUN: echo -n "" | not yaml2obj 2>&1 | FileCheck %s # 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
# 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 # 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!

View File

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

View File

@ -6,4 +6,4 @@ DummyData:
... ...
# CHECK: YAML:4:1: error: YAML Object File missing document type tag! # 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!

View File

@ -16,7 +16,7 @@
# DOC2: Name: _sym2 # DOC2: Name: _sym2
# DOC3: Name: _sym3 # DOC3: Name: _sym3
# DOC4: Name: _sym4 # DOC4: Name: _sym4
# DOC5: yaml2obj: Cannot find the 5th document # DOC5: yaml2obj: error: Cannot find the 5th document
--- !ELF --- !ELF
FileHeader: !FileHeader FileHeader: !FileHeader

View File

@ -175,4 +175,4 @@ Sections:
# ERR2: error: Section size must be greater than or equal to the content size # ERR2: error: Section size must be greater than or equal to the content size
# ERR2-NEXT: - Name: .data # ERR2-NEXT: - Name: .data
# ERR2-NEXT: ^ # ERR2-NEXT: ^
# ERR2-NEXT: yaml2obj: Failed to parse YAML file! # ERR2-NEXT: yaml2obj: error: Failed to parse YAML input!

View File

@ -1,16 +1,8 @@
set(LLVM_LINK_COMPONENTS set(LLVM_LINK_COMPONENTS
DebugInfoCodeView
MC
Object
ObjectYAML ObjectYAML
Support Support
) )
add_llvm_tool(yaml2obj add_llvm_tool(yaml2obj
yaml2obj.cpp yaml2obj.cpp
yaml2coff.cpp
yaml2elf.cpp
yaml2macho.cpp
yaml2minidump.cpp
yaml2wasm.cpp
) )

View File

@ -13,7 +13,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "yaml2obj.h" #include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
@ -21,6 +21,7 @@
#include "llvm/Support/InitLLVM.h" #include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <system_error> #include <system_error>
@ -42,32 +43,6 @@ LLVM_ATTRIBUTE_NORETURN static void error(Twine Message) {
exit(1); 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) { int main(int argc, char **argv) {
InitLLVM X(argc, argv); InitLLVM X(argc, argv);
cl::ParseCommandLineOptions(argc, argv); cl::ParseCommandLineOptions(argc, argv);
@ -87,10 +62,12 @@ int main(int argc, char **argv) {
return 1; return 1;
yaml::Input YIn(Buf.get()->getBuffer()); yaml::Input YIn(Buf.get()->getBuffer());
int Res = convertYAML(YIn, Out->os()); if (Error E = convertYAML(YIn, Out->os(), DocNum)) {
if (Res == 0) logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
Out->keep(); return 1;
}
Out->keep();
Out->os().flush(); Out->os().flush();
return Res; return 0;
} }

View File

@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(ObjectYAMLTests add_llvm_unittest(ObjectYAMLTests
MinidumpYAMLTest.cpp MinidumpYAMLTest.cpp
YAML2ObjTest.cpp
YAMLTest.cpp YAMLTest.cpp
) )

View File

@ -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<std::unique_ptr<ObjectFile>> 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<ObjectFile> ObjFile = std::move(ErrOrObj.get());
ASSERT_TRUE(ObjFile->isELF());
ASSERT_TRUE(ObjFile->isRelocatableObject());
}