From 4392ace2e7b472e0ce6839ba772110c5749c1536 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Mon, 22 Oct 2018 11:30:54 +0000 Subject: [PATCH] [llvm-dwarfdump] - Add the support of parsing .debug_loclists. This teaches llvm-dwarfdump to dump the content of .debug_loclists sections. It converts the DWARFDebugLocDWO class to DWARFDebugLoclists, teaches llvm-dwarfdump about .debug_loclists section and adds the implementation for parsing the DW_LLE_offset_pair entries. Differential revision: https://reviews.llvm.org/D53364 llvm-svn: 344895 --- include/llvm/BinaryFormat/Dwarf.def | 1 + include/llvm/DebugInfo/DWARF/DWARFContext.h | 4 +- include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h | 14 +- include/llvm/DebugInfo/DWARF/DWARFObject.h | 1 + lib/DebugInfo/DWARF/DWARFContext.cpp | 36 +++- lib/DebugInfo/DWARF/DWARFDebugLoc.cpp | 78 +++++--- lib/DebugInfo/DWARF/DWARFDie.cpp | 22 ++- .../X86/dwarfdump-debug-loclists.test | 168 ++++++++++++++++++ 8 files changed, 288 insertions(+), 36 deletions(-) create mode 100644 test/DebugInfo/X86/dwarfdump-debug-loclists.test diff --git a/include/llvm/BinaryFormat/Dwarf.def b/include/llvm/BinaryFormat/Dwarf.def index 6b7a7412f4d..512cc64926d 100644 --- a/include/llvm/BinaryFormat/Dwarf.def +++ b/include/llvm/BinaryFormat/Dwarf.def @@ -873,6 +873,7 @@ HANDLE_DWARF_SECTION(DebugTypes, ".debug_types", "debug-types") HANDLE_DWARF_SECTION(DebugLine, ".debug_line", "debug-line") HANDLE_DWARF_SECTION(DebugLineStr, ".debug_line_str", "debug-line-str") HANDLE_DWARF_SECTION(DebugLoc, ".debug_loc", "debug-loc") +HANDLE_DWARF_SECTION(DebugLoclists, ".debug_loclists", "debug-loclists") HANDLE_DWARF_SECTION(DebugFrame, ".debug_frame", "debug-frame") HANDLE_DWARF_SECTION(DebugMacro, ".debug_macro", "debug-macro") HANDLE_DWARF_SECTION(DebugNames, ".debug_names", "debug-names") diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index c5b98ea5a2a..221f1f79698 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -76,7 +76,7 @@ class DWARFContext : public DIContext { DWARFUnitVector DWOUnits; std::unique_ptr AbbrevDWO; - std::unique_ptr LocDWO; + std::unique_ptr LocDWO; /// The maximum DWARF version of all units. unsigned MaxVersion = 0; @@ -262,7 +262,7 @@ public: const DWARFDebugAbbrev *getDebugAbbrevDWO(); /// Get a pointer to the parsed DebugLoc object. - const DWARFDebugLocDWO *getDebugLocDWO(); + const DWARFDebugLoclists *getDebugLocDWO(); /// Get a pointer to the parsed DebugAranges object. const DWARFDebugAranges *getDebugAranges(); diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h index 9a73745fb6b..ad44c2c83fb 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -73,19 +73,21 @@ public: uint32_t *Offset); }; -class DWARFDebugLocDWO { +class DWARFDebugLoclists { public: struct Entry { - uint64_t Start; - uint32_t Length; + uint8_t Kind; + uint64_t Value0; + uint64_t Value1; SmallVector Loc; }; struct LocationList { unsigned Offset; SmallVector Entries; - void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize, - const MCRegisterInfo *RegInfo, unsigned Indent) const; + void dump(raw_ostream &OS, uint64_t BaseAddr, bool IsLittleEndian, + unsigned AddressSize, const MCRegisterInfo *RegInfo, + unsigned Indent) const; }; private: @@ -99,7 +101,7 @@ private: public: void parse(DataExtractor data); - void dump(raw_ostream &OS, const MCRegisterInfo *RegInfo, + void dump(raw_ostream &OS, uint64_t BaseAddr, const MCRegisterInfo *RegInfo, Optional Offset) const; /// Return the location list at the given offset or nullptr. diff --git a/include/llvm/DebugInfo/DWARF/DWARFObject.h b/include/llvm/DebugInfo/DWARF/DWARFObject.h index 6e8f370f4ae..8e582da3172 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ b/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -38,6 +38,7 @@ public: forEachTypesSections(function_ref F) const {} virtual StringRef getAbbrevSection() const { return ""; } virtual const DWARFSection &getLocSection() const { return Dummy; } + virtual const DWARFSection &getLoclistsSection() const { return Dummy; } virtual StringRef getARangeSection() const { return ""; } virtual StringRef getDebugFrameSection() const { return ""; } virtual StringRef getEHFrameSection() const { return ""; } diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index 18ec8476e9d..1f3753809a2 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -292,6 +292,27 @@ dumpRnglistsSection(raw_ostream &OS, DWARFDataExtractor &rnglistData, } } +static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts, + DWARFDataExtractor Data, + const MCRegisterInfo *MRI, + Optional DumpOffset) { + uint32_t Offset = 0; + DWARFDebugLoclists Loclists; + + DWARFListTableHeader Header(".debug_loclists", "locations"); + if (Error E = Header.extract(Data, &Offset)) { + WithColor::error() << toString(std::move(E)) << '\n'; + return; + } + + Header.dump(OS, DumpOpts); + DataExtractor LocData(Data.getData().drop_front(Offset), + Data.isLittleEndian(), Header.getAddrSize()); + + Loclists.parse(LocData); + Loclists.dump(OS, 0, MRI, DumpOffset); +} + void DWARFContext::dump( raw_ostream &OS, DIDumpOptions DumpOpts, std::array, DIDT_ID_Count> DumpOffsets) { @@ -366,9 +387,15 @@ void DWARFContext::dump( DObj->getLocSection().Data)) { getDebugLoc()->dump(OS, getRegisterInfo(), DumpOffset); } + if (shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists, + DObj->getLoclistsSection().Data)) { + DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(), + 0); + dumpLoclistsSection(OS, DumpOpts, Data, getRegisterInfo(), DumpOffset); + } if (shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc, DObj->getLocDWOSection().Data)) { - getDebugLocDWO()->dump(OS, getRegisterInfo(), DumpOffset); + getDebugLocDWO()->dump(OS, 0, getRegisterInfo(), DumpOffset); } if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame, @@ -696,11 +723,11 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() { return Loc.get(); } -const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() { +const DWARFDebugLoclists *DWARFContext::getDebugLocDWO() { if (LocDWO) return LocDWO.get(); - LocDWO.reset(new DWARFDebugLocDWO()); + LocDWO.reset(new DWARFDebugLoclists()); // Assume all compile units have the same address byte size. // FIXME: We don't need AddressSize for split DWARF since relocatable // addresses cannot appear there. At the moment DWARFExpression requires it. @@ -1213,6 +1240,7 @@ class DWARFObjInMemory final : public DWARFObject { DWARFSectionMap InfoSection; DWARFSectionMap LocSection; + DWARFSectionMap LocListsSection; DWARFSectionMap LineSection; DWARFSectionMap RangeSection; DWARFSectionMap RnglistsSection; @@ -1234,6 +1262,7 @@ class DWARFObjInMemory final : public DWARFObject { return StringSwitch(Name) .Case("debug_info", &InfoSection) .Case("debug_loc", &LocSection) + .Case("debug_loclists", &LocListsSection) .Case("debug_line", &LineSection) .Case("debug_str_offsets", &StringOffsetSection) .Case("debug_ranges", &RangeSection) @@ -1529,6 +1558,7 @@ public: StringRef getAbbrevSection() const override { return AbbrevSection; } const DWARFSection &getLocSection() const override { return LocSection; } + const DWARFSection &getLoclistsSection() const override { return LocListsSection; } StringRef getARangeSection() const override { return ARangeSection; } StringRef getDebugFrameSection() const override { return DebugFrameSection; } StringRef getEHFrameSection() const override { return EHFrameSection; } diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index 617b914ecce..bfcf799d230 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -144,24 +144,39 @@ void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { WithColor::error() << "failed to consume entire .debug_loc section\n"; } -Optional -DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) { +Optional +DWARFDebugLoclists::parseOneLocationList(DataExtractor Data, unsigned *Offset) { LocationList LL; LL.Offset = *Offset; // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. while (auto Kind = static_cast(Data.getU8(Offset))) { - if (Kind != dwarf::DW_LLE_startx_length) { + + Entry E; + E.Kind = Kind; + switch (Kind) { + case dwarf::DW_LLE_startx_length: + E.Value0 = Data.getULEB128(Offset); + E.Value1 = Data.getU32(Offset); + break; + case dwarf::DW_LLE_start_length: + E.Value0 = Data.getAddress(Offset); + E.Value1 = Data.getULEB128(Offset); + break; + case dwarf::DW_LLE_offset_pair: + E.Value0 = Data.getULEB128(Offset); + E.Value1 = Data.getULEB128(Offset); + break; + case dwarf::DW_LLE_base_address: + E.Value0 = Data.getAddress(Offset); + break; + default: WithColor::error() << "dumping support for LLE of kind " << (int)Kind << " not implemented\n"; return None; } - Entry E; - E.Start = Data.getULEB128(Offset); - E.Length = Data.getU32(Offset); - unsigned Bytes = Data.getU16(Offset); // A single location description describing the location of the object... StringRef str = Data.getData().substr(*Offset, Bytes); @@ -174,7 +189,7 @@ DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) { return LL; } -void DWARFDebugLocDWO::parse(DataExtractor data) { +void DWARFDebugLoclists::parse(DataExtractor data) { IsLittleEndian = data.isLittleEndian(); AddressSize = data.getAddressSize(); @@ -187,8 +202,8 @@ void DWARFDebugLocDWO::parse(DataExtractor data) { } } -DWARFDebugLocDWO::LocationList const * -DWARFDebugLocDWO::getLocationListAtOffset(uint64_t Offset) const { +DWARFDebugLoclists::LocationList const * +DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const { auto It = std::lower_bound( Locations.begin(), Locations.end(), Offset, [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); @@ -197,23 +212,46 @@ DWARFDebugLocDWO::getLocationListAtOffset(uint64_t Offset) const { return nullptr; } -void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, - unsigned AddressSize, - const MCRegisterInfo *MRI, - unsigned Indent) const { +void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr, + bool IsLittleEndian, + unsigned AddressSize, + const MCRegisterInfo *MRI, + unsigned Indent) const { for (const Entry &E : Entries) { - OS << '\n'; - OS.indent(Indent); - OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): "; + switch (E.Kind) { + case dwarf::DW_LLE_startx_length: + OS << '\n'; + OS.indent(Indent); + OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): "; + break; + case dwarf::DW_LLE_start_length: + OS << '\n'; + OS.indent(Indent); + OS << format("[0x%8.8x, 0x%8.8x): ", E.Value0, E.Value0 + E.Value1); + break; + case dwarf::DW_LLE_offset_pair: + OS << '\n'; + OS.indent(Indent); + OS << format("[0x%8.8x, 0x%8.8x): ", BaseAddr + E.Value0, + BaseAddr + E.Value1); + break; + case dwarf::DW_LLE_base_address: + BaseAddr = E.Value0; + break; + default: + llvm_unreachable("unreachable locations list kind"); + } + dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); } } -void DWARFDebugLocDWO::dump(raw_ostream &OS, const MCRegisterInfo *MRI, - Optional Offset) const { +void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr, + const MCRegisterInfo *MRI, + Optional Offset) const { auto DumpLocationList = [&](const LocationList &L) { OS << format("0x%8.8x: ", L.Offset); - L.dump(OS, IsLittleEndian, AddressSize, MRI, /*Indent=*/12); + L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, /*Indent=*/12); OS << "\n\n"; }; diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp index b4413653290..76430b41f18 100644 --- a/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -102,7 +102,7 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, FormValue.dump(OS, DumpOpts); if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { uint32_t Offset = *FormValue.getAsSectionOffset(); - if (!U->isDWOUnit()) { + if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) { DWARFDebugLoc DebugLoc; DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(), Obj.getAddressSize()); @@ -115,11 +115,23 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, Indent); } else OS << "error extracting location list."; - } else { - DataExtractor Data(U->getLocSectionData(), Ctx.isLittleEndian(), 0); - auto LL = DWARFDebugLocDWO::parseOneLocationList(Data, &Offset); + return; + } + + StringRef LoclistsSectionData = + U->isDWOUnit() ? U->getLocSectionData() : Obj.getLoclistsSection().Data; + if (!LoclistsSectionData.empty()) { + DataExtractor Data(LoclistsSectionData, Ctx.isLittleEndian(), + Obj.getAddressSize()); + auto LL = DWARFDebugLoclists::parseOneLocationList(Data, &Offset); + + uint64_t BaseAddr = 0; + if (Optional BA = U->getBaseAddress()) + BaseAddr = BA->Address; + if (LL) - LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent); + LL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, + Indent); else OS << "error extracting location list."; } diff --git a/test/DebugInfo/X86/dwarfdump-debug-loclists.test b/test/DebugInfo/X86/dwarfdump-debug-loclists.test new file mode 100644 index 00000000000..de8cb15596a --- /dev/null +++ b/test/DebugInfo/X86/dwarfdump-debug-loclists.test @@ -0,0 +1,168 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o %t.o +# RUN: llvm-dwarfdump -v %t.o | FileCheck %s + +# CHECK: .debug_info +# CHECK: DW_AT_name{{.*}}"stub" +# CHECK: DW_AT_location [DW_FORM_sec_offset] (0x0000000c +# CHECK-NEXT: [0x00000010, 0x00000020): DW_OP_breg5 RDI+0 +# CHECK-NEXT: [0x00000530, 0x00000540): DW_OP_breg6 RBP-8, DW_OP_deref +# CHECK-NEXT: [0x00000700, 0x00000710): DW_OP_breg5 RDI+0 + +# CHECK: .debug_loclists contents: +# CHECK-NEXT: 0x00000000: locations list header: length = 0x00000031, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +# CHECK-NEXT: 0x00000000: +# CHECK-NEXT: [0x00000000, 0x00000010): DW_OP_breg5 RDI+0 +# CHECK-NEXT: [0x00000530, 0x00000540): DW_OP_breg6 RBP-8, DW_OP_deref +# CHECK-NEXT: [0x00000700, 0x00000710): DW_OP_breg5 RDI+0 + +.section .debug_str,"MS",@progbits,1 + .asciz "stub" + +.section .debug_str_offsets,"",@progbits + .long 68 + .short 5 + .short 0 +.Lstr_offsets_base0: + .zero 64 + +.section .debug_loclists,"",@progbits + .long .Ldebug_loclist_table_end0-.Ldebug_loclist_table_start0 +.Ldebug_loclist_table_start0: + .short 5 # Version. + .byte 8 # Address size. + .byte 0 # Segmen selector size. + .long 0 # Offset entry count. +.Lloclists_table_base0: +.Ldebug_loc0: + .byte 4 # DW_LLE_offset_pair + .uleb128 0x0 # starting offset + .uleb128 0x10 # ending offset + .short 2 # Loc expr size + .byte 117 # DW_OP_breg5 + .byte 0 # 0 + + .byte 6 # DW_LLE_base_address + .quad 0x500 # Some address + .short 0 # Loc expr size = 0. + + .byte 4 # DW_LLE_offset_pair + .uleb128 0x30 # starting offset + .uleb128 0x40 # ending offset + .short 3 # Loc expr size + .byte 118 # DW_OP_breg6 + .byte 120 # -8 + .byte 6 # DW_OP_deref + + .byte 8 # DW_LLE_start_length + .quad 0x700 # Some address + .uleb128 0x10 # length + .short 2 # Loc expr size + .byte 117 # DW_OP_breg5 + .byte 0 # 0 + + .byte 0 # DW_LLE_end_of_list + +.Ldebug_loclist_table_end0: + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .ascii "\214\001" # DW_AT_loclists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long 70 # Length of Unit + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0xef DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 4 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .quad 0x10 # DW_AT_low_pc + .long 0 # DW_AT_high_pc + .long .Lloclists_table_base0 # DW_AT_loclists_base + .byte 2 # Abbrev [2] 0x2a:0x20 DW_TAG_subprogram + .quad 0 # DW_AT_low_pc + .long 0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 11 # DW_AT_linkage_name + .byte 12 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + # DW_AT_external + .byte 3 # Abbrev [3] 0x40:0xb DW_TAG_variable + .long .Ldebug_loc0 # DW_AT_location + .byte 7 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + .long 76 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + +.section .debug_line,"",@progbits +.Lline_table_start0: +