diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h index 88ac404b21b1..f4ace738ef8c 100644 --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -1,436 +1,440 @@ //===- DWARFYAML.h - DWARF 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 // //===----------------------------------------------------------------------===// /// /// \file /// This file declares classes for handling the YAML representation /// of DWARF Debug Info. /// //===----------------------------------------------------------------------===// #ifndef LLVM_OBJECTYAML_DWARFYAML_H #define LLVM_OBJECTYAML_DWARFYAML_H #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/YAMLTraits.h" #include #include namespace llvm { namespace DWARFYAML { struct InitialLength { uint32_t TotalLength; uint64_t TotalLength64; bool isDWARF64() const { return TotalLength == UINT32_MAX; } uint64_t getLength() const { return isDWARF64() ? TotalLength64 : TotalLength; } void setLength(uint64_t Len) { if (Len >= (uint64_t)UINT32_MAX) { TotalLength64 = Len; TotalLength = UINT32_MAX; } else { TotalLength = Len; } } }; struct AttributeAbbrev { llvm::dwarf::Attribute Attribute; llvm::dwarf::Form Form; llvm::yaml::Hex64 Value; // Some DWARF5 attributes have values }; struct Abbrev { Optional Code; llvm::dwarf::Tag Tag; llvm::dwarf::Constants Children; std::vector Attributes; }; struct ARangeDescriptor { llvm::yaml::Hex64 Address; uint64_t Length; }; struct ARange { dwarf::DwarfFormat Format; uint64_t Length; uint16_t Version; uint32_t CuOffset; uint8_t AddrSize; uint8_t SegSize; std::vector Descriptors; }; /// Class that describes a range list entry, or a base address selection entry /// within a range list in the .debug_ranges section. struct RangeEntry { llvm::yaml::Hex64 LowOffset; llvm::yaml::Hex64 HighOffset; }; /// Class that describes a single range list inside the .debug_ranges section. struct Ranges { Optional Offset; Optional AddrSize; std::vector Entries; }; struct PubEntry { llvm::yaml::Hex32 DieOffset; llvm::yaml::Hex8 Descriptor; StringRef Name; }; struct PubSection { InitialLength Length; uint16_t Version; uint32_t UnitOffset; uint32_t UnitSize; std::vector Entries; }; struct FormValue { llvm::yaml::Hex64 Value; StringRef CStr; std::vector BlockData; }; struct Entry { llvm::yaml::Hex32 AbbrCode; std::vector Values; }; /// Class that contains helpful context information when mapping YAML into DWARF /// data structures. struct DWARFContext { bool IsGNUPubSec = false; }; struct Unit { dwarf::FormParams FormParams; Optional Length; llvm::dwarf::UnitType Type; // Added in DWARF 5 yaml::Hex64 AbbrOffset; std::vector Entries; }; struct File { StringRef Name; uint64_t DirIdx; uint64_t ModTime; uint64_t Length; }; struct LineTableOpcode { dwarf::LineNumberOps Opcode; uint64_t ExtLen; dwarf::LineNumberExtendedOps SubOpcode; uint64_t Data; int64_t SData; File FileEntry; std::vector UnknownOpcodeData; std::vector StandardOpcodeData; }; struct LineTable { dwarf::DwarfFormat Format; uint64_t Length; uint16_t Version; uint64_t PrologueLength; uint8_t MinInstLength; uint8_t MaxOpsPerInst; uint8_t DefaultIsStmt; uint8_t LineBase; uint8_t LineRange; uint8_t OpcodeBase; std::vector StandardOpcodeLengths; std::vector IncludeDirs; std::vector Files; std::vector Opcodes; }; struct SegAddrPair { yaml::Hex64 Segment; yaml::Hex64 Address; }; struct AddrTableEntry { dwarf::DwarfFormat Format; Optional Length; yaml::Hex16 Version; Optional AddrSize; yaml::Hex8 SegSelectorSize; std::vector SegAddrPairs; }; struct StringOffsetsTable { dwarf::DwarfFormat Format; Optional Length; yaml::Hex16 Version; yaml::Hex16 Padding; std::vector Offsets; }; struct RnglistEntry { dwarf::RnglistEntries Operator; std::vector Values; }; template struct ListEntries { - std::vector Entries; + Optional> Entries; + Optional Content; }; template struct ListTable { dwarf::DwarfFormat Format; Optional Length; yaml::Hex16 Version; Optional AddrSize; yaml::Hex8 SegSelectorSize; Optional OffsetEntryCount; Optional> Offsets; std::vector> Lists; }; struct Data { bool IsLittleEndian; bool Is64BitAddrSize; std::vector AbbrevDecls; std::vector DebugStrings; Optional> DebugStrOffsets; std::vector ARanges; std::vector DebugRanges; std::vector DebugAddr; Optional PubNames; Optional PubTypes; Optional GNUPubNames; Optional GNUPubTypes; std::vector CompileUnits; std::vector DebugLines; Optional>> DebugRnglists; bool isEmpty() const; SetVector getNonEmptySectionNames() const; }; } // end namespace DWARFYAML } // end namespace llvm LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AttributeAbbrev) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Abbrev) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARangeDescriptor) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARange) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RangeEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Ranges) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::PubEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Unit) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::FormValue) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Entry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::File) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTable) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTableOpcode) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::SegAddrPair) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AddrTableEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::StringOffsetsTable) LLVM_YAML_IS_SEQUENCE_VECTOR( llvm::DWARFYAML::ListTable) LLVM_YAML_IS_SEQUENCE_VECTOR( llvm::DWARFYAML::ListEntries) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RnglistEntry) namespace llvm { namespace yaml { template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::Data &DWARF); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::Abbrev &Abbrev); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::ARangeDescriptor &Descriptor); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::ARange &ARange); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::RangeEntry &Entry); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::Ranges &Ranges); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::PubEntry &Entry); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::PubSection &Section); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::Unit &Unit); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::Entry &Entry); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::FormValue &FormValue); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::File &File); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::LineTable &LineTable); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::SegAddrPair &SegAddrPair); }; template struct MappingTraits> { static void mapping(IO &IO, DWARFYAML::ListTable &ListTable); }; template struct MappingTraits> { static void mapping(IO &IO, DWARFYAML::ListEntries &ListEntries); + static StringRef validate(IO &IO, + DWARFYAML::ListEntries &ListEntries); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::RnglistEntry &RnglistEntry); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::AddrTableEntry &AddrTable); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::StringOffsetsTable &StrOffsetsTable); }; template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::InitialLength &DWARF); }; template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, dwarf::DwarfFormat &Format) { IO.enumCase(Format, "DWARF32", dwarf::DWARF32); IO.enumCase(Format, "DWARF64", dwarf::DWARF64); } }; #define HANDLE_DW_TAG(unused, name, unused2, unused3, unused4) \ io.enumCase(value, "DW_TAG_" #name, dwarf::DW_TAG_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::Tag &value) { #include "llvm/BinaryFormat/Dwarf.def" io.enumFallback(value); } }; #define HANDLE_DW_LNS(unused, name) \ io.enumCase(value, "DW_LNS_" #name, dwarf::DW_LNS_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::LineNumberOps &value) { #include "llvm/BinaryFormat/Dwarf.def" io.enumFallback(value); } }; #define HANDLE_DW_LNE(unused, name) \ io.enumCase(value, "DW_LNE_" #name, dwarf::DW_LNE_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::LineNumberExtendedOps &value) { #include "llvm/BinaryFormat/Dwarf.def" io.enumFallback(value); } }; #define HANDLE_DW_AT(unused, name, unused2, unused3) \ io.enumCase(value, "DW_AT_" #name, dwarf::DW_AT_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::Attribute &value) { #include "llvm/BinaryFormat/Dwarf.def" io.enumFallback(value); } }; #define HANDLE_DW_FORM(unused, name, unused2, unused3) \ io.enumCase(value, "DW_FORM_" #name, dwarf::DW_FORM_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::Form &value) { #include "llvm/BinaryFormat/Dwarf.def" io.enumFallback(value); } }; #define HANDLE_DW_UT(unused, name) \ io.enumCase(value, "DW_UT_" #name, dwarf::DW_UT_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::UnitType &value) { #include "llvm/BinaryFormat/Dwarf.def" io.enumFallback(value); } }; template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::Constants &value) { io.enumCase(value, "DW_CHILDREN_no", dwarf::DW_CHILDREN_no); io.enumCase(value, "DW_CHILDREN_yes", dwarf::DW_CHILDREN_yes); io.enumFallback(value); } }; #define HANDLE_DW_RLE(unused, name) \ io.enumCase(value, "DW_RLE_" #name, dwarf::DW_RLE_##name); template <> struct ScalarEnumerationTraits { static void enumeration(IO &io, dwarf::RnglistEntries &value) { #include "llvm/BinaryFormat/Dwarf.def" } }; } // end namespace yaml } // end namespace llvm #endif // LLVM_OBJECTYAML_DWARFYAML_H diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp index f61191022fb9..b39bb003db9a 100644 --- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -1,774 +1,779 @@ //===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===// // // 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 // //===----------------------------------------------------------------------===// /// /// \file /// The DWARF component of yaml2obj. Provided as library code for tests. /// //===----------------------------------------------------------------------===// #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include using namespace llvm; template static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) { if (IsLittleEndian != sys::IsLittleEndianHost) sys::swapByteOrder(Integer); OS.write(reinterpret_cast(&Integer), sizeof(T)); } static Error writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS, bool IsLittleEndian) { if (8 == Size) writeInteger((uint64_t)Integer, OS, IsLittleEndian); else if (4 == Size) writeInteger((uint32_t)Integer, OS, IsLittleEndian); else if (2 == Size) writeInteger((uint16_t)Integer, OS, IsLittleEndian); else if (1 == Size) writeInteger((uint8_t)Integer, OS, IsLittleEndian); else return createStringError(errc::not_supported, "invalid integer write size: %zu", Size); return Error::success(); } static void ZeroFillBytes(raw_ostream &OS, size_t Size) { std::vector FillData; FillData.insert(FillData.begin(), Size, 0); OS.write(reinterpret_cast(FillData.data()), Size); } static void writeInitialLength(const DWARFYAML::InitialLength &Length, raw_ostream &OS, bool IsLittleEndian) { writeInteger((uint32_t)Length.TotalLength, OS, IsLittleEndian); if (Length.isDWARF64()) writeInteger((uint64_t)Length.TotalLength64, OS, IsLittleEndian); } static void writeInitialLength(const dwarf::DwarfFormat Format, const uint64_t Length, raw_ostream &OS, bool IsLittleEndian) { bool IsDWARF64 = Format == dwarf::DWARF64; if (IsDWARF64) cantFail(writeVariableSizedInteger(dwarf::DW_LENGTH_DWARF64, 4, OS, IsLittleEndian)); cantFail( writeVariableSizedInteger(Length, IsDWARF64 ? 8 : 4, OS, IsLittleEndian)); } static void writeDWARFOffset(uint64_t Offset, dwarf::DwarfFormat Format, raw_ostream &OS, bool IsLittleEndian) { cantFail(writeVariableSizedInteger(Offset, Format == dwarf::DWARF64 ? 8 : 4, OS, IsLittleEndian)); } Error DWARFYAML::emitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) { for (auto Str : DI.DebugStrings) { OS.write(Str.data(), Str.size()); OS.write('\0'); } return Error::success(); } Error DWARFYAML::emitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { uint64_t AbbrevCode = 0; for (auto AbbrevDecl : DI.AbbrevDecls) { AbbrevCode = AbbrevDecl.Code ? (uint64_t)*AbbrevDecl.Code : AbbrevCode + 1; encodeULEB128(AbbrevCode, OS); encodeULEB128(AbbrevDecl.Tag, OS); OS.write(AbbrevDecl.Children); for (auto Attr : AbbrevDecl.Attributes) { encodeULEB128(Attr.Attribute, OS); encodeULEB128(Attr.Form, OS); if (Attr.Form == dwarf::DW_FORM_implicit_const) encodeSLEB128(Attr.Value, OS); } encodeULEB128(0, OS); encodeULEB128(0, OS); } // The abbreviations for a given compilation unit end with an entry consisting // of a 0 byte for the abbreviation code. OS.write_zeros(1); return Error::success(); } Error DWARFYAML::emitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) { for (auto Range : DI.ARanges) { auto HeaderStart = OS.tell(); writeInitialLength(Range.Format, Range.Length, OS, DI.IsLittleEndian); writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian); writeDWARFOffset(Range.CuOffset, Range.Format, OS, DI.IsLittleEndian); writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian); writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian); auto HeaderSize = OS.tell() - HeaderStart; auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2); ZeroFillBytes(OS, FirstDescriptor - HeaderSize); for (auto Descriptor : Range.Descriptors) { if (Error Err = writeVariableSizedInteger( Descriptor.Address, Range.AddrSize, OS, DI.IsLittleEndian)) return createStringError(errc::not_supported, "unable to write debug_aranges address: %s", toString(std::move(Err)).c_str()); cantFail(writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS, DI.IsLittleEndian)); } ZeroFillBytes(OS, Range.AddrSize * 2); } return Error::success(); } Error DWARFYAML::emitDebugRanges(raw_ostream &OS, const DWARFYAML::Data &DI) { const size_t RangesOffset = OS.tell(); uint64_t EntryIndex = 0; for (auto DebugRanges : DI.DebugRanges) { const size_t CurrOffset = OS.tell() - RangesOffset; if (DebugRanges.Offset && (uint64_t)*DebugRanges.Offset < CurrOffset) return createStringError(errc::invalid_argument, "'Offset' for 'debug_ranges' with index " + Twine(EntryIndex) + " must be greater than or equal to the " "number of bytes written already (0x" + Twine::utohexstr(CurrOffset) + ")"); if (DebugRanges.Offset) ZeroFillBytes(OS, *DebugRanges.Offset - CurrOffset); uint8_t AddrSize; if (DebugRanges.AddrSize) AddrSize = *DebugRanges.AddrSize; else AddrSize = DI.Is64BitAddrSize ? 8 : 4; for (auto Entry : DebugRanges.Entries) { if (Error Err = writeVariableSizedInteger(Entry.LowOffset, AddrSize, OS, DI.IsLittleEndian)) return createStringError( errc::not_supported, "unable to write debug_ranges address offset: %s", toString(std::move(Err)).c_str()); cantFail(writeVariableSizedInteger(Entry.HighOffset, AddrSize, OS, DI.IsLittleEndian)); } ZeroFillBytes(OS, AddrSize * 2); ++EntryIndex; } return Error::success(); } Error DWARFYAML::emitPubSection(raw_ostream &OS, const DWARFYAML::PubSection &Sect, bool IsLittleEndian, bool IsGNUPubSec) { writeInitialLength(Sect.Length, OS, IsLittleEndian); writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); for (auto Entry : Sect.Entries) { writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); if (IsGNUPubSec) writeInteger((uint8_t)Entry.Descriptor, OS, IsLittleEndian); OS.write(Entry.Name.data(), Entry.Name.size()); OS.write('\0'); } return Error::success(); } static Expected writeDIE(ArrayRef AbbrevDecls, const DWARFYAML::Unit &Unit, const DWARFYAML::Entry &Entry, raw_ostream &OS, bool IsLittleEndian) { uint64_t EntryBegin = OS.tell(); encodeULEB128(Entry.AbbrCode, OS); uint32_t AbbrCode = Entry.AbbrCode; if (AbbrCode == 0 || Entry.Values.empty()) return OS.tell() - EntryBegin; if (AbbrCode > AbbrevDecls.size()) return createStringError( errc::invalid_argument, "abbrev code must be less than or equal to the number of " "entries in abbreviation table"); const DWARFYAML::Abbrev &Abbrev = AbbrevDecls[AbbrCode - 1]; auto FormVal = Entry.Values.begin(); auto AbbrForm = Abbrev.Attributes.begin(); for (; FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end(); ++FormVal, ++AbbrForm) { dwarf::Form Form = AbbrForm->Form; bool Indirect; do { Indirect = false; switch (Form) { case dwarf::DW_FORM_addr: // TODO: Test this error. if (Error Err = writeVariableSizedInteger( FormVal->Value, Unit.FormParams.AddrSize, OS, IsLittleEndian)) return std::move(Err); break; case dwarf::DW_FORM_ref_addr: // TODO: Test this error. if (Error Err = writeVariableSizedInteger( FormVal->Value, Unit.FormParams.getRefAddrByteSize(), OS, IsLittleEndian)) return std::move(Err); break; case dwarf::DW_FORM_exprloc: case dwarf::DW_FORM_block: encodeULEB128(FormVal->BlockData.size(), OS); OS.write((const char *)FormVal->BlockData.data(), FormVal->BlockData.size()); break; case dwarf::DW_FORM_block1: { writeInteger((uint8_t)FormVal->BlockData.size(), OS, IsLittleEndian); OS.write((const char *)FormVal->BlockData.data(), FormVal->BlockData.size()); break; } case dwarf::DW_FORM_block2: { writeInteger((uint16_t)FormVal->BlockData.size(), OS, IsLittleEndian); OS.write((const char *)FormVal->BlockData.data(), FormVal->BlockData.size()); break; } case dwarf::DW_FORM_block4: { writeInteger((uint32_t)FormVal->BlockData.size(), OS, IsLittleEndian); OS.write((const char *)FormVal->BlockData.data(), FormVal->BlockData.size()); break; } case dwarf::DW_FORM_strx: case dwarf::DW_FORM_addrx: case dwarf::DW_FORM_rnglistx: case dwarf::DW_FORM_loclistx: case dwarf::DW_FORM_udata: case dwarf::DW_FORM_ref_udata: case dwarf::DW_FORM_GNU_addr_index: case dwarf::DW_FORM_GNU_str_index: encodeULEB128(FormVal->Value, OS); break; case dwarf::DW_FORM_data1: case dwarf::DW_FORM_ref1: case dwarf::DW_FORM_flag: case dwarf::DW_FORM_strx1: case dwarf::DW_FORM_addrx1: writeInteger((uint8_t)FormVal->Value, OS, IsLittleEndian); break; case dwarf::DW_FORM_data2: case dwarf::DW_FORM_ref2: case dwarf::DW_FORM_strx2: case dwarf::DW_FORM_addrx2: writeInteger((uint16_t)FormVal->Value, OS, IsLittleEndian); break; case dwarf::DW_FORM_data4: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_ref_sup4: case dwarf::DW_FORM_strx4: case dwarf::DW_FORM_addrx4: writeInteger((uint32_t)FormVal->Value, OS, IsLittleEndian); break; case dwarf::DW_FORM_data8: case dwarf::DW_FORM_ref8: case dwarf::DW_FORM_ref_sup8: case dwarf::DW_FORM_ref_sig8: writeInteger((uint64_t)FormVal->Value, OS, IsLittleEndian); break; case dwarf::DW_FORM_sdata: encodeSLEB128(FormVal->Value, OS); break; case dwarf::DW_FORM_string: OS.write(FormVal->CStr.data(), FormVal->CStr.size()); OS.write('\0'); break; case dwarf::DW_FORM_indirect: encodeULEB128(FormVal->Value, OS); Indirect = true; Form = static_cast((uint64_t)FormVal->Value); ++FormVal; 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: cantFail(writeVariableSizedInteger( FormVal->Value, Unit.FormParams.getDwarfOffsetByteSize(), OS, IsLittleEndian)); break; default: break; } } while (Indirect); } return OS.tell() - EntryBegin; } Error DWARFYAML::emitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { for (const DWARFYAML::Unit &Unit : DI.CompileUnits) { uint64_t Length = 3; // sizeof(version) + sizeof(address_size) Length += Unit.FormParams.Version >= 5 ? 1 : 0; // sizeof(unit_type) Length += Unit.FormParams.getDwarfOffsetByteSize(); // sizeof(debug_abbrev_offset) // Since the length of the current compilation unit is undetermined yet, we // firstly write the content of the compilation unit to a buffer to // calculate it and then serialize the buffer content to the actual output // stream. std::string EntryBuffer; raw_string_ostream EntryBufferOS(EntryBuffer); for (const DWARFYAML::Entry &Entry : Unit.Entries) { if (Expected EntryLength = writeDIE( DI.AbbrevDecls, Unit, Entry, EntryBufferOS, DI.IsLittleEndian)) Length += *EntryLength; else return EntryLength.takeError(); } // If the length is specified in the YAML description, we use it instead of // the actual length. if (Unit.Length) Length = *Unit.Length; writeInitialLength(Unit.FormParams.Format, Length, OS, DI.IsLittleEndian); writeInteger((uint16_t)Unit.FormParams.Version, OS, DI.IsLittleEndian); if (Unit.FormParams.Version >= 5) { writeInteger((uint8_t)Unit.Type, OS, DI.IsLittleEndian); writeInteger((uint8_t)Unit.FormParams.AddrSize, OS, DI.IsLittleEndian); writeDWARFOffset(Unit.AbbrOffset, Unit.FormParams.Format, OS, DI.IsLittleEndian); } else { writeDWARFOffset(Unit.AbbrOffset, Unit.FormParams.Format, OS, DI.IsLittleEndian); writeInteger((uint8_t)Unit.FormParams.AddrSize, OS, DI.IsLittleEndian); } OS.write(EntryBuffer.data(), EntryBuffer.size()); } return Error::success(); } static void emitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { OS.write(File.Name.data(), File.Name.size()); OS.write('\0'); encodeULEB128(File.DirIdx, OS); encodeULEB128(File.ModTime, OS); encodeULEB128(File.Length, OS); } Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { for (const auto &LineTable : DI.DebugLines) { writeInitialLength(LineTable.Format, LineTable.Length, OS, DI.IsLittleEndian); uint64_t SizeOfPrologueLength = LineTable.Format == dwarf::DWARF64 ? 8 : 4; writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); cantFail(writeVariableSizedInteger( LineTable.PrologueLength, SizeOfPrologueLength, OS, DI.IsLittleEndian)); writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); if (LineTable.Version >= 4) writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); for (auto OpcodeLength : LineTable.StandardOpcodeLengths) writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); for (auto IncludeDir : LineTable.IncludeDirs) { OS.write(IncludeDir.data(), IncludeDir.size()); OS.write('\0'); } OS.write('\0'); for (auto File : LineTable.Files) emitFileEntry(OS, File); OS.write('\0'); for (auto Op : LineTable.Opcodes) { writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); if (Op.Opcode == 0) { encodeULEB128(Op.ExtLen, OS); writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); switch (Op.SubOpcode) { case dwarf::DW_LNE_set_address: case dwarf::DW_LNE_set_discriminator: // TODO: Test this error. if (Error Err = writeVariableSizedInteger( Op.Data, DI.CompileUnits[0].FormParams.AddrSize, OS, DI.IsLittleEndian)) return Err; break; case dwarf::DW_LNE_define_file: emitFileEntry(OS, Op.FileEntry); break; case dwarf::DW_LNE_end_sequence: break; default: for (auto OpByte : Op.UnknownOpcodeData) writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); } } else if (Op.Opcode < LineTable.OpcodeBase) { switch (Op.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: encodeULEB128(Op.Data, OS); break; case dwarf::DW_LNS_advance_line: encodeSLEB128(Op.SData, OS); break; case dwarf::DW_LNS_fixed_advance_pc: writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); break; default: for (auto OpData : Op.StandardOpcodeData) { encodeULEB128(OpData, OS); } } } } } return Error::success(); } Error DWARFYAML::emitDebugAddr(raw_ostream &OS, const Data &DI) { for (const AddrTableEntry &TableEntry : DI.DebugAddr) { uint8_t AddrSize; if (TableEntry.AddrSize) AddrSize = *TableEntry.AddrSize; else AddrSize = DI.Is64BitAddrSize ? 8 : 4; uint64_t Length; if (TableEntry.Length) Length = (uint64_t)*TableEntry.Length; else // 2 (version) + 1 (address_size) + 1 (segment_selector_size) = 4 Length = 4 + (AddrSize + TableEntry.SegSelectorSize) * TableEntry.SegAddrPairs.size(); writeInitialLength(TableEntry.Format, Length, OS, DI.IsLittleEndian); writeInteger((uint16_t)TableEntry.Version, OS, DI.IsLittleEndian); writeInteger((uint8_t)AddrSize, OS, DI.IsLittleEndian); writeInteger((uint8_t)TableEntry.SegSelectorSize, OS, DI.IsLittleEndian); for (const SegAddrPair &Pair : TableEntry.SegAddrPairs) { if (TableEntry.SegSelectorSize != 0) if (Error Err = writeVariableSizedInteger(Pair.Segment, TableEntry.SegSelectorSize, OS, DI.IsLittleEndian)) return createStringError(errc::not_supported, "unable to write debug_addr segment: %s", toString(std::move(Err)).c_str()); if (AddrSize != 0) if (Error Err = writeVariableSizedInteger(Pair.Address, AddrSize, OS, DI.IsLittleEndian)) return createStringError(errc::not_supported, "unable to write debug_addr address: %s", toString(std::move(Err)).c_str()); } } return Error::success(); } Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, const Data &DI) { assert(DI.DebugStrOffsets && "unexpected emitDebugStrOffsets() call"); for (const DWARFYAML::StringOffsetsTable &Table : *DI.DebugStrOffsets) { uint64_t Length; if (Table.Length) Length = *Table.Length; else // sizeof(version) + sizeof(padding) = 4 Length = 4 + Table.Offsets.size() * (Table.Format == dwarf::DWARF64 ? 8 : 4); writeInitialLength(Table.Format, Length, OS, DI.IsLittleEndian); writeInteger((uint16_t)Table.Version, OS, DI.IsLittleEndian); writeInteger((uint16_t)Table.Padding, OS, DI.IsLittleEndian); for (uint64_t Offset : Table.Offsets) writeDWARFOffset(Offset, Table.Format, OS, DI.IsLittleEndian); } return Error::success(); } static Error checkListEntryOperands(StringRef EncodingString, ArrayRef Values, uint64_t ExpectedOperands) { if (Values.size() != ExpectedOperands) return createStringError( errc::invalid_argument, "invalid number (%zu) of operands for the operator: %s, %" PRIu64 " expected", Values.size(), EncodingString.str().c_str(), ExpectedOperands); return Error::success(); } static Error writeListEntryAddress(StringRef EncodingName, raw_ostream &OS, uint64_t Addr, uint8_t AddrSize, bool IsLittleEndian) { if (Error Err = writeVariableSizedInteger(Addr, AddrSize, OS, IsLittleEndian)) return createStringError(errc::invalid_argument, "unable to write address for the operator %s: %s", EncodingName.str().c_str(), toString(std::move(Err)).c_str()); return Error::success(); } static Expected writeListEntry(raw_ostream &OS, const DWARFYAML::RnglistEntry &Entry, uint8_t AddrSize, bool IsLittleEndian) { uint64_t BeginOffset = OS.tell(); writeInteger((uint8_t)Entry.Operator, OS, IsLittleEndian); StringRef EncodingName = dwarf::RangeListEncodingString(Entry.Operator); auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error { return checkListEntryOperands(EncodingName, Entry.Values, ExpectedOperands); }; auto WriteAddress = [&](uint64_t Addr) -> Error { return writeListEntryAddress(EncodingName, OS, Addr, AddrSize, IsLittleEndian); }; switch (Entry.Operator) { case dwarf::DW_RLE_end_of_list: if (Error Err = CheckOperands(0)) return std::move(Err); break; case dwarf::DW_RLE_base_addressx: if (Error Err = CheckOperands(1)) return std::move(Err); encodeULEB128(Entry.Values[0], OS); break; case dwarf::DW_RLE_startx_endx: case dwarf::DW_RLE_startx_length: case dwarf::DW_RLE_offset_pair: if (Error Err = CheckOperands(2)) return std::move(Err); encodeULEB128(Entry.Values[0], OS); encodeULEB128(Entry.Values[1], OS); break; case dwarf::DW_RLE_base_address: if (Error Err = CheckOperands(1)) return std::move(Err); if (Error Err = WriteAddress(Entry.Values[0])) return std::move(Err); break; case dwarf::DW_RLE_start_end: if (Error Err = CheckOperands(2)) return std::move(Err); if (Error Err = WriteAddress(Entry.Values[0])) return std::move(Err); cantFail(WriteAddress(Entry.Values[1])); break; case dwarf::DW_RLE_start_length: if (Error Err = CheckOperands(2)) return std::move(Err); if (Error Err = WriteAddress(Entry.Values[0])) return std::move(Err); encodeULEB128(Entry.Values[1], OS); break; } return OS.tell() - BeginOffset; } template Error writeDWARFLists(raw_ostream &OS, ArrayRef> Tables, bool IsLittleEndian, bool Is64BitAddrSize) { for (const DWARFYAML::ListTable &Table : Tables) { // sizeof(version) + sizeof(address_size) + sizeof(segment_selector_size) + // sizeof(offset_entry_count) = 8 uint64_t Length = 8; uint8_t AddrSize; if (Table.AddrSize) AddrSize = *Table.AddrSize; else AddrSize = Is64BitAddrSize ? 8 : 4; // Since the length of the current range/location lists entry is // undetermined yet, we firstly write the content of the range/location // lists to a buffer to calculate the length and then serialize the buffer // content to the actual output stream. std::string ListBuffer; raw_string_ostream ListBufferOS(ListBuffer); // Offsets holds offsets for each range/location list. The i-th element is // the offset from the beginning of the first range/location list to the // location of the i-th range list. std::vector Offsets; for (const DWARFYAML::ListEntries &List : Table.Lists) { Offsets.push_back(ListBufferOS.tell()); - for (const EntryType &Entry : List.Entries) { - Expected EntrySize = - writeListEntry(ListBufferOS, Entry, AddrSize, IsLittleEndian); - if (!EntrySize) - return EntrySize.takeError(); - Length += *EntrySize; + if (List.Content) { + List.Content->writeAsBinary(ListBufferOS, UINT64_MAX); + Length += List.Content->binary_size(); + } else if (List.Entries) { + for (const EntryType &Entry : *List.Entries) { + Expected EntrySize = + writeListEntry(ListBufferOS, Entry, AddrSize, IsLittleEndian); + if (!EntrySize) + return EntrySize.takeError(); + Length += *EntrySize; + } } } // If the offset_entry_count field isn't specified, yaml2obj will infer it // from the 'Offsets' field in the YAML description. If the 'Offsets' field // isn't specified either, yaml2obj will infer it from the auto-generated // offsets. uint32_t OffsetEntryCount; if (Table.OffsetEntryCount) OffsetEntryCount = *Table.OffsetEntryCount; else OffsetEntryCount = Table.Offsets ? Table.Offsets->size() : Offsets.size(); uint64_t OffsetsSize = OffsetEntryCount * (Table.Format == dwarf::DWARF64 ? 8 : 4); Length += OffsetsSize; // If the length is specified in the YAML description, we use it instead of // the actual length. if (Table.Length) Length = *Table.Length; writeInitialLength(Table.Format, Length, OS, IsLittleEndian); writeInteger((uint16_t)Table.Version, OS, IsLittleEndian); writeInteger((uint8_t)AddrSize, OS, IsLittleEndian); writeInteger((uint8_t)Table.SegSelectorSize, OS, IsLittleEndian); writeInteger((uint32_t)OffsetEntryCount, OS, IsLittleEndian); auto EmitOffsets = [&](ArrayRef Offsets, uint64_t OffsetsSize) { for (uint64_t Offset : Offsets) writeDWARFOffset(OffsetsSize + Offset, Table.Format, OS, IsLittleEndian); }; if (Table.Offsets) EmitOffsets(ArrayRef((const uint64_t *)Table.Offsets->data(), Table.Offsets->size()), 0); else EmitOffsets(Offsets, OffsetsSize); OS.write(ListBuffer.data(), ListBuffer.size()); } return Error::success(); } Error DWARFYAML::emitDebugRnglists(raw_ostream &OS, const Data &DI) { assert(DI.DebugRnglists && "unexpected emitDebugRnglists() call"); return writeDWARFLists( OS, *DI.DebugRnglists, DI.IsLittleEndian, DI.Is64BitAddrSize); } using EmitFuncType = Error (*)(raw_ostream &, const DWARFYAML::Data &); static Error emitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc, StringRef Sec, StringMap> &OutputBuffers) { std::string Data; raw_string_ostream DebugInfoStream(Data); if (Error Err = EmitFunc(DebugInfoStream, DI)) return Err; DebugInfoStream.flush(); if (!Data.empty()) OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data); return Error::success(); } Expected>> DWARFYAML::emitDebugSections(StringRef YAMLString, bool IsLittleEndian) { auto CollectDiagnostic = [](const SMDiagnostic &Diag, void *DiagContext) { *static_cast(DiagContext) = Diag; }; SMDiagnostic GeneratedDiag; yaml::Input YIn(YAMLString, /*Ctxt=*/nullptr, CollectDiagnostic, &GeneratedDiag); DWARFYAML::Data DI; DI.IsLittleEndian = IsLittleEndian; YIn >> DI; if (YIn.error()) return createStringError(YIn.error(), GeneratedDiag.getMessage()); StringMap> DebugSections; Error Err = emitDebugSectionImpl(DI, &DWARFYAML::emitDebugInfo, "debug_info", DebugSections); Err = joinErrors(std::move(Err), emitDebugSectionImpl(DI, &DWARFYAML::emitDebugLine, "debug_line", DebugSections)); Err = joinErrors(std::move(Err), emitDebugSectionImpl(DI, &DWARFYAML::emitDebugStr, "debug_str", DebugSections)); Err = joinErrors(std::move(Err), emitDebugSectionImpl(DI, &DWARFYAML::emitDebugAbbrev, "debug_abbrev", DebugSections)); Err = joinErrors(std::move(Err), emitDebugSectionImpl(DI, &DWARFYAML::emitDebugAranges, "debug_aranges", DebugSections)); Err = joinErrors(std::move(Err), emitDebugSectionImpl(DI, &DWARFYAML::emitDebugRanges, "debug_ranges", DebugSections)); if (Err) return std::move(Err); return std::move(DebugSections); } diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp index e5c77bc3721f..adc167249226 100644 --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -1,273 +1,282 @@ //===- DWARFYAML.cpp - DWARF YAMLIO implementation ------------------------===// // // 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 defines classes for handling the YAML representation of DWARF Debug // Info. // //===----------------------------------------------------------------------===// #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/BinaryFormat/Dwarf.h" namespace llvm { bool DWARFYAML::Data::isEmpty() const { return DebugStrings.empty() && AbbrevDecls.empty() && ARanges.empty() && DebugRanges.empty() && !PubNames && !PubTypes && !GNUPubNames && !GNUPubTypes && CompileUnits.empty() && DebugLines.empty(); } SetVector DWARFYAML::Data::getNonEmptySectionNames() const { SetVector SecNames; if (!DebugStrings.empty()) SecNames.insert("debug_str"); if (!ARanges.empty()) SecNames.insert("debug_aranges"); if (!DebugRanges.empty()) SecNames.insert("debug_ranges"); if (!DebugLines.empty()) SecNames.insert("debug_line"); if (!DebugAddr.empty()) SecNames.insert("debug_addr"); if (!AbbrevDecls.empty()) SecNames.insert("debug_abbrev"); if (!CompileUnits.empty()) SecNames.insert("debug_info"); if (PubNames) SecNames.insert("debug_pubnames"); if (PubTypes) SecNames.insert("debug_pubtypes"); if (GNUPubNames) SecNames.insert("debug_gnu_pubnames"); if (GNUPubTypes) SecNames.insert("debug_gnu_pubtypes"); if (DebugStrOffsets) SecNames.insert("debug_str_offsets"); if (DebugRnglists) SecNames.insert("debug_rnglists"); return SecNames; } namespace yaml { void MappingTraits::mapping(IO &IO, DWARFYAML::Data &DWARF) { void *OldContext = IO.getContext(); DWARFYAML::DWARFContext DWARFCtx; IO.setContext(&DWARFCtx); IO.mapOptional("debug_str", DWARF.DebugStrings); IO.mapOptional("debug_abbrev", DWARF.AbbrevDecls); if (!DWARF.ARanges.empty() || !IO.outputting()) IO.mapOptional("debug_aranges", DWARF.ARanges); if (!DWARF.DebugRanges.empty() || !IO.outputting()) IO.mapOptional("debug_ranges", DWARF.DebugRanges); IO.mapOptional("debug_pubnames", DWARF.PubNames); IO.mapOptional("debug_pubtypes", DWARF.PubTypes); DWARFCtx.IsGNUPubSec = true; IO.mapOptional("debug_gnu_pubnames", DWARF.GNUPubNames); IO.mapOptional("debug_gnu_pubtypes", DWARF.GNUPubTypes); IO.mapOptional("debug_info", DWARF.CompileUnits); IO.mapOptional("debug_line", DWARF.DebugLines); IO.mapOptional("debug_addr", DWARF.DebugAddr); IO.mapOptional("debug_str_offsets", DWARF.DebugStrOffsets); IO.mapOptional("debug_rnglists", DWARF.DebugRnglists); IO.setContext(OldContext); } void MappingTraits::mapping(IO &IO, DWARFYAML::Abbrev &Abbrev) { IO.mapOptional("Code", Abbrev.Code); IO.mapRequired("Tag", Abbrev.Tag); IO.mapRequired("Children", Abbrev.Children); IO.mapRequired("Attributes", Abbrev.Attributes); } void MappingTraits::mapping( IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev) { IO.mapRequired("Attribute", AttAbbrev.Attribute); IO.mapRequired("Form", AttAbbrev.Form); if(AttAbbrev.Form == dwarf::DW_FORM_implicit_const) IO.mapRequired("Value", AttAbbrev.Value); } void MappingTraits::mapping( IO &IO, DWARFYAML::ARangeDescriptor &Descriptor) { IO.mapRequired("Address", Descriptor.Address); IO.mapRequired("Length", Descriptor.Length); } void MappingTraits::mapping(IO &IO, DWARFYAML::ARange &ARange) { IO.mapOptional("Format", ARange.Format, dwarf::DWARF32); IO.mapRequired("Length", ARange.Length); IO.mapRequired("Version", ARange.Version); IO.mapRequired("CuOffset", ARange.CuOffset); IO.mapRequired("AddrSize", ARange.AddrSize); IO.mapRequired("SegSize", ARange.SegSize); IO.mapRequired("Descriptors", ARange.Descriptors); } void MappingTraits::mapping( IO &IO, DWARFYAML::RangeEntry &Descriptor) { IO.mapRequired("LowOffset", Descriptor.LowOffset); IO.mapRequired("HighOffset", Descriptor.HighOffset); } void MappingTraits::mapping(IO &IO, DWARFYAML::Ranges &DebugRanges) { IO.mapOptional("Offset", DebugRanges.Offset); IO.mapOptional("AddrSize", DebugRanges.AddrSize); IO.mapRequired("Entries", DebugRanges.Entries); } void MappingTraits::mapping(IO &IO, DWARFYAML::PubEntry &Entry) { IO.mapRequired("DieOffset", Entry.DieOffset); if (static_cast(IO.getContext())->IsGNUPubSec) IO.mapRequired("Descriptor", Entry.Descriptor); IO.mapRequired("Name", Entry.Name); } void MappingTraits::mapping( IO &IO, DWARFYAML::PubSection &Section) { IO.mapRequired("Length", Section.Length); IO.mapRequired("Version", Section.Version); IO.mapRequired("UnitOffset", Section.UnitOffset); IO.mapRequired("UnitSize", Section.UnitSize); IO.mapRequired("Entries", Section.Entries); } void MappingTraits::mapping(IO &IO, DWARFYAML::Unit &Unit) { IO.mapOptional("Format", Unit.FormParams.Format, dwarf::DWARF32); IO.mapOptional("Length", Unit.Length); IO.mapRequired("Version", Unit.FormParams.Version); if (Unit.FormParams.Version >= 5) IO.mapRequired("UnitType", Unit.Type); IO.mapRequired("AbbrOffset", Unit.AbbrOffset); IO.mapRequired("AddrSize", Unit.FormParams.AddrSize); IO.mapOptional("Entries", Unit.Entries); } void MappingTraits::mapping(IO &IO, DWARFYAML::Entry &Entry) { IO.mapRequired("AbbrCode", Entry.AbbrCode); IO.mapRequired("Values", Entry.Values); } void MappingTraits::mapping( IO &IO, DWARFYAML::FormValue &FormValue) { IO.mapOptional("Value", FormValue.Value); if (!FormValue.CStr.empty() || !IO.outputting()) IO.mapOptional("CStr", FormValue.CStr); if (!FormValue.BlockData.empty() || !IO.outputting()) IO.mapOptional("BlockData", FormValue.BlockData); } void MappingTraits::mapping(IO &IO, DWARFYAML::File &File) { IO.mapRequired("Name", File.Name); IO.mapRequired("DirIdx", File.DirIdx); IO.mapRequired("ModTime", File.ModTime); IO.mapRequired("Length", File.Length); } void MappingTraits::mapping( IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode) { IO.mapRequired("Opcode", LineTableOpcode.Opcode); if (LineTableOpcode.Opcode == dwarf::DW_LNS_extended_op) { IO.mapRequired("ExtLen", LineTableOpcode.ExtLen); IO.mapRequired("SubOpcode", LineTableOpcode.SubOpcode); } if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) IO.mapOptional("UnknownOpcodeData", LineTableOpcode.UnknownOpcodeData); if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) IO.mapOptional("StandardOpcodeData", LineTableOpcode.StandardOpcodeData); if (!LineTableOpcode.FileEntry.Name.empty() || !IO.outputting()) IO.mapOptional("FileEntry", LineTableOpcode.FileEntry); if (LineTableOpcode.Opcode == dwarf::DW_LNS_advance_line || !IO.outputting()) IO.mapOptional("SData", LineTableOpcode.SData); IO.mapOptional("Data", LineTableOpcode.Data); } void MappingTraits::mapping( IO &IO, DWARFYAML::LineTable &LineTable) { IO.mapOptional("Format", LineTable.Format, dwarf::DWARF32); IO.mapRequired("Length", LineTable.Length); IO.mapRequired("Version", LineTable.Version); IO.mapRequired("PrologueLength", LineTable.PrologueLength); IO.mapRequired("MinInstLength", LineTable.MinInstLength); if(LineTable.Version >= 4) IO.mapRequired("MaxOpsPerInst", LineTable.MaxOpsPerInst); IO.mapRequired("DefaultIsStmt", LineTable.DefaultIsStmt); IO.mapRequired("LineBase", LineTable.LineBase); IO.mapRequired("LineRange", LineTable.LineRange); IO.mapRequired("OpcodeBase", LineTable.OpcodeBase); IO.mapRequired("StandardOpcodeLengths", LineTable.StandardOpcodeLengths); IO.mapRequired("IncludeDirs", LineTable.IncludeDirs); IO.mapRequired("Files", LineTable.Files); IO.mapRequired("Opcodes", LineTable.Opcodes); } void MappingTraits::mapping( IO &IO, DWARFYAML::SegAddrPair &SegAddrPair) { IO.mapOptional("Segment", SegAddrPair.Segment, 0); IO.mapOptional("Address", SegAddrPair.Address, 0); } void MappingTraits::mapping( IO &IO, DWARFYAML::AddrTableEntry &AddrTable) { IO.mapOptional("Format", AddrTable.Format, dwarf::DWARF32); IO.mapOptional("Length", AddrTable.Length); IO.mapRequired("Version", AddrTable.Version); IO.mapOptional("AddressSize", AddrTable.AddrSize); IO.mapOptional("SegmentSelectorSize", AddrTable.SegSelectorSize, 0); IO.mapOptional("Entries", AddrTable.SegAddrPairs); } void MappingTraits::mapping( IO &IO, DWARFYAML::StringOffsetsTable &StrOffsetsTable) { IO.mapOptional("Format", StrOffsetsTable.Format, dwarf::DWARF32); IO.mapOptional("Length", StrOffsetsTable.Length); IO.mapOptional("Version", StrOffsetsTable.Version, 5); IO.mapOptional("Padding", StrOffsetsTable.Padding, 0); IO.mapOptional("Offsets", StrOffsetsTable.Offsets); } void MappingTraits::mapping( IO &IO, DWARFYAML::RnglistEntry &RnglistEntry) { IO.mapRequired("Operator", RnglistEntry.Operator); IO.mapOptional("Values", RnglistEntry.Values); } template void MappingTraits>::mapping( IO &IO, DWARFYAML::ListEntries &ListEntries) { IO.mapOptional("Entries", ListEntries.Entries); + IO.mapOptional("Content", ListEntries.Content); +} + +template +StringRef MappingTraits>::validate( + IO &IO, DWARFYAML::ListEntries &ListEntries) { + if (ListEntries.Entries && ListEntries.Content) + return "Entries and Content can't be used together"; + return StringRef(); } template void MappingTraits>::mapping( IO &IO, DWARFYAML::ListTable &ListTable) { IO.mapOptional("Format", ListTable.Format, dwarf::DWARF32); IO.mapOptional("Length", ListTable.Length); IO.mapOptional("Version", ListTable.Version, 5); IO.mapOptional("AddressSize", ListTable.AddrSize); IO.mapOptional("SegmentSelectorSize", ListTable.SegSelectorSize, 0); IO.mapOptional("OffsetEntryCount", ListTable.OffsetEntryCount); IO.mapOptional("Offsets", ListTable.Offsets); IO.mapOptional("Lists", ListTable.Lists); } void MappingTraits::mapping( IO &IO, DWARFYAML::InitialLength &InitialLength) { IO.mapRequired("TotalLength", InitialLength.TotalLength); if (InitialLength.isDWARF64()) IO.mapRequired("TotalLength64", InitialLength.TotalLength64); } } // end namespace yaml } // end namespace llvm diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml index 80dc9b9fdeb3..248cb190235b 100644 --- a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml @@ -1,610 +1,671 @@ ## Test that yaml2obj emits a .debug_rnglists section when requested. ## a) Generate and verify a little endian DWARF32 .debug_rnglists section in a 64-bit object file. # RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2LSB %s -o %t1.le.dwarf32.o # RUN: llvm-readobj --sections --section-data %t1.le.dwarf32.o | \ # RUN: FileCheck -DSIZE=99 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF32-LE # SHDR: Index: 1 # SHDR-NEXT: Name: .debug_rnglists (1) # SHDR-NEXT: Type: SHT_PROGBITS (0x1) # SHDR-NEXT: Flags [ (0x0) # SHDR-NEXT: ] # SHDR-NEXT: Address: 0x0 # SHDR-NEXT: Offset: 0x40 # SHDR-NEXT: Size: [[SIZE]] # SHDR-NEXT: Link: 0 # SHDR-NEXT: Info: 0 # SHDR-NEXT: AddressAlignment: [[ADDRALIGN]] # SHDR-NEXT: EntrySize: 0 # DWARF32-LE-NEXT: SectionData ( # DWARF32-LE-NEXT: 0000: 24000000 05000800 02000000 08000000 |$...............| ## ^------- unit_length (4-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) ## ^------- offset_entry_count (4-byte) ## ^------- offsets[0] (4-byte) # DWARF32-LE-NEXT: 0010: 11000000 01B42402 B424B424 0003B424 |......$..$.$...$| ## ^------- offsets[1] (4-byte) ## ^- DW_RLE_base_addressx (1-byte) ## ^--- operands[0] (ULEB128) 0x1234 ## ^- DW_RLE_startx_endx (1-byte) ## ^--- operands[0] (ULEB128) 0x1234 ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_end_of_list (1-byte) ## ^- DW_RLE_startx_length (1-byte) ## ^--- operands[0] (ULEB128) 0x1234 # DWARF32-LE-NEXT: 0020: B42404B4 24B42400 37000000 05000800 |.$..$.$.7.......| ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_offset_pair (1-byte) ## ^---- operands[0] (ULEB128) 0x1234 ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_end_of_list (1-byte) ## ^------- unit_length (4-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) # DWARF32-LE-NEXT: 0030: 02000000 08000000 23000000 05341200 |........#....4..| ## ^------- offset_entry_count (4-byte) ## ^------- offsets[0] (4-byte) ## ^------- offsets[1] (4-byte) ## ^- DW_RLE_base_address (1-byte) ## ^----- operands[0] (8-byte) # DWARF32-LE-NEXT: 0040: 00000000 00063412 00000000 00003412 |......4.......4.| ## ----------- ## ^- DW_RLE_start_end (1-byte) ## ^----------------- operands[0] (8-byte) ## ^--- operands[1] (8-byte) # DWARF32-LE-NEXT: 0050: 00000000 00000007 34120000 00000000 |........4.......| ## ------------- ## ^- DW_RLE_end_of_list (1-byte) ## ^- DW_RLE_start_length (1-byte) ## ^---------------- operands[0] (8-byte) # DWARF32-LE-NEXT: 0060: B42400 |.$.| ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_end_of_list (1-byte) # DWARF32-LE-NEXT: ) --- !ELF FileHeader: Class: ELFCLASS64 Data: [[ENDIAN]] Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - Lists: - Entries: - Operator: DW_RLE_base_addressx Values: [ 0x1234 ] - Operator: DW_RLE_startx_endx Values: [ 0x1234, 0x1234 ] - Operator: DW_RLE_end_of_list - Entries: - Operator: DW_RLE_startx_length Values: [ 0x1234, 0x1234 ] - Operator: DW_RLE_offset_pair Values: [ 0x1234, 0x1234 ] - Operator: DW_RLE_end_of_list - Lists: - Entries: - Operator: DW_RLE_base_address Values: [ 0x1234 ] - Operator: DW_RLE_start_end Values: [ 0x1234, 0x1234 ] - Operator: DW_RLE_end_of_list - Entries: - Operator: DW_RLE_start_length Values: [ 0x1234, 0x1234 ] - Operator: DW_RLE_end_of_list ## b) Generate and verify a big endian DWARF32 .debug_rnglists section in a 64-bit object file. # RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2MSB %s -o %t1.be.dwarf32.o # RUN: llvm-readobj --sections --section-data %t1.be.dwarf32.o | \ # RUN: FileCheck -DSIZE=99 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF32-BE # DWARF32-BE-NEXT: SectionData ( # DWARF32-BE-NEXT: 0000: 00000024 00050800 00000002 00000008 |...$............| ## ^------- unit_length (4-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) ## ^------- offset_entry_count (4-byte) ## ^------- offsets[0] (4-byte) # DWARF32-BE-NEXT: 0010: 00000011 01B42402 B424B424 0003B424 |......$..$.$...$| ## ^------- offsets[1] (4-byte) ## ^- DW_RLE_base_addressx (1-byte) ## ^--- operands[0] (ULEB128) 0x1234 ## ^- DW_RLE_startx_endx (1-byte) ## ^--- operands[0] (ULEB128) 0x1234 ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_end_of_list (1-byte) ## ^- DW_RLE_startx_length (1-byte) ## ^--- operands[0] (ULEB128) 0x1234 # DWARF32-BE-NEXT: 0020: B42404B4 24B42400 00000037 00050800 |.$..$.$....7....| ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_offset_pair (1-byte) ## ^---- operands[0] (ULEB128) 0x1234 ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_end_of_list (1-byte) ## ^------- unit_length (4-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) # DWARF32-BE-NEXT: 0030: 00000002 00000008 00000023 05000000 |...........#....| ## ^------- offset_entry_count (4-byte) ## ^------- offsets[0] (4-byte) ## ^------- offsets[1] (4-byte) ## ^- DW_RLE_base_address (1-byte) ## ^----- operands[0] (8-byte) # DWARF32-BE-NEXT: 0040: 00000012 34060000 00000000 12340000 |....4........4..| ## ----------- ## ^- DW_RLE_start_end (1-byte) ## ^----------------- operands[0] (8-byte) ## ^--- operands[1] (8-byte) # DWARF32-BE-NEXT: 0050: 00000000 12340007 00000000 00001234 |.....4.........4| ## ------------- ## ^- DW_RLE_end_of_list (1-byte) ## ^- DW_RLE_start_length (1-byte) ## ^---------------- operands[0] (8-byte) # DWARF32-BE-NEXT: 0060: B42400 |.$.| ## ^--- operands[1] (ULEB128) 0x1234 ## ^- DW_RLE_end_of_list (1-byte) # DWARF32-BE-NEXT: ) ## c) Generate and verify a little endian DWARF64 .debug_rnglists section in a 64-bit object file. # RUN: yaml2obj --docnum=2 -DENDIAN=ELFDATA2LSB %s -o %t2.le.dwarf64.o # RUN: llvm-readobj --sections --section-data %t2.le.dwarf64.o | \ # RUN: FileCheck -DSIZE=38 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF64-LE # DWARF64-LE-NEXT: SectionData ( # DWARF64-LE-NEXT: 0000: FFFFFFFF 1A000000 00000000 05000800 |................| ## ^------------------------- unit_length (12-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) # DWARF64-LE-NEXT: 0010: 02000000 10000000 00000000 11000000 |................| ## ^------- offset_entry_count (4-byte) ## ^---------------- offsets[0] (8-byte) ## ^------- offsets[1] (8-byte) # DWARF64-LE-NEXT: 0020: 00000000 0000 |......| ## -------- ## ^- DW_RLE_end_of_list (1-byte) ## ^- DW_RLE_end_of_list (1-byte) # DWARF64-LE-NEXT: ) --- !ELF FileHeader: Class: ELFCLASS64 Data: [[ENDIAN]] Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - Format: DWARF64 Lists: - Entries: - Operator: DW_RLE_end_of_list - Entries: - Operator: DW_RLE_end_of_list ## d) Generate and verify a big endian DWARF64 .debug_rnglists section in a 64-bit object file. # RUN: yaml2obj --docnum=2 -DENDIAN=ELFDATA2MSB %s -o %t2.be.dwarf64.o # RUN: llvm-readobj --sections --section-data %t2.be.dwarf64.o | \ # RUN: FileCheck -DSIZE=38 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF64-BE # DWARF64-BE-NEXT: SectionData ( # DWARF64-BE-NEXT: 0000: FFFFFFFF 00000000 0000001A 00050800 |................| ## ^------------------------- unit_length (12-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) # DWARF64-BE-NEXT: 0010: 00000002 00000000 00000010 00000000 |................| ## ^------- offset_entry_count (4-byte) ## ^---------------- offsets[0] (8-byte) ## ^------- offsets[1] (8-byte) # DWARF64-BE-NEXT: 0020: 00000011 0000 |......| ## -------- ## ^- DW_RLE_end_of_list (1-byte) ## ^- DW_RLE_end_of_list (1-byte) # DWARF64-BE-NEXT: ) ## e) Test that the length, version, segment_selector_size, address_size, offset_entry_count ## and offsets fields can be specified manually. # RUN: yaml2obj --docnum=3 %s -o %t3.o # RUN: llvm-readelf --hex-dump=.debug_rnglists %t3.o | \ # RUN: FileCheck %s --check-prefix=OVERWRITE # OVERWRITE: Hex dump of section '.debug_rnglists': # OVERWRITE-NEXT: 0x00000000 34120000 06000303 04000000 01000000 4............... ## ^------- unit_length (4-byte) ## ^--- version (2-byte) ## ^- address_size (1-byte) ## ^- segment_selector_size (1-byte) ## ^------- offset_entry_count (4-byte) ## ^------- offsets[0] (4-byte) # OVERWRITE-NEXT: 0x00000010 0000 .. --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - Length: 0x1234 Version: 6 AddressSize: 3 SegmentSelectorSize: 3 OffsetEntryCount: 4 Offsets: [ 0x01 ] Lists: - Entries: - Operator: DW_RLE_end_of_list - Entries: - Operator: DW_RLE_end_of_list ## f) Test that the default value of the address_size field in a 32-bit object file is 4. # RUN: yaml2obj --docnum=4 %s -o %t4.o # RUN: llvm-readelf --hex-dump=.debug_rnglists %t4.o | \ # RUN: FileCheck %s --check-prefix=ADDRSIZE32 # ADDRSIZE32: Hex dump of section '.debug_rnglists': # ADDRSIZE32-NEXT: 0x00000000 22000000 05000400 01000000 04000000 "............... ## ^- address_size (1-byte) # ADDRSIZE32-NEXT: 0x00000010 05341200 00063412 00002143 00000734 .4....4...!C...4 ## ^- DW_RLE_base_address (1-byte) ## ^-------- operands[0] (4-byte) ## ^- DW_RLE_start_end (1-byte) ## ^-------- operands[0] (4-byte) ## ^-------- operands[1] (4-byte) ## ^- DW_RLE_start_length (1-byte) ## ^- operands[0] (4-byte) # ADDRSIZE32-NEXT: 0x00000020 120000a1 8601 ...... ## ------ ## ^------ operands[1] (ULEB128) 0x4321 --- !ELF FileHeader: Class: ELFCLASS32 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - Lists: - Entries: - Operator: DW_RLE_base_address Values: [ 0x1234 ] - Operator: DW_RLE_start_end Values: [ 0x1234, 0x4321 ] - Operator: DW_RLE_start_length Values: [ 0x1234, 0x4321 ] ## g) Test that the address_size field can be specified manually and the size of ## corresponding operands will be changed accordingly. # RUN: yaml2obj --docnum=5 %s -o %t5.o # RUN: llvm-readelf --hex-dump=.debug_rnglists %t5.o | \ # RUN: FileCheck %s --check-prefix=ADDRSIZE # ADDRSIZE: Hex dump of section '.debug_rnglists': # ADDRSIZE-NEXT: 0x00000000 22000000 05000400 01000000 04000000 "............... ## ^- address_size 0x04 # ADDRSIZE-NEXT: 0x00000010 05341200 00063412 00002143 00000734 .4....4...!C...4 ## ^- DW_RLE_base_address ## ^-------- operands[0] (4-byte) ## ^- DW_RLE_start_end ## ^-------- operands[0] (4-byte) ## ^-------- operands[1] (4-byte) ## ^- DW_RLE_start_length ## ^- operands[0] (4-byte) # ADDRSIZE-NEXT: 0x00000020 120000b4 2400 ....$. ## ------ ## ^---- operands[1] (ULEB128) ## ^- DW_RLE_end_of_list --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - AddressSize: 4 Lists: - Entries: - Operator: DW_RLE_base_address Values: [ 0x1234 ] - Operator: DW_RLE_start_end Values: [ 0x1234, 0x4321 ] - Operator: DW_RLE_start_length Values: [ 0x1234, 0x1234 ] - Operator: DW_RLE_end_of_list ## h) Test that yaml2obj emits an error message if we try to assign an invalid value to ## 'AddressSize' when there is an entry whose operands contain address. # RUN: not yaml2obj -DOPERATOR=base_address -DVALUES=[0x01] --docnum=6 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=base_address %s --check-prefix=INVALID-ADDRSIZE # RUN: not yaml2obj -DOPERATOR=start_end -DVALUES=[0x01,0x02] --docnum=6 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=start_end %s --check-prefix=INVALID-ADDRSIZE # RUN: not yaml2obj -DOPERATOR=start_length -DVALUES=[0x01,0x02] --docnum=6 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=start_length %s --check-prefix=INVALID-ADDRSIZE # INVALID-ADDRSIZE: yaml2obj: error: unable to write address for the operator DW_RLE_[[OPERATOR]]: invalid integer write size: 3 --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - AddressSize: 3 Lists: - Entries: - Operator: DW_RLE_[[OPERATOR]] Values: [[VALUES]] ## i) Test that an invalid address_size can be used when there are no address-using operators. # RUN: yaml2obj --docnum=7 %s -o %t7.o # RUN: llvm-readelf --hex-dump=.debug_rnglists %t7.o | \ # RUN: FileCheck %s --check-prefix=ADDRSIZE-NOERROR # ADDRSIZE-NOERROR: Hex dump of section '.debug_rnglists': # ADDRSIZE-NOERROR-NEXT: 0x00000000 0e000000 05000300 01000000 04000000 ................ ## ^- address_size (1-byte) 0x03 # ADDRSIZE-NOERROR-NEXT: 0x00000010 0101 .. --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - AddressSize: 3 Lists: - Entries: - Operator: DW_RLE_base_addressx Values: [ 0x01 ] ## j) Test that yaml2obj emits an error message if we specify invalid numbers of operands ## for an operator. # RUN: not yaml2obj -DOPERATOR=end_of_list -DVALUES=[0x01] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=end_of_list -DACTUAL=1 -DEXPECTED=0 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=base_addressx -DVALUES=[] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=base_addressx -DACTUAL=0 -DEXPECTED=1 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=startx_endx -DVALUES=[0x01] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=startx_endx -DACTUAL=1 -DEXPECTED=2 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=startx_length -DVALUES=[0x01] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=startx_length -DACTUAL=1 -DEXPECTED=2 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=offset_pair -DVALUES=[] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=offset_pair -DACTUAL=0 -DEXPECTED=2 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=base_address -DVALUES=[0x01,0x02] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=base_address -DACTUAL=2 -DEXPECTED=1 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=start_end -DVALUES=[0x01,0x02,0x03] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=start_end -DACTUAL=3 -DEXPECTED=2 %s --check-prefix=INVALID-OPERANDS # RUN: not yaml2obj -DOPERATOR=start_length -DVALUES=[0x01] --docnum=8 %s 2>&1 | \ # RUN: FileCheck -DOPERATOR=start_length -DACTUAL=1 -DEXPECTED=2 %s --check-prefix=INVALID-OPERANDS # INVALID-OPERANDS: yaml2obj: error: invalid number ([[ACTUAL]]) of operands for the operator: DW_RLE_[[OPERATOR]], [[EXPECTED]] expected --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - AddressSize: 3 Lists: - Entries: - Operator: DW_RLE_[[OPERATOR]] Values: [[VALUES]] ## k) Test that an empty list is allowed for a range list table. # RUN: yaml2obj --docnum=9 %s -o %t9.o # RUN: llvm-readelf --hex-dump=.debug_rnglists %t9.o | \ # RUN: FileCheck %s --check-prefix=EMPTY-LIST # EMPTY-LIST: Hex dump of section '.debug_rnglists': # EMPTY-LIST-NEXT: 0x00000000 08000000 05000800 00000000 ............ ## ^------- unit_length (4-byte) ## ^--- version (2-byte) ## ^--- address_size (1-byte) ## ^------- offset_entry_count (4-byte) --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: - Lists: [] ## l) Generate the .debug_rnglists section from raw section content. # RUN: yaml2obj --docnum=10 %s -o %t10.o # RUN: llvm-readobj --sections --section-data %t10.o | \ # RUN: FileCheck %s -DSIZE=3 -DADDRALIGN=0 --check-prefixes=SHDR,ARBITRARY-CONTENT # ARBITRARY-CONTENT: SectionData ( # ARBITRARY-CONTENT-NEXT: 0000: 112233 # ARBITRARY-CONTENT-NEXT: ) --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .debug_rnglists Type: SHT_PROGBITS Content: "112233" ## m) Generate the .debug_rnglists section when the "Size" is specified. # RUN: yaml2obj --docnum=11 %s -o %t11.o # RUN: llvm-readelf --hex-dump=.debug_rnglists %t11.o | \ # RUN: FileCheck %s --check-prefix=SIZE # SIZE: Hex dump of section '.debug_rnglists': # SIZE-NEXT: 0x00000000 00000000 00000000 00000000 00000000 ................ # SIZE-EMPTY: --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .debug_rnglists Type: SHT_PROGBITS Size: 0x10 ## n) Test that yaml2obj emits an error message when both the "Size" and the ## "debug_rnglists" entry are specified at the same time. # RUN: not yaml2obj --docnum=12 %s 2>&1 | FileCheck %s --check-prefix=ERROR # ERROR: yaml2obj: error: cannot specify section '.debug_rnglists' contents in the 'DWARF' entry and the 'Content' or 'Size' in the 'Sections' entry at the same time --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .debug_rnglists Type: SHT_PROGBITS Size: 0x10 DWARF: debug_rnglists: - Lists: [] ## o) Test that yaml2obj emits an error message when both the "Content" and the ## "debug_rnglists" entry are specified at the same time. # RUN: not yaml2obj --docnum=13 %s 2>&1 | FileCheck %s --check-prefix=ERROR --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .debug_rnglists Type: SHT_PROGBITS Content: "00" DWARF: debug_rnglists: - Lists: [] ## p) Test that all the properties can be overridden by the section header when ## the "debug_rnglists" entry doesn't exist. # RUN: yaml2obj --docnum=14 %s -o %t14.o # RUN: llvm-readelf --sections %t14.o | FileCheck %s --check-prefix=OVERRIDDEN # OVERRIDDEN: [Nr] Name Type Address Off Size ES Flg Lk Inf Al # OVERRIDDEN: [ 1] .debug_rnglists STRTAB 0000000000002020 000050 00000c 01 A 2 1 2 # OVERRIDDEN-NEXT: [ 2] .sec STRTAB 0000000000000000 00005c 000000 00 0 0 0 --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .debug_rnglists Type: SHT_STRTAB ## SHT_PROGBITS by default. Flags: [SHF_ALLOC] ## 0 by default. Link: .sec ## 0 by default. EntSize: 1 ## 0 by default. Info: 1 ## 0 by default. AddressAlign: 2 ## 0 by default. Address: 0x2020 ## 0x00 by default. Offset: 0x50 ## 0x40 for the first section. Size: 0x0c ## Set the "Size" so that we can reuse the check tag "OVERRIDDEN". - Name: .sec ## Linked by .debug_rnglists. Type: SHT_STRTAB ## q) Test that all the properties can be overridden by the section header when ## the "debug_rnglists" entry exists. # RUN: yaml2obj --docnum=15 %s -o %t15.o # RUN: llvm-readelf --sections %t15.o | FileCheck %s --check-prefix=OVERRIDDEN --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .debug_rnglists Type: SHT_STRTAB ## SHT_PROGBITS by default. Flags: [SHF_ALLOC] ## 0 by default. Link: .sec ## 0 by default. EntSize: 1 ## 0 by default. Info: 1 ## 0 by default. AddressAlign: 2 ## 1 by default. Address: 0x2020 ## 0x00 by default. Offset: 0x50 ## 0x40 for the first section. - Name: .sec ## Linked by .debug_rnglists. Type: SHT_STRTAB DWARF: debug_rnglists: - Lists: [] ## r) Test that the .debug_rnglists section header is emitted if the "debug_rnglists" ## entry is empty. # RUN: yaml2obj --docnum=16 %s -o %t16.o # RUN: llvm-readobj --sections --section-data %t16.o | \ # RUN: FileCheck -DSIZE=0 -DADDRALIGN=1 %s --check-prefixes=SHDR,EMPTY-CONTENT # EMPTY-CONTENT-NEXT: SectionData ( # EMPTY-CONTENT-NEXT: ) --- !ELF FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB Type: ET_EXEC Machine: EM_X86_64 DWARF: debug_rnglists: [] + +## s) Test that we are able to generate a range list via raw binary data. + +# RUN: yaml2obj --docnum=17 %s -o %t17.o +# RUN: llvm-readelf --hex-dump=.debug_rnglists %t17.o | \ +# RUN: FileCheck %s --check-prefix=CUSTOM-LIST + +# CUSTOM-LIST: Hex dump of section '.debug_rnglists': +# CUSTOM-LIST-NEXT: 0x00000000 29000000 05000800 03000000 0c000000 )............... +## ^------- unit_length (4-byte) +## ^--- version (2-byte) +## ^- address_size (1-byte) +## ^- segment_selector_size (1-byte) +## ^------- offset_entry_count (4-byte) +## ^------- offsets[0] (4-byte) +# CUSTOM-LIST-NEXT: 0x00000010 11000000 19000000 02b424b4 24123456 ..........$.$.4V +## ^------- offsets[1] (4-byte) +## ^------- offsets[2] (4-byte) +## ^- DW_RLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^---- operands[1] (ULEB128) 0x1234 +## ^----- custom list content +# CUSTOM-LIST-NEXT: 0x00000020 7890abcd efabcdef 12345678 90 x........4Vx. +## ----------- +## ^----------------- custom list content + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_rnglists: + - Lists: + - Entries: + - Operator: DW_RLE_startx_endx + Values: [ 0x1234, 0x1234 ] + - Content: '1234567890abcdef' + - Content: 'abcdef1234567890' + +## t) Test that yaml2obj emits an error message when 'Content' and 'Entries' are specified +## at the same time. + +# RUN: not yaml2obj --docnum=18 %s 2>&1 | FileCheck %s --check-prefix=ERR + +# ERR: YAML:{{.*}}: error: Entries and Content can't be used together +# ERR-NEXT: - Entries: [] +# ERR-NEXT: ^ + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_rnglists: + - Lists: + - Entries: [] + Content: ''