aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm14/tools/obj2yaml
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
committervitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
commit6ffe9e53658409f212834330e13564e4952558f6 (patch)
tree85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/llvm14/tools/obj2yaml
parent726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff)
downloadydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/llvm14/tools/obj2yaml')
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/archive2yaml.cpp114
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/coff2yaml.cpp366
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/dwarf2yaml.cpp463
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/elf2yaml.cpp1596
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/macho2yaml.cpp672
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/minidump2yaml.cpp23
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/obj2yaml.cpp95
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/obj2yaml.h57
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/wasm2yaml.cpp405
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/xcoff2yaml.cpp152
-rw-r--r--contrib/libs/llvm14/tools/obj2yaml/ya.make47
11 files changed, 3990 insertions, 0 deletions
diff --git a/contrib/libs/llvm14/tools/obj2yaml/archive2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/archive2yaml.cpp
new file mode 100644
index 0000000000..c7b0ee4802
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/archive2yaml.cpp
@@ -0,0 +1,114 @@
+//===------ utils/archive2yaml.cpp - obj2yaml conversion tool ---*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/ObjectYAML/ArchiveYAML.h"
+
+using namespace llvm;
+
+namespace {
+
+class ArchiveDumper {
+public:
+ Expected<ArchYAML::Archive *> dump(MemoryBufferRef Source) {
+ StringRef Buffer = Source.getBuffer();
+ assert(file_magic::archive == identify_magic(Buffer));
+
+ std::unique_ptr<ArchYAML::Archive> Obj =
+ std::make_unique<ArchYAML::Archive>();
+
+ StringRef Magic = "!<arch>\n";
+ if (!Buffer.startswith(Magic))
+ return createStringError(std::errc::not_supported,
+ "only regular archives are supported");
+ Obj->Magic = Magic;
+ Buffer = Buffer.drop_front(Magic.size());
+
+ Obj->Members.emplace();
+ while (!Buffer.empty()) {
+ uint64_t Offset = Buffer.data() - Source.getBuffer().data();
+ if (Buffer.size() < sizeof(ArchiveHeader))
+ return createStringError(
+ std::errc::illegal_byte_sequence,
+ "unable to read the header of a child at offset 0x%" PRIx64,
+ Offset);
+
+ const ArchiveHeader &Hdr =
+ *reinterpret_cast<const ArchiveHeader *>(Buffer.data());
+ Buffer = Buffer.drop_front(sizeof(ArchiveHeader));
+
+ auto ToString = [](ArrayRef<char> V) {
+ // We don't want to dump excessive spaces.
+ return StringRef(V.data(), V.size()).rtrim(' ');
+ };
+
+ ArchYAML::Archive::Child C;
+ C.Fields["Name"].Value = ToString(Hdr.Name);
+ C.Fields["LastModified"].Value = ToString(Hdr.LastModified);
+ C.Fields["UID"].Value = ToString(Hdr.UID);
+ C.Fields["GID"].Value = ToString(Hdr.GID);
+ C.Fields["AccessMode"].Value = ToString(Hdr.AccessMode);
+ StringRef SizeStr = ToString(Hdr.Size);
+ C.Fields["Size"].Value = SizeStr;
+ C.Fields["Terminator"].Value = ToString(Hdr.Terminator);
+
+ uint64_t Size;
+ if (SizeStr.getAsInteger(10, Size))
+ return createStringError(
+ std::errc::illegal_byte_sequence,
+ "unable to read the size of a child at offset 0x%" PRIx64
+ " as integer: \"%s\"",
+ Offset, SizeStr.str().c_str());
+ if (Buffer.size() < Size)
+ return createStringError(
+ std::errc::illegal_byte_sequence,
+ "unable to read the data of a child at offset 0x%" PRIx64
+ " of size %" PRId64 ": the remaining archive size is %zu",
+ Offset, Size, Buffer.size());
+ if (!Buffer.empty())
+ C.Content = arrayRefFromStringRef(Buffer.take_front(Size));
+
+ const bool HasPaddingByte = (Size & 1) && Buffer.size() > Size;
+ if (HasPaddingByte)
+ C.PaddingByte = Buffer[Size];
+
+ Obj->Members->push_back(C);
+ // If the size is odd, consume a padding byte.
+ Buffer = Buffer.drop_front(HasPaddingByte ? Size + 1 : Size);
+ }
+
+ return Obj.release();
+ }
+
+private:
+ struct ArchiveHeader {
+ char Name[16];
+ char LastModified[12];
+ char UID[6];
+ char GID[6];
+ char AccessMode[8];
+ char Size[10];
+ char Terminator[2];
+ };
+};
+
+} // namespace
+
+Error archive2yaml(raw_ostream &Out, MemoryBufferRef Source) {
+ ArchiveDumper Dumper;
+ Expected<ArchYAML::Archive *> YAMLOrErr = Dumper.dump(Source);
+ if (!YAMLOrErr)
+ return YAMLOrErr.takeError();
+
+ std::unique_ptr<ArchYAML::Archive> YAML(YAMLOrErr.get());
+ yaml::Output Yout(Out);
+ Yout << *YAML;
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/coff2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/coff2yaml.cpp
new file mode 100644
index 0000000000..604799fb27
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/coff2yaml.cpp
@@ -0,0 +1,366 @@
+//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/ObjectYAML/COFFYAML.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+
+namespace {
+
+class COFFDumper {
+ const object::COFFObjectFile &Obj;
+ COFFYAML::Object YAMLObj;
+ template <typename T>
+ void dumpOptionalHeader(T OptionalHeader);
+ void dumpHeader();
+ void dumpSections(unsigned numSections);
+ void dumpSymbols(unsigned numSymbols);
+
+public:
+ COFFDumper(const object::COFFObjectFile &Obj);
+ COFFYAML::Object &getYAMLObj();
+};
+
+}
+
+COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) {
+ if (const object::pe32_header *PE32Header = Obj.getPE32Header())
+ dumpOptionalHeader(PE32Header);
+ else if (const object::pe32plus_header *PE32PlusHeader =
+ Obj.getPE32PlusHeader())
+ dumpOptionalHeader(PE32PlusHeader);
+
+ dumpHeader();
+ dumpSections(Obj.getNumberOfSections());
+ dumpSymbols(Obj.getNumberOfSymbols());
+}
+
+template <typename T> void COFFDumper::dumpOptionalHeader(T OptionalHeader) {
+ YAMLObj.OptionalHeader = COFFYAML::PEHeader();
+ YAMLObj.OptionalHeader->Header.AddressOfEntryPoint =
+ OptionalHeader->AddressOfEntryPoint;
+ YAMLObj.OptionalHeader->Header.ImageBase = OptionalHeader->ImageBase;
+ YAMLObj.OptionalHeader->Header.SectionAlignment =
+ OptionalHeader->SectionAlignment;
+ YAMLObj.OptionalHeader->Header.FileAlignment = OptionalHeader->FileAlignment;
+ YAMLObj.OptionalHeader->Header.MajorOperatingSystemVersion =
+ OptionalHeader->MajorOperatingSystemVersion;
+ YAMLObj.OptionalHeader->Header.MinorOperatingSystemVersion =
+ OptionalHeader->MinorOperatingSystemVersion;
+ YAMLObj.OptionalHeader->Header.MajorImageVersion =
+ OptionalHeader->MajorImageVersion;
+ YAMLObj.OptionalHeader->Header.MinorImageVersion =
+ OptionalHeader->MinorImageVersion;
+ YAMLObj.OptionalHeader->Header.MajorSubsystemVersion =
+ OptionalHeader->MajorSubsystemVersion;
+ YAMLObj.OptionalHeader->Header.MinorSubsystemVersion =
+ OptionalHeader->MinorSubsystemVersion;
+ YAMLObj.OptionalHeader->Header.Subsystem = OptionalHeader->Subsystem;
+ YAMLObj.OptionalHeader->Header.DLLCharacteristics =
+ OptionalHeader->DLLCharacteristics;
+ YAMLObj.OptionalHeader->Header.SizeOfStackReserve =
+ OptionalHeader->SizeOfStackReserve;
+ YAMLObj.OptionalHeader->Header.SizeOfStackCommit =
+ OptionalHeader->SizeOfStackCommit;
+ YAMLObj.OptionalHeader->Header.SizeOfHeapReserve =
+ OptionalHeader->SizeOfHeapReserve;
+ YAMLObj.OptionalHeader->Header.SizeOfHeapCommit =
+ OptionalHeader->SizeOfHeapCommit;
+ YAMLObj.OptionalHeader->Header.NumberOfRvaAndSize =
+ OptionalHeader->NumberOfRvaAndSize;
+ unsigned I = 0;
+ for (auto &DestDD : YAMLObj.OptionalHeader->DataDirectories) {
+ const object::data_directory *DD = Obj.getDataDirectory(I++);
+ if (!DD)
+ continue;
+ DestDD = COFF::DataDirectory();
+ DestDD->RelativeVirtualAddress = DD->RelativeVirtualAddress;
+ DestDD->Size = DD->Size;
+ }
+}
+
+void COFFDumper::dumpHeader() {
+ YAMLObj.Header.Machine = Obj.getMachine();
+ YAMLObj.Header.Characteristics = Obj.getCharacteristics();
+}
+
+static void
+initializeFileAndStringTable(const llvm::object::COFFObjectFile &Obj,
+ codeview::StringsAndChecksumsRef &SC) {
+
+ ExitOnError Err("invalid .debug$S section");
+ // Iterate all .debug$S sections looking for the checksums and string table.
+ // Exit as soon as both sections are found.
+ for (const auto &S : Obj.sections()) {
+ if (SC.hasStrings() && SC.hasChecksums())
+ break;
+
+ Expected<StringRef> SectionNameOrErr = S.getName();
+ if (!SectionNameOrErr) {
+ consumeError(SectionNameOrErr.takeError());
+ continue;
+ }
+
+ ArrayRef<uint8_t> sectionData;
+ if ((*SectionNameOrErr) != ".debug$S")
+ continue;
+
+ const object::coff_section *COFFSection = Obj.getCOFFSection(S);
+
+ cantFail(Obj.getSectionContents(COFFSection, sectionData));
+
+ BinaryStreamReader Reader(sectionData, support::little);
+ uint32_t Magic;
+
+ Err(Reader.readInteger(Magic));
+ assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
+
+ codeview::DebugSubsectionArray Subsections;
+ Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
+
+ SC.initialize(Subsections);
+ }
+}
+
+void COFFDumper::dumpSections(unsigned NumSections) {
+ std::vector<COFFYAML::Section> &YAMLSections = YAMLObj.Sections;
+ codeview::StringsAndChecksumsRef SC;
+ initializeFileAndStringTable(Obj, SC);
+
+ ExitOnError Err("invalid section table");
+ StringMap<bool> SymbolUnique;
+ for (const auto &S : Obj.symbols()) {
+ StringRef Name = Err(Obj.getSymbolName(Obj.getCOFFSymbol(S)));
+ StringMap<bool>::iterator It;
+ bool Inserted;
+ std::tie(It, Inserted) = SymbolUnique.insert(std::make_pair(Name, true));
+ if (!Inserted)
+ It->second = false;
+ }
+
+ for (const auto &ObjSection : Obj.sections()) {
+ const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection);
+ COFFYAML::Section NewYAMLSection;
+
+ if (Expected<StringRef> NameOrErr = ObjSection.getName())
+ NewYAMLSection.Name = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ NewYAMLSection.Header.Characteristics = COFFSection->Characteristics;
+ NewYAMLSection.Header.VirtualAddress = COFFSection->VirtualAddress;
+ NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize;
+ NewYAMLSection.Header.NumberOfLineNumbers =
+ COFFSection->NumberOfLinenumbers;
+ NewYAMLSection.Header.NumberOfRelocations =
+ COFFSection->NumberOfRelocations;
+ NewYAMLSection.Header.PointerToLineNumbers =
+ COFFSection->PointerToLinenumbers;
+ NewYAMLSection.Header.PointerToRawData = COFFSection->PointerToRawData;
+ NewYAMLSection.Header.PointerToRelocations =
+ COFFSection->PointerToRelocations;
+ NewYAMLSection.Header.SizeOfRawData = COFFSection->SizeOfRawData;
+ uint32_t Shift = (COFFSection->Characteristics >> 20) & 0xF;
+ NewYAMLSection.Alignment = (1U << Shift) >> 1;
+ assert(NewYAMLSection.Alignment <= 8192);
+
+ ArrayRef<uint8_t> sectionData;
+ if (!ObjSection.isBSS())
+ cantFail(Obj.getSectionContents(COFFSection, sectionData));
+ NewYAMLSection.SectionData = yaml::BinaryRef(sectionData);
+
+ if (NewYAMLSection.Name == ".debug$S")
+ NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC);
+ else if (NewYAMLSection.Name == ".debug$T")
+ NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData,
+ NewYAMLSection.Name);
+ else if (NewYAMLSection.Name == ".debug$P")
+ NewYAMLSection.DebugP = CodeViewYAML::fromDebugT(sectionData,
+ NewYAMLSection.Name);
+ else if (NewYAMLSection.Name == ".debug$H")
+ NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData);
+
+ std::vector<COFFYAML::Relocation> Relocations;
+ for (const auto &Reloc : ObjSection.relocations()) {
+ const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc);
+ COFFYAML::Relocation Rel;
+ object::symbol_iterator Sym = Reloc.getSymbol();
+ Expected<StringRef> SymbolNameOrErr = Sym->getName();
+ if (!SymbolNameOrErr) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(SymbolNameOrErr.takeError(), OS);
+ report_fatal_error(Twine(OS.str()));
+ }
+ if (SymbolUnique.lookup(*SymbolNameOrErr))
+ Rel.SymbolName = *SymbolNameOrErr;
+ else
+ Rel.SymbolTableIndex = reloc->SymbolTableIndex;
+ Rel.VirtualAddress = reloc->VirtualAddress;
+ Rel.Type = reloc->Type;
+ Relocations.push_back(Rel);
+ }
+ NewYAMLSection.Relocations = Relocations;
+ YAMLSections.push_back(NewYAMLSection);
+ }
+}
+
+static void
+dumpFunctionDefinition(COFFYAML::Symbol *Sym,
+ const object::coff_aux_function_definition *ObjFD) {
+ COFF::AuxiliaryFunctionDefinition YAMLFD;
+ YAMLFD.TagIndex = ObjFD->TagIndex;
+ YAMLFD.TotalSize = ObjFD->TotalSize;
+ YAMLFD.PointerToLinenumber = ObjFD->PointerToLinenumber;
+ YAMLFD.PointerToNextFunction = ObjFD->PointerToNextFunction;
+
+ Sym->FunctionDefinition = YAMLFD;
+}
+
+static void
+dumpbfAndEfLineInfo(COFFYAML::Symbol *Sym,
+ const object::coff_aux_bf_and_ef_symbol *ObjBES) {
+ COFF::AuxiliarybfAndefSymbol YAMLAAS;
+ YAMLAAS.Linenumber = ObjBES->Linenumber;
+ YAMLAAS.PointerToNextFunction = ObjBES->PointerToNextFunction;
+
+ Sym->bfAndefSymbol = YAMLAAS;
+}
+
+static void dumpWeakExternal(COFFYAML::Symbol *Sym,
+ const object::coff_aux_weak_external *ObjWE) {
+ COFF::AuxiliaryWeakExternal YAMLWE;
+ YAMLWE.TagIndex = ObjWE->TagIndex;
+ YAMLWE.Characteristics = ObjWE->Characteristics;
+
+ Sym->WeakExternal = YAMLWE;
+}
+
+static void
+dumpSectionDefinition(COFFYAML::Symbol *Sym,
+ const object::coff_aux_section_definition *ObjSD,
+ bool IsBigObj) {
+ COFF::AuxiliarySectionDefinition YAMLASD;
+ int32_t AuxNumber = ObjSD->getNumber(IsBigObj);
+ YAMLASD.Length = ObjSD->Length;
+ YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations;
+ YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers;
+ YAMLASD.CheckSum = ObjSD->CheckSum;
+ YAMLASD.Number = AuxNumber;
+ YAMLASD.Selection = ObjSD->Selection;
+
+ Sym->SectionDefinition = YAMLASD;
+}
+
+static void
+dumpCLRTokenDefinition(COFFYAML::Symbol *Sym,
+ const object::coff_aux_clr_token *ObjCLRToken) {
+ COFF::AuxiliaryCLRToken YAMLCLRToken;
+ YAMLCLRToken.AuxType = ObjCLRToken->AuxType;
+ YAMLCLRToken.SymbolTableIndex = ObjCLRToken->SymbolTableIndex;
+
+ Sym->CLRToken = YAMLCLRToken;
+}
+
+void COFFDumper::dumpSymbols(unsigned NumSymbols) {
+ ExitOnError Err("invalid symbol table");
+
+ std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols;
+ for (const auto &S : Obj.symbols()) {
+ object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S);
+ COFFYAML::Symbol Sym;
+ Sym.Name = Err(Obj.getSymbolName(Symbol));
+ Sym.SimpleType = COFF::SymbolBaseType(Symbol.getBaseType());
+ Sym.ComplexType = COFF::SymbolComplexType(Symbol.getComplexType());
+ Sym.Header.StorageClass = Symbol.getStorageClass();
+ Sym.Header.Value = Symbol.getValue();
+ Sym.Header.SectionNumber = Symbol.getSectionNumber();
+ Sym.Header.NumberOfAuxSymbols = Symbol.getNumberOfAuxSymbols();
+
+ if (Symbol.getNumberOfAuxSymbols() > 0) {
+ ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol);
+ if (Symbol.isFunctionDefinition()) {
+ // This symbol represents a function definition.
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this function!");
+
+ const object::coff_aux_function_definition *ObjFD =
+ reinterpret_cast<const object::coff_aux_function_definition *>(
+ AuxData.data());
+ dumpFunctionDefinition(&Sym, ObjFD);
+ } else if (Symbol.isFunctionLineInfo()) {
+ // This symbol describes function line number information.
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this function!");
+
+ const object::coff_aux_bf_and_ef_symbol *ObjBES =
+ reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>(
+ AuxData.data());
+ dumpbfAndEfLineInfo(&Sym, ObjBES);
+ } else if (Symbol.isAnyUndefined()) {
+ // This symbol represents a weak external definition.
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this weak symbol!");
+
+ const object::coff_aux_weak_external *ObjWE =
+ reinterpret_cast<const object::coff_aux_weak_external *>(
+ AuxData.data());
+ dumpWeakExternal(&Sym, ObjWE);
+ } else if (Symbol.isFileRecord()) {
+ // This symbol represents a file record.
+ Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()),
+ Symbol.getNumberOfAuxSymbols() *
+ Obj.getSymbolTableEntrySize())
+ .rtrim(StringRef("\0", /*length=*/1));
+ } else if (Symbol.isSectionDefinition()) {
+ // This symbol represents a section definition.
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this section!");
+
+ const object::coff_aux_section_definition *ObjSD =
+ reinterpret_cast<const object::coff_aux_section_definition *>(
+ AuxData.data());
+ dumpSectionDefinition(&Sym, ObjSD, Symbol.isBigObj());
+ } else if (Symbol.isCLRToken()) {
+ // This symbol represents a CLR token definition.
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this CLR Token!");
+
+ const object::coff_aux_clr_token *ObjCLRToken =
+ reinterpret_cast<const object::coff_aux_clr_token *>(
+ AuxData.data());
+ dumpCLRTokenDefinition(&Sym, ObjCLRToken);
+ } else {
+ llvm_unreachable("Unhandled auxiliary symbol!");
+ }
+ }
+ Symbols.push_back(Sym);
+ }
+}
+
+COFFYAML::Object &COFFDumper::getYAMLObj() {
+ return YAMLObj;
+}
+
+std::error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) {
+ COFFDumper Dumper(Obj);
+
+ yaml::Output Yout(Out);
+ Yout << Dumper.getYAMLObj();
+
+ return std::error_code();
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/dwarf2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/dwarf2yaml.cpp
new file mode 100644
index 0000000000..8cae1f3c49
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/dwarf2yaml.cpp
@@ -0,0 +1,463 @@
+//===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
+//
+// 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/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+
+#include <algorithm>
+
+using namespace llvm;
+
+void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ auto AbbrevSetPtr = DCtx.getDebugAbbrev();
+ if (AbbrevSetPtr) {
+ uint64_t AbbrevTableID = 0;
+ for (auto AbbrvDeclSet : *AbbrevSetPtr) {
+ Y.DebugAbbrev.emplace_back();
+ Y.DebugAbbrev.back().ID = AbbrevTableID++;
+ for (auto AbbrvDecl : AbbrvDeclSet.second) {
+ DWARFYAML::Abbrev Abbrv;
+ Abbrv.Code = AbbrvDecl.getCode();
+ Abbrv.Tag = AbbrvDecl.getTag();
+ Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes
+ : dwarf::DW_CHILDREN_no;
+ for (auto Attribute : AbbrvDecl.attributes()) {
+ DWARFYAML::AttributeAbbrev AttAbrv;
+ AttAbrv.Attribute = Attribute.Attr;
+ AttAbrv.Form = Attribute.Form;
+ if (AttAbrv.Form == dwarf::DW_FORM_implicit_const)
+ AttAbrv.Value = Attribute.getImplicitConstValue();
+ Abbrv.Attributes.push_back(AttAbrv);
+ }
+ Y.DebugAbbrev.back().Table.push_back(Abbrv);
+ }
+ }
+ }
+}
+
+Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ DWARFDebugAddrTable AddrTable;
+ DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
+ DCtx.getDWARFObj().getAddrSection(),
+ DCtx.isLittleEndian(), /*AddressSize=*/0);
+ std::vector<DWARFYAML::AddrTableEntry> AddrTables;
+ uint64_t Offset = 0;
+ while (AddrData.isValidOffset(Offset)) {
+ // We ignore any errors that don't prevent parsing the section, since we can
+ // still represent such sections.
+ if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0,
+ consumeError))
+ return Err;
+ AddrTables.emplace_back();
+ for (uint64_t Addr : AddrTable.getAddressEntries()) {
+ // Currently, the parser doesn't support parsing an address table with non
+ // linear addresses (segment_selector_size != 0). The segment selectors
+ // are specified to be zero.
+ AddrTables.back().SegAddrPairs.push_back(
+ {/*SegmentSelector=*/0, /*Address=*/Addr});
+ }
+
+ AddrTables.back().Format = AddrTable.getFormat();
+ AddrTables.back().Length = AddrTable.getLength();
+ AddrTables.back().Version = AddrTable.getVersion();
+ AddrTables.back().AddrSize = AddrTable.getAddressSize();
+ AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize();
+ }
+ Y.DebugAddr = std::move(AddrTables);
+ return Error::success();
+}
+
+Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ DataExtractor StrData = DCtx.getStringExtractor();
+ uint64_t Offset = 0;
+ std::vector<StringRef> DebugStr;
+ Error Err = Error::success();
+ while (StrData.isValidOffset(Offset)) {
+ const char *CStr = StrData.getCStr(&Offset, &Err);
+ if (Err)
+ return Err;
+ DebugStr.push_back(CStr);
+ }
+
+ Y.DebugStrings = DebugStr;
+ return Err;
+}
+
+Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
+ DCtx.isLittleEndian(), 0);
+ uint64_t Offset = 0;
+ DWARFDebugArangeSet Set;
+ std::vector<DWARFYAML::ARange> DebugAranges;
+
+ // We ignore any errors that don't prevent parsing the section, since we can
+ // still represent such sections. These errors are recorded via the
+ // WarningHandler parameter of Set.extract().
+ auto DiscardError = [](Error Err) { consumeError(std::move(Err)); };
+
+ while (ArangesData.isValidOffset(Offset)) {
+ if (Error E = Set.extract(ArangesData, &Offset, DiscardError))
+ return E;
+ DWARFYAML::ARange Range;
+ Range.Format = Set.getHeader().Format;
+ Range.Length = Set.getHeader().Length;
+ Range.Version = Set.getHeader().Version;
+ Range.CuOffset = Set.getHeader().CuOffset;
+ Range.AddrSize = Set.getHeader().AddrSize;
+ Range.SegSize = Set.getHeader().SegSize;
+ for (auto Descriptor : Set.descriptors()) {
+ DWARFYAML::ARangeDescriptor Desc;
+ Desc.Address = Descriptor.Address;
+ Desc.Length = Descriptor.Length;
+ Range.Descriptors.push_back(Desc);
+ }
+ DebugAranges.push_back(Range);
+ }
+
+ Y.DebugAranges = DebugAranges;
+ return ErrorSuccess();
+}
+
+Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ // We are assuming all address byte sizes will be consistent across all
+ // compile units.
+ uint8_t AddrSize = 0;
+ for (const auto &CU : DCtx.compile_units()) {
+ const uint8_t CUAddrSize = CU->getAddressByteSize();
+ if (AddrSize == 0)
+ AddrSize = CUAddrSize;
+ else if (CUAddrSize != AddrSize)
+ return createStringError(std::errc::invalid_argument,
+ "address sizes vary in different compile units");
+ }
+
+ DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
+ DCtx.isLittleEndian(), AddrSize);
+ uint64_t Offset = 0;
+ DWARFDebugRangeList DwarfRanges;
+ std::vector<DWARFYAML::Ranges> DebugRanges;
+
+ while (Data.isValidOffset(Offset)) {
+ DWARFYAML::Ranges YamlRanges;
+ YamlRanges.Offset = Offset;
+ YamlRanges.AddrSize = AddrSize;
+ if (Error E = DwarfRanges.extract(Data, &Offset))
+ return E;
+ for (const auto &RLE : DwarfRanges.getEntries())
+ YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
+ DebugRanges.push_back(std::move(YamlRanges));
+ }
+
+ Y.DebugRanges = DebugRanges;
+ return ErrorSuccess();
+}
+
+static Optional<DWARFYAML::PubSection>
+dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
+ bool IsGNUStyle) {
+ DWARFYAML::PubSection Y;
+ DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
+ DCtx.isLittleEndian(), 0);
+ DWARFDebugPubTable Table;
+ // We ignore any errors that don't prevent parsing the section, since we can
+ // still represent such sections.
+ Table.extract(PubSectionData, IsGNUStyle,
+ [](Error Err) { consumeError(std::move(Err)); });
+ ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData();
+ if (Sets.empty())
+ return None;
+
+ // FIXME: Currently, obj2yaml only supports dumping the first pubtable.
+ Y.Format = Sets[0].Format;
+ Y.Length = Sets[0].Length;
+ Y.Version = Sets[0].Version;
+ Y.UnitOffset = Sets[0].Offset;
+ Y.UnitSize = Sets[0].Size;
+
+ for (const DWARFDebugPubTable::Entry &E : Sets[0].Entries)
+ Y.Entries.push_back(DWARFYAML::PubEntry{(uint32_t)E.SecOffset,
+ E.Descriptor.toBits(), E.Name});
+
+ return Y;
+}
+
+void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ const DWARFObject &D = DCtx.getDWARFObj();
+
+ Y.PubNames =
+ dumpPubSection(DCtx, D.getPubnamesSection(), /*IsGNUStyle=*/false);
+ Y.PubTypes =
+ dumpPubSection(DCtx, D.getPubtypesSection(), /*IsGNUStyle=*/false);
+ // TODO: Test dumping .debug_gnu_pubnames section.
+ Y.GNUPubNames =
+ dumpPubSection(DCtx, D.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
+ // TODO: Test dumping .debug_gnu_pubtypes section.
+ Y.GNUPubTypes =
+ dumpPubSection(DCtx, D.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
+}
+
+void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ for (const auto &CU : DCtx.compile_units()) {
+ DWARFYAML::Unit NewUnit;
+ NewUnit.Format = CU->getFormat();
+ NewUnit.Length = CU->getLength();
+ NewUnit.Version = CU->getVersion();
+ if (NewUnit.Version >= 5)
+ NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
+ const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev();
+ NewUnit.AbbrevTableID = std::distance(
+ DebugAbbrev->begin(),
+ llvm::find_if(
+ *DebugAbbrev,
+ [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
+ return P.first == CU->getAbbreviations()->getOffset();
+ }));
+ NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset();
+ NewUnit.AddrSize = CU->getAddressByteSize();
+ for (auto DIE : CU->dies()) {
+ DWARFYAML::Entry NewEntry;
+ DataExtractor EntryData = CU->getDebugInfoExtractor();
+ uint64_t offset = DIE.getOffset();
+
+ assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
+ if (!EntryData.isValidOffset(offset))
+ continue;
+
+ NewEntry.AbbrCode = EntryData.getULEB128(&offset);
+
+ auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
+ if (AbbrevDecl) {
+ for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+ DWARFYAML::FormValue NewValue;
+ NewValue.Value = 0xDEADBEEFDEADBEEF;
+ DWARFDie DIEWrapper(CU.get(), &DIE);
+ auto FormValue = DIEWrapper.find(AttrSpec.Attr);
+ if (!FormValue)
+ return;
+ auto Form = FormValue.getValue().getForm();
+ bool indirect = false;
+ do {
+ indirect = false;
+ switch (Form) {
+ case dwarf::DW_FORM_addr:
+ case dwarf::DW_FORM_GNU_addr_index:
+ if (auto Val = FormValue.getValue().getAsAddress())
+ NewValue.Value = Val.getValue();
+ break;
+ case dwarf::DW_FORM_ref_addr:
+ case dwarf::DW_FORM_ref1:
+ case dwarf::DW_FORM_ref2:
+ case dwarf::DW_FORM_ref4:
+ case dwarf::DW_FORM_ref8:
+ case dwarf::DW_FORM_ref_udata:
+ case dwarf::DW_FORM_ref_sig8:
+ if (auto Val = FormValue.getValue().getAsReferenceUVal())
+ NewValue.Value = Val.getValue();
+ break;
+ case dwarf::DW_FORM_exprloc:
+ case dwarf::DW_FORM_block:
+ case dwarf::DW_FORM_block1:
+ case dwarf::DW_FORM_block2:
+ case dwarf::DW_FORM_block4:
+ if (auto Val = FormValue.getValue().getAsBlock()) {
+ auto BlockData = Val.getValue();
+ std::copy(BlockData.begin(), BlockData.end(),
+ std::back_inserter(NewValue.BlockData));
+ }
+ NewValue.Value = NewValue.BlockData.size();
+ break;
+ case dwarf::DW_FORM_data1:
+ case dwarf::DW_FORM_flag:
+ case dwarf::DW_FORM_data2:
+ case dwarf::DW_FORM_data4:
+ case dwarf::DW_FORM_data8:
+ case dwarf::DW_FORM_sdata:
+ case dwarf::DW_FORM_udata:
+ case dwarf::DW_FORM_ref_sup4:
+ case dwarf::DW_FORM_ref_sup8:
+ if (auto Val = FormValue.getValue().getAsUnsignedConstant())
+ NewValue.Value = Val.getValue();
+ break;
+ case dwarf::DW_FORM_string:
+ if (auto Val = dwarf::toString(FormValue))
+ NewValue.CStr = *Val;
+ break;
+ case dwarf::DW_FORM_indirect:
+ indirect = true;
+ if (auto Val = FormValue.getValue().getAsUnsignedConstant()) {
+ NewValue.Value = Val.getValue();
+ NewEntry.Values.push_back(NewValue);
+ Form = static_cast<dwarf::Form>(Val.getValue());
+ }
+ break;
+ case dwarf::DW_FORM_strp:
+ case dwarf::DW_FORM_sec_offset:
+ case dwarf::DW_FORM_GNU_ref_alt:
+ case dwarf::DW_FORM_GNU_strp_alt:
+ case dwarf::DW_FORM_line_strp:
+ case dwarf::DW_FORM_strp_sup:
+ case dwarf::DW_FORM_GNU_str_index:
+ case dwarf::DW_FORM_strx:
+ if (auto Val = FormValue.getValue().getAsCStringOffset())
+ NewValue.Value = Val.getValue();
+ break;
+ case dwarf::DW_FORM_flag_present:
+ NewValue.Value = 1;
+ break;
+ default:
+ break;
+ }
+ } while (indirect);
+ NewEntry.Values.push_back(NewValue);
+ }
+ }
+
+ NewUnit.Entries.push_back(NewEntry);
+ }
+ Y.CompileUnits.push_back(NewUnit);
+ }
+}
+
+bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
+ DWARFYAML::File &File) {
+ File.Name = Data.getCStr(&Offset);
+ if (File.Name.empty())
+ return false;
+ File.DirIdx = Data.getULEB128(&Offset);
+ File.ModTime = Data.getULEB128(&Offset);
+ File.Length = Data.getULEB128(&Offset);
+ return true;
+}
+
+void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+ for (const auto &CU : DCtx.compile_units()) {
+ auto CUDIE = CU->getUnitDIE();
+ if (!CUDIE)
+ continue;
+ if (auto StmtOffset =
+ dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
+ DWARFYAML::LineTable DebugLines;
+ DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data,
+ DCtx.isLittleEndian(), CU->getAddressByteSize());
+ uint64_t Offset = *StmtOffset;
+ uint64_t LengthOrDWARF64Prefix = LineData.getU32(&Offset);
+ if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) {
+ DebugLines.Format = dwarf::DWARF64;
+ DebugLines.Length = LineData.getU64(&Offset);
+ } else {
+ DebugLines.Format = dwarf::DWARF32;
+ DebugLines.Length = LengthOrDWARF64Prefix;
+ }
+ assert(DebugLines.Length);
+ uint64_t LineTableLength = *DebugLines.Length;
+ uint64_t SizeOfPrologueLength =
+ DebugLines.Format == dwarf::DWARF64 ? 8 : 4;
+ DebugLines.Version = LineData.getU16(&Offset);
+ DebugLines.PrologueLength =
+ LineData.getUnsigned(&Offset, SizeOfPrologueLength);
+ assert(DebugLines.PrologueLength);
+ const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset;
+
+ DebugLines.MinInstLength = LineData.getU8(&Offset);
+ if (DebugLines.Version >= 4)
+ DebugLines.MaxOpsPerInst = LineData.getU8(&Offset);
+ DebugLines.DefaultIsStmt = LineData.getU8(&Offset);
+ DebugLines.LineBase = LineData.getU8(&Offset);
+ DebugLines.LineRange = LineData.getU8(&Offset);
+ DebugLines.OpcodeBase = LineData.getU8(&Offset);
+
+ DebugLines.StandardOpcodeLengths.emplace();
+ for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
+ DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
+
+ while (Offset < EndPrologue) {
+ StringRef Dir = LineData.getCStr(&Offset);
+ if (!Dir.empty())
+ DebugLines.IncludeDirs.push_back(Dir);
+ else
+ break;
+ }
+
+ while (Offset < EndPrologue) {
+ DWARFYAML::File TmpFile;
+ if (dumpFileEntry(LineData, Offset, TmpFile))
+ DebugLines.Files.push_back(TmpFile);
+ else
+ break;
+ }
+
+ const uint64_t LineEnd =
+ LineTableLength + *StmtOffset + SizeOfPrologueLength;
+ while (Offset < LineEnd) {
+ DWARFYAML::LineTableOpcode NewOp = {};
+ NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset);
+ if (NewOp.Opcode == 0) {
+ auto StartExt = Offset;
+ NewOp.ExtLen = LineData.getULEB128(&Offset);
+ NewOp.SubOpcode =
+ (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset);
+ switch (NewOp.SubOpcode) {
+ case dwarf::DW_LNE_set_address:
+ case dwarf::DW_LNE_set_discriminator:
+ NewOp.Data = LineData.getAddress(&Offset);
+ break;
+ case dwarf::DW_LNE_define_file:
+ dumpFileEntry(LineData, Offset, NewOp.FileEntry);
+ break;
+ case dwarf::DW_LNE_end_sequence:
+ break;
+ default:
+ while (Offset < StartExt + *NewOp.ExtLen)
+ NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
+ }
+ } else if (NewOp.Opcode < *DebugLines.OpcodeBase) {
+ switch (NewOp.Opcode) {
+ case dwarf::DW_LNS_copy:
+ case dwarf::DW_LNS_negate_stmt:
+ case dwarf::DW_LNS_set_basic_block:
+ case dwarf::DW_LNS_const_add_pc:
+ case dwarf::DW_LNS_set_prologue_end:
+ case dwarf::DW_LNS_set_epilogue_begin:
+ break;
+
+ case dwarf::DW_LNS_advance_pc:
+ case dwarf::DW_LNS_set_file:
+ case dwarf::DW_LNS_set_column:
+ case dwarf::DW_LNS_set_isa:
+ NewOp.Data = LineData.getULEB128(&Offset);
+ break;
+
+ case dwarf::DW_LNS_advance_line:
+ NewOp.SData = LineData.getSLEB128(&Offset);
+ break;
+
+ case dwarf::DW_LNS_fixed_advance_pc:
+ NewOp.Data = LineData.getU16(&Offset);
+ break;
+
+ default:
+ for (uint8_t i = 0;
+ i <
+ DebugLines.StandardOpcodeLengths.getValue()[NewOp.Opcode - 1];
+ ++i)
+ NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
+ }
+ }
+ DebugLines.Opcodes.push_back(NewOp);
+ }
+ Y.DebugLines.push_back(DebugLines);
+ }
+ }
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/elf2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/elf2yaml.cpp
new file mode 100644
index 0000000000..9d1713c859
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/elf2yaml.cpp
@@ -0,0 +1,1596 @@
+//===------ utils/elf2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+
+namespace {
+
+template <class ELFT>
+class ELFDumper {
+ LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+
+ ArrayRef<Elf_Shdr> Sections;
+ ArrayRef<Elf_Sym> SymTable;
+
+ DenseMap<StringRef, uint32_t> UsedSectionNames;
+ std::vector<std::string> SectionNames;
+ Optional<uint32_t> ShStrTabIndex;
+
+ DenseMap<StringRef, uint32_t> UsedSymbolNames;
+ std::vector<std::string> SymbolNames;
+
+ BumpPtrAllocator StringAllocator;
+
+ Expected<StringRef> getUniquedSectionName(const Elf_Shdr &Sec);
+ Expected<StringRef> getUniquedSymbolName(const Elf_Sym *Sym,
+ StringRef StrTable,
+ const Elf_Shdr *SymTab);
+ Expected<StringRef> getSymbolName(uint32_t SymtabNdx, uint32_t SymbolNdx);
+
+ const object::ELFFile<ELFT> &Obj;
+ std::unique_ptr<DWARFContext> DWARFCtx;
+
+ DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
+
+ Expected<std::vector<ELFYAML::ProgramHeader>>
+ dumpProgramHeaders(ArrayRef<std::unique_ptr<ELFYAML::Chunk>> Sections);
+
+ Optional<DWARFYAML::Data>
+ dumpDWARFSections(std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections);
+
+ Error dumpSymbols(const Elf_Shdr *Symtab,
+ Optional<std::vector<ELFYAML::Symbol>> &Symbols);
+ Error dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
+ StringRef StrTable, ELFYAML::Symbol &S);
+ Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>> dumpSections();
+ Error dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S);
+ Error dumpCommonRelocationSection(const Elf_Shdr *Shdr,
+ ELFYAML::RelocationSection &S);
+ template <class RelT>
+ Error dumpRelocation(const RelT *Rel, const Elf_Shdr *SymTab,
+ ELFYAML::Relocation &R);
+
+ Expected<ELFYAML::AddrsigSection *> dumpAddrsigSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::LinkerOptionsSection *>
+ dumpLinkerOptionsSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::DependentLibrariesSection *>
+ dumpDependentLibrariesSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::CallGraphProfileSection *>
+ dumpCallGraphProfileSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::DynamicSection *> dumpDynamicSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::RelocationSection *> dumpRelocSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::RelrSection *> dumpRelrSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::RawContentSection *>
+ dumpContentSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::SymtabShndxSection *>
+ dumpSymtabShndxSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::NoBitsSection *> dumpNoBitsSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::HashSection *> dumpHashSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::NoteSection *> dumpNoteSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::GnuHashSection *> dumpGnuHashSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::VerdefSection *> dumpVerdefSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::SymverSection *> dumpSymverSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::GroupSection *> dumpGroupSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::ARMIndexTableSection *>
+ dumpARMIndexTableSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::MipsABIFlags *> dumpMipsABIFlags(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::StackSizesSection *>
+ dumpStackSizesSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::BBAddrMapSection *>
+ dumpBBAddrMapSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::RawContentSection *>
+ dumpPlaceholderSection(const Elf_Shdr *Shdr);
+
+ bool shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr,
+ Optional<DWARFYAML::Data> DWARF);
+
+public:
+ ELFDumper(const object::ELFFile<ELFT> &O, std::unique_ptr<DWARFContext> DCtx);
+ Expected<ELFYAML::Object *> dump();
+};
+
+}
+
+template <class ELFT>
+ELFDumper<ELFT>::ELFDumper(const object::ELFFile<ELFT> &O,
+ std::unique_ptr<DWARFContext> DCtx)
+ : Obj(O), DWARFCtx(std::move(DCtx)) {}
+
+template <class ELFT>
+Expected<StringRef>
+ELFDumper<ELFT>::getUniquedSectionName(const Elf_Shdr &Sec) {
+ unsigned SecIndex = &Sec - &Sections[0];
+ if (!SectionNames[SecIndex].empty())
+ return SectionNames[SecIndex];
+
+ auto NameOrErr = Obj.getSectionName(Sec);
+ if (!NameOrErr)
+ return NameOrErr;
+ StringRef Name = *NameOrErr;
+ // In some specific cases we might have more than one section without a
+ // name (sh_name == 0). It normally doesn't happen, but when we have this case
+ // it doesn't make sense to uniquify their names and add noise to the output.
+ if (Name.empty())
+ return "";
+
+ std::string &Ret = SectionNames[SecIndex];
+
+ auto It = UsedSectionNames.insert({Name, 0});
+ if (!It.second)
+ Ret = ELFYAML::appendUniqueSuffix(Name, Twine(++It.first->second));
+ else
+ Ret = std::string(Name);
+ return Ret;
+}
+
+template <class ELFT>
+Expected<StringRef>
+ELFDumper<ELFT>::getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable,
+ const Elf_Shdr *SymTab) {
+ Expected<StringRef> SymbolNameOrErr = Sym->getName(StrTable);
+ if (!SymbolNameOrErr)
+ return SymbolNameOrErr;
+ StringRef Name = *SymbolNameOrErr;
+ if (Name.empty() && Sym->getType() == ELF::STT_SECTION) {
+ Expected<const Elf_Shdr *> ShdrOrErr =
+ Obj.getSection(*Sym, SymTab, ShndxTables.lookup(SymTab));
+ if (!ShdrOrErr)
+ return ShdrOrErr.takeError();
+ // The null section has no name.
+ return (*ShdrOrErr == nullptr) ? "" : getUniquedSectionName(**ShdrOrErr);
+ }
+
+ // Symbols in .symtab can have duplicate names. For example, it is a common
+ // situation for local symbols in a relocatable object. Here we assign unique
+ // suffixes for such symbols so that we can differentiate them.
+ if (SymTab->sh_type == ELF::SHT_SYMTAB) {
+ unsigned Index = Sym - SymTable.data();
+ if (!SymbolNames[Index].empty())
+ return SymbolNames[Index];
+
+ auto It = UsedSymbolNames.insert({Name, 0});
+ if (!It.second)
+ SymbolNames[Index] =
+ ELFYAML::appendUniqueSuffix(Name, Twine(++It.first->second));
+ else
+ SymbolNames[Index] = std::string(Name);
+ return SymbolNames[Index];
+ }
+
+ return Name;
+}
+
+template <class ELFT>
+bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
+ const Elf_Shdr &SHdr,
+ Optional<DWARFYAML::Data> DWARF) {
+ // We only print the SHT_NULL section at index 0 when it
+ // has at least one non-null field, because yaml2obj
+ // normally creates the zero section at index 0 implicitly.
+ if (S.Type == ELF::SHT_NULL && (&SHdr == &Sections[0])) {
+ const uint8_t *Begin = reinterpret_cast<const uint8_t *>(&SHdr);
+ const uint8_t *End = Begin + sizeof(Elf_Shdr);
+ return std::any_of(Begin, End, [](uint8_t V) { return V != 0; });
+ }
+
+ // Normally we use "DWARF:" to describe contents of DWARF sections. Sometimes
+ // the content of DWARF sections can be successfully parsed into the "DWARF:"
+ // entry but their section headers may have special flags, entry size, address
+ // alignment, etc. We will preserve the header for them under such
+ // circumstances.
+ StringRef SecName = S.Name.substr(1);
+ if (DWARF && DWARF->getNonEmptySectionNames().count(SecName)) {
+ if (const ELFYAML::RawContentSection *RawSec =
+ dyn_cast<const ELFYAML::RawContentSection>(&S)) {
+ if (RawSec->Type != ELF::SHT_PROGBITS || RawSec->Link || RawSec->Info ||
+ RawSec->AddressAlign != yaml::Hex64{1} || RawSec->Address ||
+ RawSec->EntSize)
+ return true;
+
+ ELFYAML::ELF_SHF ShFlags = RawSec->Flags.getValueOr(ELFYAML::ELF_SHF(0));
+
+ if (SecName == "debug_str")
+ return ShFlags != ELFYAML::ELF_SHF(ELF::SHF_MERGE | ELF::SHF_STRINGS);
+
+ return ShFlags != ELFYAML::ELF_SHF{0};
+ }
+ }
+
+ // Normally we use "Symbols:" and "DynamicSymbols:" to describe contents of
+ // symbol tables. We also build and emit corresponding string tables
+ // implicitly. But sometimes it is important to preserve positions and virtual
+ // addresses of allocatable sections, e.g. for creating program headers.
+ // Generally we are trying to reduce noise in the YAML output. Because
+ // of that we do not print non-allocatable versions of such sections and
+ // assume they are placed at the end.
+ // We also dump symbol tables when the Size field is set. It happens when they
+ // are empty, which should not normally happen.
+ if (S.Type == ELF::SHT_STRTAB || S.Type == ELF::SHT_SYMTAB ||
+ S.Type == ELF::SHT_DYNSYM) {
+ return S.Size || S.Flags.getValueOr(ELFYAML::ELF_SHF(0)) & ELF::SHF_ALLOC;
+ }
+
+ return true;
+}
+
+template <class ELFT>
+static void dumpSectionOffsets(const typename ELFT::Ehdr &Header,
+ ArrayRef<ELFYAML::ProgramHeader> Phdrs,
+ std::vector<std::unique_ptr<ELFYAML::Chunk>> &V,
+ ArrayRef<typename ELFT::Shdr> S) {
+ if (V.empty())
+ return;
+
+ uint64_t ExpectedOffset;
+ if (Header.e_phoff > 0)
+ ExpectedOffset = Header.e_phoff + Header.e_phentsize * Header.e_phnum;
+ else
+ ExpectedOffset = sizeof(typename ELFT::Ehdr);
+
+ for (const std::unique_ptr<ELFYAML::Chunk> &C :
+ makeArrayRef(V).drop_front()) {
+ ELFYAML::Section &Sec = *cast<ELFYAML::Section>(C.get());
+ const typename ELFT::Shdr &SecHdr = S[Sec.OriginalSecNdx];
+
+ ExpectedOffset = alignTo(ExpectedOffset,
+ SecHdr.sh_addralign ? SecHdr.sh_addralign : 1uLL);
+
+ // We only set the "Offset" field when it can't be naturally derived
+ // from the offset and size of the previous section. This reduces
+ // the noise in the YAML output.
+ if (SecHdr.sh_offset != ExpectedOffset)
+ Sec.Offset = (yaml::Hex64)SecHdr.sh_offset;
+
+ if (Sec.Type == ELF::SHT_NOBITS &&
+ !ELFYAML::shouldAllocateFileSpace(Phdrs,
+ *cast<ELFYAML::NoBitsSection>(&Sec)))
+ ExpectedOffset = SecHdr.sh_offset;
+ else
+ ExpectedOffset = SecHdr.sh_offset + SecHdr.sh_size;
+ }
+}
+
+template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
+ auto Y = std::make_unique<ELFYAML::Object>();
+
+ // Dump header. We do not dump EPh* and ESh* fields. When not explicitly set,
+ // the values are set by yaml2obj automatically and there is no need to dump
+ // them here.
+ Y->Header.Class = ELFYAML::ELF_ELFCLASS(Obj.getHeader().getFileClass());
+ Y->Header.Data = ELFYAML::ELF_ELFDATA(Obj.getHeader().getDataEncoding());
+ Y->Header.OSABI = Obj.getHeader().e_ident[ELF::EI_OSABI];
+ Y->Header.ABIVersion = Obj.getHeader().e_ident[ELF::EI_ABIVERSION];
+ Y->Header.Type = Obj.getHeader().e_type;
+ if (Obj.getHeader().e_machine != 0)
+ Y->Header.Machine = ELFYAML::ELF_EM(Obj.getHeader().e_machine);
+ Y->Header.Flags = Obj.getHeader().e_flags;
+ Y->Header.Entry = Obj.getHeader().e_entry;
+
+ // Dump sections
+ auto SectionsOrErr = Obj.sections();
+ if (!SectionsOrErr)
+ return SectionsOrErr.takeError();
+ Sections = *SectionsOrErr;
+ SectionNames.resize(Sections.size());
+
+ if (Sections.size() > 0) {
+ ShStrTabIndex = Obj.getHeader().e_shstrndx;
+ if (*ShStrTabIndex == ELF::SHN_XINDEX)
+ ShStrTabIndex = Sections[0].sh_link;
+ // TODO: Set EShStrndx if the value doesn't represent a real section.
+ }
+
+ // Normally an object that does not have sections has e_shnum == 0.
+ // Also, e_shnum might be 0, when the the number of entries in the section
+ // header table is larger than or equal to SHN_LORESERVE (0xff00). In this
+ // case the real number of entries is held in the sh_size member of the
+ // initial entry. We have a section header table when `e_shoff` is not 0.
+ if (Obj.getHeader().e_shoff != 0 && Obj.getHeader().e_shnum == 0)
+ Y->Header.EShNum = 0;
+
+ // Dump symbols. We need to do this early because other sections might want
+ // to access the deduplicated symbol names that we also create here.
+ const Elf_Shdr *SymTab = nullptr;
+ const Elf_Shdr *DynSymTab = nullptr;
+
+ for (const Elf_Shdr &Sec : Sections) {
+ if (Sec.sh_type == ELF::SHT_SYMTAB) {
+ SymTab = &Sec;
+ } else if (Sec.sh_type == ELF::SHT_DYNSYM) {
+ DynSymTab = &Sec;
+ } else if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) {
+ // We need to locate SHT_SYMTAB_SHNDX sections early, because they
+ // might be needed for dumping symbols.
+ if (Expected<ArrayRef<Elf_Word>> TableOrErr = Obj.getSHNDXTable(Sec)) {
+ // The `getSHNDXTable` calls the `getSection` internally when validates
+ // the symbol table section linked to the SHT_SYMTAB_SHNDX section.
+ const Elf_Shdr *LinkedSymTab = cantFail(Obj.getSection(Sec.sh_link));
+ if (!ShndxTables.insert({LinkedSymTab, *TableOrErr}).second)
+ return createStringError(
+ errc::invalid_argument,
+ "multiple SHT_SYMTAB_SHNDX sections are "
+ "linked to the same symbol table with index " +
+ Twine(Sec.sh_link));
+ } else {
+ return createStringError(errc::invalid_argument,
+ "unable to read extended section indexes: " +
+ toString(TableOrErr.takeError()));
+ }
+ }
+ }
+
+ if (SymTab)
+ if (Error E = dumpSymbols(SymTab, Y->Symbols))
+ return std::move(E);
+
+ if (DynSymTab)
+ if (Error E = dumpSymbols(DynSymTab, Y->DynamicSymbols))
+ return std::move(E);
+
+ // We dump all sections first. It is simple and allows us to verify that all
+ // sections are valid and also to generalize the code. But we are not going to
+ // keep all of them in the final output (see comments for
+ // 'shouldPrintSection()'). Undesired chunks will be removed later.
+ Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>> ChunksOrErr =
+ dumpSections();
+ if (!ChunksOrErr)
+ return ChunksOrErr.takeError();
+ std::vector<std::unique_ptr<ELFYAML::Chunk>> Chunks = std::move(*ChunksOrErr);
+
+ std::vector<ELFYAML::Section *> OriginalOrder;
+ if (!Chunks.empty())
+ for (const std::unique_ptr<ELFYAML::Chunk> &C :
+ makeArrayRef(Chunks).drop_front())
+ OriginalOrder.push_back(cast<ELFYAML::Section>(C.get()));
+
+ // Sometimes the order of sections in the section header table does not match
+ // their actual order. Here we sort sections by the file offset.
+ llvm::stable_sort(Chunks, [&](const std::unique_ptr<ELFYAML::Chunk> &A,
+ const std::unique_ptr<ELFYAML::Chunk> &B) {
+ return Sections[cast<ELFYAML::Section>(A.get())->OriginalSecNdx].sh_offset <
+ Sections[cast<ELFYAML::Section>(B.get())->OriginalSecNdx].sh_offset;
+ });
+
+ // Dump program headers.
+ Expected<std::vector<ELFYAML::ProgramHeader>> PhdrsOrErr =
+ dumpProgramHeaders(Chunks);
+ if (!PhdrsOrErr)
+ return PhdrsOrErr.takeError();
+ Y->ProgramHeaders = std::move(*PhdrsOrErr);
+
+ dumpSectionOffsets<ELFT>(Obj.getHeader(), Y->ProgramHeaders, Chunks,
+ Sections);
+
+ // Dump DWARF sections.
+ Y->DWARF = dumpDWARFSections(Chunks);
+
+ // We emit the "SectionHeaderTable" key when the order of sections in the
+ // sections header table doesn't match the file order.
+ const bool SectionsSorted =
+ llvm::is_sorted(Chunks, [&](const std::unique_ptr<ELFYAML::Chunk> &A,
+ const std::unique_ptr<ELFYAML::Chunk> &B) {
+ return cast<ELFYAML::Section>(A.get())->OriginalSecNdx <
+ cast<ELFYAML::Section>(B.get())->OriginalSecNdx;
+ });
+ if (!SectionsSorted) {
+ std::unique_ptr<ELFYAML::SectionHeaderTable> SHT =
+ std::make_unique<ELFYAML::SectionHeaderTable>(/*IsImplicit=*/false);
+ SHT->Sections.emplace();
+ for (ELFYAML::Section *S : OriginalOrder)
+ SHT->Sections->push_back({S->Name});
+ Chunks.push_back(std::move(SHT));
+ }
+
+ llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr<ELFYAML::Chunk> &C) {
+ if (isa<ELFYAML::SectionHeaderTable>(*C.get()))
+ return false;
+
+ const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
+ return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);
+ });
+
+ // The section header string table by default is assumed to be called
+ // ".shstrtab" and be in its own unique section. However, it's possible for it
+ // to be called something else and shared with another section. If the name
+ // isn't the default, provide this in the YAML.
+ if (ShStrTabIndex && *ShStrTabIndex != ELF::SHN_UNDEF &&
+ *ShStrTabIndex < Sections.size()) {
+ StringRef ShStrtabName;
+ if (SymTab && SymTab->sh_link == *ShStrTabIndex) {
+ // Section header string table is shared with the symbol table. Use that
+ // section's name (usually .strtab).
+ ShStrtabName = cantFail(Obj.getSectionName(Sections[SymTab->sh_link]));
+ } else if (DynSymTab && DynSymTab->sh_link == *ShStrTabIndex) {
+ // Section header string table is shared with the dynamic symbol table.
+ // Use that section's name (usually .dynstr).
+ ShStrtabName = cantFail(Obj.getSectionName(Sections[DynSymTab->sh_link]));
+ } else {
+ // Otherwise, the section name potentially needs uniquifying.
+ ShStrtabName = cantFail(getUniquedSectionName(Sections[*ShStrTabIndex]));
+ }
+ if (ShStrtabName != ".shstrtab")
+ Y->Header.SectionHeaderStringTable = ShStrtabName;
+ }
+
+ Y->Chunks = std::move(Chunks);
+ return Y.release();
+}
+
+template <class ELFT>
+static bool isInSegment(const ELFYAML::Section &Sec,
+ const typename ELFT::Shdr &SHdr,
+ const typename ELFT::Phdr &Phdr) {
+ if (Sec.Type == ELF::SHT_NULL)
+ return false;
+
+ // A section is within a segment when its location in a file is within the
+ // [p_offset, p_offset + p_filesz] region.
+ bool FileOffsetsMatch =
+ SHdr.sh_offset >= Phdr.p_offset &&
+ (SHdr.sh_offset + SHdr.sh_size <= Phdr.p_offset + Phdr.p_filesz);
+
+ bool VirtualAddressesMatch = SHdr.sh_addr >= Phdr.p_vaddr &&
+ SHdr.sh_addr <= Phdr.p_vaddr + Phdr.p_memsz;
+
+ if (FileOffsetsMatch) {
+ // An empty section on the edges of a program header can be outside of the
+ // virtual address space of the segment. This means it is not included in
+ // the segment and we should ignore it.
+ if (SHdr.sh_size == 0 && (SHdr.sh_offset == Phdr.p_offset ||
+ SHdr.sh_offset == Phdr.p_offset + Phdr.p_filesz))
+ return VirtualAddressesMatch;
+ return true;
+ }
+
+ // SHT_NOBITS sections usually occupy no physical space in a file. Such
+ // sections belong to a segment when they reside in the segment's virtual
+ // address space.
+ if (Sec.Type != ELF::SHT_NOBITS)
+ return false;
+ return VirtualAddressesMatch;
+}
+
+template <class ELFT>
+Expected<std::vector<ELFYAML::ProgramHeader>>
+ELFDumper<ELFT>::dumpProgramHeaders(
+ ArrayRef<std::unique_ptr<ELFYAML::Chunk>> Chunks) {
+ std::vector<ELFYAML::ProgramHeader> Ret;
+ Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers();
+ if (!PhdrsOrErr)
+ return PhdrsOrErr.takeError();
+
+ for (const typename ELFT::Phdr &Phdr : *PhdrsOrErr) {
+ ELFYAML::ProgramHeader PH;
+ PH.Type = Phdr.p_type;
+ PH.Flags = Phdr.p_flags;
+ PH.VAddr = Phdr.p_vaddr;
+ PH.PAddr = Phdr.p_paddr;
+
+ // yaml2obj sets the alignment of a segment to 1 by default.
+ // We do not print the default alignment to reduce noise in the output.
+ if (Phdr.p_align != 1)
+ PH.Align = static_cast<llvm::yaml::Hex64>(Phdr.p_align);
+
+ // Here we match sections with segments.
+ // It is not possible to have a non-Section chunk, because
+ // obj2yaml does not create Fill chunks.
+ for (const std::unique_ptr<ELFYAML::Chunk> &C : Chunks) {
+ ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
+ if (isInSegment<ELFT>(S, Sections[S.OriginalSecNdx], Phdr)) {
+ if (!PH.FirstSec)
+ PH.FirstSec = S.Name;
+ PH.LastSec = S.Name;
+ PH.Chunks.push_back(C.get());
+ }
+ }
+
+ Ret.push_back(PH);
+ }
+
+ return Ret;
+}
+
+template <class ELFT>
+Optional<DWARFYAML::Data> ELFDumper<ELFT>::dumpDWARFSections(
+ std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections) {
+ DWARFYAML::Data DWARF;
+ for (std::unique_ptr<ELFYAML::Chunk> &C : Sections) {
+ if (!C->Name.startswith(".debug_"))
+ continue;
+
+ if (ELFYAML::RawContentSection *RawSec =
+ dyn_cast<ELFYAML::RawContentSection>(C.get())) {
+ // FIXME: The dumpDebug* functions should take the content as stored in
+ // RawSec. Currently, they just use the last section with the matching
+ // name, which defeats this attempt to skip reading a section header
+ // string table with the same name as a DWARF section.
+ if (ShStrTabIndex && RawSec->OriginalSecNdx == *ShStrTabIndex)
+ continue;
+ Error Err = Error::success();
+ cantFail(std::move(Err));
+
+ if (RawSec->Name == ".debug_aranges")
+ Err = dumpDebugARanges(*DWARFCtx.get(), DWARF);
+ else if (RawSec->Name == ".debug_str")
+ Err = dumpDebugStrings(*DWARFCtx.get(), DWARF);
+ else if (RawSec->Name == ".debug_ranges")
+ Err = dumpDebugRanges(*DWARFCtx.get(), DWARF);
+ else if (RawSec->Name == ".debug_addr")
+ Err = dumpDebugAddr(*DWARFCtx.get(), DWARF);
+ else
+ continue;
+
+ // If the DWARF section cannot be successfully parsed, emit raw content
+ // instead of an entry in the DWARF section of the YAML.
+ if (Err)
+ consumeError(std::move(Err));
+ else
+ RawSec->Content.reset();
+ }
+ }
+
+ if (DWARF.getNonEmptySectionNames().empty())
+ return None;
+ return DWARF;
+}
+
+template <class ELFT>
+Expected<ELFYAML::RawContentSection *>
+ELFDumper<ELFT>::dumpPlaceholderSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::RawContentSection>();
+ if (Error E = dumpCommonSection(Shdr, *S.get()))
+ return std::move(E);
+
+ // Normally symbol tables should not be empty. We dump the "Size"
+ // key when they are.
+ if ((Shdr->sh_type == ELF::SHT_SYMTAB || Shdr->sh_type == ELF::SHT_DYNSYM) &&
+ !Shdr->sh_size)
+ S->Size.emplace();
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<std::vector<std::unique_ptr<ELFYAML::Chunk>>>
+ELFDumper<ELFT>::dumpSections() {
+ std::vector<std::unique_ptr<ELFYAML::Chunk>> Ret;
+ auto Add = [&](Expected<ELFYAML::Chunk *> SecOrErr) -> Error {
+ if (!SecOrErr)
+ return SecOrErr.takeError();
+ Ret.emplace_back(*SecOrErr);
+ return Error::success();
+ };
+
+ auto GetDumper = [this](unsigned Type)
+ -> std::function<Expected<ELFYAML::Chunk *>(const Elf_Shdr *)> {
+ if (Obj.getHeader().e_machine == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX)
+ return [this](const Elf_Shdr *S) { return dumpARMIndexTableSection(S); };
+
+ if (Obj.getHeader().e_machine == ELF::EM_MIPS &&
+ Type == ELF::SHT_MIPS_ABIFLAGS)
+ return [this](const Elf_Shdr *S) { return dumpMipsABIFlags(S); };
+
+ switch (Type) {
+ case ELF::SHT_DYNAMIC:
+ return [this](const Elf_Shdr *S) { return dumpDynamicSection(S); };
+ case ELF::SHT_SYMTAB_SHNDX:
+ return [this](const Elf_Shdr *S) { return dumpSymtabShndxSection(S); };
+ case ELF::SHT_REL:
+ case ELF::SHT_RELA:
+ return [this](const Elf_Shdr *S) { return dumpRelocSection(S); };
+ case ELF::SHT_RELR:
+ return [this](const Elf_Shdr *S) { return dumpRelrSection(S); };
+ case ELF::SHT_GROUP:
+ return [this](const Elf_Shdr *S) { return dumpGroupSection(S); };
+ case ELF::SHT_NOBITS:
+ return [this](const Elf_Shdr *S) { return dumpNoBitsSection(S); };
+ case ELF::SHT_NOTE:
+ return [this](const Elf_Shdr *S) { return dumpNoteSection(S); };
+ case ELF::SHT_HASH:
+ return [this](const Elf_Shdr *S) { return dumpHashSection(S); };
+ case ELF::SHT_GNU_HASH:
+ return [this](const Elf_Shdr *S) { return dumpGnuHashSection(S); };
+ case ELF::SHT_GNU_verdef:
+ return [this](const Elf_Shdr *S) { return dumpVerdefSection(S); };
+ case ELF::SHT_GNU_versym:
+ return [this](const Elf_Shdr *S) { return dumpSymverSection(S); };
+ case ELF::SHT_GNU_verneed:
+ return [this](const Elf_Shdr *S) { return dumpVerneedSection(S); };
+ case ELF::SHT_LLVM_ADDRSIG:
+ return [this](const Elf_Shdr *S) { return dumpAddrsigSection(S); };
+ case ELF::SHT_LLVM_LINKER_OPTIONS:
+ return [this](const Elf_Shdr *S) { return dumpLinkerOptionsSection(S); };
+ case ELF::SHT_LLVM_DEPENDENT_LIBRARIES:
+ return [this](const Elf_Shdr *S) {
+ return dumpDependentLibrariesSection(S);
+ };
+ case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
+ return
+ [this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); };
+ case ELF::SHT_LLVM_BB_ADDR_MAP:
+ return [this](const Elf_Shdr *S) { return dumpBBAddrMapSection(S); };
+ case ELF::SHT_STRTAB:
+ case ELF::SHT_SYMTAB:
+ case ELF::SHT_DYNSYM:
+ // The contents of these sections are described by other parts of the YAML
+ // file. But we still want to dump them, because their properties can be
+ // important. See comments for 'shouldPrintSection()' for more details.
+ return [this](const Elf_Shdr *S) { return dumpPlaceholderSection(S); };
+ default:
+ return nullptr;
+ }
+ };
+
+ for (const Elf_Shdr &Sec : Sections) {
+ // We have dedicated dumping functions for most of the section types.
+ // Try to use one of them first.
+ if (std::function<Expected<ELFYAML::Chunk *>(const Elf_Shdr *)> DumpFn =
+ GetDumper(Sec.sh_type)) {
+ if (Error E = Add(DumpFn(&Sec)))
+ return std::move(E);
+ continue;
+ }
+
+ // Recognize some special SHT_PROGBITS sections by name.
+ if (Sec.sh_type == ELF::SHT_PROGBITS) {
+ auto NameOrErr = Obj.getSectionName(Sec);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ if (ELFYAML::StackSizesSection::nameMatches(*NameOrErr)) {
+ if (Error E = Add(dumpStackSizesSection(&Sec)))
+ return std::move(E);
+ continue;
+ }
+ }
+
+ if (Error E = Add(dumpContentSection(&Sec)))
+ return std::move(E);
+ }
+
+ return std::move(Ret);
+}
+
+template <class ELFT>
+Error ELFDumper<ELFT>::dumpSymbols(
+ const Elf_Shdr *Symtab, Optional<std::vector<ELFYAML::Symbol>> &Symbols) {
+ if (!Symtab)
+ return Error::success();
+
+ auto SymtabOrErr = Obj.symbols(Symtab);
+ if (!SymtabOrErr)
+ return SymtabOrErr.takeError();
+
+ if (SymtabOrErr->empty())
+ return Error::success();
+
+ auto StrTableOrErr = Obj.getStringTableForSymtab(*Symtab);
+ if (!StrTableOrErr)
+ return StrTableOrErr.takeError();
+
+ if (Symtab->sh_type == ELF::SHT_SYMTAB) {
+ SymTable = *SymtabOrErr;
+ SymbolNames.resize(SymTable.size());
+ }
+
+ Symbols.emplace();
+ for (const auto &Sym : (*SymtabOrErr).drop_front()) {
+ ELFYAML::Symbol S;
+ if (auto EC = dumpSymbol(&Sym, Symtab, *StrTableOrErr, S))
+ return EC;
+ Symbols->push_back(S);
+ }
+
+ return Error::success();
+}
+
+template <class ELFT>
+Error ELFDumper<ELFT>::dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
+ StringRef StrTable, ELFYAML::Symbol &S) {
+ S.Type = Sym->getType();
+ if (Sym->st_value)
+ S.Value = (yaml::Hex64)Sym->st_value;
+ if (Sym->st_size)
+ S.Size = (yaml::Hex64)Sym->st_size;
+ S.Other = Sym->st_other;
+ S.Binding = Sym->getBinding();
+
+ Expected<StringRef> SymbolNameOrErr =
+ getUniquedSymbolName(Sym, StrTable, SymTab);
+ if (!SymbolNameOrErr)
+ return SymbolNameOrErr.takeError();
+ S.Name = SymbolNameOrErr.get();
+
+ if (Sym->st_shndx >= ELF::SHN_LORESERVE) {
+ S.Index = (ELFYAML::ELF_SHN)Sym->st_shndx;
+ return Error::success();
+ }
+
+ auto ShdrOrErr = Obj.getSection(*Sym, SymTab, ShndxTables.lookup(SymTab));
+ if (!ShdrOrErr)
+ return ShdrOrErr.takeError();
+ const Elf_Shdr *Shdr = *ShdrOrErr;
+ if (!Shdr)
+ return Error::success();
+
+ auto NameOrErr = getUniquedSectionName(*Shdr);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ S.Section = NameOrErr.get();
+
+ return Error::success();
+}
+
+template <class ELFT>
+template <class RelT>
+Error ELFDumper<ELFT>::dumpRelocation(const RelT *Rel, const Elf_Shdr *SymTab,
+ ELFYAML::Relocation &R) {
+ R.Type = Rel->getType(Obj.isMips64EL());
+ R.Offset = Rel->r_offset;
+ R.Addend = 0;
+
+ auto SymOrErr = Obj.getRelocationSymbol(*Rel, SymTab);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+
+ // We have might have a relocation with symbol index 0,
+ // e.g. R_X86_64_NONE or R_X86_64_GOTPC32.
+ const Elf_Sym *Sym = *SymOrErr;
+ if (!Sym)
+ return Error::success();
+
+ auto StrTabSec = Obj.getSection(SymTab->sh_link);
+ if (!StrTabSec)
+ return StrTabSec.takeError();
+ auto StrTabOrErr = Obj.getStringTable(**StrTabSec);
+ if (!StrTabOrErr)
+ return StrTabOrErr.takeError();
+
+ Expected<StringRef> NameOrErr =
+ getUniquedSymbolName(Sym, *StrTabOrErr, SymTab);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ R.Symbol = NameOrErr.get();
+
+ return Error::success();
+}
+
+template <class ELFT>
+Error ELFDumper<ELFT>::dumpCommonSection(const Elf_Shdr *Shdr,
+ ELFYAML::Section &S) {
+ // Dump fields. We do not dump the ShOffset field. When not explicitly
+ // set, the value is set by yaml2obj automatically.
+ S.Type = Shdr->sh_type;
+ if (Shdr->sh_flags)
+ S.Flags = static_cast<ELFYAML::ELF_SHF>(Shdr->sh_flags);
+ if (Shdr->sh_addr)
+ S.Address = static_cast<uint64_t>(Shdr->sh_addr);
+ S.AddressAlign = Shdr->sh_addralign;
+
+ S.OriginalSecNdx = Shdr - &Sections[0];
+
+ Expected<StringRef> NameOrErr = getUniquedSectionName(*Shdr);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ S.Name = NameOrErr.get();
+
+ if (Shdr->sh_entsize != ELFYAML::getDefaultShEntSize<ELFT>(
+ Obj.getHeader().e_machine, S.Type, S.Name))
+ S.EntSize = static_cast<llvm::yaml::Hex64>(Shdr->sh_entsize);
+
+ if (Shdr->sh_link != ELF::SHN_UNDEF) {
+ Expected<const Elf_Shdr *> LinkSection = Obj.getSection(Shdr->sh_link);
+ if (!LinkSection)
+ return make_error<StringError>(
+ "unable to resolve sh_link reference in section '" + S.Name +
+ "': " + toString(LinkSection.takeError()),
+ inconvertibleErrorCode());
+
+ NameOrErr = getUniquedSectionName(**LinkSection);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ S.Link = NameOrErr.get();
+ }
+
+ return Error::success();
+}
+
+template <class ELFT>
+Error ELFDumper<ELFT>::dumpCommonRelocationSection(
+ const Elf_Shdr *Shdr, ELFYAML::RelocationSection &S) {
+ if (Error E = dumpCommonSection(Shdr, S))
+ return E;
+
+ // Having a zero sh_info field is normal: .rela.dyn is a dynamic
+ // relocation section that normally has no value in this field.
+ if (!Shdr->sh_info)
+ return Error::success();
+
+ auto InfoSection = Obj.getSection(Shdr->sh_info);
+ if (!InfoSection)
+ return InfoSection.takeError();
+
+ Expected<StringRef> NameOrErr = getUniquedSectionName(**InfoSection);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ S.RelocatableSec = NameOrErr.get();
+
+ return Error::success();
+}
+
+template <class ELFT>
+Expected<ELFYAML::StackSizesSection *>
+ELFDumper<ELFT>::dumpStackSizesSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::StackSizesSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ DataExtractor Data(Content, Obj.isLE(), ELFT::Is64Bits ? 8 : 4);
+
+ std::vector<ELFYAML::StackSizeEntry> Entries;
+ DataExtractor::Cursor Cur(0);
+ while (Cur && Cur.tell() < Content.size()) {
+ uint64_t Address = Data.getAddress(Cur);
+ uint64_t Size = Data.getULEB128(Cur);
+ Entries.push_back({Address, Size});
+ }
+
+ if (Content.empty() || !Cur) {
+ // If .stack_sizes cannot be decoded, we dump it as an array of bytes.
+ consumeError(Cur.takeError());
+ S->Content = yaml::BinaryRef(Content);
+ } else {
+ S->Entries = std::move(Entries);
+ }
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::BBAddrMapSection *>
+ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::BBAddrMapSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (Content.empty())
+ return S.release();
+
+ DataExtractor Data(Content, Obj.isLE(), ELFT::Is64Bits ? 8 : 4);
+
+ std::vector<ELFYAML::BBAddrMapEntry> Entries;
+ DataExtractor::Cursor Cur(0);
+ while (Cur && Cur.tell() < Content.size()) {
+ uint64_t Address = Data.getAddress(Cur);
+ uint64_t NumBlocks = Data.getULEB128(Cur);
+ std::vector<ELFYAML::BBAddrMapEntry::BBEntry> BBEntries;
+ // Read the specified number of BB entries, or until decoding fails.
+ for (uint64_t BlockID = 0; Cur && BlockID < NumBlocks; ++BlockID) {
+ uint64_t Offset = Data.getULEB128(Cur);
+ uint64_t Size = Data.getULEB128(Cur);
+ uint64_t Metadata = Data.getULEB128(Cur);
+ BBEntries.push_back({Offset, Size, Metadata});
+ }
+ Entries.push_back({Address, /*NumBlocks=*/{}, BBEntries});
+ }
+
+ if (!Cur) {
+ // If the section cannot be decoded, we dump it as an array of bytes.
+ consumeError(Cur.takeError());
+ S->Content = yaml::BinaryRef(Content);
+ } else {
+ S->Entries = std::move(Entries);
+ }
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::AddrsigSection *>
+ELFDumper<ELFT>::dumpAddrsigSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::AddrsigSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ DataExtractor::Cursor Cur(0);
+ DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0);
+ std::vector<ELFYAML::YAMLFlowString> Symbols;
+ while (Cur && Cur.tell() < Content.size()) {
+ uint64_t SymNdx = Data.getULEB128(Cur);
+ if (!Cur)
+ break;
+
+ Expected<StringRef> SymbolName = getSymbolName(Shdr->sh_link, SymNdx);
+ if (!SymbolName || SymbolName->empty()) {
+ consumeError(SymbolName.takeError());
+ Symbols.emplace_back(
+ StringRef(std::to_string(SymNdx)).copy(StringAllocator));
+ continue;
+ }
+
+ Symbols.emplace_back(*SymbolName);
+ }
+
+ if (Cur) {
+ S->Symbols = std::move(Symbols);
+ return S.release();
+ }
+
+ consumeError(Cur.takeError());
+ S->Content = yaml::BinaryRef(Content);
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::LinkerOptionsSection *>
+ELFDumper<ELFT>::dumpLinkerOptionsSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::LinkerOptionsSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (Content.empty() || Content.back() != 0) {
+ S->Content = Content;
+ return S.release();
+ }
+
+ SmallVector<StringRef, 16> Strings;
+ toStringRef(Content.drop_back()).split(Strings, '\0');
+ if (Strings.size() % 2 != 0) {
+ S->Content = Content;
+ return S.release();
+ }
+
+ S->Options.emplace();
+ for (size_t I = 0, E = Strings.size(); I != E; I += 2)
+ S->Options->push_back({Strings[I], Strings[I + 1]});
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::DependentLibrariesSection *>
+ELFDumper<ELFT>::dumpDependentLibrariesSection(const Elf_Shdr *Shdr) {
+ auto DL = std::make_unique<ELFYAML::DependentLibrariesSection>();
+ if (Error E = dumpCommonSection(Shdr, *DL))
+ return std::move(E);
+
+ Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (!Content.empty() && Content.back() != 0) {
+ DL->Content = Content;
+ return DL.release();
+ }
+
+ DL->Libs.emplace();
+ for (const uint8_t *I = Content.begin(), *E = Content.end(); I < E;) {
+ StringRef Lib((const char *)I);
+ DL->Libs->emplace_back(Lib);
+ I += Lib.size() + 1;
+ }
+
+ return DL.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::CallGraphProfileSection *>
+ELFDumper<ELFT>::dumpCallGraphProfileSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::CallGraphProfileSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ const uint32_t SizeOfEntry = ELFYAML::getDefaultShEntSize<ELFT>(
+ Obj.getHeader().e_machine, S->Type, S->Name);
+ // Dump the section by using the Content key when it is truncated.
+ // There is no need to create either "Content" or "Entries" fields when the
+ // section is empty.
+ if (Content.empty() || Content.size() % SizeOfEntry != 0) {
+ if (!Content.empty())
+ S->Content = yaml::BinaryRef(Content);
+ return S.release();
+ }
+
+ std::vector<ELFYAML::CallGraphEntryWeight> Entries(Content.size() /
+ SizeOfEntry);
+ DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0);
+ DataExtractor::Cursor Cur(0);
+ auto ReadEntry = [&](ELFYAML::CallGraphEntryWeight &E) {
+ E.Weight = Data.getU64(Cur);
+ if (!Cur) {
+ consumeError(Cur.takeError());
+ return false;
+ }
+ return true;
+ };
+
+ for (ELFYAML::CallGraphEntryWeight &E : Entries) {
+ if (ReadEntry(E))
+ continue;
+ S->Content = yaml::BinaryRef(Content);
+ return S.release();
+ }
+
+ S->Entries = std::move(Entries);
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::DynamicSection *>
+ELFDumper<ELFT>::dumpDynamicSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::DynamicSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto DynTagsOrErr = Obj.template getSectionContentsAsArray<Elf_Dyn>(*Shdr);
+ if (!DynTagsOrErr)
+ return DynTagsOrErr.takeError();
+
+ S->Entries.emplace();
+ for (const Elf_Dyn &Dyn : *DynTagsOrErr)
+ S->Entries->push_back({(ELFYAML::ELF_DYNTAG)Dyn.getTag(), Dyn.getVal()});
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::RelocationSection *>
+ELFDumper<ELFT>::dumpRelocSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::RelocationSection>();
+ if (auto E = dumpCommonRelocationSection(Shdr, *S))
+ return std::move(E);
+
+ auto SymTabOrErr = Obj.getSection(Shdr->sh_link);
+ if (!SymTabOrErr)
+ return SymTabOrErr.takeError();
+
+ if (Shdr->sh_size != 0)
+ S->Relocations.emplace();
+
+ if (Shdr->sh_type == ELF::SHT_REL) {
+ auto Rels = Obj.rels(*Shdr);
+ if (!Rels)
+ return Rels.takeError();
+ for (const Elf_Rel &Rel : *Rels) {
+ ELFYAML::Relocation R;
+ if (Error E = dumpRelocation(&Rel, *SymTabOrErr, R))
+ return std::move(E);
+ S->Relocations->push_back(R);
+ }
+ } else {
+ auto Rels = Obj.relas(*Shdr);
+ if (!Rels)
+ return Rels.takeError();
+ for (const Elf_Rela &Rel : *Rels) {
+ ELFYAML::Relocation R;
+ if (Error E = dumpRelocation(&Rel, *SymTabOrErr, R))
+ return std::move(E);
+ R.Addend = Rel.r_addend;
+ S->Relocations->push_back(R);
+ }
+ }
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::RelrSection *>
+ELFDumper<ELFT>::dumpRelrSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::RelrSection>();
+ if (auto E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ if (Expected<ArrayRef<Elf_Relr>> Relrs = Obj.relrs(*Shdr)) {
+ S->Entries.emplace();
+ for (Elf_Relr Rel : *Relrs)
+ S->Entries->emplace_back(Rel);
+ return S.release();
+ } else {
+ // Ignore. We are going to dump the data as raw content below.
+ consumeError(Relrs.takeError());
+ }
+
+ Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+ S->Content = *ContentOrErr;
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::RawContentSection *>
+ELFDumper<ELFT>::dumpContentSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::RawContentSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ unsigned SecIndex = Shdr - &Sections[0];
+ if (SecIndex != 0 || Shdr->sh_type != ELF::SHT_NULL) {
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (!Content.empty())
+ S->Content = yaml::BinaryRef(Content);
+ } else {
+ S->Size = static_cast<llvm::yaml::Hex64>(Shdr->sh_size);
+ }
+
+ if (Shdr->sh_info)
+ S->Info = static_cast<llvm::yaml::Hex64>(Shdr->sh_info);
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::SymtabShndxSection *>
+ELFDumper<ELFT>::dumpSymtabShndxSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::SymtabShndxSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto EntriesOrErr = Obj.template getSectionContentsAsArray<Elf_Word>(*Shdr);
+ if (!EntriesOrErr)
+ return EntriesOrErr.takeError();
+
+ S->Entries.emplace();
+ for (const Elf_Word &E : *EntriesOrErr)
+ S->Entries->push_back(E);
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::NoBitsSection *>
+ELFDumper<ELFT>::dumpNoBitsSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::NoBitsSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+ if (Shdr->sh_size)
+ S->Size = static_cast<llvm::yaml::Hex64>(Shdr->sh_size);
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::NoteSection *>
+ELFDumper<ELFT>::dumpNoteSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::NoteSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ std::vector<ELFYAML::NoteEntry> Entries;
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ while (!Content.empty()) {
+ if (Content.size() < sizeof(Elf_Nhdr)) {
+ S->Content = yaml::BinaryRef(*ContentOrErr);
+ return S.release();
+ }
+
+ const Elf_Nhdr *Header = reinterpret_cast<const Elf_Nhdr *>(Content.data());
+ if (Content.size() < Header->getSize()) {
+ S->Content = yaml::BinaryRef(*ContentOrErr);
+ return S.release();
+ }
+
+ Elf_Note Note(*Header);
+ Entries.push_back(
+ {Note.getName(), Note.getDesc(), (ELFYAML::ELF_NT)Note.getType()});
+
+ Content = Content.drop_front(Header->getSize());
+ }
+
+ S->Notes = std::move(Entries);
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::HashSection *>
+ELFDumper<ELFT>::dumpHashSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::HashSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (Content.size() % 4 != 0 || Content.size() < 8) {
+ S->Content = yaml::BinaryRef(Content);
+ return S.release();
+ }
+
+ DataExtractor::Cursor Cur(0);
+ DataExtractor Data(Content, Obj.isLE(), /*AddressSize=*/0);
+ uint64_t NBucket = Data.getU32(Cur);
+ uint64_t NChain = Data.getU32(Cur);
+ if (Content.size() != (2 + NBucket + NChain) * 4) {
+ S->Content = yaml::BinaryRef(Content);
+ if (Cur)
+ return S.release();
+ llvm_unreachable("entries were not read correctly");
+ }
+
+ S->Bucket.emplace(NBucket);
+ for (uint32_t &V : *S->Bucket)
+ V = Data.getU32(Cur);
+
+ S->Chain.emplace(NChain);
+ for (uint32_t &V : *S->Chain)
+ V = Data.getU32(Cur);
+
+ if (Cur)
+ return S.release();
+ llvm_unreachable("entries were not read correctly");
+}
+
+template <class ELFT>
+Expected<ELFYAML::GnuHashSection *>
+ELFDumper<ELFT>::dumpGnuHashSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::GnuHashSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ unsigned AddrSize = ELFT::Is64Bits ? 8 : 4;
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ DataExtractor Data(Content, Obj.isLE(), AddrSize);
+
+ ELFYAML::GnuHashHeader Header;
+ DataExtractor::Cursor Cur(0);
+ uint64_t NBuckets = Data.getU32(Cur);
+ Header.SymNdx = Data.getU32(Cur);
+ uint64_t MaskWords = Data.getU32(Cur);
+ Header.Shift2 = Data.getU32(Cur);
+
+ // Set just the raw binary content if we were unable to read the header
+ // or when the section data is truncated or malformed.
+ uint64_t Size = Data.getData().size() - Cur.tell();
+ if (!Cur || (Size < MaskWords * AddrSize + NBuckets * 4) ||
+ (Size % 4 != 0)) {
+ consumeError(Cur.takeError());
+ S->Content = yaml::BinaryRef(Content);
+ return S.release();
+ }
+
+ S->Header = Header;
+
+ S->BloomFilter.emplace(MaskWords);
+ for (llvm::yaml::Hex64 &Val : *S->BloomFilter)
+ Val = Data.getAddress(Cur);
+
+ S->HashBuckets.emplace(NBuckets);
+ for (llvm::yaml::Hex32 &Val : *S->HashBuckets)
+ Val = Data.getU32(Cur);
+
+ S->HashValues.emplace((Data.getData().size() - Cur.tell()) / 4);
+ for (llvm::yaml::Hex32 &Val : *S->HashValues)
+ Val = Data.getU32(Cur);
+
+ if (Cur)
+ return S.release();
+ llvm_unreachable("GnuHashSection was not read correctly");
+}
+
+template <class ELFT>
+Expected<ELFYAML::VerdefSection *>
+ELFDumper<ELFT>::dumpVerdefSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::VerdefSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link);
+ if (!StringTableShdrOrErr)
+ return StringTableShdrOrErr.takeError();
+
+ auto StringTableOrErr = Obj.getStringTable(**StringTableShdrOrErr);
+ if (!StringTableOrErr)
+ return StringTableOrErr.takeError();
+
+ auto Contents = Obj.getSectionContents(*Shdr);
+ if (!Contents)
+ return Contents.takeError();
+
+ S->Entries.emplace();
+
+ llvm::ArrayRef<uint8_t> Data = *Contents;
+ const uint8_t *Buf = Data.data();
+ while (Buf) {
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(Buf);
+ ELFYAML::VerdefEntry Entry;
+ if (Verdef->vd_version != 1)
+ return createStringError(errc::invalid_argument,
+ "invalid SHT_GNU_verdef section version: " +
+ Twine(Verdef->vd_version));
+
+ if (Verdef->vd_flags != 0)
+ Entry.Flags = Verdef->vd_flags;
+
+ if (Verdef->vd_ndx != 0)
+ Entry.VersionNdx = Verdef->vd_ndx;
+
+ if (Verdef->vd_hash != 0)
+ Entry.Hash = Verdef->vd_hash;
+
+ const uint8_t *BufAux = Buf + Verdef->vd_aux;
+ while (BufAux) {
+ const Elf_Verdaux *Verdaux =
+ reinterpret_cast<const Elf_Verdaux *>(BufAux);
+ Entry.VerNames.push_back(
+ StringTableOrErr->drop_front(Verdaux->vda_name).data());
+ BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr;
+ }
+
+ S->Entries->push_back(Entry);
+ Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr;
+ }
+
+ if (Shdr->sh_info != S->Entries->size())
+ S->Info = (llvm::yaml::Hex64)Shdr->sh_info;
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::SymverSection *>
+ELFDumper<ELFT>::dumpSymverSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::SymverSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto VersionsOrErr = Obj.template getSectionContentsAsArray<Elf_Half>(*Shdr);
+ if (!VersionsOrErr)
+ return VersionsOrErr.takeError();
+
+ S->Entries.emplace();
+ for (const Elf_Half &E : *VersionsOrErr)
+ S->Entries->push_back(E);
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::VerneedSection *>
+ELFDumper<ELFT>::dumpVerneedSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::VerneedSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto Contents = Obj.getSectionContents(*Shdr);
+ if (!Contents)
+ return Contents.takeError();
+
+ auto StringTableShdrOrErr = Obj.getSection(Shdr->sh_link);
+ if (!StringTableShdrOrErr)
+ return StringTableShdrOrErr.takeError();
+
+ auto StringTableOrErr = Obj.getStringTable(**StringTableShdrOrErr);
+ if (!StringTableOrErr)
+ return StringTableOrErr.takeError();
+
+ S->VerneedV.emplace();
+
+ llvm::ArrayRef<uint8_t> Data = *Contents;
+ const uint8_t *Buf = Data.data();
+ while (Buf) {
+ const Elf_Verneed *Verneed = reinterpret_cast<const Elf_Verneed *>(Buf);
+
+ ELFYAML::VerneedEntry Entry;
+ Entry.Version = Verneed->vn_version;
+ Entry.File =
+ StringRef(StringTableOrErr->drop_front(Verneed->vn_file).data());
+
+ const uint8_t *BufAux = Buf + Verneed->vn_aux;
+ while (BufAux) {
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(BufAux);
+
+ ELFYAML::VernauxEntry Aux;
+ Aux.Hash = Vernaux->vna_hash;
+ Aux.Flags = Vernaux->vna_flags;
+ Aux.Other = Vernaux->vna_other;
+ Aux.Name =
+ StringRef(StringTableOrErr->drop_front(Vernaux->vna_name).data());
+
+ Entry.AuxV.push_back(Aux);
+ BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr;
+ }
+
+ S->VerneedV->push_back(Entry);
+ Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr;
+ }
+
+ if (Shdr->sh_info != S->VerneedV->size())
+ S->Info = (llvm::yaml::Hex64)Shdr->sh_info;
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<StringRef> ELFDumper<ELFT>::getSymbolName(uint32_t SymtabNdx,
+ uint32_t SymbolNdx) {
+ auto SymtabOrErr = Obj.getSection(SymtabNdx);
+ if (!SymtabOrErr)
+ return SymtabOrErr.takeError();
+
+ const Elf_Shdr *Symtab = *SymtabOrErr;
+ auto SymOrErr = Obj.getSymbol(Symtab, SymbolNdx);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+
+ auto StrTabOrErr = Obj.getStringTableForSymtab(*Symtab);
+ if (!StrTabOrErr)
+ return StrTabOrErr.takeError();
+ return getUniquedSymbolName(*SymOrErr, *StrTabOrErr, Symtab);
+}
+
+template <class ELFT>
+Expected<ELFYAML::GroupSection *>
+ELFDumper<ELFT>::dumpGroupSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::GroupSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ // Get symbol with index sh_info. This symbol's name is the signature of the group.
+ Expected<StringRef> SymbolName = getSymbolName(Shdr->sh_link, Shdr->sh_info);
+ if (!SymbolName)
+ return SymbolName.takeError();
+ S->Signature = *SymbolName;
+
+ auto MembersOrErr = Obj.template getSectionContentsAsArray<Elf_Word>(*Shdr);
+ if (!MembersOrErr)
+ return MembersOrErr.takeError();
+
+ S->Members.emplace();
+ for (Elf_Word Member : *MembersOrErr) {
+ if (Member == llvm::ELF::GRP_COMDAT) {
+ S->Members->push_back({"GRP_COMDAT"});
+ continue;
+ }
+
+ Expected<const Elf_Shdr *> SHdrOrErr = Obj.getSection(Member);
+ if (!SHdrOrErr)
+ return SHdrOrErr.takeError();
+ Expected<StringRef> NameOrErr = getUniquedSectionName(**SHdrOrErr);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ S->Members->push_back({*NameOrErr});
+ }
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::ARMIndexTableSection *>
+ELFDumper<ELFT>::dumpARMIndexTableSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::ARMIndexTableSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ if (ContentOrErr->size() % (sizeof(Elf_Word) * 2) != 0) {
+ S->Content = yaml::BinaryRef(*ContentOrErr);
+ return S.release();
+ }
+
+ ArrayRef<Elf_Word> Words(
+ reinterpret_cast<const Elf_Word *>(ContentOrErr->data()),
+ ContentOrErr->size() / sizeof(Elf_Word));
+
+ S->Entries.emplace();
+ for (size_t I = 0, E = Words.size(); I != E; I += 2)
+ S->Entries->push_back({(yaml::Hex32)Words[I], (yaml::Hex32)Words[I + 1]});
+
+ return S.release();
+}
+
+template <class ELFT>
+Expected<ELFYAML::MipsABIFlags *>
+ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {
+ assert(Shdr->sh_type == ELF::SHT_MIPS_ABIFLAGS &&
+ "Section type is not SHT_MIPS_ABIFLAGS");
+ auto S = std::make_unique<ELFYAML::MipsABIFlags>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ auto *Flags = reinterpret_cast<const object::Elf_Mips_ABIFlags<ELFT> *>(
+ ContentOrErr.get().data());
+ S->Version = Flags->version;
+ S->ISALevel = Flags->isa_level;
+ S->ISARevision = Flags->isa_rev;
+ S->GPRSize = Flags->gpr_size;
+ S->CPR1Size = Flags->cpr1_size;
+ S->CPR2Size = Flags->cpr2_size;
+ S->FpABI = Flags->fp_abi;
+ S->ISAExtension = Flags->isa_ext;
+ S->ASEs = Flags->ases;
+ S->Flags1 = Flags->flags1;
+ S->Flags2 = Flags->flags2;
+ return S.release();
+}
+
+template <class ELFT>
+static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj,
+ std::unique_ptr<DWARFContext> DWARFCtx) {
+ ELFDumper<ELFT> Dumper(Obj, std::move(DWARFCtx));
+ Expected<ELFYAML::Object *> YAMLOrErr = Dumper.dump();
+ if (!YAMLOrErr)
+ return YAMLOrErr.takeError();
+
+ std::unique_ptr<ELFYAML::Object> YAML(YAMLOrErr.get());
+ yaml::Output Yout(Out);
+ Yout << *YAML;
+
+ return Error::success();
+}
+
+Error elf2yaml(raw_ostream &Out, const object::ObjectFile &Obj) {
+ std::unique_ptr<DWARFContext> DWARFCtx = DWARFContext::create(Obj);
+ if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(&Obj))
+ return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx));
+
+ if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(&Obj))
+ return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx));
+
+ if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(&Obj))
+ return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx));
+
+ if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(&Obj))
+ return elf2yaml(Out, ELFObj->getELFFile(), std::move(DWARFCtx));
+
+ llvm_unreachable("unknown ELF file format");
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/macho2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/macho2yaml.cpp
new file mode 100644
index 0000000000..a6339b2663
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/macho2yaml.cpp
@@ -0,0 +1,672 @@
+//===------ macho2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+
+#include <string.h> // for memcpy
+
+using namespace llvm;
+
+class MachODumper {
+
+ template <typename StructType>
+ Expected<const char *> processLoadCommandData(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y);
+
+ const object::MachOObjectFile &Obj;
+ std::unique_ptr<DWARFContext> DWARFCtx;
+ unsigned RawSegment;
+ void dumpHeader(std::unique_ptr<MachOYAML::Object> &Y);
+ Error dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpRebaseOpcodes(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpBindOpcodes(std::vector<MachOYAML::BindOpcode> &BindOpcodes,
+ ArrayRef<uint8_t> OpcodeBuffer, bool Lazy = false);
+ void dumpExportTrie(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpSymbols(std::unique_ptr<MachOYAML::Object> &Y);
+ void dumpIndirectSymbols(std::unique_ptr<MachOYAML::Object> &Y);
+
+ template <typename SectionType>
+ Expected<MachOYAML::Section> constructSectionCommon(SectionType Sec,
+ size_t SecIndex);
+ template <typename SectionType>
+ Expected<MachOYAML::Section> constructSection(SectionType Sec,
+ size_t SecIndex);
+ template <typename SectionType, typename SegmentType>
+ Expected<const char *>
+ extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ std::vector<MachOYAML::Section> &Sections,
+ MachOYAML::Object &Y);
+
+public:
+ MachODumper(const object::MachOObjectFile &O,
+ std::unique_ptr<DWARFContext> DCtx, unsigned RawSegments)
+ : Obj(O), DWARFCtx(std::move(DCtx)), RawSegment(RawSegments) {}
+ Expected<std::unique_ptr<MachOYAML::Object>> dump();
+};
+
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ memcpy((void *)&(LC.Data.LCStruct##_data), LoadCmd.Ptr, \
+ sizeof(MachO::LCStruct)); \
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \
+ MachO::swapStruct(LC.Data.LCStruct##_data); \
+ if (Expected<const char *> ExpectedEndPtr = \
+ processLoadCommandData<MachO::LCStruct>(LC, LoadCmd, *Y.get())) \
+ EndPtr = *ExpectedEndPtr; \
+ else \
+ return ExpectedEndPtr.takeError(); \
+ break;
+
+template <typename SectionType>
+Expected<MachOYAML::Section>
+MachODumper::constructSectionCommon(SectionType Sec, size_t SecIndex) {
+ MachOYAML::Section TempSec;
+ memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16);
+ memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16);
+ TempSec.addr = Sec.addr;
+ TempSec.size = Sec.size;
+ TempSec.offset = Sec.offset;
+ TempSec.align = Sec.align;
+ TempSec.reloff = Sec.reloff;
+ TempSec.nreloc = Sec.nreloc;
+ TempSec.flags = Sec.flags;
+ TempSec.reserved1 = Sec.reserved1;
+ TempSec.reserved2 = Sec.reserved2;
+ TempSec.reserved3 = 0;
+ if (!MachO::isVirtualSection(Sec.flags & MachO::SECTION_TYPE))
+ TempSec.content =
+ yaml::BinaryRef(Obj.getSectionContents(Sec.offset, Sec.size));
+
+ if (Expected<object::SectionRef> SecRef = Obj.getSection(SecIndex)) {
+ TempSec.relocations.reserve(TempSec.nreloc);
+ for (const object::RelocationRef &Reloc : SecRef->relocations()) {
+ const object::DataRefImpl Rel = Reloc.getRawDataRefImpl();
+ const MachO::any_relocation_info RE = Obj.getRelocation(Rel);
+ MachOYAML::Relocation R;
+ R.address = Obj.getAnyRelocationAddress(RE);
+ R.is_pcrel = Obj.getAnyRelocationPCRel(RE);
+ R.length = Obj.getAnyRelocationLength(RE);
+ R.type = Obj.getAnyRelocationType(RE);
+ R.is_scattered = Obj.isRelocationScattered(RE);
+ R.symbolnum = (R.is_scattered ? 0 : Obj.getPlainRelocationSymbolNum(RE));
+ R.is_extern =
+ (R.is_scattered ? false : Obj.getPlainRelocationExternal(RE));
+ R.value = (R.is_scattered ? Obj.getScatteredRelocationValue(RE) : 0);
+ TempSec.relocations.push_back(R);
+ }
+ } else {
+ return SecRef.takeError();
+ }
+ return TempSec;
+}
+
+template <>
+Expected<MachOYAML::Section> MachODumper::constructSection(MachO::section Sec,
+ size_t SecIndex) {
+ Expected<MachOYAML::Section> TempSec = constructSectionCommon(Sec, SecIndex);
+ if (TempSec)
+ TempSec->reserved3 = 0;
+ return TempSec;
+}
+
+template <>
+Expected<MachOYAML::Section>
+MachODumper::constructSection(MachO::section_64 Sec, size_t SecIndex) {
+ Expected<MachOYAML::Section> TempSec = constructSectionCommon(Sec, SecIndex);
+ if (TempSec)
+ TempSec->reserved3 = Sec.reserved3;
+ return TempSec;
+}
+
+static Error dumpDebugSection(StringRef SecName, DWARFContext &DCtx,
+ DWARFYAML::Data &DWARF) {
+ if (SecName == "__debug_abbrev") {
+ dumpDebugAbbrev(DCtx, DWARF);
+ return Error::success();
+ }
+ if (SecName == "__debug_aranges")
+ return dumpDebugARanges(DCtx, DWARF);
+ if (SecName == "__debug_info") {
+ dumpDebugInfo(DCtx, DWARF);
+ return Error::success();
+ }
+ if (SecName == "__debug_line") {
+ dumpDebugLines(DCtx, DWARF);
+ return Error::success();
+ }
+ if (SecName.startswith("__debug_pub")) {
+ // FIXME: We should extract pub-section dumpers from this function.
+ dumpDebugPubSections(DCtx, DWARF);
+ return Error::success();
+ }
+ if (SecName == "__debug_ranges")
+ return dumpDebugRanges(DCtx, DWARF);
+ if (SecName == "__debug_str")
+ return dumpDebugStrings(DCtx, DWARF);
+ return createStringError(errc::not_supported,
+ "dumping " + SecName + " section is not supported");
+}
+
+template <typename SectionType, typename SegmentType>
+Expected<const char *> MachODumper::extractSections(
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ std::vector<MachOYAML::Section> &Sections, MachOYAML::Object &Y) {
+ auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
+ const SectionType *Curr =
+ reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
+ for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
+ SectionType Sec;
+ memcpy((void *)&Sec, Curr, sizeof(SectionType));
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(Sec);
+ // For MachO section indices start from 1.
+ if (Expected<MachOYAML::Section> S =
+ constructSection(Sec, Sections.size() + 1)) {
+ StringRef SecName(S->sectname);
+
+ // Copy data sections if requested.
+ if ((RawSegment & ::RawSegments::data) &&
+ StringRef(S->segname).startswith("__DATA"))
+ S->content =
+ yaml::BinaryRef(Obj.getSectionContents(Sec.offset, Sec.size));
+
+ if (SecName.startswith("__debug_")) {
+ // If the DWARF section cannot be successfully parsed, emit raw content
+ // instead of an entry in the DWARF section of the YAML.
+ if (Error Err = dumpDebugSection(SecName, *DWARFCtx.get(), Y.DWARF))
+ consumeError(std::move(Err));
+ else
+ S->content.reset();
+ }
+ Sections.push_back(std::move(*S));
+ } else
+ return S.takeError();
+ }
+ return reinterpret_cast<const char *>(Curr);
+}
+
+template <typename StructType>
+Expected<const char *> MachODumper::processLoadCommandData(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ return LoadCmd.Ptr + sizeof(StructType);
+}
+
+template <>
+Expected<const char *>
+MachODumper::processLoadCommandData<MachO::segment_command>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ return extractSections<MachO::section, MachO::segment_command>(
+ LoadCmd, LC.Sections, Y);
+}
+
+template <>
+Expected<const char *>
+MachODumper::processLoadCommandData<MachO::segment_command_64>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ return extractSections<MachO::section_64, MachO::segment_command_64>(
+ LoadCmd, LC.Sections, Y);
+}
+
+template <typename StructType>
+const char *
+readString(MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) {
+ auto Start = LoadCmd.Ptr + sizeof(StructType);
+ auto MaxSize = LoadCmd.C.cmdsize - sizeof(StructType);
+ auto Size = strnlen(Start, MaxSize);
+ LC.Content = StringRef(Start, Size).str();
+ return Start + Size;
+}
+
+template <>
+Expected<const char *>
+MachODumper::processLoadCommandData<MachO::dylib_command>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ return readString<MachO::dylib_command>(LC, LoadCmd);
+}
+
+template <>
+Expected<const char *>
+MachODumper::processLoadCommandData<MachO::dylinker_command>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ return readString<MachO::dylinker_command>(LC, LoadCmd);
+}
+
+template <>
+Expected<const char *>
+MachODumper::processLoadCommandData<MachO::rpath_command>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ return readString<MachO::rpath_command>(LC, LoadCmd);
+}
+
+template <>
+Expected<const char *>
+MachODumper::processLoadCommandData<MachO::build_version_command>(
+ MachOYAML::LoadCommand &LC,
+ const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ MachOYAML::Object &Y) {
+ auto Start = LoadCmd.Ptr + sizeof(MachO::build_version_command);
+ auto NTools = LC.Data.build_version_command_data.ntools;
+ for (unsigned i = 0; i < NTools; ++i) {
+ auto Curr = Start + i * sizeof(MachO::build_tool_version);
+ MachO::build_tool_version BV;
+ memcpy((void *)&BV, Curr, sizeof(MachO::build_tool_version));
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(BV);
+ LC.Tools.push_back(BV);
+ }
+ return Start + NTools * sizeof(MachO::build_tool_version);
+}
+
+Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() {
+ auto Y = std::make_unique<MachOYAML::Object>();
+ Y->IsLittleEndian = Obj.isLittleEndian();
+ dumpHeader(Y);
+ if (Error Err = dumpLoadCommands(Y))
+ return std::move(Err);
+ if (RawSegment & ::RawSegments::linkedit)
+ Y->RawLinkEditSegment =
+ yaml::BinaryRef(Obj.getSegmentContents("__LINKEDIT"));
+ else
+ dumpLinkEdit(Y);
+
+ return std::move(Y);
+}
+
+void MachODumper::dumpHeader(std::unique_ptr<MachOYAML::Object> &Y) {
+ Y->Header.magic = Obj.getHeader().magic;
+ Y->Header.cputype = Obj.getHeader().cputype;
+ Y->Header.cpusubtype = Obj.getHeader().cpusubtype;
+ Y->Header.filetype = Obj.getHeader().filetype;
+ Y->Header.ncmds = Obj.getHeader().ncmds;
+ Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds;
+ Y->Header.flags = Obj.getHeader().flags;
+ Y->Header.reserved = 0;
+}
+
+Error MachODumper::dumpLoadCommands(std::unique_ptr<MachOYAML::Object> &Y) {
+ for (auto LoadCmd : Obj.load_commands()) {
+ MachOYAML::LoadCommand LC;
+ const char *EndPtr = LoadCmd.Ptr;
+ switch (LoadCmd.C.cmd) {
+ default:
+ memcpy((void *)&(LC.Data.load_command_data), LoadCmd.Ptr,
+ sizeof(MachO::load_command));
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(LC.Data.load_command_data);
+ if (Expected<const char *> ExpectedEndPtr =
+ processLoadCommandData<MachO::load_command>(LC, LoadCmd,
+ *Y.get()))
+ EndPtr = *ExpectedEndPtr;
+ else
+ return ExpectedEndPtr.takeError();
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+ }
+ auto RemainingBytes = LoadCmd.C.cmdsize - (EndPtr - LoadCmd.Ptr);
+ if (!std::all_of(EndPtr, &EndPtr[RemainingBytes],
+ [](const char C) { return C == 0; })) {
+ LC.PayloadBytes.insert(LC.PayloadBytes.end(), EndPtr,
+ &EndPtr[RemainingBytes]);
+ RemainingBytes = 0;
+ }
+ LC.ZeroPadBytes = RemainingBytes;
+ Y->LoadCommands.push_back(std::move(LC));
+ }
+ return Error::success();
+}
+
+void MachODumper::dumpLinkEdit(std::unique_ptr<MachOYAML::Object> &Y) {
+ dumpRebaseOpcodes(Y);
+ dumpBindOpcodes(Y->LinkEdit.BindOpcodes, Obj.getDyldInfoBindOpcodes());
+ dumpBindOpcodes(Y->LinkEdit.WeakBindOpcodes,
+ Obj.getDyldInfoWeakBindOpcodes());
+ dumpBindOpcodes(Y->LinkEdit.LazyBindOpcodes, Obj.getDyldInfoLazyBindOpcodes(),
+ true);
+ dumpExportTrie(Y);
+ dumpSymbols(Y);
+ dumpIndirectSymbols(Y);
+}
+
+void MachODumper::dumpRebaseOpcodes(std::unique_ptr<MachOYAML::Object> &Y) {
+ MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+
+ auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes();
+ for (auto OpCode = RebaseOpcodes.begin(); OpCode != RebaseOpcodes.end();
+ ++OpCode) {
+ MachOYAML::RebaseOpcode RebaseOp;
+ RebaseOp.Opcode =
+ static_cast<MachO::RebaseOpcode>(*OpCode & MachO::REBASE_OPCODE_MASK);
+ RebaseOp.Imm = *OpCode & MachO::REBASE_IMMEDIATE_MASK;
+
+ unsigned Count;
+ uint64_t ULEB = 0;
+
+ switch (RebaseOp.Opcode) {
+ case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+
+ ULEB = decodeULEB128(OpCode + 1, &Count);
+ RebaseOp.ExtraData.push_back(ULEB);
+ OpCode += Count;
+ LLVM_FALLTHROUGH;
+ // Intentionally no break here -- This opcode has two ULEB values
+ case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:
+ case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+
+ ULEB = decodeULEB128(OpCode + 1, &Count);
+ RebaseOp.ExtraData.push_back(ULEB);
+ OpCode += Count;
+ break;
+ default:
+ break;
+ }
+
+ LEData.RebaseOpcodes.push_back(RebaseOp);
+
+ if (RebaseOp.Opcode == MachO::REBASE_OPCODE_DONE)
+ break;
+ }
+}
+
+StringRef ReadStringRef(const uint8_t *Start) {
+ const uint8_t *Itr = Start;
+ for (; *Itr; ++Itr)
+ ;
+ return StringRef(reinterpret_cast<const char *>(Start), Itr - Start);
+}
+
+void MachODumper::dumpBindOpcodes(
+ std::vector<MachOYAML::BindOpcode> &BindOpcodes,
+ ArrayRef<uint8_t> OpcodeBuffer, bool Lazy) {
+ for (auto OpCode = OpcodeBuffer.begin(); OpCode != OpcodeBuffer.end();
+ ++OpCode) {
+ MachOYAML::BindOpcode BindOp;
+ BindOp.Opcode =
+ static_cast<MachO::BindOpcode>(*OpCode & MachO::BIND_OPCODE_MASK);
+ BindOp.Imm = *OpCode & MachO::BIND_IMMEDIATE_MASK;
+
+ unsigned Count;
+ uint64_t ULEB = 0;
+ int64_t SLEB = 0;
+
+ switch (BindOp.Opcode) {
+ case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ ULEB = decodeULEB128(OpCode + 1, &Count);
+ BindOp.ULEBExtraData.push_back(ULEB);
+ OpCode += Count;
+ LLVM_FALLTHROUGH;
+ // Intentionally no break here -- this opcode has two ULEB values
+
+ case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ case MachO::BIND_OPCODE_ADD_ADDR_ULEB:
+ case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ ULEB = decodeULEB128(OpCode + 1, &Count);
+ BindOp.ULEBExtraData.push_back(ULEB);
+ OpCode += Count;
+ break;
+
+ case MachO::BIND_OPCODE_SET_ADDEND_SLEB:
+ SLEB = decodeSLEB128(OpCode + 1, &Count);
+ BindOp.SLEBExtraData.push_back(SLEB);
+ OpCode += Count;
+ break;
+
+ case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ BindOp.Symbol = ReadStringRef(OpCode + 1);
+ OpCode += BindOp.Symbol.size() + 1;
+ break;
+ default:
+ break;
+ }
+
+ BindOpcodes.push_back(BindOp);
+
+ // Lazy bindings have DONE opcodes between operations, so we need to keep
+ // processing after a DONE.
+ if (!Lazy && BindOp.Opcode == MachO::BIND_OPCODE_DONE)
+ break;
+ }
+}
+
+/*!
+ * /brief processes a node from the export trie, and its children.
+ *
+ * To my knowledge there is no documentation of the encoded format of this data
+ * other than in the heads of the Apple linker engineers. To that end hopefully
+ * this comment and the implementation below can serve to light the way for
+ * anyone crazy enough to come down this path in the future.
+ *
+ * This function reads and preserves the trie structure of the export trie. To
+ * my knowledge there is no code anywhere else that reads the data and preserves
+ * the Trie. LD64 (sources available at opensource.apple.com) has a similar
+ * implementation that parses the export trie into a vector. That code as well
+ * as LLVM's libObject MachO implementation were the basis for this.
+ *
+ * The export trie is an encoded trie. The node serialization is a bit awkward.
+ * The below pseudo-code is the best description I've come up with for it.
+ *
+ * struct SerializedNode {
+ * ULEB128 TerminalSize;
+ * struct TerminalData { <-- This is only present if TerminalSize > 0
+ * ULEB128 Flags;
+ * ULEB128 Address; <-- Present if (! Flags & REEXPORT )
+ * ULEB128 Other; <-- Present if ( Flags & REEXPORT ||
+ * Flags & STUB_AND_RESOLVER )
+ * char[] ImportName; <-- Present if ( Flags & REEXPORT )
+ * }
+ * uint8_t ChildrenCount;
+ * Pair<char[], ULEB128> ChildNameOffsetPair[ChildrenCount];
+ * SerializedNode Children[ChildrenCount]
+ * }
+ *
+ * Terminal nodes are nodes that represent actual exports. They can appear
+ * anywhere in the tree other than at the root; they do not need to be leaf
+ * nodes. When reading the data out of the trie this routine reads it in-order,
+ * but it puts the child names and offsets directly into the child nodes. This
+ * results in looping over the children twice during serialization and
+ * de-serialization, but it makes the YAML representation more human readable.
+ *
+ * Below is an example of the graph from a "Hello World" executable:
+ *
+ * -------
+ * | '' |
+ * -------
+ * |
+ * -------
+ * | '_' |
+ * -------
+ * |
+ * |----------------------------------------|
+ * | |
+ * ------------------------ ---------------------
+ * | '_mh_execute_header' | | 'main' |
+ * | Flags: 0x00000000 | | Flags: 0x00000000 |
+ * | Addr: 0x00000000 | | Addr: 0x00001160 |
+ * ------------------------ ---------------------
+ *
+ * This graph represents the trie for the exports "__mh_execute_header" and
+ * "_main". In the graph only the "_main" and "__mh_execute_header" nodes are
+ * terminal.
+*/
+
+const uint8_t *processExportNode(const uint8_t *CurrPtr,
+ const uint8_t *const End,
+ MachOYAML::ExportEntry &Entry) {
+ if (CurrPtr >= End)
+ return CurrPtr;
+ unsigned Count = 0;
+ Entry.TerminalSize = decodeULEB128(CurrPtr, &Count);
+ CurrPtr += Count;
+ if (Entry.TerminalSize != 0) {
+ Entry.Flags = decodeULEB128(CurrPtr, &Count);
+ CurrPtr += Count;
+ if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
+ Entry.Address = 0;
+ Entry.Other = decodeULEB128(CurrPtr, &Count);
+ CurrPtr += Count;
+ Entry.ImportName = std::string(reinterpret_cast<const char *>(CurrPtr));
+ } else {
+ Entry.Address = decodeULEB128(CurrPtr, &Count);
+ CurrPtr += Count;
+ if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
+ Entry.Other = decodeULEB128(CurrPtr, &Count);
+ CurrPtr += Count;
+ } else
+ Entry.Other = 0;
+ }
+ }
+ uint8_t childrenCount = *CurrPtr++;
+ if (childrenCount == 0)
+ return CurrPtr;
+
+ Entry.Children.insert(Entry.Children.begin(), (size_t)childrenCount,
+ MachOYAML::ExportEntry());
+ for (auto &Child : Entry.Children) {
+ Child.Name = std::string(reinterpret_cast<const char *>(CurrPtr));
+ CurrPtr += Child.Name.length() + 1;
+ Child.NodeOffset = decodeULEB128(CurrPtr, &Count);
+ CurrPtr += Count;
+ }
+ for (auto &Child : Entry.Children) {
+ CurrPtr = processExportNode(CurrPtr, End, Child);
+ }
+ return CurrPtr;
+}
+
+void MachODumper::dumpExportTrie(std::unique_ptr<MachOYAML::Object> &Y) {
+ MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+ auto ExportsTrie = Obj.getDyldInfoExportsTrie();
+ processExportNode(ExportsTrie.begin(), ExportsTrie.end(), LEData.ExportTrie);
+}
+
+template <typename nlist_t>
+MachOYAML::NListEntry constructNameList(const nlist_t &nlist) {
+ MachOYAML::NListEntry NL;
+ NL.n_strx = nlist.n_strx;
+ NL.n_type = nlist.n_type;
+ NL.n_sect = nlist.n_sect;
+ NL.n_desc = nlist.n_desc;
+ NL.n_value = nlist.n_value;
+ return NL;
+}
+
+void MachODumper::dumpSymbols(std::unique_ptr<MachOYAML::Object> &Y) {
+ MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+
+ for (auto Symbol : Obj.symbols()) {
+ MachOYAML::NListEntry NLE =
+ Obj.is64Bit()
+ ? constructNameList<MachO::nlist_64>(
+ Obj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
+ : constructNameList<MachO::nlist>(
+ Obj.getSymbolTableEntry(Symbol.getRawDataRefImpl()));
+ LEData.NameList.push_back(NLE);
+ }
+
+ StringRef RemainingTable = Obj.getStringTableData();
+ while (RemainingTable.size() > 0) {
+ auto SymbolPair = RemainingTable.split('\0');
+ RemainingTable = SymbolPair.second;
+ LEData.StringTable.push_back(SymbolPair.first);
+ }
+}
+
+void MachODumper::dumpIndirectSymbols(std::unique_ptr<MachOYAML::Object> &Y) {
+ MachOYAML::LinkEditData &LEData = Y->LinkEdit;
+
+ MachO::dysymtab_command DLC = Obj.getDysymtabLoadCommand();
+ for (unsigned i = 0; i < DLC.nindirectsyms; ++i)
+ LEData.IndirectSymbols.push_back(Obj.getIndirectSymbolTableEntry(DLC, i));
+}
+
+Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj,
+ unsigned RawSegments) {
+ std::unique_ptr<DWARFContext> DCtx = DWARFContext::create(Obj);
+ MachODumper Dumper(Obj, std::move(DCtx), RawSegments);
+ Expected<std::unique_ptr<MachOYAML::Object>> YAML = Dumper.dump();
+ if (!YAML)
+ return YAML.takeError();
+
+ yaml::YamlObjectFile YAMLFile;
+ YAMLFile.MachO = std::move(YAML.get());
+
+ yaml::Output Yout(Out);
+ Yout << YAMLFile;
+ return Error::success();
+}
+
+Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj,
+ unsigned RawSegments) {
+ 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();
+
+ 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();
+
+ std::unique_ptr<DWARFContext> DCtx = DWARFContext::create(*SliceObj.get());
+ MachODumper Dumper(*SliceObj.get(), std::move(DCtx), RawSegments);
+ 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();
+}
+
+Error macho2yaml(raw_ostream &Out, const object::Binary &Binary,
+ unsigned RawSegments) {
+ if (const auto *MachOObj = dyn_cast<object::MachOUniversalBinary>(&Binary))
+ return macho2yaml(Out, *MachOObj, RawSegments);
+
+ if (const auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Binary))
+ return macho2yaml(Out, *MachOObj, RawSegments);
+
+ llvm_unreachable("unexpected Mach-O file format");
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/minidump2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/minidump2yaml.cpp
new file mode 100644
index 0000000000..7b25b1869c
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/minidump2yaml.cpp
@@ -0,0 +1,23 @@
+//===- minidump2yaml.cpp - Minidump to yaml conversion tool -----*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/Object/Minidump.h"
+#include "llvm/ObjectYAML/MinidumpYAML.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+
+Error minidump2yaml(raw_ostream &Out, const object::MinidumpFile &Obj) {
+ auto ExpectedObject = MinidumpYAML::Object::create(Obj);
+ if (!ExpectedObject)
+ return ExpectedObject.takeError();
+ yaml::Output Output(Out);
+ Output << *ExpectedObject;
+ return llvm::Error::success();
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/obj2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/obj2yaml.cpp
new file mode 100644
index 0000000000..9c7a338585
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/obj2yaml.cpp
@@ -0,0 +1,95 @@
+//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -----------------===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/Minidump.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/InitLLVM.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+static cl::opt<std::string>
+ InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
+static cl::bits<RawSegments> RawSegment(
+ "raw-segment",
+ cl::desc("Mach-O: dump the raw contents of the listed segments instead of "
+ "parsing them:"),
+ cl::values(clEnumVal(data, "__DATA"), clEnumVal(linkedit, "__LINKEDIT")));
+
+static Error dumpObject(const ObjectFile &Obj) {
+ if (Obj.isCOFF())
+ return errorCodeToError(coff2yaml(outs(), cast<COFFObjectFile>(Obj)));
+
+ if (Obj.isXCOFF())
+ return xcoff2yaml(outs(), cast<XCOFFObjectFile>(Obj));
+
+ if (Obj.isELF())
+ return elf2yaml(outs(), Obj);
+
+ if (Obj.isWasm())
+ return errorCodeToError(wasm2yaml(outs(), cast<WasmObjectFile>(Obj)));
+
+ llvm_unreachable("unexpected object file format");
+}
+
+static Error dumpInput(StringRef File) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+ MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false,
+ /*RequiresNullTerminator=*/false);
+ if (std::error_code EC = FileOrErr.getError())
+ return errorCodeToError(EC);
+ std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
+ MemoryBufferRef MemBuf = Buffer->getMemBufferRef();
+ if (file_magic::archive == identify_magic(MemBuf.getBuffer()))
+ return archive2yaml(outs(), MemBuf);
+
+ Expected<std::unique_ptr<Binary>> BinOrErr =
+ createBinary(MemBuf, /*Context=*/nullptr);
+ if (!BinOrErr)
+ return BinOrErr.takeError();
+
+ Binary &Binary = *BinOrErr->get();
+ // 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, RawSegment.getBits());
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
+ return dumpObject(*Obj);
+ if (MinidumpFile *Minidump = dyn_cast<MinidumpFile>(&Binary))
+ return minidump2yaml(outs(), *Minidump);
+
+ return Error::success();
+}
+
+static void reportError(StringRef Input, Error Err) {
+ if (Input == "-")
+ Input = "<stdin>";
+ std::string ErrMsg;
+ raw_string_ostream OS(ErrMsg);
+ logAllUnhandledErrors(std::move(Err), OS);
+ OS.flush();
+ errs() << "Error reading file: " << Input << ": " << ErrMsg;
+ errs().flush();
+}
+
+int main(int argc, char *argv[]) {
+ InitLLVM X(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv);
+
+ if (Error Err = dumpInput(InputFilename)) {
+ reportError(InputFilename, std::move(Err));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/obj2yaml.h b/contrib/libs/llvm14/tools/obj2yaml/obj2yaml.h
new file mode 100644
index 0000000000..c026482eaf
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/obj2yaml.h
@@ -0,0 +1,57 @@
+//===------ utils/obj2yaml.hpp - obj2yaml conversion tool -------*- C++ -*-===//
+//
+// 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
+//
+// This file declares some helper routines, and also the format-specific
+// writers. To add a new format, add the declaration here, and, in a separate
+// source file, implement it.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJ2YAML_OBJ2YAML_H
+#define LLVM_TOOLS_OBJ2YAML_OBJ2YAML_H
+
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/Minidump.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include <system_error>
+
+enum RawSegments : unsigned { none = 0, data = 1, linkedit = 1 << 1 };
+std::error_code coff2yaml(llvm::raw_ostream &Out,
+ const llvm::object::COFFObjectFile &Obj);
+llvm::Error elf2yaml(llvm::raw_ostream &Out,
+ const llvm::object::ObjectFile &Obj);
+llvm::Error macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj,
+ unsigned RawSegments);
+llvm::Error minidump2yaml(llvm::raw_ostream &Out,
+ const llvm::object::MinidumpFile &Obj);
+llvm::Error xcoff2yaml(llvm::raw_ostream &Out,
+ const llvm::object::XCOFFObjectFile &Obj);
+std::error_code wasm2yaml(llvm::raw_ostream &Out,
+ const llvm::object::WasmObjectFile &Obj);
+llvm::Error archive2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source);
+
+// Forward decls for dwarf2yaml
+namespace llvm {
+class DWARFContext;
+namespace DWARFYAML {
+struct Data;
+}
+}
+
+void dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+llvm::Error dumpDebugAddr(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+llvm::Error dumpDebugARanges(llvm::DWARFContext &DCtx,
+ llvm::DWARFYAML::Data &Y);
+void dumpDebugPubSections(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+void dumpDebugInfo(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+void dumpDebugLines(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+llvm::Error dumpDebugRanges(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
+llvm::Error dumpDebugStrings(llvm::DWARFContext &DCtx,
+ llvm::DWARFYAML::Data &Y);
+
+#endif
diff --git a/contrib/libs/llvm14/tools/obj2yaml/wasm2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/wasm2yaml.cpp
new file mode 100644
index 0000000000..e4a56524e3
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/wasm2yaml.cpp
@@ -0,0 +1,405 @@
+//===------ utils/wasm2yaml.cpp - obj2yaml conversion tool ------*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/ObjectYAML/WasmYAML.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+using object::WasmSection;
+
+namespace {
+
+class WasmDumper {
+ const object::WasmObjectFile &Obj;
+
+public:
+ WasmDumper(const object::WasmObjectFile &O) : Obj(O) {}
+
+ ErrorOr<WasmYAML::Object *> dump();
+
+ std::unique_ptr<WasmYAML::CustomSection>
+ dumpCustomSection(const WasmSection &WasmSec);
+};
+
+} // namespace
+
+static WasmYAML::Limits makeLimits(const wasm::WasmLimits &Limits) {
+ WasmYAML::Limits L;
+ L.Flags = Limits.Flags;
+ L.Minimum = Limits.Minimum;
+ L.Maximum = Limits.Maximum;
+ return L;
+}
+
+static WasmYAML::Table makeTable(uint32_t Index,
+ const wasm::WasmTableType &Type) {
+ WasmYAML::Table T;
+ T.Index = Index;
+ T.ElemType = Type.ElemType;
+ T.TableLimits = makeLimits(Type.Limits);
+ return T;
+}
+
+std::unique_ptr<WasmYAML::CustomSection>
+WasmDumper::dumpCustomSection(const WasmSection &WasmSec) {
+ std::unique_ptr<WasmYAML::CustomSection> CustomSec;
+ if (WasmSec.Name == "dylink" || WasmSec.Name == "dylink.0") {
+ std::unique_ptr<WasmYAML::DylinkSection> DylinkSec =
+ std::make_unique<WasmYAML::DylinkSection>();
+ const wasm::WasmDylinkInfo& Info = Obj.dylinkInfo();
+ DylinkSec->MemorySize = Info.MemorySize;
+ DylinkSec->MemoryAlignment = Info.MemoryAlignment;
+ DylinkSec->TableSize = Info.TableSize;
+ DylinkSec->TableAlignment = Info.TableAlignment;
+ DylinkSec->Needed = Info.Needed;
+ for (const auto &Imp : Info.ImportInfo)
+ DylinkSec->ImportInfo.push_back({Imp.Module, Imp.Field, Imp.Flags});
+ for (const auto &Exp : Info.ExportInfo)
+ DylinkSec->ExportInfo.push_back({Exp.Name, Exp.Flags});
+ CustomSec = std::move(DylinkSec);
+ } else if (WasmSec.Name == "name") {
+ std::unique_ptr<WasmYAML::NameSection> NameSec =
+ std::make_unique<WasmYAML::NameSection>();
+ for (const llvm::wasm::WasmDebugName &Name : Obj.debugNames()) {
+ WasmYAML::NameEntry NameEntry;
+ NameEntry.Name = Name.Name;
+ NameEntry.Index = Name.Index;
+ if (Name.Type == llvm::wasm::NameType::FUNCTION) {
+ NameSec->FunctionNames.push_back(NameEntry);
+ } else if (Name.Type == llvm::wasm::NameType::GLOBAL) {
+ NameSec->GlobalNames.push_back(NameEntry);
+ } else {
+ assert(Name.Type == llvm::wasm::NameType::DATA_SEGMENT);
+ NameSec->DataSegmentNames.push_back(NameEntry);
+ }
+ }
+ CustomSec = std::move(NameSec);
+ } else if (WasmSec.Name == "linking") {
+ std::unique_ptr<WasmYAML::LinkingSection> LinkingSec =
+ std::make_unique<WasmYAML::LinkingSection>();
+ LinkingSec->Version = Obj.linkingData().Version;
+
+ ArrayRef<StringRef> Comdats = Obj.linkingData().Comdats;
+ for (StringRef ComdatName : Comdats)
+ LinkingSec->Comdats.emplace_back(WasmYAML::Comdat{ComdatName, {}});
+ for (auto &Func : Obj.functions()) {
+ if (Func.Comdat != UINT32_MAX) {
+ LinkingSec->Comdats[Func.Comdat].Entries.emplace_back(
+ WasmYAML::ComdatEntry{wasm::WASM_COMDAT_FUNCTION, Func.Index});
+ }
+ }
+
+ uint32_t SegmentIndex = 0;
+ for (const object::WasmSegment &Segment : Obj.dataSegments()) {
+ if (!Segment.Data.Name.empty()) {
+ WasmYAML::SegmentInfo SegmentInfo;
+ SegmentInfo.Name = Segment.Data.Name;
+ SegmentInfo.Index = SegmentIndex;
+ SegmentInfo.Alignment = Segment.Data.Alignment;
+ SegmentInfo.Flags = Segment.Data.LinkingFlags;
+ LinkingSec->SegmentInfos.push_back(SegmentInfo);
+ }
+ if (Segment.Data.Comdat != UINT32_MAX) {
+ LinkingSec->Comdats[Segment.Data.Comdat].Entries.emplace_back(
+ WasmYAML::ComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
+ }
+ SegmentIndex++;
+ }
+ uint32_t SectionIndex = 0;
+ for (const auto &Sec : Obj.sections()) {
+ const WasmSection &WasmSec = Obj.getWasmSection(Sec);
+ if (WasmSec.Comdat != UINT32_MAX)
+ LinkingSec->Comdats[WasmSec.Comdat].Entries.emplace_back(
+ WasmYAML::ComdatEntry{wasm::WASM_COMDAT_SECTION, SectionIndex});
+ SectionIndex++;
+ }
+
+ uint32_t SymbolIndex = 0;
+ for (const wasm::WasmSymbolInfo &Symbol : Obj.linkingData().SymbolTable) {
+ WasmYAML::SymbolInfo Info;
+ Info.Index = SymbolIndex++;
+ Info.Kind = static_cast<uint32_t>(Symbol.Kind);
+ Info.Name = Symbol.Name;
+ Info.Flags = Symbol.Flags;
+ switch (Symbol.Kind) {
+ case wasm::WASM_SYMBOL_TYPE_DATA:
+ Info.DataRef = Symbol.DataRef;
+ break;
+ case wasm::WASM_SYMBOL_TYPE_FUNCTION:
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ case wasm::WASM_SYMBOL_TYPE_TABLE:
+ case wasm::WASM_SYMBOL_TYPE_TAG:
+ Info.ElementIndex = Symbol.ElementIndex;
+ break;
+ case wasm::WASM_SYMBOL_TYPE_SECTION:
+ Info.ElementIndex = Symbol.ElementIndex;
+ break;
+ }
+ LinkingSec->SymbolTable.emplace_back(Info);
+ }
+
+ for (const wasm::WasmInitFunc &Func : Obj.linkingData().InitFunctions) {
+ WasmYAML::InitFunction F{Func.Priority, Func.Symbol};
+ LinkingSec->InitFunctions.emplace_back(F);
+ }
+
+ CustomSec = std::move(LinkingSec);
+ } else if (WasmSec.Name == "producers") {
+ std::unique_ptr<WasmYAML::ProducersSection> ProducersSec =
+ std::make_unique<WasmYAML::ProducersSection>();
+ const llvm::wasm::WasmProducerInfo &Info = Obj.getProducerInfo();
+ for (auto &E : Info.Languages) {
+ WasmYAML::ProducerEntry Producer;
+ Producer.Name = E.first;
+ Producer.Version = E.second;
+ ProducersSec->Languages.push_back(Producer);
+ }
+ for (auto &E : Info.Tools) {
+ WasmYAML::ProducerEntry Producer;
+ Producer.Name = E.first;
+ Producer.Version = E.second;
+ ProducersSec->Tools.push_back(Producer);
+ }
+ for (auto &E : Info.SDKs) {
+ WasmYAML::ProducerEntry Producer;
+ Producer.Name = E.first;
+ Producer.Version = E.second;
+ ProducersSec->SDKs.push_back(Producer);
+ }
+ CustomSec = std::move(ProducersSec);
+ } else if (WasmSec.Name == "target_features") {
+ std::unique_ptr<WasmYAML::TargetFeaturesSection> TargetFeaturesSec =
+ std::make_unique<WasmYAML::TargetFeaturesSection>();
+ for (auto &E : Obj.getTargetFeatures()) {
+ WasmYAML::FeatureEntry Feature;
+ Feature.Prefix = E.Prefix;
+ Feature.Name = E.Name;
+ TargetFeaturesSec->Features.push_back(Feature);
+ }
+ CustomSec = std::move(TargetFeaturesSec);
+ } else {
+ CustomSec = std::make_unique<WasmYAML::CustomSection>(WasmSec.Name);
+ }
+ CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
+ return CustomSec;
+}
+
+ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
+ auto Y = std::make_unique<WasmYAML::Object>();
+
+ // Dump header
+ Y->Header.Version = Obj.getHeader().Version;
+
+ // Dump sections
+ for (const auto &Sec : Obj.sections()) {
+ const WasmSection &WasmSec = Obj.getWasmSection(Sec);
+ std::unique_ptr<WasmYAML::Section> S;
+ switch (WasmSec.Type) {
+ case wasm::WASM_SEC_CUSTOM: {
+ if (WasmSec.Name.startswith("reloc.")) {
+ // Relocations are attached the sections they apply to rather than
+ // being represented as a custom section in the YAML output.
+ continue;
+ }
+ S = dumpCustomSection(WasmSec);
+ break;
+ }
+ case wasm::WASM_SEC_TYPE: {
+ auto TypeSec = std::make_unique<WasmYAML::TypeSection>();
+ uint32_t Index = 0;
+ for (const auto &FunctionSig : Obj.types()) {
+ WasmYAML::Signature Sig;
+ Sig.Index = Index++;
+ for (const auto &ParamType : FunctionSig.Params)
+ Sig.ParamTypes.emplace_back(static_cast<uint32_t>(ParamType));
+ for (const auto &ReturnType : FunctionSig.Returns)
+ Sig.ReturnTypes.emplace_back(static_cast<uint32_t>(ReturnType));
+ TypeSec->Signatures.push_back(Sig);
+ }
+ S = std::move(TypeSec);
+ break;
+ }
+ case wasm::WASM_SEC_IMPORT: {
+ auto ImportSec = std::make_unique<WasmYAML::ImportSection>();
+ for (auto &Import : Obj.imports()) {
+ WasmYAML::Import Im;
+ Im.Module = Import.Module;
+ Im.Field = Import.Field;
+ Im.Kind = Import.Kind;
+ switch (Im.Kind) {
+ case wasm::WASM_EXTERNAL_FUNCTION:
+ Im.SigIndex = Import.SigIndex;
+ break;
+ case wasm::WASM_EXTERNAL_GLOBAL:
+ Im.GlobalImport.Type = Import.Global.Type;
+ Im.GlobalImport.Mutable = Import.Global.Mutable;
+ break;
+ case wasm::WASM_EXTERNAL_TAG:
+ Im.SigIndex = Import.SigIndex;
+ break;
+ case wasm::WASM_EXTERNAL_TABLE:
+ // FIXME: Currently we always output an index of 0 for any imported
+ // table.
+ Im.TableImport = makeTable(0, Import.Table);
+ break;
+ case wasm::WASM_EXTERNAL_MEMORY:
+ Im.Memory = makeLimits(Import.Memory);
+ break;
+ }
+ ImportSec->Imports.push_back(Im);
+ }
+ S = std::move(ImportSec);
+ break;
+ }
+ case wasm::WASM_SEC_FUNCTION: {
+ auto FuncSec = std::make_unique<WasmYAML::FunctionSection>();
+ for (const auto &Func : Obj.functions()) {
+ FuncSec->FunctionTypes.push_back(Func.SigIndex);
+ }
+ S = std::move(FuncSec);
+ break;
+ }
+ case wasm::WASM_SEC_TABLE: {
+ auto TableSec = std::make_unique<WasmYAML::TableSection>();
+ for (const wasm::WasmTable &Table : Obj.tables()) {
+ TableSec->Tables.push_back(makeTable(Table.Index, Table.Type));
+ }
+ S = std::move(TableSec);
+ break;
+ }
+ case wasm::WASM_SEC_MEMORY: {
+ auto MemorySec = std::make_unique<WasmYAML::MemorySection>();
+ for (const wasm::WasmLimits &Memory : Obj.memories()) {
+ MemorySec->Memories.push_back(makeLimits(Memory));
+ }
+ S = std::move(MemorySec);
+ break;
+ }
+ case wasm::WASM_SEC_TAG: {
+ auto TagSec = std::make_unique<WasmYAML::TagSection>();
+ for (auto &Tag : Obj.tags()) {
+ TagSec->TagTypes.push_back(Tag.SigIndex);
+ }
+ S = std::move(TagSec);
+ break;
+ }
+ case wasm::WASM_SEC_GLOBAL: {
+ auto GlobalSec = std::make_unique<WasmYAML::GlobalSection>();
+ for (auto &Global : Obj.globals()) {
+ WasmYAML::Global G;
+ G.Index = Global.Index;
+ G.Type = Global.Type.Type;
+ G.Mutable = Global.Type.Mutable;
+ G.InitExpr = Global.InitExpr;
+ GlobalSec->Globals.push_back(G);
+ }
+ S = std::move(GlobalSec);
+ break;
+ }
+ case wasm::WASM_SEC_START: {
+ auto StartSec = std::make_unique<WasmYAML::StartSection>();
+ StartSec->StartFunction = Obj.startFunction();
+ S = std::move(StartSec);
+ break;
+ }
+ case wasm::WASM_SEC_EXPORT: {
+ auto ExportSec = std::make_unique<WasmYAML::ExportSection>();
+ for (auto &Export : Obj.exports()) {
+ WasmYAML::Export Ex;
+ Ex.Name = Export.Name;
+ Ex.Kind = Export.Kind;
+ Ex.Index = Export.Index;
+ ExportSec->Exports.push_back(Ex);
+ }
+ S = std::move(ExportSec);
+ break;
+ }
+ case wasm::WASM_SEC_ELEM: {
+ auto ElemSec = std::make_unique<WasmYAML::ElemSection>();
+ for (auto &Segment : Obj.elements()) {
+ WasmYAML::ElemSegment Seg;
+ Seg.Flags = Segment.Flags;
+ Seg.TableNumber = Segment.TableNumber;
+ Seg.ElemKind = Segment.ElemKind;
+ Seg.Offset = Segment.Offset;
+ append_range(Seg.Functions, Segment.Functions);
+ ElemSec->Segments.push_back(Seg);
+ }
+ S = std::move(ElemSec);
+ break;
+ }
+ case wasm::WASM_SEC_CODE: {
+ auto CodeSec = std::make_unique<WasmYAML::CodeSection>();
+ for (auto &Func : Obj.functions()) {
+ WasmYAML::Function Function;
+ Function.Index = Func.Index;
+ for (auto &Local : Func.Locals) {
+ WasmYAML::LocalDecl LocalDecl;
+ LocalDecl.Type = Local.Type;
+ LocalDecl.Count = Local.Count;
+ Function.Locals.push_back(LocalDecl);
+ }
+ Function.Body = yaml::BinaryRef(Func.Body);
+ CodeSec->Functions.push_back(Function);
+ }
+ S = std::move(CodeSec);
+ break;
+ }
+ case wasm::WASM_SEC_DATA: {
+ auto DataSec = std::make_unique<WasmYAML::DataSection>();
+ for (const object::WasmSegment &Segment : Obj.dataSegments()) {
+ WasmYAML::DataSegment Seg;
+ Seg.SectionOffset = Segment.SectionOffset;
+ Seg.InitFlags = Segment.Data.InitFlags;
+ Seg.MemoryIndex = Segment.Data.MemoryIndex;
+ Seg.Offset = Segment.Data.Offset;
+ Seg.Content = yaml::BinaryRef(Segment.Data.Content);
+ DataSec->Segments.push_back(Seg);
+ }
+ S = std::move(DataSec);
+ break;
+ }
+ case wasm::WASM_SEC_DATACOUNT: {
+ auto DataCountSec = std::make_unique<WasmYAML::DataCountSection>();
+ DataCountSec->Count = Obj.dataSegments().size();
+ S = std::move(DataCountSec);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown section type");
+ break;
+ }
+ for (const wasm::WasmRelocation &Reloc : WasmSec.Relocations) {
+ WasmYAML::Relocation R;
+ R.Type = Reloc.Type;
+ R.Index = Reloc.Index;
+ R.Offset = Reloc.Offset;
+ R.Addend = Reloc.Addend;
+ S->Relocations.push_back(R);
+ }
+ Y->Sections.push_back(std::move(S));
+ }
+
+ return Y.release();
+}
+
+std::error_code wasm2yaml(raw_ostream &Out, const object::WasmObjectFile &Obj) {
+ WasmDumper Dumper(Obj);
+ ErrorOr<WasmYAML::Object *> YAMLOrErr = Dumper.dump();
+ if (std::error_code EC = YAMLOrErr.getError())
+ return EC;
+
+ std::unique_ptr<WasmYAML::Object> YAML(YAMLOrErr.get());
+ yaml::Output Yout(Out);
+ Yout << *YAML;
+
+ return std::error_code();
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/xcoff2yaml.cpp b/contrib/libs/llvm14/tools/obj2yaml/xcoff2yaml.cpp
new file mode 100644
index 0000000000..882c410496
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/xcoff2yaml.cpp
@@ -0,0 +1,152 @@
+//===------ xcoff2yaml.cpp - XCOFF YAMLIO implementation --------*- C++ -*-===//
+//
+// 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 "obj2yaml.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/ObjectYAML/XCOFFYAML.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+using namespace llvm::object;
+namespace {
+
+class XCOFFDumper {
+ const object::XCOFFObjectFile &Obj;
+ XCOFFYAML::Object YAMLObj;
+ void dumpHeader();
+ Error dumpSections();
+ Error dumpSymbols();
+ template <typename Shdr, typename Reloc>
+ Error dumpSections(ArrayRef<Shdr> Sections);
+
+public:
+ XCOFFDumper(const object::XCOFFObjectFile &obj) : Obj(obj) {}
+ Error dump();
+ XCOFFYAML::Object &getYAMLObj() { return YAMLObj; }
+};
+} // namespace
+
+Error XCOFFDumper::dump() {
+ dumpHeader();
+ if (Error E = dumpSections())
+ return E;
+ return dumpSymbols();
+}
+
+void XCOFFDumper::dumpHeader() {
+ YAMLObj.Header.Magic = Obj.getMagic();
+ YAMLObj.Header.NumberOfSections = Obj.getNumberOfSections();
+ YAMLObj.Header.TimeStamp = Obj.getTimeStamp();
+ YAMLObj.Header.SymbolTableOffset = Obj.is64Bit()
+ ? Obj.getSymbolTableOffset64()
+ : Obj.getSymbolTableOffset32();
+ YAMLObj.Header.NumberOfSymTableEntries =
+ Obj.is64Bit() ? Obj.getNumberOfSymbolTableEntries64()
+ : Obj.getRawNumberOfSymbolTableEntries32();
+ YAMLObj.Header.AuxHeaderSize = Obj.getOptionalHeaderSize();
+ YAMLObj.Header.Flags = Obj.getFlags();
+}
+
+Error XCOFFDumper::dumpSections() {
+ if (Obj.is64Bit())
+ return dumpSections<XCOFFSectionHeader64, XCOFFRelocation64>(
+ Obj.sections64());
+ return dumpSections<XCOFFSectionHeader32, XCOFFRelocation32>(
+ Obj.sections32());
+}
+
+template <typename Shdr, typename Reloc>
+Error XCOFFDumper::dumpSections(ArrayRef<Shdr> Sections) {
+ std::vector<XCOFFYAML::Section> &YamlSections = YAMLObj.Sections;
+ for (const Shdr &S : Sections) {
+ XCOFFYAML::Section YamlSec;
+ YamlSec.SectionName = S.getName();
+ YamlSec.Address = S.PhysicalAddress;
+ YamlSec.Size = S.SectionSize;
+ YamlSec.NumberOfRelocations = S.NumberOfRelocations;
+ YamlSec.NumberOfLineNumbers = S.NumberOfLineNumbers;
+ YamlSec.FileOffsetToData = S.FileOffsetToRawData;
+ YamlSec.FileOffsetToRelocations = S.FileOffsetToRelocationInfo;
+ YamlSec.FileOffsetToLineNumbers = S.FileOffsetToLineNumberInfo;
+ YamlSec.Flags = S.Flags;
+
+ // Dump section data.
+ if (S.FileOffsetToRawData) {
+ DataRefImpl SectionDRI;
+ SectionDRI.p = reinterpret_cast<uintptr_t>(&S);
+ Expected<ArrayRef<uint8_t>> SecDataRefOrErr =
+ Obj.getSectionContents(SectionDRI);
+ if (!SecDataRefOrErr)
+ return SecDataRefOrErr.takeError();
+ YamlSec.SectionData = SecDataRefOrErr.get();
+ }
+
+ // Dump relocations.
+ if (S.NumberOfRelocations) {
+ auto RelRefOrErr = Obj.relocations<Shdr, Reloc>(S);
+ if (!RelRefOrErr)
+ return RelRefOrErr.takeError();
+ for (const Reloc &R : RelRefOrErr.get()) {
+ XCOFFYAML::Relocation YamlRel;
+ YamlRel.Type = R.Type;
+ YamlRel.Info = R.Info;
+ YamlRel.SymbolIndex = R.SymbolIndex;
+ YamlRel.VirtualAddress = R.VirtualAddress;
+ YamlSec.Relocations.push_back(YamlRel);
+ }
+ }
+ YamlSections.push_back(YamlSec);
+ }
+ return Error::success();
+}
+
+Error XCOFFDumper::dumpSymbols() {
+ std::vector<XCOFFYAML::Symbol> &Symbols = YAMLObj.Symbols;
+
+ for (const SymbolRef &S : Obj.symbols()) {
+ DataRefImpl SymbolDRI = S.getRawDataRefImpl();
+ const XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
+ XCOFFYAML::Symbol Sym;
+
+ Expected<StringRef> SymNameRefOrErr = Obj.getSymbolName(SymbolDRI);
+ if (!SymNameRefOrErr) {
+ return SymNameRefOrErr.takeError();
+ }
+ Sym.SymbolName = SymNameRefOrErr.get();
+
+ Sym.Value = SymbolEntRef.getValue();
+
+ Expected<StringRef> SectionNameRefOrErr =
+ Obj.getSymbolSectionName(SymbolEntRef);
+ if (!SectionNameRefOrErr)
+ return SectionNameRefOrErr.takeError();
+
+ Sym.SectionName = SectionNameRefOrErr.get();
+
+ Sym.Type = SymbolEntRef.getSymbolType();
+ Sym.StorageClass = SymbolEntRef.getStorageClass();
+ Sym.NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
+
+ Symbols.push_back(std::move(Sym));
+ }
+
+ return Error::success();
+}
+
+Error xcoff2yaml(raw_ostream &Out, const object::XCOFFObjectFile &Obj) {
+ XCOFFDumper Dumper(Obj);
+
+ if (Error E = Dumper.dump())
+ return E;
+
+ yaml::Output Yout(Out);
+ Yout << Dumper.getYAMLObj();
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/tools/obj2yaml/ya.make b/contrib/libs/llvm14/tools/obj2yaml/ya.make
new file mode 100644
index 0000000000..01f6a855f7
--- /dev/null
+++ b/contrib/libs/llvm14/tools/obj2yaml/ya.make
@@ -0,0 +1,47 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/BinaryFormat
+ contrib/libs/llvm14/lib/Bitcode/Reader
+ contrib/libs/llvm14/lib/Bitstream/Reader
+ contrib/libs/llvm14/lib/DebugInfo/CodeView
+ contrib/libs/llvm14/lib/DebugInfo/DWARF
+ contrib/libs/llvm14/lib/Demangle
+ contrib/libs/llvm14/lib/IR
+ contrib/libs/llvm14/lib/MC
+ contrib/libs/llvm14/lib/MC/MCParser
+ contrib/libs/llvm14/lib/Object
+ contrib/libs/llvm14/lib/ObjectYAML
+ contrib/libs/llvm14/lib/Remarks
+ contrib/libs/llvm14/lib/Support
+ contrib/libs/llvm14/lib/TextAPI
+)
+
+ADDINCL(
+ contrib/libs/llvm14/tools/obj2yaml
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ archive2yaml.cpp
+ coff2yaml.cpp
+ dwarf2yaml.cpp
+ elf2yaml.cpp
+ macho2yaml.cpp
+ minidump2yaml.cpp
+ obj2yaml.cpp
+ wasm2yaml.cpp
+ xcoff2yaml.cpp
+)
+
+END()