[llvm] [llvm-debuginfo-analyzer] Support DW_TAG_module (PR #137228)
Javier Lopez-Gomez via llvm-commits
llvm-commits at lists.llvm.org
Wed May 21 03:24:23 PDT 2025
https://github.com/jalopezg-git updated https://github.com/llvm/llvm-project/pull/137228
>From 6bc023d2dd44d05cb6a8a8f775a67191357f2e4a Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Tue, 13 May 2025 13:25:24 +0200
Subject: [PATCH 1/2] [llvm-debuginfo-analyzer] Add support for parsing DWARF
DW_TAG_module
---
.../CommandGuide/llvm-debuginfo-analyzer.rst | 1 +
.../DebugInfo/LogicalView/Core/LVElement.h | 1 +
.../DebugInfo/LogicalView/Core/LVReader.h | 2 ++
.../llvm/DebugInfo/LogicalView/Core/LVScope.h | 19 +++++++++++++++++
.../DebugInfo/LogicalView/Core/LVScope.cpp | 16 ++++++++++++++
.../LogicalView/Readers/LVDWARFReader.cpp | 3 +++
.../tools/llvm-debuginfo-analyzer/Options.cpp | 1 +
.../DebugInfo/LogicalView/DWARFReaderTest.cpp | 20 ++++++++++++++++++
.../Inputs/test-dwarf-clang-module.o | Bin 0 -> 960 bytes
9 files changed, 63 insertions(+)
create mode 100644 llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-module.o
diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 60fa024db5e99..f4a87aceeafd8 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -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 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
>From f1d43487342b6cce1b3ccf441bfc513800426083 Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Tue, 13 May 2025 13:25:24 +0200
Subject: [PATCH 2/2] [llvm-debuginfo-analyzer] Minor reorder in
`--select-lines=` section
---
llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index f4a87aceeafd8..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.
More information about the llvm-commits
mailing list