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: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -253,6 +253,19 @@ Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); TypeList *type_list = dwarf->GetTypeList(); if (type_ptr == NULL) { + + if (DWARFDIE signature_die = die.GetAttributeValueAsReferenceDIE(DW_AT_signature)) { + type_sp = ParseTypeFromDWARF(sc, signature_die, log, type_is_new_ptr); + if (type_sp) { + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + clang::DeclContext *decl_ctx = + GetCachedClangDeclContextForDIE(signature_die); + if (decl_ctx) + LinkDeclContextToDIE(decl_ctx, die); + return type_sp; + } + } + if (type_is_new_ptr) *type_is_new_ptr = true; 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; }