[Lldb-commits] [lldb] [lldb] Load embedded type summary section (#7859) (#8040) (PR #113743)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 25 16:25:36 PDT 2024


https://github.com/adrian-prantl created https://github.com/llvm/llvm-project/pull/113743

Add support for type summaries embedded into the binary.

These embedded summaries will typically be generated by Swift macros, but can also be generated by any other means.

rdar://115184658

This upstreams the embedded type summary feature from the swiftlang branch of LLDB, since it shares a lot of the same goals and design points with https://github.com/llvm/llvm-project/pull/113398/

>From c9a4d24f222a70c7c108deebb6c25222893d7159 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 24 Jan 2024 12:42:45 -0800
Subject: [PATCH] [lldb] Load embedded type summary section (#7859) (#8040)

Add support for type summaries embedded into the binary.

These embedded summaries will typically be generated by Swift macros,
but can also be generated by any other means.

rdar://115184658
---
 lldb/include/lldb/lldb-enumerations.h         |  1 +
 lldb/source/Core/Section.cpp                  |  3 +
 .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp  |  1 +
 .../ObjectFile/Mach-O/ObjectFileMachO.cpp     |  4 ++
 .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp    |  1 +
 lldb/source/Symbol/ObjectFile.cpp             |  1 +
 lldb/source/Target/Target.cpp                 | 72 +++++++++++++++++++
 .../data-formatter/embedded-summary/Makefile  |  2 +
 .../TestEmbeddedTypeSummary.py                | 12 ++++
 .../data-formatter/embedded-summary/main.c    | 22 ++++++
 10 files changed, 119 insertions(+)
 create mode 100644 lldb/test/API/functionalities/data-formatter/embedded-summary/Makefile
 create mode 100644 lldb/test/API/functionalities/data-formatter/embedded-summary/TestEmbeddedTypeSummary.py
 create mode 100644 lldb/test/API/functionalities/data-formatter/embedded-summary/main.c

diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 938f6e3abe8f2a..1ca4aa62218c09 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -761,6 +761,7 @@ enum SectionType {
   eSectionTypeDWARFDebugLocListsDwo,
   eSectionTypeDWARFDebugTuIndex,
   eSectionTypeCTF,
+  eSectionTypeLLDBTypeSummaries,
   eSectionTypeSwiftModules,
 };
 
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
index 0763e88d4608f4..ee01b4ce06ca1e 100644
--- a/lldb/source/Core/Section.cpp
+++ b/lldb/source/Core/Section.cpp
@@ -147,6 +147,8 @@ const char *Section::GetTypeAsCString() const {
     return "dwarf-gnu-debugaltlink";
   case eSectionTypeCTF:
     return "ctf";
+  case eSectionTypeLLDBTypeSummaries:
+    return "lldb-type-summaries";
   case eSectionTypeOther:
     return "regular";
   case eSectionTypeSwiftModules:
@@ -457,6 +459,7 @@ bool Section::ContainsOnlyDebugInfo() const {
   case eSectionTypeDWARFAppleObjC:
   case eSectionTypeDWARFGNUDebugAltLink:
   case eSectionTypeCTF:
+  case eSectionTypeLLDBTypeSummaries:
   case eSectionTypeSwiftModules:
     return true;
   }
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 10d09662c0a47a..ad4a84ef02bf72 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1678,6 +1678,7 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
       .Case(".gnu_debugaltlink", eSectionTypeDWARFGNUDebugAltLink)
       .Case(".gosymtab", eSectionTypeGoSymtab)
       .Case(".text", eSectionTypeCode)
+      .Case(".lldbsummaries", lldb::eSectionTypeLLDBTypeSummaries)
       .Case(".swift_ast", eSectionTypeSwiftModules)
       .Default(eSectionTypeOther);
 }
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index b542e237f023d4..d6bec5d84aea19 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -1209,6 +1209,7 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
         case eSectionTypeDWARFAppleObjC:
         case eSectionTypeDWARFGNUDebugAltLink:
         case eSectionTypeCTF:
+        case eSectionTypeLLDBTypeSummaries:
         case eSectionTypeSwiftModules:
           return AddressClass::eDebug;
 
@@ -1484,6 +1485,7 @@ static lldb::SectionType GetSectionType(uint32_t flags,
   static ConstString g_sect_name_data("__data");
   static ConstString g_sect_name_go_symtab("__gosymtab");
   static ConstString g_sect_name_ctf("__ctf");
+  static ConstString g_sect_name_lldb_summaries("__lldbsummaries");
   static ConstString g_sect_name_swift_ast("__swift_ast");
 
   if (section_name == g_sect_name_dwarf_debug_abbrev)
@@ -1564,6 +1566,8 @@ static lldb::SectionType GetSectionType(uint32_t flags,
     return eSectionTypeGoSymtab;
   if (section_name == g_sect_name_ctf)
     return eSectionTypeCTF;
+  if (section_name == g_sect_name_lldb_summaries)
+    return lldb::eSectionTypeLLDBTypeSummaries;
   if (section_name == g_sect_name_swift_ast)
     return eSectionTypeSwiftModules;
   if (section_name == g_sect_name_objc_data ||
diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
index 8d9c919bc9b101..bb712da7f6d67d 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -1010,6 +1010,7 @@ SectionType ObjectFilePECOFF::GetSectionType(llvm::StringRef sect_name,
           // .eh_frame can be truncated to 8 chars.
           .Cases(".eh_frame", ".eh_fram", eSectionTypeEHFrame)
           .Case(".gosymtab", eSectionTypeGoSymtab)
+          .Case(".lldbsummaries", lldb::eSectionTypeLLDBTypeSummaries)
           .Case("swiftast", eSectionTypeSwiftModules)
           .Default(eSectionTypeInvalid);
   if (section_type != eSectionTypeInvalid)
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 35317d209de1f9..3100e6b813b631 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -366,6 +366,7 @@ AddressClass ObjectFile::GetAddressClass(addr_t file_addr) {
           case eSectionTypeDWARFAppleObjC:
           case eSectionTypeDWARFGNUDebugAltLink:
           case eSectionTypeCTF:
+          case eSectionTypeLLDBTypeSummaries:
           case eSectionTypeSwiftModules:
             return AddressClass::eDebug;
           case eSectionTypeEHFrame:
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 04395e37f0425d..37670b108d9631 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -26,6 +26,7 @@
 #include "lldb/Core/StructuredDataImpl.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/DataVisualization.h"
 #include "lldb/Expression/DiagnosticManager.h"
 #include "lldb/Expression/ExpressionVariable.h"
 #include "lldb/Expression/REPL.h"
@@ -1537,6 +1538,76 @@ static void LoadScriptingResourceForModule(const ModuleSP &module_sp,
                                                   feedback_stream.GetData());
 }
 
+// Load type summaries embedded in the binary. These are type summaries provided
+// by the authors of the code.
+static void LoadTypeSummariesForModule(ModuleSP module_sp) {
+  auto *sections = module_sp->GetSectionList();
+  if (!sections)
+    return;
+
+  auto summaries_sp =
+      sections->FindSectionByType(eSectionTypeLLDBTypeSummaries, true);
+  if (!summaries_sp)
+    return;
+
+  Log *log = GetLog(LLDBLog::DataFormatters);
+  const char *module_name = module_sp->GetObjectName().GetCString();
+
+  TypeCategoryImplSP category;
+  DataVisualization::Categories::GetCategory(ConstString("default"), category);
+
+  // The type summary record is serialized as follows.
+  //
+  // Each record contains, in order:
+  //   * Version number of the record format
+  //   * The remaining size of the record
+  //   * The size of the type identifier
+  //   * The type identifier, either a type name, or a regex
+  //   * The size of the summary string
+  //   * The summary string
+  //
+  // Integers are encoded using ULEB.
+  //
+  // Strings are encoded with first a length (ULEB), then the string contents,
+  // and lastly a null terminator. The length includes the null.
+
+  DataExtractor extractor;
+  auto section_size = summaries_sp->GetSectionData(extractor);
+  lldb::offset_t offset = 0;
+  while (offset < section_size) {
+    uint64_t version = extractor.GetULEB128(&offset);
+    uint64_t record_size = extractor.GetULEB128(&offset);
+    if (version == 1) {
+      uint64_t type_size = extractor.GetULEB128(&offset);
+      llvm::StringRef type_name = extractor.GetCStr(&offset, type_size);
+      uint64_t summary_size = extractor.GetULEB128(&offset);
+      llvm::StringRef summary_string = extractor.GetCStr(&offset, summary_size);
+      if (!type_name.empty() && !summary_string.empty()) {
+        TypeSummaryImpl::Flags flags;
+        auto summary_sp =
+            std::make_shared<StringSummaryFormat>(flags, summary_string.data());
+        FormatterMatchType match_type = eFormatterMatchExact;
+        if (summary_string.front() == '^' && summary_string.back() == '$')
+          match_type = eFormatterMatchRegex;
+        category->AddTypeSummary(type_name, match_type, summary_sp);
+        LLDB_LOGF(log, "Loaded embedded type summary for '%s' from %s.",
+                  type_name.data(), module_name);
+      } else {
+        if (type_name.empty())
+          LLDB_LOGF(log, "Missing string(s) in embedded type summary in %s.",
+                    module_name);
+      }
+    } else {
+      // Skip unsupported record.
+      offset += record_size;
+      LLDB_LOGF(
+          log,
+          "Skipping unsupported embedded type summary of version %llu in %s.",
+          version, module_name);
+    }
+  }
+}
+
 void Target::ClearModules(bool delete_locations) {
   ModulesDidUnload(m_images, delete_locations);
   m_section_load_history.Clear();
@@ -1775,6 +1846,7 @@ void Target::ModulesDidLoad(ModuleList &module_list) {
     for (size_t idx = 0; idx < num_images; ++idx) {
       ModuleSP module_sp(module_list.GetModuleAtIndex(idx));
       LoadScriptingResourceForModule(module_sp, this);
+      LoadTypeSummariesForModule(module_sp);
     }
     m_breakpoint_list.UpdateBreakpoints(module_list, true, false);
     m_internal_breakpoint_list.UpdateBreakpoints(module_list, true, false);
diff --git a/lldb/test/API/functionalities/data-formatter/embedded-summary/Makefile b/lldb/test/API/functionalities/data-formatter/embedded-summary/Makefile
new file mode 100644
index 00000000000000..c9319d6e6888a4
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/embedded-summary/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/embedded-summary/TestEmbeddedTypeSummary.py b/lldb/test/API/functionalities/data-formatter/embedded-summary/TestEmbeddedTypeSummary.py
new file mode 100644
index 00000000000000..b8ce7d9f76eb9e
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/embedded-summary/TestEmbeddedTypeSummary.py
@@ -0,0 +1,12 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    @skipUnlessDarwin
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
+        self.expect("v player", substrs=['"Dirk" (41)'])
diff --git a/lldb/test/API/functionalities/data-formatter/embedded-summary/main.c b/lldb/test/API/functionalities/data-formatter/embedded-summary/main.c
new file mode 100644
index 00000000000000..9ddd64246f726c
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/embedded-summary/main.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+struct Player {
+  char *name;
+  int number;
+};
+
+__attribute__((used, section("__DATA_CONST,__lldbsummaries"))) unsigned char
+    _Player_type_summary[] = "\x01"     // version
+                             "\x25"     // record size
+                             "\x07"     // type name size
+                             "Player\0" // type name
+                             "\x1c"     // summary string size
+                             "${var.name} (${var.number})"; // summary string
+
+int main() {
+  struct Player player;
+  player.name = "Dirk";
+  player.number = 41;
+  puts("break here");
+  return 0;
+}



More information about the lldb-commits mailing list