diff --git a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h --- a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h +++ b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h @@ -40,6 +40,7 @@ Error emitDebugAddr(raw_ostream &OS, const Data &DI); Error emitDebugStrOffsets(raw_ostream &OS, const Data &DI); Error emitDebugRnglists(raw_ostream &OS, const Data &DI); +Error emitDebugLoclists(raw_ostream &OS, const Data &DI); Expected>> emitDebugSections(StringRef YAMLString, 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 @@ -183,11 +183,23 @@ std::vector Offsets; }; +struct DWARFOperation { + dwarf::LocationAtom Operator; + std::vector Values; +}; + struct RnglistEntry { dwarf::RnglistEntries Operator; std::vector Values; }; +struct LoclistEntry { + dwarf::LoclistEntries Operator; + std::vector Values; + Optional DescriptionsLength; + std::vector Descriptions; +}; + template struct ListEntries { std::vector Entries; }; @@ -222,6 +234,7 @@ std::vector DebugLines; Optional>> DebugRnglists; + Optional>> DebugLoclists; bool isEmpty() const; @@ -252,6 +265,12 @@ LLVM_YAML_IS_SEQUENCE_VECTOR( llvm::DWARFYAML::ListEntries) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RnglistEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR( + llvm::DWARFYAML::ListTable) +LLVM_YAML_IS_SEQUENCE_VECTOR( + llvm::DWARFYAML::ListEntries) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LoclistEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DWARFOperation) namespace llvm { namespace yaml { @@ -320,6 +339,10 @@ static void mapping(IO &IO, DWARFYAML::SegAddrPair &SegAddrPair); }; +template <> struct MappingTraits { + static void mapping(IO &IO, DWARFYAML::DWARFOperation &DWARFOperation); +}; + template struct MappingTraits> { static void mapping(IO &IO, DWARFYAML::ListTable &ListTable); @@ -334,6 +357,10 @@ static void mapping(IO &IO, DWARFYAML::RnglistEntry &RnglistEntry); }; +template <> struct MappingTraits { + static void mapping(IO &IO, DWARFYAML::LoclistEntry &LoclistEntry); +}; + template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::AddrTableEntry &AddrTable); }; @@ -430,6 +457,24 @@ } }; +#define HANDLE_DW_LLE(unused, name) \ + io.enumCase(value, "DW_LLE_" #name, dwarf::DW_LLE_##name); + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, dwarf::LoclistEntries &value) { +#include "llvm/BinaryFormat/Dwarf.def" + } +}; + +#define HANDLE_DW_OP(id, name, version, vendor) \ + io.enumCase(value, "DW_OP_" #name, dwarf::DW_OP_##name); + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, dwarf::LocationAtom &value) { +#include "llvm/BinaryFormat/Dwarf.def" + } +}; + } // end namespace yaml } // end namespace llvm 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 @@ -568,6 +568,38 @@ return Error::success(); } +static Expected +writeDWARFExpression(raw_ostream &OS, + const DWARFYAML::DWARFOperation &Operation, + uint8_t AddrSize, bool IsLittleEndian) { + auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error { + return checkOperandsNumber( + dwarf::OperationEncodingString(Operation.Operator), Operation.Values, + ExpectedOperands); + }; + + uint64_t ExpressionBegin = OS.tell(); + writeInteger((uint8_t)Operation.Operator, OS, IsLittleEndian); + switch (Operation.Operator) { + case dwarf::DW_OP_consts: + if (Error Err = CheckOperands(1)) + return std::move(Err); + encodeSLEB128(Operation.Values[0], OS); + break; + case dwarf::DW_OP_stack_value: + if (Error Err = CheckOperands(0)) + return std::move(Err); + break; + default: + return createStringError( + errc::not_supported, + "DWARF expression: " + + dwarf::OperationEncodingString(Operation.Operator) + + " is not supported"); + } + return OS.tell() - ExpressionBegin; +} + static Expected writeListEntry(raw_ostream &OS, const DWARFYAML::RnglistEntry &Entry, uint8_t AddrSize, @@ -629,6 +661,103 @@ return OS.tell() - BeginOffset; } +static Expected writeListEntry(raw_ostream &OS, + const DWARFYAML::LoclistEntry &Entry, + uint8_t AddrSize, + bool IsLittleEndian) { + uint64_t BeginOffset = OS.tell(); + writeInteger((uint8_t)Entry.Operator, OS, IsLittleEndian); + + StringRef EncodingName = dwarf::LocListEncodingString(Entry.Operator); + + auto CheckOperands = [&](uint64_t ExpectedOperands) -> Error { + return checkOperandsNumber(EncodingName, Entry.Values, ExpectedOperands); + }; + + auto WriteAddress = [&](uint64_t Addr) -> Error { + return writeListEntryAddress(EncodingName, OS, Addr, AddrSize, + IsLittleEndian); + }; + + auto WriteDWARFOperations = [&]() -> Error { + std::string OpBuffer; + raw_string_ostream OpBufferOS(OpBuffer); + uint64_t DescriptionsLength = 0; + + for (const DWARFYAML::DWARFOperation &Op : Entry.Descriptions) { + if (Expected OpSize = + writeDWARFExpression(OpBufferOS, Op, AddrSize, IsLittleEndian)) + DescriptionsLength += *OpSize; + else + return OpSize.takeError(); + } + + if (Entry.DescriptionsLength) + DescriptionsLength = *Entry.DescriptionsLength; + else + DescriptionsLength = OpBuffer.size(); + + encodeULEB128(DescriptionsLength, OS); + OS.write(OpBuffer.data(), OpBuffer.size()); + + return Error::success(); + }; + + switch (Entry.Operator) { + case dwarf::DW_LLE_end_of_list: + if (Error Err = CheckOperands(0)) + return std::move(Err); + break; + case dwarf::DW_LLE_base_addressx: + if (Error Err = CheckOperands(1)) + return std::move(Err); + encodeULEB128(Entry.Values[0], OS); + break; + case dwarf::DW_LLE_startx_endx: + case dwarf::DW_LLE_startx_length: + case dwarf::DW_LLE_offset_pair: + if (Error Err = CheckOperands(2)) + return std::move(Err); + encodeULEB128(Entry.Values[0], OS); + encodeULEB128(Entry.Values[1], OS); + if (Error Err = WriteDWARFOperations()) + return std::move(Err); + break; + case dwarf::DW_LLE_default_location: + if (Error Err = CheckOperands(0)) + return std::move(Err); + if (Error Err = WriteDWARFOperations()) + return std::move(Err); + break; + case dwarf::DW_LLE_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_LLE_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])); + if (Error Err = WriteDWARFOperations()) + return std::move(Err); + break; + case dwarf::DW_LLE_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); + if (Error Err = WriteDWARFOperations()) + return std::move(Err); + break; + } + + return OS.tell() - BeginOffset; +} + template Error writeDWARFLists(raw_ostream &OS, ArrayRef> Tables, @@ -716,6 +845,12 @@ OS, *DI.DebugRnglists, DI.IsLittleEndian, DI.Is64BitAddrSize); } +Error DWARFYAML::emitDebugLoclists(raw_ostream &OS, const Data &DI) { + assert(DI.DebugLoclists && "unexpected emitDebugRnglists() call"); + return writeDWARFLists( + OS, *DI.DebugLoclists, DI.IsLittleEndian, DI.Is64BitAddrSize); +} + using EmitFuncType = Error (*)(raw_ostream &, const DWARFYAML::Data &); static Error 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 @@ -50,6 +50,8 @@ SecNames.insert("debug_str_offsets"); if (DebugRnglists) SecNames.insert("debug_rnglists"); + if (DebugLoclists) + SecNames.insert("debug_loclists"); return SecNames; } @@ -75,6 +77,7 @@ IO.mapOptional("debug_addr", DWARF.DebugAddr); IO.mapOptional("debug_str_offsets", DWARF.DebugStrOffsets); IO.mapOptional("debug_rnglists", DWARF.DebugRnglists); + IO.mapOptional("debug_loclists", DWARF.DebugLoclists); IO.setContext(OldContext); } @@ -236,12 +239,26 @@ IO.mapOptional("Offsets", StrOffsetsTable.Offsets); } +void MappingTraits::mapping( + IO &IO, DWARFYAML::DWARFOperation &DWARFOperation) { + IO.mapRequired("Operator", DWARFOperation.Operator); + IO.mapOptional("Values", DWARFOperation.Values); +} + void MappingTraits::mapping( IO &IO, DWARFYAML::RnglistEntry &RnglistEntry) { IO.mapRequired("Operator", RnglistEntry.Operator); IO.mapOptional("Values", RnglistEntry.Values); } +void MappingTraits::mapping( + IO &IO, DWARFYAML::LoclistEntry &LoclistEntry) { + IO.mapRequired("Operator", LoclistEntry.Operator); + IO.mapOptional("Values", LoclistEntry.Values); + IO.mapOptional("DescriptionsLength", LoclistEntry.DescriptionsLength); + IO.mapOptional("Descriptions", LoclistEntry.Descriptions); +} + template void MappingTraits>::mapping( IO &IO, DWARFYAML::ListEntries &ListEntries) { diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -978,6 +978,8 @@ Err = DWARFYAML::emitDebugStrOffsets(*OS, DWARF); else if (Name == ".debug_rnglists") Err = DWARFYAML::emitDebugRnglists(*OS, DWARF); + else if (Name == ".debug_loclists") + Err = DWARFYAML::emitDebugLoclists(*OS, DWARF); else llvm_unreachable("unexpected emitDWARF() call"); diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-loclists.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-loclists.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-loclists.yaml @@ -0,0 +1,777 @@ +## Test that yaml2obj emits a .debug_loclists section when requested. + +## a) Generate and verify a little endian DWARF32 .debug_loclists section in a 64-bit object file. + +# RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2LSB %s -o %t1.dwarf32.le.o +# RUN: llvm-readobj --sections --section-data %t1.dwarf32.le.o | \ +# RUN: FileCheck -DSIZE=133 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF32-LE + +# SHDR: Index: 1 +# SHDR-NEXT: Name: .debug_loclists (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: 3D000000 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) +# DWARF32-LE-NEXT: 0010: 1B000000 2F000000 01B42402 B424A186 |..../.....$..$..| +## ^------- offsets[1] (4-byte) +## ^------- offsets[2] (4-byte) +## ^- DW_LLE_base_addressx +## ^--- operands[0] (ULEB128) 0x1234 +## ^- DW_LLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^--- operands[1] (ULEB128) 0x4321 +# DWARF32-LE-NEXT: 0020: 010411B4 249F0003 B424A186 0102117D |....$....$.....}| +## -- +## ^- location descriptions length (ULEB128) 0x04 +## ^- DW_OP_consts +## ^---- operands[0] (SLEB128) +0x1234 +## ^- DW_OP_stack_value +## ^- DW_LLE_end_of_list +## ^- DW_LLE_startx_length +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x02 +## ^- DW_OP_consts +## ^- operands[0] (SLEB128) -0x03 +# DWARF32-LE-NEXT: 0030: 04B424A1 86010311 B4240005 0311B424 |..$......$.....$| +## ^- DW_LLE_offset_pair +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +## ^- DW_LLE_default_location +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +# DWARF32-LE-NEXT: 0040: 00400000 00050008 00020000 00080000 |.@..............| +## ^- DW_LLE_end_of_list +## ^-------- 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: 0050: 00270000 00063412 00000000 00000734 |.'....4........4| +## -- +## ^-------- offsets[1] (4-byte) +## ^- DW_LLE_base_address +## ^----------------- operands[0] (8-byte) +## ^- DW_LLE_start_end +## ^- operands[0] (8-byte) +# DWARF32-LE-NEXT: 0060: 12000000 00000021 43000000 00000003 |.......!C.......| +## --------------- +## ^----------------- operands[1] (8-byte) +## ^- location descriptions length (ULEB128) 0x03 +# DWARF32-LE-NEXT: 0070: 11B42400 08341200 00000000 00A18601 |..$..4..........| +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +## ^- DW_LLE_start_length +## ^----------------- operands[0] (8-byte) +## ^----- operands[1] (LEB128) 0x4321 +# DWARF32-LE-NEXT: 0080: 0311B424 00 |...$.| +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +# DWARF32-LE-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: [[ENDIAN]] + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: + - Entries: + - Operator: DW_LLE_base_addressx + Values: [ 0x1234 ] + - Operator: DW_LLE_startx_endx + Values: [ 0x1234, 0x4321 ] + Descriptions: + - Operator: DW_OP_consts + Values: [ 0x1234 ] + - Operator: DW_OP_stack_value + - Operator: DW_LLE_end_of_list + - Entries: + - Operator: DW_LLE_startx_length + Values: [ 0x1234, 0x4321 ] + Descriptions: + - Operator: DW_OP_consts + ## Test a negative number (-3). + Values: [ 0xfffffffffffffffd ] + - Operator: DW_LLE_offset_pair + Values: [ 0x1234, 0x4321 ] + Descriptions: + - Operator: DW_OP_consts + Values: [ 0x1234 ] + - Operator: DW_LLE_end_of_list + - Entries: + - Operator: DW_LLE_default_location + Descriptions: + - Operator: DW_OP_consts + Values: [ 0x1234 ] + - Operator: DW_LLE_end_of_list + - Lists: + - Entries: + - Operator: DW_LLE_base_address + Values: [ 0x1234 ] + - Operator: DW_LLE_start_end + Values: [ 0x1234, 0x4321 ] + Descriptions: + - Operator: DW_OP_consts + Values: [ 0x1234 ] + - Operator: DW_LLE_end_of_list + - Entries: + - Operator: DW_LLE_start_length + Values: [ 0x1234, 0x4321 ] + Descriptions: + - Operator: DW_OP_consts + Values: [ 0x1234 ] + - Operator: DW_LLE_end_of_list + +## b) Generate and verify a big endian DWARF32 .debug_loclists section in a 64-bit object file. + +# RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2MSB %s -o %t.dwarf32.be.o +# RUN: llvm-readobj --sections --section-data %t.dwarf32.be.o | \ +# RUN: FileCheck -DSIZE=133 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF32-BE + +# DWARF32-BE-NEXT: SectionData ( +# DWARF32-BE-NEXT: 0000: 0000003D 00050800 00000003 0000000C |...=............| +## ^------- 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: 0000001B 0000002F 01B42402 B424A186 |......./..$..$..| +## ^------- offsets[1] (4-byte) +## ^------- offsets[2] (4-byte) +## ^- DW_LLE_base_addressx +## ^--- operands[0] (ULEB128) 0x1234 +## ^- DW_LLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^--- operands[1] (ULEB128) 0x4321 +# DWARF32-BE-NEXT: 0020: 010411B4 249F0003 B424A186 0102117D |....$....$.....}| +## -- +## ^- location descriptions length (ULEB128) 0x04 +## ^- DW_OP_consts +## ^---- operands[0] (SLEB128) +0x1234 +## ^- DW_OP_stack_value +## ^- DW_LLE_end_of_list +## ^- DW_LLE_startx_length +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x02 +## ^- DW_OP_consts +## ^- operands[0] (SLEB128) -0x03 +# DWARF32-BE-NEXT: 0030: 04B424A1 86010311 B4240005 0311B424 |..$......$.....$| +## ^- DW_LLE_offset_pair +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +## ^- DW_LLE_default_location +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +# DWARF32-BE-NEXT: 0040: 00000000 40000508 00000000 02000000 |....@...........| +## ^- DW_LLE_end_of_list +## ^-------- 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: 0050: 08000000 27060000 00000000 12340700 |....'........4..| +## -- +## ^-------- offsets[1] (4-byte) +## ^- DW_LLE_base_address +## ^----------------- operands[0] (8-byte) +## ^- DW_LLE_start_end +## ^- operands[0] (8-byte) +# DWARF32-BE-NEXT: 0060: 00000000 00123400 00000000 00432103 |......4......C!.| +## --------------- +## ^----------------- operands[1] (8-byte) +## ^- location descriptions length (ULEB128) 0x03 +# DWARF32-BE-NEXT: 0070: 11B42400 08000000 00000012 34A18601 |..$.........4...| +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +## ^- DW_LLE_start_length +## ^----------------- operands[0] (8-byte) +## ^----- operands[1] (LEB128) 0x4321 +# DWARF32-BE-NEXT: 0080: 0311B424 00 |...$.| +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +# DWARF32-BE-NEXT: ) + +## c) Generate and verify a little endian DWARF64 .debug_loclists section in a 64-bit object file. + +# RUN: yaml2obj --docnum=2 -DENDIAN=ELFDATA2LSB %s -o %t2.dwarf64.le.o +# RUN: llvm-readobj --sections --section-data %t2.dwarf64.le.o | \ +# RUN: FileCheck -DSIZE=47 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF64-LE + +# DWARF64-LE-NEXT: SectionData ( +# DWARF64-LE-NEXT: 0000: FFFFFFFF 23000000 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 1A000000 |................| +## ^------- offset_entry_count (4-byte) +## ^---------------- offsets[0] (8-byte) +## ^------- offsets[1] (8-byte) +# DWARF64-LE-NEXT: 0020: 00000000 02B424A1 86010311 B42400 |......$......$.| +## -------- +## ^- DW_LLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +# DWARF64-LE-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: [[ENDIAN]] + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Format: DWARF64 + Lists: + - Entries: + - Operator: DW_LLE_startx_endx + Values: [ 0x1234, 0x4321 ] + Descriptions: + - Operator: DW_OP_consts + Values: [ 0x1234 ] + - Entries: + - Operator: DW_LLE_end_of_list + +## d) Generate and verify a big endian DWARF64 .debug_loclists section in a 64-bit object file. + +# RUN: yaml2obj --docnum=2 -DENDIAN=ELFDATA2MSB %s -o %t2.dwarf64.be.o +# RUN: llvm-readobj --sections --section-data %t2.dwarf64.be.o | \ +# RUN: FileCheck -DSIZE=47 -DADDRALIGN=1 %s --check-prefixes=SHDR,DWARF64-BE + +# DWARF64-BE-NEXT: SectionData ( +# DWARF64-BE-NEXT: 0000: FFFFFFFF 00000000 00000023 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: 0000001A 02B424A1 86010311 B42400 |......$......$.| +## -------- +## ^- DW_LLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x03 +## ^- DW_OP_consts +## ^--- operands[0] (SLEB128) +0x1234 +## ^- DW_LLE_end_of_list +# DWARF64-BE-NEXT: ) + +## e) Test that the length, version, segment_selector_size, address_size, offset_entry_count, +## offsets and location descriptions length fields can be specified manually. + +# RUN: yaml2obj --docnum=3 %s -o %t3.o +# RUN: llvm-readelf --hex-dump=.debug_loclists %t3.o | \ +# RUN: FileCheck %s --check-prefix=OVERWRITE + +# OVERWRITE: Hex dump of section '.debug_loclists': +# OVERWRITE-NEXT: 0x00000000 34120000 06000303 04000000 01000000 4............... +## ^------- unit_length (4-byte) 0x1234 +## ^--- version (2-byte) 0x06 +## ^- address_size (1-byte) 0x03 +## ^- segment_selector_size (1-byte) 0x03 +## ^------- offset_entry_count (4-byte) 0x04 +## ^------- offsets[0] (4-byte) 0x01 +# OVERWRITE-NEXT: 0x00000010 02b424a1 8601a186 019f00 ..$........ +## ^- DW_LLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^------ location descriptions length (ULEB128) 0x4321 +## ^- DW_OP_stack_value +## ^- DW_LLE_end_of_list + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Length: 0x1234 + Version: 6 + AddressSize: 3 + SegmentSelectorSize: 3 + OffsetEntryCount: 4 + Offsets: [ 0x01 ] + Lists: + - Entries: + - Operator: DW_LLE_startx_endx + Values: [ 0x1234, 0x4321 ] + DescriptionsLength: 0x4321 + Descriptions: + - Operator: DW_OP_stack_value + - Entries: + - Operator: DW_LLE_end_of_list + +## f) Test that location descriptions can be omitted from the YAML description. + +# RUN: yaml2obj --docnum=4 %s -o %t4.o +# RUN: llvm-readelf --hex-dump=.debug_loclists %t4.o | \ +# RUN: FileCheck %s --check-prefix=OMIT-DESCRIPTIONS + +# OMIT-DESCRIPTIONS: Hex dump of section '.debug_loclists': +# OMIT-DESCRIPTIONS-NEXT: 0x00000000 42000000 05000800 01000000 04000000 B............... +# OMIT-DESCRIPTIONS-NEXT: 0x00000010 02b424a1 86010003 b424a186 010004b4 ..$......$...... +## ^- DW_LLE_startx_endx +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x00 +## ^- DW_LLE_startx_length +## ^--- operands[0] (ULEB128) 0x1234 +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x00 +## ^- DW_LLE_offset_pair +## ^- operands[0] (ULEB128) 0x1234 +# OMIT-DESCRIPTIONS-NEXT: 0x00000020 24a18601 00050007 34120000 00000000 $.......4....... +## -- +## ^----- operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x00 +## ^- DW_LLE_default_location +## ^- location descriptions length (ULEB128) 0x00 +## ^- DW_LLE_start_end +## ^---------------- operands[0] (8-byte) +# OMIT-DESCRIPTIONS-NEXT: 0x00000030 21430000 00000000 00083412 00000000 !C........4..... +## ^---------------- operands[1] (8-byte) +## ^- location descriptions length (ULEB128) 0x00 +## ^- DW_LLE_start_length +## ^------------ operands[0] (8-byte) +# OMIT-DESCRIPTIONS-NEXT: 0x00000040 0000a186 0100 ...... +## ---- +## ^------ operands[1] (ULEB128) 0x4321 +## ^- location descriptions length (ULEB128) 0x00 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: + - Entries: + - Operator: DW_LLE_startx_endx + Values: [ 0x1234, 0x4321 ] + - Operator: DW_LLE_startx_length + Values: [ 0x1234, 0x4321 ] + - Operator: DW_LLE_offset_pair + Values: [ 0x1234, 0x4321 ] + - Operator: DW_LLE_default_location + - Operator: DW_LLE_start_end + Values: [ 0x1234, 0x4321 ] + - Operator: DW_LLE_start_length + Values: [ 0x1234, 0x4321 ] + +## g) Test that the default value of the address_size field in a 32-bit object file is 4. + +# RUN: yaml2obj --docnum=5 %s -o %t5.o +# RUN: llvm-readelf --hex-dump=.debug_loclists %t5.o | \ +# RUN: FileCheck %s --check-prefix=ADDRSIZE32 + +# ADDRSIZE32: Hex dump of section '.debug_loclists': +# ADDRSIZE32-NEXT: 0x00000000 24000000 05000400 01000000 04000000 $............... +## ^- address_size (1-byte) 0x04 +# ADDRSIZE32-NEXT: 0x00000010 06341200 00073412 00002143 00000008 .4....4...!C.... +## ^- DW_LLE_base_address +## ^-------- operands[0] (4-byte) +## ^- DW_LLE_start_end +## ^-------- operands[0] (4-byte) +## ^-------- operands[1] (4-byte) +## ^- counted location description +## ^- DW_LLE_start_length +# ADDRSIZE32-NEXT: 0x00000020 34120000 a1860100 4....... +## ^------- operands[0] (4-byte) +## ^----- operands[1] (ULEB128) 0x4321 +## ^- counted location description + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: + - Entries: + - Operator: DW_LLE_base_address + Values: [ 0x1234 ] + - Operator: DW_LLE_start_end + Values: [ 0x1234, 0x4321 ] + - Operator: DW_LLE_start_length + Values: [ 0x1234, 0x4321 ] + +## h) Test that the address_size field can be specified manually and the size of +## corresponding operands will be changed accordingly. + +# RUN: yaml2obj --docnum=6 %s -o %t6.o +# RUN: llvm-readelf --hex-dump=.debug_loclists %t6.o | \ +# RUN: FileCheck %s --check-prefix=ADDRSIZE32 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - AddressSize: 4 + Lists: + - Entries: + - Operator: DW_LLE_base_address + Values: [ 0x1234 ] + - Operator: DW_LLE_start_end + Values: [ 0x1234, 0x4321 ] + - Operator: DW_LLE_start_length + Values: [ 0x1234, 0x4321 ] + +## i) 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=7 %s 2>&1 | \ +# RUN: FileCheck -DOPERATOR=base_address %s --check-prefix=INVALID-ADDRSIZE + +# RUN: not yaml2obj -DOPERATOR=start_end -DVALUES=[0x01,0x02] --docnum=7 %s 2>&1 | \ +# RUN: FileCheck -DOPERATOR=start_end %s --check-prefix=INVALID-ADDRSIZE + +# RUN: not yaml2obj -DOPERATOR=start_length -DVALUES=[0x01,0x02] --docnum=7 %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_LLE_[[OPERATOR]]: invalid integer write size: 3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - AddressSize: 3 + Lists: + - Entries: + - Operator: DW_LLE_[[OPERATOR]] + Values: [[VALUES]] + +## j) Test that yaml2obj emits an error message if we specify invalid numbers of operands +## for a location list encoding. + +# 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-LLE-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-LLE-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-LLE-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-LLE-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-LLE-OPERANDS + +# RUN: not yaml2obj -DOPERATOR=default_location -DVALUES=[0x01] --docnum=8 %s 2>&1 | \ +# RUN: FileCheck -DOPERATOR=default_location -DACTUAL=1 -DEXPECTED=0 %s --check-prefix=INVALID-LLE-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-LLE-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-LLE-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-LLE-OPERANDS + +# INVALID-LLE-OPERANDS: yaml2obj: error: invalid number ([[ACTUAL]]) of operands for the operator: DW_LLE_[[OPERATOR]], [[EXPECTED]] expected + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: + - Entries: + - Operator: DW_LLE_[[OPERATOR]] + Values: [[VALUES]] + +## k) Test that yaml2obj emits an error message if we specify invalid numbers of operands +## for a DWARF expression operator. + +# RUN: not yaml2obj --docnum=9 -DOPERATOR=consts -DVALUES=[0x01,0x02] %s 2>&1 | \ +# RUN: FileCheck -DACTUAL=2 -DEXPECTED=1 -DOPERATOR=consts %s --check-prefix=INVALID-OP-OPERANDS + +# RUN: not yaml2obj --docnum=9 -DOPERATOR=stack_value -DVALUES=[0x01] %s 2>&1 | \ +# RUN: FileCheck -DACTUAL=1 -DEXPECTED=0 -DOPERATOR=stack_value %s --check-prefix=INVALID-OP-OPERANDS + +# INVALID-OP-OPERANDS: yaml2obj: error: invalid number ([[ACTUAL]]) of operands for the operator: DW_OP_[[OPERATOR]], [[EXPECTED]] expected + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: + - Entries: + - Operator: DW_LLE_startx_endx + Values: [ 0x01, 0x02 ] + Descriptions: + - Operator: DW_OP_[[OPERATOR]] + Values: [[VALUES]] + +## l) Test that an empty list is allowed for a location list table. + +# RUN: yaml2obj --docnum=10 %s -o %t10.o +# RUN: llvm-readelf --hex-dump=.debug_loclists %t10.o | \ +# RUN: FileCheck %s --check-prefix=EMPTY-LIST + +# EMPTY-LIST: Hex dump of section '.debug_loclists': +# EMPTY-LIST-NEXT: 0x00000000 08000000 05000800 00000000 ............ +## ^------- unit_length (4-byte) +## ^--- version (2-byte) +## ^- address_size (1-byte) +## ^- segment_selector_size (1-byte) +## ^------- offset_entry_count (4-byte) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: [] + +## m) Generate the .debug_loclists section from raw section content. + +# RUN: yaml2obj --docnum=11 %s -o %t11.o +# RUN: llvm-readobj --sections --section-data %t11.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_loclists + Type: SHT_PROGBITS + Content: "112233" + +## n) Generate the .debug_loclists section when the "Size" is specified. + +# RUN: yaml2obj --docnum=12 %s -o %t12.o +# RUN: llvm-readelf --hex-dump=.debug_loclists %t12.o | \ +# RUN: FileCheck %s --check-prefix=SIZE + +# SIZE: Hex dump of section '.debug_loclists': +# 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_loclists + Type: SHT_PROGBITS + Size: 0x10 + +## o) Test that yaml2obj emits an error message when both the "Size" and the +## "debug_loclists" entry are specified at the same time. + +# RUN: not yaml2obj --docnum=13 %s 2>&1 | FileCheck %s --check-prefix=ERROR + +# ERROR: yaml2obj: error: cannot specify section '.debug_loclists' 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_loclists + Type: SHT_PROGBITS + Size: 0x10 +DWARF: + debug_loclists: + - Lists: [] + +## p) Test that yaml2obj emits an error message when both the "Content" and the +## "debug_loclists" entry are specified at the same time. + +# RUN: not yaml2obj --docnum=14 %s 2>&1 | FileCheck %s --check-prefix=ERROR + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_loclists + Type: SHT_PROGBITS + Content: "00" +DWARF: + debug_loclists: + - Lists: [] + +## q) Test that all the properties can be overridden by the section header when +## the "debug_loclists" entry doesn't exist. + +# RUN: yaml2obj --docnum=15 %s -o %t15.o +# RUN: llvm-readelf --sections %t15.o | FileCheck %s --check-prefix=OVERRIDDEN + +# OVERRIDDEN: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# OVERRIDDEN: [ 1] .debug_loclists 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_loclists + 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_loclists. + Type: SHT_STRTAB + +## r) Test that all the properties can be overridden by the section header when +## the "debug_loclists" entry exists. + +# RUN: yaml2obj --docnum=16 %s -o %t16.o +# RUN: llvm-readelf --sections %t16.o | FileCheck %s --check-prefix=OVERRIDDEN + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_loclists + 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_loclists. + Type: SHT_STRTAB +DWARF: + debug_loclists: + - Lists: [] + +## s) Test that the .debug_loclists section header is emitted if the "debug_loclists" +## entry is empty. + +# RUN: yaml2obj --docnum=17 %s -o %t17.o +# RUN: llvm-readobj --sections --section-data %t17.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_loclists: [] + +## t) Test that yaml2obj emits an error message if we use an unimplemented DWARF expression +## operator. + +# RUN: not yaml2obj --docnum=18 %s -o %t18.o 2>&1 | \ +# RUN: FileCheck %s --check-prefix=UNIMPLEMENTED-OP + +# UNIMPLEMENTED-OP: yaml2obj: error: DWARF expression: DW_OP_reg0 is not supported + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_loclists: + - Lists: + - Entries: + - Operator: DW_LLE_default_location + Descriptions: + - Operator: DW_OP_reg0 diff --git a/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp b/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp --- a/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp +++ b/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp @@ -9,6 +9,8 @@ #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Testing/Support/Error.h"