[llvm] [llvm-debuginfo-analyzer] Improve DWARF parsing capabilities (PR #137228)

Javier Lopez-Gomez via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 24 11:28:03 PDT 2025


https://github.com/jalopezg-git created https://github.com/llvm/llvm-project/pull/137228

This pull request improves `LVDWARFReader` to deal with a couple of unhandled cases.  Specifically,

- Add support for `DW_TAG_module` DIEs and recurse over their children.  Prior to this patchset, entities hanging below `DW_TAG_module` were just not visible.  This DIE kind is commonly generated by Objective-C modules.  
This patch suggests to add `LVScopeModule` to represent such entities, which will print as
```
[0x000000000b][001]              {CompileUnit} '/llvm/tools/clang/test/modules/<stdin>'
[0x000000000b][002]                {Producer} 'LLVM version 3.7.0'
                                   {Directory} '/llvm/tools/clang/test/modules'
                                   {File} '<stdin>'
[0x0000000023][002]                {Module} 'debugmodule'
```

The minimal test case included is just the result of
```
$ llc llvm/test/DebugInfo/X86/DIModule.ll -accel-tables=Dwarf -o llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o -filetype=obj
```

- Introduce handling of `DW_AT_byte_size`.  Most DWARF emitters include this attribute for types to specify the size of an entity of the given type.

FYI, @CarlosAlbertoEnciso.  I belive this patchset is also complete; feel free to start review at your earliest discretion :+1:.

>From 65fde25f5e3aba2415704c24703549b33e03c0ae Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Thu, 24 Apr 2025 19:44:49 +0200
Subject: [PATCH 1/2] [llvm-debuginfo-analyzer] Add support for DWARF
 `DW_AT_byte_size`

---
 llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h | 1 +
 llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h   | 6 ++++++
 llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h    | 7 +++++++
 llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp           | 5 ++++-
 llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp | 5 +++++
 llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp | 6 ++++++
 6 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 17fa04040ad77..26be557eebf6a 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -239,6 +239,7 @@ class LVElement : public LVObject {
   virtual bool isBase() const { return false; }
   virtual bool isTemplateParam() const { return false; }
 
+  uint32_t getStorageSizeInBytes() const { return (getBitSize() + 7u) / 8u; }
   virtual uint32_t getBitSize() const { return 0; }
   virtual void setBitSize(uint32_t Size) {}
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 1b3c377cd7dbb..1cf61d085d84f 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -93,6 +93,9 @@ class LVScope : public LVElement {
   LVProperties<Property> Properties;
   static LVScopeDispatch Dispatch;
 
+  // Size in bits if this scope represents also a compound type.
+  uint32_t BitSize = 0;
+
   // Coverage factor in units (bytes).
   unsigned CoverageFactor = 0;
 
@@ -269,6 +272,9 @@ class LVScope : public LVElement {
   bool removeElement(LVElement *Element) override;
   void updateLevel(LVScope *Parent, bool Moved) override;
 
+  uint32_t getBitSize() const override { return BitSize; }
+  void setBitSize(uint32_t Size) override { BitSize = Size; }
+
   void resolve() override;
   void resolveName() override;
   void resolveReferences() override;
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
index 28881b3c95b17..58d5bc48c3a72 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
@@ -56,6 +56,9 @@ class LVType : public LVElement {
   LVProperties<Property> Properties;
   static LVTypeDispatch Dispatch;
 
+  // Size in bits of a symbol of this type.
+  uint32_t BitSize = 0;
+
   // Find the current type in the given 'Targets'.
   LVType *findIn(const LVTypes *Targets) const;
 
@@ -109,6 +112,10 @@ class LVType : public LVElement {
   virtual LVElement *getUnderlyingType() { return nullptr; }
   virtual void setUnderlyingType(LVElement *Element) {}
 
+  // Return the size in bits of an entity of this type.
+  uint32_t getBitSize() const override { return BitSize; }
+  void setBitSize(uint32_t Size) override { BitSize = Size; }
+
   void resolveName() override;
   void resolveReferences() override;
 
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
index 28bccadce598c..e5c9936c008e2 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
@@ -292,7 +292,10 @@ void LVType::print(raw_ostream &OS, bool Full) const {
 }
 
 void LVType::printExtra(raw_ostream &OS, bool Full) const {
-  OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
+  OS << formattedKind(kind()) << " " << formattedName(getName());
+  if (uint32_t Size = getStorageSizeInBytes())
+    OS << " [Size = " << Size << "]";
+  OS << "\n";
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 42da957233667..3ddf1dc05b25c 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -307,6 +307,11 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
   case dwarf::DW_AT_bit_size:
     CurrentElement->setBitSize(GetAsUnsignedConstant());
     break;
+  case dwarf::DW_AT_byte_size:
+    // Assume 8-bit bytes; this is consistent, e.g. with
+    // lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp.
+    CurrentElement->setBitSize(GetAsUnsignedConstant() * 8u);
+    break;
   case dwarf::DW_AT_call_file:
     CurrentElement->setCallFilenameIndex(IncrementFileIndex
                                              ? GetAsUnsignedConstant() + 1
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index c062c15481da9..6c53be959d951 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -155,6 +155,12 @@ void checkElementSelection(LVReader *Reader) {
   ASSERT_NE(Element, nullptr);
   EXPECT_NE(Element->getName().find("INTEGER"), StringRef::npos);
   EXPECT_EQ(Element->getIsType(), 1);
+  // Underlying type is `int`
+  const LVElement *UnderlyingType =
+      static_cast<LVType *>(Element)->getUnderlyingType();
+  EXPECT_EQ(UnderlyingType->getIsType(), 1);
+  EXPECT_EQ(UnderlyingType->getBitSize(), 32u);
+  EXPECT_EQ(UnderlyingType->getStorageSizeInBytes(), 4u);
 
   Element = MapElements[0x000000000f]; // 'movl	%edx, %eax'
   ASSERT_NE(Element, nullptr);

>From 2c8b270fa4a843b9b93ff5457f6142232520c628 Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Thu, 24 Apr 2025 19:44:49 +0200
Subject: [PATCH 2/2] [llvm-debuginfo-analyzer] Add support for parsing DWARF
 DW_TAG_module

---
 .../DebugInfo/LogicalView/Core/LVElement.h    |   1 +
 .../DebugInfo/LogicalView/Core/LVReader.h     |   2 ++
 .../llvm/DebugInfo/LogicalView/Core/LVScope.h |  19 +++++++++++++++++
 .../DebugInfo/LogicalView/Core/LVScope.cpp    |  18 +++++++++++++++-
 .../LogicalView/Readers/LVDWARFReader.cpp     |   3 +++
 .../DebugInfo/LogicalView/DWARFReaderTest.cpp |  20 ++++++++++++++++++
 .../Inputs/test-dwarf-clang-module.o          | Bin 0 -> 960 bytes
 7 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o

diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 26be557eebf6a..36f90e0b6a6d8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -45,6 +45,7 @@ enum class LVSubclassID : unsigned char {
   LV_SCOPE_NAMESPACE,
   LV_SCOPE_ROOT,
   LV_SCOPE_TEMPLATE_PACK,
+  LV_SCOPE_MODULE,
   LV_SCOPE_LAST,
   LV_SYMBOL_FIRST,
   LV_SYMBOL,
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 9ce26398e48df..b0d8ff4952d79 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -107,6 +107,7 @@ class LVReader {
   LV_OBJECT_ALLOCATOR(ScopeNamespace)
   LV_OBJECT_ALLOCATOR(ScopeRoot)
   LV_OBJECT_ALLOCATOR(ScopeTemplatePack)
+  LV_OBJECT_ALLOCATOR(ScopeModule)
 
   // Symbols allocator.
   LV_OBJECT_ALLOCATOR(Symbol)
@@ -213,6 +214,7 @@ class LVReader {
   LV_CREATE_OBJECT(ScopeNamespace)
   LV_CREATE_OBJECT(ScopeRoot)
   LV_CREATE_OBJECT(ScopeTemplatePack)
+  LV_CREATE_OBJECT(ScopeModule)
 
   // Symbols creation.
   LV_CREATE_OBJECT(Symbol)
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 1cf61d085d84f..23553297e54c2 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -57,6 +57,7 @@ enum class LVScopeKind {
   IsTemplatePack,
   IsTryBlock,
   IsUnion,
+  IsModule,
   LastEntry
 };
 using LVScopeKindSet = std::set<LVScopeKind>;
@@ -184,6 +185,7 @@ class LVScope : public LVElement {
   KIND(LVScopeKind, IsTemplatePack);
   KIND_1(LVScopeKind, IsTryBlock, IsBlock);
   KIND_1(LVScopeKind, IsUnion, IsAggregate);
+  KIND_3(LVScopeKind, IsModule, CanHaveRanges, CanHaveLines, TransformName);
 
   PROPERTY(Property, HasDiscriminator);
   PROPERTY(Property, CanHaveRanges);
@@ -832,6 +834,23 @@ class LVScopeTemplatePack final : public LVScope {
   void printExtra(raw_ostream &OS, bool Full = true) const override;
 };
 
+// Class to represent a DWARF Module.
+class LVScopeModule final : public LVScope {
+public:
+  LVScopeModule() : LVScope() {
+    setIsModule();
+    setIsLexicalBlock();
+  }
+  LVScopeModule(const LVScopeModule &) = delete;
+  LVScopeModule &operator=(const LVScopeModule &) = delete;
+  ~LVScopeModule() = default;
+
+  // Returns true if current scope is logically equal to the given 'Scope'.
+  bool equals(const LVScope *Scope) const override;
+
+  void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
 } // end namespace logicalview
 } // end namespace llvm
 
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 8bbaf93db0caa..7ffeed8f18f8a 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -40,6 +40,7 @@ const char *const KindTemplateAlias = "TemplateAlias";
 const char *const KindTemplatePack = "TemplatePack";
 const char *const KindUndefined = "Undefined";
 const char *const KindUnion = "Union";
+const char *const KindModule = "Module";
 } // end anonymous namespace
 
 //===----------------------------------------------------------------------===//
@@ -50,6 +51,8 @@ const char *LVScope::kind() const {
   const char *Kind = KindUndefined;
   if (getIsArray())
     Kind = KindArray;
+  else if (getIsModule())
+    Kind = KindModule;
   else if (getIsBlock())
     Kind = KindBlock;
   else if (getIsCallSite())
@@ -101,7 +104,8 @@ LVScopeDispatch LVScope::Dispatch = {
     {LVScopeKind::IsTemplateAlias, &LVScope::getIsTemplateAlias},
     {LVScopeKind::IsTemplatePack, &LVScope::getIsTemplatePack},
     {LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock},
-    {LVScopeKind::IsUnion, &LVScope::getIsUnion}};
+    {LVScopeKind::IsUnion, &LVScope::getIsUnion},
+    {LVScopeKind::IsModule, &LVScope::getIsModule}};
 
 void LVScope::addToChildren(LVElement *Element) {
   if (!Children)
@@ -2107,3 +2111,15 @@ bool LVScopeTemplatePack::equals(const LVScope *Scope) const {
 void LVScopeTemplatePack::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
 }
+
+//===----------------------------------------------------------------------===//
+// DWARF module (DW_TAG_module).
+//===----------------------------------------------------------------------===//
+bool LVScopeModule::equals(const LVScope *Scope) const {
+  // For lexical blocks, LVScope::equals() compares the parent scope.
+  return LVScope::equals(Scope) && (Scope->getName() == getName());
+}
+
+void LVScopeModule::printExtra(raw_ostream &OS, bool Full) const {
+  OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
+}
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 3ddf1dc05b25c..fbac5ddcc8a06 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -233,6 +233,9 @@ LVElement *LVDWARFReader::createElement(dwarf::Tag Tag) {
   case dwarf::DW_TAG_GNU_template_parameter_pack:
     CurrentScope = createScopeTemplatePack();
     return CurrentScope;
+  case dwarf::DW_TAG_module:
+    CurrentScope = createScopeModule();
+    return CurrentScope;
   default:
     // Collect TAGs not implemented.
     if (options().getInternalTag() && Tag)
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index 6c53be959d951..7362ea6468b61 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -30,6 +30,7 @@ extern const char *TestMainArgv0;
 namespace {
 
 const char *DwarfClang = "test-dwarf-clang.o";
+const char *DwarfClangModule = "test-dwarf-clang-module.o";
 const char *DwarfGcc = "test-dwarf-gcc.o";
 
 // Helper function to get the first compile unit.
@@ -124,6 +125,22 @@ void checkElementProperties(LVReader *Reader) {
   ASSERT_EQ(Lines->size(), 0x12u);
 }
 
+// Check the basic properties on parsed DW_TAG_module.
+void checkScopeModule(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  EXPECT_EQ(Root->getFileFormatName(), "Mach-O 64-bit x86-64");
+  EXPECT_EQ(Root->getName(), DwarfClangModule);
+
+  ASSERT_NE(CompileUnit->getChildren(), nullptr);
+  LVElement *FirstChild = *(CompileUnit->getChildren()->begin());
+  EXPECT_EQ(FirstChild->getIsScope(), 1);
+  LVScopeModule *Module = static_cast<LVScopeModule *>(FirstChild);
+  EXPECT_EQ(Module->getIsModule(), 1);
+  EXPECT_EQ(Module->getName(), "debugmodule");
+}
+
 // Check the logical elements selection.
 void checkElementSelection(LVReader *Reader) {
   LVScopeRoot *Root = Reader->getScopesRoot();
@@ -270,6 +287,9 @@ void elementProperties(SmallString<128> &InputsDir) {
   std::unique_ptr<LVReader> Reader =
       createReader(ReaderHandler, InputsDir, DwarfClang);
   checkElementProperties(Reader.get());
+
+  Reader = createReader(ReaderHandler, InputsDir, DwarfClangModule);
+  checkScopeModule(Reader.get());
 }
 
 // Logical elements selection.
diff --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o
new file mode 100644
index 0000000000000000000000000000000000000000..0cded9bfb37d1693729ab5a3ed263bfa6c57fa21
GIT binary patch
literal 960
zcmaiy-%A2P5Xa{{EkRlgA1Z<nBIuz!qrfl|f-?-1pzOz+XkKz~-ifzLg^&f&U)0~x
zU(sW4JrzVVcf06azXoP!=DRzeo4ecR_t(#907V5{gs(<0Nu#4JpnJ7feP1{=p_Qoz
zP1eW+ at +lJ0>UC~haX<I#TIswtuEUw+P3WVE9C<CH*>Bey&1TOS5MMvrJKCQ-;^iAc
z`GF at U_76y&X<s^|gn5!v5WMR^w<iV^$#Z$n+YIwMg7YBaQ=t2Ip55peE^dc;Z-TQe
zVgY|>2pK5le3oe&)Dq^c$^R;NoGwVv0z73_Sz)P|%I=3OIk(7OZWB1b5~%EM$VNl<
zIAj279P){s#C!@tG-%WV#=S=+fz-UG_%RZpk6lKmdvb%WDzRk at P^p|&(*vXDnvR{`
z%;Yjz&@5}v(YWJSu6AKH?6$@Ymupq0)wc{+E4aL6+C|Vnr)%TOu&!4R^^;2Jc=unx
zf!*zM7dn|n*R&mE;}~1$F?8{%FdOHj#nEZhY%ZInJ!v{7Q7Gc7D9Q($p+M)+mA~Hu
JK)#54<`)_HeKP<6

literal 0
HcmV?d00001




More information about the llvm-commits mailing list