labath created this revision.
labath added reviewers: JDevlieghere, clayborg, aprantl.
Herald added a subscriber: mgorny.

This patch introduces the DWARFTypeUnit class, and teaches lldb to parse
type units out of the debug_types section.

The most important piece of functionality - resolving DW_AT_signatures
to connect type forward declarations to their definitions - is not
implemented here, but even without that, a lot of functionality becomes
available. I've added tests for the commands that start to work after
this patch.

The changes in this patch were greatly inspired by D61505 
<https://reviews.llvm.org/D61505>, which in turn took
over changes from D32167 <https://reviews.llvm.org/D32167>.


https://reviews.llvm.org/D62008

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/lit.local.cfg
  source/Plugins/SymbolFile/DWARF/CMakeLists.txt
  source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
  source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.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
@@ -172,6 +172,10 @@
 protected:
   DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid);
 
+  llvm::Error ExtractHeader(SymbolFileDWARF *dwarf,
+                            const lldb_private::DWARFDataExtractor &data,
+                            lldb::offset_t *offset_ptr);
+
   SymbolFileDWARF *m_dwarf = nullptr;
   std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file;
   const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr;
Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/Timer.h"
+#include "llvm/Object/Error.h"
 
 #include "DWARFDebugAranges.h"
 #include "DWARFDebugInfo.h"
@@ -790,3 +791,54 @@
   return *m_func_aranges_up;
 }
 
+llvm::Error DWARFUnit::ExtractHeader(SymbolFileDWARF *dwarf,
+                                     const DWARFDataExtractor &data,
+                                     lldb::offset_t *offset_ptr) {
+  m_offset = *offset_ptr;
+
+  dw_offset_t abbr_offset;
+  const DWARFDebugAbbrev *abbr = dwarf->DebugAbbrev();
+  if (!abbr)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "No debug_abbrev data");
+
+  m_length = data.GetDWARFInitialLength(offset_ptr);
+  m_version = data.GetU16(offset_ptr);
+
+  if (m_version == 5) {
+    m_unit_type = data.GetU8(offset_ptr);
+    m_addr_size = data.GetU8(offset_ptr);
+    abbr_offset = data.GetDWARFOffset(offset_ptr);
+
+    if (m_unit_type == llvm::dwarf::DW_UT_skeleton)
+      m_dwo_id = data.GetU64(offset_ptr);
+  } else {
+    abbr_offset = data.GetDWARFOffset(offset_ptr);
+    m_addr_size = data.GetU8(offset_ptr);
+  }
+
+  bool length_OK = data.ValidOffset(GetNextUnitOffset() - 1);
+  bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+  bool abbr_offset_OK = dwarf->get_debug_abbrev_data().ValidOffset(abbr_offset);
+  bool addr_size_OK = (m_addr_size == 4) || (m_addr_size == 8);
+
+  if (!length_OK)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "Invalid compile unit length");
+  if (!version_OK)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "Unsupported compile unit version");
+  if (!abbr_offset_OK)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "Abbreviation offset for compile unit is not valid");
+  if (!addr_size_OK)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "Invalid compile unit address size");
+
+  m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset);
+  if (!m_abbrevs)
+    return llvm::make_error<llvm::object::GenericBinaryError>(
+        "No abbrev exists at the specified offset.");
+
+  return llvm::Error::success();
+}
Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h
@@ -0,0 +1,45 @@
+//===-- DWARFTypeUnit.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFTypeUnit_h_
+#define SymbolFileDWARF_DWARFTypeUnit_h_
+
+#include "DWARFUnit.h"
+#include "llvm/Support/Error.h"
+
+class DWARFTypeUnit : public DWARFUnit {
+public:
+  static llvm::Expected<DWARFUnitSP>
+  extract(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid,
+          const lldb_private::DWARFDataExtractor &debug_info,
+          lldb::offset_t *offset_ptr);
+  void Dump(lldb_private::Stream *s) const override;
+
+  /// Get the data that contains the DIE information for this unit.
+  ///
+  /// \return
+  ///   The correct data (.debug_types for DWARF 4 and earlier, and
+  ///   .debug_info for DWARF 5 and later) for the DIE information in
+  ///   this unit.
+  const lldb_private::DWARFDataExtractor &GetData() const override;
+
+  /// Get the size in bytes of the header.
+  ///
+  /// \return
+  ///     Byte size of the type unit header
+  uint32_t GetHeaderByteSize() const override { return 23; }
+
+  DIERef::Section GetDebugSection() const override {
+    return DIERef::Section::DebugTypes;
+  }
+
+private:
+  DWARFTypeUnit(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid);
+};
+
+#endif // SymbolFileDWARF_DWARFTypeUnit_h_
Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp
@@ -0,0 +1,45 @@
+//===-- DWARFTypeUnit.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFTypeUnit.h"
+
+#include "SymbolFileDWARF.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DWARFTypeUnit::DWARFTypeUnit(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid)
+    : DWARFUnit(dwarf2Data, uid) {}
+
+llvm::Expected<DWARFUnitSP>
+DWARFTypeUnit::extract(SymbolFileDWARF *dwarf2Data, user_id_t uid,
+                       const DWARFDataExtractor &debug_info,
+                       lldb::offset_t *offset_ptr) {
+  assert(debug_info.ValidOffset(*offset_ptr));
+
+  // std::make_shared would require the ctor to be public.
+  std::shared_ptr<DWARFTypeUnit> tu_sp(new DWARFTypeUnit(dwarf2Data, uid));
+
+  if (llvm::Error E = tu_sp->ExtractHeader(dwarf2Data, debug_info, offset_ptr))
+    return std::move(E);
+
+  return tu_sp;
+}
+
+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 "
+            "{0x%8.8x})\n",
+            m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size,
+            GetNextUnitOffset());
+}
+
+const lldb_private::DWARFDataExtractor &DWARFTypeUnit::GetData() const {
+  return m_dwarf->get_debug_types_data();
+}
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -22,6 +22,7 @@
 #include "DWARFDebugInfo.h"
 #include "DWARFDebugInfoEntry.h"
 #include "DWARFFormValue.h"
+#include "DWARFTypeUnit.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -73,34 +74,41 @@
   return *m_cu_aranges_up;
 }
 
-void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
-  if (!m_units.empty())
-    return;
-  if (!m_dwarf2Data)
-    return;
-
+template <typename Unit>
+void Parse(SymbolFileDWARF *dwarf, const DWARFDataExtractor &data,
+           std::vector<DWARFUnitSP> &units) {
   lldb::offset_t offset = 0;
-  const auto &debug_info_data = m_dwarf2Data->get_debug_info_data();
+  while (data.ValidOffset(offset)) {
+    llvm::Expected<DWARFUnitSP> unit_sp =
+        Unit::extract(dwarf, units.size(), data, &offset);
 
-  while (debug_info_data.ValidOffset(offset)) {
-    llvm::Expected<DWARFUnitSP> cu_sp = DWARFCompileUnit::extract(
-        m_dwarf2Data, m_units.size(), debug_info_data, &offset);
-
-    if (!cu_sp) {
+    if (!unit_sp) {
       // FIXME: Propagate this error up.
-      llvm::consumeError(cu_sp.takeError());
+      llvm::consumeError(unit_sp.takeError());
       return;
     }
 
     // If it didn't return an error, then it should be returning a valid Unit.
-    assert(*cu_sp);
+    assert(*unit_sp);
 
-    m_units.push_back(*cu_sp);
+    units.push_back(*unit_sp);
 
-    offset = (*cu_sp)->GetNextUnitOffset();
+    offset = (*unit_sp)->GetNextUnitOffset();
   }
 }
 
+void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
+  if (!m_units.empty())
+    return;
+  if (!m_dwarf2Data)
+    return;
+
+  Parse<DWARFCompileUnit>(m_dwarf2Data, m_dwarf2Data->get_debug_info_data(),
+                          m_units);
+  Parse<DWARFTypeUnit>(m_dwarf2Data, m_dwarf2Data->get_debug_types_data(),
+                       m_units);
+}
+
 size_t DWARFDebugInfo::GetNumUnits() {
   ParseUnitHeadersIfNeeded();
   return m_units.size();
Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -10,7 +10,6 @@
 
 #include "SymbolFileDWARF.h"
 #include "lldb/Utility/Stream.h"
-#include "llvm/Object/Error.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -29,52 +28,8 @@
   std::shared_ptr<DWARFCompileUnit> cu_sp(
       new DWARFCompileUnit(dwarf2Data, uid));
 
-  cu_sp->m_offset = *offset_ptr;
-
-  dw_offset_t abbr_offset;
-  const DWARFDebugAbbrev *abbr = dwarf2Data->DebugAbbrev();
-  if (!abbr)
-    return llvm::make_error<llvm::object::GenericBinaryError>(
-        "No debug_abbrev data");
-
-  cu_sp->m_length = debug_info.GetDWARFInitialLength(offset_ptr);
-  cu_sp->m_version = debug_info.GetU16(offset_ptr);
-
-  if (cu_sp->m_version == 5) {
-    cu_sp->m_unit_type = debug_info.GetU8(offset_ptr);
-    cu_sp->m_addr_size = debug_info.GetU8(offset_ptr);
-    abbr_offset = debug_info.GetDWARFOffset(offset_ptr);
-
-    if (cu_sp->m_unit_type == llvm::dwarf::DW_UT_skeleton)
-      cu_sp->m_dwo_id = debug_info.GetU64(offset_ptr);
-  } else {
-    abbr_offset = debug_info.GetDWARFOffset(offset_ptr);
-    cu_sp->m_addr_size = debug_info.GetU8(offset_ptr);
-  }
-
-  bool length_OK = debug_info.ValidOffset(cu_sp->GetNextUnitOffset() - 1);
-  bool version_OK = SymbolFileDWARF::SupportedVersion(cu_sp->m_version);
-  bool abbr_offset_OK =
-      dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset);
-  bool addr_size_OK = (cu_sp->m_addr_size == 4) || (cu_sp->m_addr_size == 8);
-
-  if (!length_OK)
-    return llvm::make_error<llvm::object::GenericBinaryError>(
-        "Invalid compile unit length");
-  if (!version_OK)
-    return llvm::make_error<llvm::object::GenericBinaryError>(
-        "Unsupported compile unit version");
-  if (!abbr_offset_OK)
-    return llvm::make_error<llvm::object::GenericBinaryError>(
-        "Abbreviation offset for compile unit is not valid");
-  if (!addr_size_OK)
-    return llvm::make_error<llvm::object::GenericBinaryError>(
-        "Invalid compile unit address size");
-
-  cu_sp->m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset);
-  if (!cu_sp->m_abbrevs)
-    return llvm::make_error<llvm::object::GenericBinaryError>(
-        "No abbrev exists at the specified offset.");
+  if (llvm::Error E = cu_sp->ExtractHeader(dwarf2Data, debug_info, offset_ptr))
+    return std::move(E);
 
   return cu_sp;
 }
Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt
===================================================================
--- source/Plugins/SymbolFile/DWARF/CMakeLists.txt
+++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt
@@ -22,6 +22,7 @@
   DWARFDIE.cpp
   DWARFFormValue.cpp
   DWARFIndex.cpp
+  DWARFTypeUnit.cpp
   DWARFUnit.cpp
   HashedNameToDIE.cpp
   LogChannelDWARF.cpp
Index: lit/SymbolFile/DWARF/lit.local.cfg
===================================================================
--- lit/SymbolFile/DWARF/lit.local.cfg
+++ lit/SymbolFile/DWARF/lit.local.cfg
@@ -1 +1 @@
-config.suffixes = ['.cpp', '.s']
+config.suffixes = ['.cpp', '.s', '.test']
Index: lit/SymbolFile/DWARF/debug-types-expressions.test
===================================================================
--- /dev/null
+++ lit/SymbolFile/DWARF/debug-types-expressions.test
@@ -0,0 +1,22 @@
+# UNSUPPORTED: system-darwin, system-windows
+
+# RUN: %clangxx %S/Inputs/debug-types-expressions.cpp \
+# RUN:   -g -fdebug-types-section -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+breakpoint set -n foo
+process launch
+
+# CHECK: Process {{.*}} stopped
+
+frame variable a
+# CHECK-LABEL: frame variable a
+# CHECK: (B *) a =
+
+print a->f()
+# CHECK-LABEL: print a->f()
+# CHECK: (int) $0 = 47
+
+print ns::A()
+# CHECK-LABEL: print ns::A()
+# CHECK: (ns::A) $1 = (i = 147)
Index: lit/SymbolFile/DWARF/debug-types-basic.test
===================================================================
--- /dev/null
+++ lit/SymbolFile/DWARF/debug-types-basic.test
@@ -0,0 +1,39 @@
+# REQUIRES: lld
+
+# RUN: %clangxx -target x86_64-pc-linux %S/Inputs/debug-types-basic.cpp \
+# RUN:   -g -fdebug-types-section -c -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: %lldb %t -s %s -o exit | FileCheck %s
+
+type lookup A
+# CHECK-LABEL: type lookup A
+# CHECK:      struct A {
+# CHECK-NEXT:   int i;
+# CHECK-NEXT:   long l;
+# CHECK-NEXT:   float f;
+# CHECK-NEXT:   double d;
+# CHECK-NEXT: }
+
+type lookup E
+# CHECK-LABEL: type lookup E
+# CHECK:      enum E {
+# CHECK-NEXT:   e1,
+# CHECK-NEXT:   e2,
+# CHECK-NEXT:   e3
+# CHECK-NEXT: }
+
+type lookup EC
+# CHECK-LABEL: type lookup EC
+# CHECK:      enum class EC {
+# CHECK-NEXT:   e1,
+# CHECK-NEXT:   e2,
+# CHECK-NEXT:   e3
+# CHECK-NEXT: }
+
+print (E) 1
+# CHECK-LABEL: print (E) 1
+# CHECK: (E) $0 = e2
+
+print (EC) 1
+# CHECK-LABEL: print (EC) 1
+# CHECK: (EC) $1 = e2
Index: lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp
===================================================================
--- /dev/null
+++ lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp
@@ -0,0 +1,25 @@
+struct A {
+  int i = 47;
+  int f() { return i; }
+  virtual ~A() = default;
+};
+
+struct B: public A {
+  int j = 42;
+};
+
+namespace ns {
+struct A {
+  int i = 147;
+  A();
+};
+A::A() = default;
+}
+
+int foo(A *a) {
+  return a->f();
+}
+
+int main() {
+  return foo(new B);
+}
Index: lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp
===================================================================
--- /dev/null
+++ lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp
@@ -0,0 +1,13 @@
+struct A {
+  int i;
+  long l;
+  float f;
+  double d;
+};
+
+enum E { e1, e2, e3 };
+enum class EC { e1, e2, e3 };
+
+extern constexpr A a{42, 47l, 4.2f, 4.7};
+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