[llvm] cb57578 - [llvm-debuginfo-analyzer] Support DW_TAG_module (#137228)

via llvm-commits llvm-commits at lists.llvm.org
Wed May 21 07:05:14 PDT 2025


Author: Javier Lopez-Gomez
Date: 2025-05-21T15:05:10+01:00
New Revision: cb575785b96ead29d699201b2d1e1d1203fdb494

URL: https://github.com/llvm/llvm-project/commit/cb575785b96ead29d699201b2d1e1d1203fdb494
DIFF: https://github.com/llvm/llvm-project/commit/cb575785b96ead29d699201b2d1e1d1203fdb494.diff

LOG: [llvm-debuginfo-analyzer] Support DW_TAG_module (#137228)

- Adds support for `DW_TAG_module` DIEs and recurse over their children.
Prior to this patch, entities hanging below `DW_TAG_module` were just
not visible. This DIE kind is commonly generated by Objective-C modules.

This patch will represent such entities, which will print as
```
[001]    {CompileUnit} '/llvm/tools/clang/test/modules/<stdin>'
[002]      {Producer} 'LLVM version 3.7.0'
           {Directory} '/llvm/tools/clang/test/modules'
           {File} '<stdin>'
[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
```

Added: 
    llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o

Modified: 
    llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
    llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
    llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
    llvm/tools/llvm-debuginfo-analyzer/Options.cpp
    llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 60fa024db5e99..0ab249087ea9e 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -489,8 +489,8 @@ The given criteria describes the debug line state machine registers.
    =Discriminator: Line that has a discriminator.
    =EndSequence: Marks the end in the sequence of lines.
    =EpilogueBegin: Marks the start of a function epilogue.
-   =LineDebug: Lines that correspond to debug lines.
    =LineAssembler: Lines that correspond to disassembly text.
+   =LineDebug: Lines that correspond to debug lines.
    =NeverStepInto: marks a never step into.
    =NewStatement: Marks a new statement.
    =PrologueEnd: Marks the end of a function prologue.
@@ -519,6 +519,7 @@ The following options allow printing of scopes that match the given <kind>.
     =InlinedFunction: An inlined function.
     =Label: A label.
     =LexicalBlock: A lexical block.
+    =Module: A module.
     =Namespace: A namespace.
     =Root: The element representing the main scope.
     =Structure: A structure.

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 17fa04040ad77..0e564bf2b0802 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -42,6 +42,7 @@ enum class LVSubclassID : unsigned char {
   LV_SCOPE_FUNCTION,
   LV_SCOPE_FUNCTION_INLINED,
   LV_SCOPE_FUNCTION_TYPE,
+  LV_SCOPE_MODULE,
   LV_SCOPE_NAMESPACE,
   LV_SCOPE_ROOT,
   LV_SCOPE_TEMPLATE_PACK,

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 9ce26398e48df..870b53f6774a8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -104,6 +104,7 @@ class LVReader {
   LV_OBJECT_ALLOCATOR(ScopeFunction)
   LV_OBJECT_ALLOCATOR(ScopeFunctionInlined)
   LV_OBJECT_ALLOCATOR(ScopeFunctionType)
+  LV_OBJECT_ALLOCATOR(ScopeModule)
   LV_OBJECT_ALLOCATOR(ScopeNamespace)
   LV_OBJECT_ALLOCATOR(ScopeRoot)
   LV_OBJECT_ALLOCATOR(ScopeTemplatePack)
@@ -210,6 +211,7 @@ class LVReader {
   LV_CREATE_OBJECT(ScopeFunction)
   LV_CREATE_OBJECT(ScopeFunctionInlined)
   LV_CREATE_OBJECT(ScopeFunctionType)
+  LV_CREATE_OBJECT(ScopeModule)
   LV_CREATE_OBJECT(ScopeNamespace)
   LV_CREATE_OBJECT(ScopeRoot)
   LV_CREATE_OBJECT(ScopeTemplatePack)

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 1b3c377cd7dbb..cbeb3944b9ec8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -48,6 +48,7 @@ enum class LVScopeKind {
   IsLabel,
   IsLexicalBlock,
   IsMember,
+  IsModule,
   IsNamespace,
   IsRoot,
   IsStructure,
@@ -181,6 +182,7 @@ class LVScope : public LVElement {
   KIND(LVScopeKind, IsTemplatePack);
   KIND_1(LVScopeKind, IsTryBlock, IsBlock);
   KIND_1(LVScopeKind, IsUnion, IsAggregate);
+  KIND_2(LVScopeKind, IsModule, CanHaveRanges, CanHaveLines);
 
   PROPERTY(Property, HasDiscriminator);
   PROPERTY(Property, CanHaveRanges);
@@ -748,6 +750,23 @@ class LVScopeFunctionType final : public LVScopeFunction {
   void resolveExtra() 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;
+};
+
 // Class to represent a DWARF Namespace.
 class LVScopeNamespace final : public LVScope {
   LVScope *Reference = nullptr; // Reference to DW_AT_extension attribute.

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 594b6816f14c5..dc9a4ecee3e8b 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -34,6 +34,7 @@ const char *const KindEnumeration = "Enumeration";
 const char *const KindFile = "File";
 const char *const KindFunction = "Function";
 const char *const KindInlinedFunction = "InlinedFunction";
+const char *const KindModule = "Module";
 const char *const KindNamespace = "Namespace";
 const char *const KindStruct = "Struct";
 const char *const KindTemplateAlias = "TemplateAlias";
@@ -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())
@@ -94,6 +97,7 @@ LVScopeDispatch LVScope::Dispatch = {
     {LVScopeKind::IsInlinedFunction, &LVScope::getIsInlinedFunction},
     {LVScopeKind::IsLabel, &LVScope::getIsLabel},
     {LVScopeKind::IsLexicalBlock, &LVScope::getIsLexicalBlock},
+    {LVScopeKind::IsModule, &LVScope::getIsModule},
     {LVScopeKind::IsNamespace, &LVScope::getIsNamespace},
     {LVScopeKind::IsRoot, &LVScope::getIsRoot},
     {LVScopeKind::IsStructure, &LVScope::getIsStructure},
@@ -1962,6 +1966,18 @@ void LVScopeFunctionType::resolveExtra() {
   setName(Name);
 }
 
+//===----------------------------------------------------------------------===//
+// 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";
+}
+
 //===----------------------------------------------------------------------===//
 // DWARF namespace (DW_TAG_namespace).
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 37bc60d4045c7..763e070e5d98f 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/tools/llvm-debuginfo-analyzer/Options.cpp b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
index e5566b3390fd2..99ed67ce5346f 100644
--- a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
+++ b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
@@ -354,6 +354,7 @@ cl::list<LVScopeKind> cmdline::SelectScopes(
         clEnumValN(LVScopeKind::IsLabel, "Label", "Label."),
         clEnumValN(LVScopeKind::IsLexicalBlock, "LexicalBlock",
                    "Lexical block."),
+        clEnumValN(LVScopeKind::IsModule, "Module", "Module."),
         clEnumValN(LVScopeKind::IsNamespace, "Namespace", "Namespace."),
         clEnumValN(LVScopeKind::IsRoot, "Root", "Root."),
         clEnumValN(LVScopeKind::IsStructure, "Structure", "Structure."),

diff  --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index 03bf394631c99..0d3a5d8959679 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -33,6 +33,7 @@ const char *DwarfClang = "test-dwarf-clang.o";
 // Two compile units: one declares `extern int foo_printf(const char *, ...);`
 // and another one that defines the function.
 const char *DwarfClangUnspecParams = "test-dwarf-clang-unspec-params.elf";
+const char *DwarfClangModule = "test-dwarf-clang-module.o";
 const char *DwarfGcc = "test-dwarf-gcc.o";
 
 // Helper function to get the first compile unit.
@@ -157,6 +158,22 @@ void checkUnspecifiedParameters(LVReader *Reader) {
             true);
 }
 
+// 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();
@@ -301,6 +318,9 @@ void elementProperties(SmallString<128> &InputsDir) {
 
   Reader = createReader(ReaderHandler, InputsDir, DwarfClangUnspecParams);
   checkUnspecifiedParameters(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 0000000000000..0cded9bfb37d1
Binary files /dev/null and b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o 
diff er


        


More information about the llvm-commits mailing list