Index: lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp =================================================================== --- lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp +++ lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp @@ -1,13 +1,15 @@ +enum E { e1, e2, e3 }; +enum class EC { e1, e2, e3 }; + struct A { int i; long l; float f; double d; + E e; + EC ec; }; -enum E { e1, e2, e3 }; -enum class EC { e1, e2, e3 }; - -extern constexpr A a{42, 47l, 4.2f, 4.7}; +extern constexpr A a{42, 47l, 4.2f, 4.7, e1, EC::e3}; extern constexpr E e(e2); extern constexpr EC ec(EC::e2); Index: lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp =================================================================== --- lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp +++ lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp @@ -11,11 +11,19 @@ namespace ns { struct A { int i = 147; + ::A getA(); A(); }; A::A() = default; + +::A A::getA() { + ::A a; + a.i = i - 1; + return a; } +} // namespace ns + int foo(A *a) { return a->f(); } Index: lit/SymbolFile/DWARF/debug-types-basic.test =================================================================== --- lit/SymbolFile/DWARF/debug-types-basic.test +++ lit/SymbolFile/DWARF/debug-types-basic.test @@ -19,6 +19,8 @@ # CHECK-NEXT: long l; # CHECK-NEXT: float f; # CHECK-NEXT: double d; +# CHECK-NEXT: E e; +# CHECK-NEXT: EC ec; # CHECK-NEXT: } type lookup E @@ -44,3 +46,9 @@ print (EC) 1 # CHECK-LABEL: print (EC) 1 # CHECK: (EC) $1 = e2 + +target variable a e ec +# CHECK-LABEL: target variable a e ec +# CHECK: (const A) a = (i = 42, l = 47, f = 4.{{[12].*}}, d = 4.{{[67].*}}, e = e1, ec = e3) +# CHECK: (const E) e = e2 +# CHECK: (const EC) ec = e2 Index: lit/SymbolFile/DWARF/debug-types-expressions.test =================================================================== --- lit/SymbolFile/DWARF/debug-types-expressions.test +++ lit/SymbolFile/DWARF/debug-types-expressions.test @@ -19,6 +19,13 @@ # CHECK-LABEL: frame variable a # CHECK: (B *) a = +frame variable *a +# CHECK-LABEL: frame variable *a +# CHECK: (B) *a = { +# CHECK-NEXT: A = (i = 47) +# CHECK-NEXT: j = 42 +# CHECK-NEXT: } + print a->f() # CHECK-LABEL: print a->f() # CHECK: (int) $0 = 47 @@ -26,3 +33,11 @@ print ns::A() # CHECK-LABEL: print ns::A() # CHECK: (ns::A) $1 = (i = 147) + +print ns::A().i + a->i +# CHECK-LABEL: print ns::A().i + a->i +# CHECK: (int) $2 = 194 + +print ns::A().getA() +# CHECK-LABEL: ns::A().getA() +# CHECK: (A) $3 = (i = 146) Index: lit/SymbolFile/DWARF/debug-types-missing-signature.test =================================================================== --- /dev/null +++ lit/SymbolFile/DWARF/debug-types-missing-signature.test @@ -0,0 +1,26 @@ +Create a dangling DW_AT_signature reference by stripping the debug_types +section, and make sure lldb does something reasonable. +RUN: %clangxx -target x86_64-pc-linux %S/Inputs/debug-types-basic.cpp \ +RUN: -g -gdwarf-4 -fdebug-types-section -c -o %t.o +RUN: llvm-objcopy --remove-section=.debug_types %t.o %t + + +RUN: %lldb %t -b -o "type lookup A" | FileCheck --check-prefix=LOOKUPA %s +LOOKUPA: no type was found matching 'A' + +RUN: %lldb %t -b -o "type lookup E" | FileCheck --check-prefix=LOOKUPE %s +LOOKUPE: no type was found matching 'E' + +RUN: %lldb %t -b -o "type lookup EC" | FileCheck --check-prefix=LOOKUPEC %s +LOOKUPEC: no type was found matching 'EC' + +RUN: %lldb %t -b -o "print (E) 1" 2>&1 | FileCheck --check-prefix=PRINTE %s +PRINTE: use of undeclared identifier 'E' + +RUN: %lldb %t -b -o "print (EC) 1" 2>&1 | FileCheck --check-prefix=PRINTEC %s +PRINTEC: use of undeclared identifier 'EC' + +RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s +VARS: (const (anonymous struct)) a = {} +VARS: (const (anonymous enum)) e = 1 +VARS: (const (anonymous enum)) ec = 1 Index: lit/SymbolFile/DWARF/debug-types-signature-loop.s =================================================================== --- /dev/null +++ lit/SymbolFile/DWARF/debug-types-signature-loop.s @@ -0,0 +1,115 @@ +# REQUIRES: lld + +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux -o %t.o %s +# RUN: ld.lld %t.o -o %t +# RUN: %lldb %t -o "target variable e" -b | FileCheck %s + +# CHECK: e = + + .type e,@object # @e + .section .rodata,"a",@progbits + .globl e + .p2align 2 +e: + .long 0 # 0x0 + .size e, 4 + +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "Hand-written DWARF" +.Linfo_string1: + .asciz "a.cpp" +.Linfo_string3: + .asciz "e" +.Linfo_string4: + .asciz "unsigned int" +.Linfo_string5: + .asciz "e1" +.Linfo_string6: + .asciz "E" + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 65 # DW_TAG_type_unit + .byte 1 # DW_CHILDREN_yes + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 4 # DW_TAG_enumeration_type + .byte 0 # DW_CHILDREN_no + .byte 60 # DW_AT_declaration + .byte 25 # DW_FORM_flag_present + .byte 105 # DW_AT_signature + .byte 32 # DW_FORM_ref_sig8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Ltu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 2 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad 5390450678491038984 # Type Signature + .long .LE-.Ltu_begin0 # Type DIE Offset + .byte 1 # Abbrev [1] 0x18:0x1d DW_TAG_type_unit + .short 4 # DW_AT_language +.LE: + .byte 8 # Abbrev [8] 0x23:0xd DW_TAG_enumeration_type + # DW_AT_declaration + .quad 5390450678491038984 # DW_AT_signature +.Lbase: + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + +.Lcu_begin0: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 5 # Abbrev [5] 0xc:0x2c DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 4 # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .byte 6 # Abbrev [6] 0x1e:0xb DW_TAG_variable + .long .Linfo_string3 # DW_AT_name + .long .LE_sig-.Lcu_begin0 # DW_AT_type + .byte 9 # DW_AT_location + .byte 3 + .quad e +.LE_sig: + .byte 8 # Abbrev [8] 0x2e:0x9 DW_TAG_enumeration_type + # DW_AT_declaration + .quad 5390450678491038984 # DW_AT_signature + .byte 0 # End Of Children Mark +.Ldebug_info_end1: Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -237,7 +237,6 @@ AccessType accessibility = eAccessNone; if (!die) return nullptr; - SymbolFileDWARF *dwarf = die.GetDWARF(); if (log) { DWARFDIE context_die; @@ -252,11 +251,27 @@ die.GetTagAsCString(), die.GetName()); } + Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); if (type_ptr == DIE_IS_BEING_PARSED) return nullptr; if (type_ptr) return type_ptr->shared_from_this(); + // Set a bit that lets us know that we are currently parsing this + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + + if (DWARFDIE signature_die = + die.GetAttributeValueAsReferenceDIE(DW_AT_signature)) { + if (TypeSP type_sp = + ParseTypeFromDWARF(sc, signature_die, log, type_is_new_ptr)) { + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + if (clang::DeclContext *decl_ctx = + GetCachedClangDeclContextForDIE(signature_die)) + LinkDeclContextToDIE(decl_ctx, die); + return type_sp; + } + return nullptr; + } TypeList *type_list = dwarf->GetTypeList(); if (type_is_new_ptr) @@ -289,9 +304,6 @@ case DW_TAG_restrict_type: case DW_TAG_volatile_type: case DW_TAG_unspecified_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; - const size_t num_attributes = die.GetAttributes(attributes); uint32_t encoding = 0; DWARFFormValue encoding_uid; @@ -540,9 +552,6 @@ case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; - LanguageType class_language = eLanguageTypeUnknown; bool is_complete_objc_class = false; size_t calling_convention = llvm::dwarf::CallingConvention::DW_CC_normal; @@ -974,9 +983,6 @@ } break; case DW_TAG_enumeration_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; - bool is_scoped = false; DWARFFormValue encoding_form; @@ -1136,9 +1142,6 @@ case DW_TAG_inlined_subroutine: case DW_TAG_subprogram: case DW_TAG_subroutine_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; - DWARFFormValue type_die_form; bool is_variadic = false; bool is_inline = false; @@ -1658,9 +1661,6 @@ } break; case DW_TAG_array_type: { - // Set a bit that lets us know that we are currently parsing this - dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; - DWARFFormValue type_die_form; uint32_t byte_stride = 0; uint32_t bit_stride = 0; Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -13,6 +13,7 @@ #include #include "DWARFDIE.h" +#include "DWARFTypeUnit.h" #include "DWARFUnit.h" #include "SymbolFileDWARF.h" #include "lldb/Core/STLUtils.h" @@ -46,6 +47,7 @@ DWARFUnit *GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset); DWARFUnit *GetUnit(const DIERef &die_ref); + DWARFTypeUnit *GetTypeUnitForHash(uint64_t hash); DWARFDIE GetDIEForDIEOffset(DIERef::Section section, dw_offset_t die_offset); DWARFDIE GetDIE(const DIERef &die_ref); @@ -69,11 +71,15 @@ std::unique_ptr m_cu_aranges_up; // A quick address to compile unit table + std::vector> m_type_hash_to_unit_index; + private: // All parsing needs to be done partially any managed by this class as // accessors are called. void ParseUnitHeadersIfNeeded(); + void ParseUnitsFor(DIERef::Section section); + uint32_t FindUnitIndex(DIERef::Section section, dw_offset_t offset); DISALLOW_COPY_AND_ASSIGN(DWARFDebugInfo); Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -15,6 +15,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" +#include "llvm/Support/Casting.h" #include "DWARFCompileUnit.h" #include "DWARFContext.h" @@ -74,12 +75,14 @@ return *m_cu_aranges_up; } -void Parse(SymbolFileDWARF *dwarf, const DWARFDataExtractor &data, - DIERef::Section section, std::vector &units) { +void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { + DWARFDataExtractor data = section == DIERef::Section::DebugTypes + ? m_context.getOrLoadDebugTypesData() + : m_context.getOrLoadDebugInfoData(); lldb::offset_t offset = 0; while (data.ValidOffset(offset)) { - llvm::Expected unit_sp = - DWARFUnit::extract(dwarf, units.size(), data, section, &offset); + llvm::Expected unit_sp = DWARFUnit::extract( + m_dwarf2Data, m_units.size(), data, section, &offset); if (!unit_sp) { // FIXME: Propagate this error up. @@ -89,10 +92,13 @@ // If it didn't return an error, then it should be returning a valid Unit. assert(*unit_sp); - - units.push_back(*unit_sp); - + m_units.push_back(*unit_sp); offset = (*unit_sp)->GetNextUnitOffset(); + + if (auto *type_unit = llvm::dyn_cast(unit_sp->get())) { + m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(), + unit_sp.get()->GetID()); + } } } @@ -102,10 +108,9 @@ if (!m_dwarf2Data) return; - Parse(m_dwarf2Data, m_context.getOrLoadDebugInfoData(), - DIERef::Section::DebugInfo, m_units); - Parse(m_dwarf2Data, m_context.getOrLoadDebugTypesData(), - DIERef::Section::DebugTypes, m_units); + ParseUnitsFor(DIERef::Section::DebugInfo); + ParseUnitsFor(DIERef::Section::DebugTypes); + llvm::sort(m_type_hash_to_unit_index, llvm::less_first()); } size_t DWARFDebugInfo::GetNumUnits() { @@ -169,6 +174,14 @@ return result; } +DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) { + auto pos = llvm::lower_bound(m_type_hash_to_unit_index, + std::make_pair(hash, 0u), llvm::less_first()); + if (pos == m_type_hash_to_unit_index.end() || pos->first != hash) + return nullptr; + return llvm::cast(GetUnitAtIndex(pos->second)); +} + DWARFDIE DWARFDebugInfo::GetDIEForDIEOffset(DIERef::Section section, dw_offset_t die_offset) { Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -585,6 +585,14 @@ return ref_cu->GetDIE(value); } + case DW_FORM_ref_sig8: { + DWARFTypeUnit *tu = + m_unit->GetSymbolFileDWARF()->DebugInfo()->GetTypeUnitForHash(value); + if (!tu) + return {}; + return tu->GetDIE(tu->GetTypeOffset()); + } + default: return {}; } Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -18,6 +18,14 @@ void Dump(lldb_private::Stream *s) const override; + uint64_t GetTypeHash() { return m_header.GetTypeHash(); } + + dw_offset_t GetTypeOffset() { return GetOffset() + m_header.GetTypeOffset(); } + + static bool classof(const DWARFUnit *unit) { + return unit->GetUnitType() == DW_UT_type; + } + private: DWARFTypeUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp @@ -14,7 +14,6 @@ using namespace lldb; using namespace lldb_private; - void DWARFTypeUnit::Dump(Stream *s) const { s->Printf("0x%8.8x: Type Unit: length = 0x%8.8x, version = 0x%4.4x, " "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at " Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -41,6 +41,10 @@ dw_offset_t m_abbr_offset = 0; uint8_t m_unit_type = 0; uint8_t m_addr_size = 0; + + uint64_t m_type_hash = 0; + uint32_t m_type_offset = 0; + uint64_t m_dwo_id = 0; DWARFUnitHeader() = default; @@ -52,6 +56,8 @@ dw_offset_t GetLength() const { return m_length; } dw_offset_t GetAbbrOffset() const { return m_abbr_offset; } uint8_t GetUnitType() const { return m_unit_type; } + uint64_t GetTypeHash() const { return m_type_hash; } + dw_offset_t GetTypeOffset() const { return m_type_offset; } bool IsTypeUnit() const { return m_unit_type == DW_UT_type || m_unit_type == DW_UT_split_type; } @@ -205,6 +211,8 @@ DIERef::Section GetDebugSection() const { return m_section; } + uint8_t GetUnitType() const { return m_header.GetUnitType(); } + protected: DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -714,9 +714,16 @@ section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile; } + if (header.IsTypeUnit()) { + header.m_type_hash = data.GetU64(offset_ptr); + header.m_type_offset = data.GetDWARFOffset(offset_ptr); + } + bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1); bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version); bool addr_size_OK = (header.m_addr_size == 4) || (header.m_addr_size == 8); + bool type_offset_OK = + !header.IsTypeUnit() || (header.m_type_offset <= header.GetLength()); if (!length_OK) return llvm::make_error( @@ -727,6 +734,9 @@ if (!addr_size_OK) return llvm::make_error( "Invalid unit address size"); + if (!type_offset_OK) + return llvm::make_error( + "Type offset out of range"); return header; }