diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -185,8 +185,18 @@ std::vector Offsets; }; +enum ListEntryOperandTypes { + Unsigned8, + Unsigned16, + Unsigned32, + Unsigned64, + ULEB128, + SLEB128, +}; + struct RnglistEntry { dwarf::RnglistEntries Operator; + Optional> Types; std::vector Values; }; @@ -254,6 +264,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR( llvm::DWARFYAML::ListEntries) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RnglistEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ListEntryOperandTypes) namespace llvm { namespace yaml { @@ -423,12 +434,28 @@ } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, DWARFYAML::ListEntryOperandTypes &value) { + io.enumCase(value, "Unsigned8", + DWARFYAML::ListEntryOperandTypes::Unsigned8); + io.enumCase(value, "Unsigned16", + DWARFYAML::ListEntryOperandTypes::Unsigned16); + io.enumCase(value, "Unsigned32", + DWARFYAML::ListEntryOperandTypes::Unsigned32); + io.enumCase(value, "Unsigned64", + DWARFYAML::ListEntryOperandTypes::Unsigned64); + io.enumCase(value, "ULEB128", DWARFYAML::ListEntryOperandTypes::ULEB128); + io.enumCase(value, "SLEB128", DWARFYAML::ListEntryOperandTypes::SLEB128); + } +}; + #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" + io.enumFallback(value); } }; diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp --- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -468,6 +468,41 @@ return Error::success(); } +static Error +writeCustomListEntryOperands(ArrayRef Types, + ArrayRef Values, raw_ostream &OS, + bool IsLittleEndian) { + if (Types.size() != Values.size()) + return createStringError( + errc::invalid_argument, + "the number of operands should match the number of their types"); + + for (size_t I = 0; I < Types.size(); ++I) { + switch (Types[I]) { + case DWARFYAML::ListEntryOperandTypes::Unsigned8: + writeInteger((uint8_t)Values[I], OS, IsLittleEndian); + break; + case DWARFYAML::ListEntryOperandTypes::Unsigned16: + writeInteger((uint16_t)Values[I], OS, IsLittleEndian); + break; + case DWARFYAML::ListEntryOperandTypes::Unsigned32: + writeInteger((uint32_t)Values[I], OS, IsLittleEndian); + break; + case DWARFYAML::ListEntryOperandTypes::Unsigned64: + writeInteger((uint64_t)Values[I], OS, IsLittleEndian); + break; + case DWARFYAML::ListEntryOperandTypes::ULEB128: + encodeULEB128((uint64_t)Values[I], OS); + break; + case DWARFYAML::ListEntryOperandTypes::SLEB128: + encodeSLEB128((int64_t)Values[I], OS); + break; + } + } + + return Error::success(); +} + static Expected writeListEntry(raw_ostream &OS, const DWARFYAML::RnglistEntry &Entry, uint8_t AddrSize, @@ -486,6 +521,13 @@ IsLittleEndian); }; + if (Entry.Types) { + if (Error Err = writeCustomListEntryOperands(*Entry.Types, Entry.Values, OS, + IsLittleEndian)) + return std::move(Err); + return OS.tell() - BeginOffset; + } + switch (Entry.Operator) { case dwarf::DW_RLE_end_of_list: if (Error Err = CheckOperands(0)) @@ -524,6 +566,10 @@ return std::move(Err); encodeULEB128(Entry.Values[1], OS); break; + default: + return createStringError(errc::invalid_argument, + "unrecognized operator: 0x" + + utohexstr(Entry.Operator)); } return OS.tell() - BeginOffset; diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -239,6 +239,7 @@ void MappingTraits::mapping( IO &IO, DWARFYAML::RnglistEntry &RnglistEntry) { IO.mapRequired("Operator", RnglistEntry.Operator); + IO.mapOptional("Types", RnglistEntry.Types); IO.mapOptional("Values", RnglistEntry.Values); } diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml --- a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-rnglists.yaml @@ -608,3 +608,88 @@ Machine: EM_X86_64 DWARF: debug_rnglists: [] + +## s) Test that yaml2obj is able to emit custom operands for range list entries. + +# RUN: yaml2obj --docnum=17 %s -o %t17.o +# RUN: llvm-readelf --hex-dump=.debug_rnglists %t17.o | \ +# RUN: FileCheck %s --check-prefix=CUSTOM-OPERANDS + +# CUSTOM-OPERANDS: Hex dump of section '.debug_rnglists': +# CUSTOM-OPERANDS-NEXT: 0x00000000 21000000 05000800 01000000 04000000 !............... +## ^------- 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-OPERANDS-NEXT: 0x00000010 00013412 78563412 efcdab90 78563412 ..4.xV4.....xV4. +## ^- DW_RLE_end_of_list +## ^- operands[0] (uint8_t) +## ^--- operands[1] (uint16_t) +## ^------- operands[2] (uint32_t) +## ^---------------- operands[3] (uint64_t) +# CUSTOM-OPERANDS-NEXT: 0x00000020 b4247dff 12 .$}.. +## ^--- operands[4] (ULEB128) +## ^- operands[5] (SLEB128) -3 +## ^- operator: 0xff +## ^- operands[0] (uint8_t) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_rnglists: + - Lists: + - Entries: + - Operator: DW_RLE_end_of_list + Types: [ Unsigned8, Unsigned16, Unsigned32, Unsigned64, ULEB128, SLEB128 ] + Values: [ 0x01, 0x1234, 0x12345678, 0x1234567890abcdef, 0x1234, 0xfffffffffffffffd ] ## 0xfffffffffffffffd is -3 + - Operator: 0xff + Types: [ Unsigned8 ] + Values: [ 0x12 ] + +## t) Test that yaml2obj emits an error message if we specify an unrecognized operator but don't +## specify the type(s) for its operand(s). + +# RUN: not yaml2obj --docnum=18 %s 2>&1 | \ +# RUN: FileCheck %s --check-prefix=UNRECOGNIZED + +# UNRECOGNIZED: yaml2obj: error: unrecognized operator: 0xFF + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_rnglists: + - Lists: + - Entries: + - Operator: 0xff + +## u) Test that yaml2obj emits an error message if the number of operands doesn't match +## the number of their types. + +# RUN: not yaml2obj --docnum=19 %s 2>&1 | \ +# RUN: FileCheck %s --check-prefix=UNMATCH-TYPES + +# UNMATCH-TYPES: yaml2obj: error: the number of operands should match the number of their types + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_rnglists: + - Lists: + - Entries: + - Operator: DW_RLE_end_of_list + Types: [ ULEB128 ] + Values: [ 0x01, 0x02 ]