labath created this revision.
labath added reviewers: clayborg, JDevlieghere, aprantl.
Herald added a subscriber: mgrang.
Herald added a reviewer: alexshap.
labath added a subscriber: jankratochvil.

This patch implements the main feature of type units. When completing a
type, if we encounter a DW_AT_signature attribute, we use it's value to
lookup the complete definition of the type in the relevant type unit.

To enable this lookup, we build up a map of all type units in a symbol
file when parsing the units. Then we consult this map when resolving the
DW_AT_signature attribute.

I include add a couple of tests which exercise the type lookup feature,
including one that ensure we do something reasonable in case we fail to
lookup the type.

A lot of the ideas in this patch have been taken from D32167 
<https://reviews.llvm.org/D32167> and D61505 <https://reviews.llvm.org/D61505>.


https://reviews.llvm.org/D62246

Files:
  lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp
  lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp
  lit/SymbolFile/DWARF/debug-types-basic.test
  lit/SymbolFile/DWARF/debug-types-expressions.test
  lit/SymbolFile/DWARF/debug-types-missing-signature.test
  source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
  source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
  source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
  source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
  source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp
  source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h
  source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
  source/Plugins/SymbolFile/DWARF/DWARFUnit.h

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<llvm::object::GenericBinaryError>(
@@ -727,6 +734,9 @@
   if (!addr_size_OK)
     return llvm::make_error<llvm::object::GenericBinaryError>(
         "Invalid unit address size");
+  if (!type_offset_OK)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "Type offset out of range");
 
   return header;
 }
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/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/DWARFDebugInfo.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -13,6 +13,7 @@
 #include <vector>
 
 #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<DWARFDebugAranges>
       m_cu_aranges_up; // A quick address to compile unit table
 
+  std::vector<std::pair<uint64_t, uint32_t>> 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<DWARFUnitSP> &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<DWARFUnitSP> unit_sp =
-        DWARFUnit::extract(dwarf, units.size(), data, section, &offset);
+    llvm::Expected<DWARFUnitSP> 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<DWARFTypeUnit>(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<DWARFTypeUnit>(GetUnitAtIndex(pos->second));
+}
+
 DWARFDIE
 DWARFDebugInfo::GetDIEForDIEOffset(DIERef::Section section,
                                    dw_offset_t die_offset) {
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: 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-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-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/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/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);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to