[llvm] [llvm][dwarfdump] Add --child-tags option to filter by DWARF tags (PR #165720)
Michael Buch via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 30 06:47:14 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/165720
>From 80328f1cc998a4779f14f92ed9f57684950c0d0e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 21 Oct 2025 16:51:43 +0100
Subject: [PATCH 1/2] [llvm][dwarfdump] Add --child-tags option to filter by
DWARF tags
This patch adds a new option `--child-tags` (`-t` for short), which
makes dwarfdump only dump children whose DWARF tag is in the list of
tags specified by the user.
Motivating examples are:
* dumping all global variables in a CU
* dumping all non-static data members of a structure
* dumping all module import declarations of a CU
* etc.
For tags not known to dwarfdump, we pretend that the tag wasn't specified.
---
llvm/include/llvm/DebugInfo/DIContext.h | 2 ++
llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 4 +++-
llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp | 24 ++++++++++++++++++++
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index e7e87bbfebf38..32ce4520dbca7 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -202,6 +202,8 @@ struct DIDumpOptions {
bool ShowAddresses = true;
bool ShowChildren = false;
bool ShowParents = false;
+ /// List of DWARF tags to filter children by.
+ llvm::SmallVector<unsigned> ChildTagsFilter;
bool ShowForm = false;
bool SummarizeTypes = false;
bool Verbose = false;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index db5cc37c93f90..7558fbda18459 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -676,7 +676,9 @@ void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
DIDumpOptions ChildDumpOpts = DumpOpts;
ChildDumpOpts.ShowParents = false;
while (Child) {
- Child.dump(OS, Indent + 2, ChildDumpOpts);
+ if (DumpOpts.ChildTagsFilter.empty() ||
+ llvm::is_contained(DumpOpts.ChildTagsFilter, Child.getTag()))
+ Child.dump(OS, Indent + 2, ChildDumpOpts);
Child = Child.getSibling();
}
}
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 79f05278c329d..eb5f8b4af95a6 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
@@ -241,6 +242,15 @@ static opt<bool>
cat(DwarfDumpCategory));
static alias ShowParentsAlias("p", desc("Alias for --show-parents."),
aliasopt(ShowParents), cl::NotHidden);
+
+static list<std::string>
+ ChildTags("child-tags",
+ desc("When --show-children is specified, show only DIEs with the "
+ "specified DWARF tags."),
+ value_desc("list of DWARF tags"), cat(DwarfDumpCategory));
+static alias TagsAlias("t", desc("Alias for --child-tags."),
+ aliasopt(ChildTags), cl::NotHidden);
+
static opt<bool>
ShowForm("show-form",
desc("Show DWARF form types after the DWARF attribute types."),
@@ -329,6 +339,13 @@ static cl::extrahelp
/// @}
//===----------------------------------------------------------------------===//
+static llvm::SmallVector<unsigned>
+makeTagVector(const list<std::string> &TagStrings) {
+ return llvm::map_to_vector(TagStrings, [](const std::string &Tag) {
+ return llvm::dwarf::getTag(Tag);
+ });
+}
+
static void error(Error Err) {
if (!Err)
return;
@@ -355,6 +372,7 @@ static DIDumpOptions getDumpOpts(DWARFContext &C) {
DumpOpts.ShowAddresses = !Diff;
DumpOpts.ShowChildren = ShowChildren;
DumpOpts.ShowParents = ShowParents;
+ DumpOpts.ChildTagsFilter = makeTagVector(ChildTags);
DumpOpts.ShowForm = ShowForm;
DumpOpts.SummarizeTypes = SummarizeTypes;
DumpOpts.Verbose = Verbose;
@@ -898,6 +916,12 @@ int main(int argc, char **argv) {
Find.empty() && !FindAllApple)
ShowChildren = true;
+ if (!ShowChildren && !ChildTags.empty()) {
+ WithColor::error()
+ << "incompatible arguments: --child-tags requires --show-children";
+ return 1;
+ }
+
// Defaults to a.out if no filenames specified.
if (InputFilenames.empty())
InputFilenames.push_back("a.out");
>From 72a3f5b1292b1d1bd6e11d3e094794af96c9019f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 30 Oct 2025 13:46:47 +0000
Subject: [PATCH 2/2] fixup! add test
---
.../llvm-dwarfdump/X86/child-tags-filter.yaml | 127 ++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/child-tags-filter.yaml
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/child-tags-filter.yaml b/llvm/test/tools/llvm-dwarfdump/X86/child-tags-filter.yaml
new file mode 100644
index 0000000000000..608cba24cbb4a
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/child-tags-filter.yaml
@@ -0,0 +1,127 @@
+# Tests the --child-tags (-t) option.
+# RUN: yaml2obj %s -o %t.o
+# RUN: llvm-dwarfdump %t.o --child-tags=DW_TAG_structure_type | FileCheck %s --check-prefix=ONLY_STRUCT
+# RUN: llvm-dwarfdump %t.o -t DW_TAG_structure_type -t DW_TAG_namespace | FileCheck %s --check-prefix=STRUCT_AND_NS --implicit-check-not=DW_TAG_subprogram --implicit-check-not=DW_TAG_member
+# RUN: llvm-dwarfdump %t.o -c --name=Foo -t DW_TAG_member | FileCheck %s --check-prefix=FOO_MEM --implicit-check-not=DW_TAG_compile_unit --implicit-check-not=DW_TAG_subprogram --implicit-check-not=DW_TAG_namespace
+# RUN: llvm-dwarfdump %t.o -c --name=Foo -t not_a_tag -t DW_TAG_member | FileCheck %s --check-prefix=SINGLE_INVALID_TAG --implicit-check-not=DW_TAG_compile_unit --implicit-check-not=DW_TAG_subprogram --implicit-check-not=DW_TAG_namespace
+# RUN: llvm-dwarfdump %t.o -c --name=Foo -t not_a_tag | FileCheck %s --check-prefix=ONLY_INVALID_TAGS --implicit-check-not=DW_TAG_compile_unit --implicit-check-not=DW_TAG_subprogram --implicit-check-not=DW_TAG_namespace --implicit-check-not=DW_TAG_member
+# RUN: llvm-dwarfdump %t.o -c -p --name=Foo -t DW_TAG_member | FileCheck %s --check-prefix=FOO_MEM_WITH_PARENT --implicit-check-not=DW_TAG_subprogram
+# RUN: not llvm-dwarfdump %t.o --name=Foo -t DW_TAG_member 2>&1 | FileCheck %s --check-prefix=ERROR_NO_SHOW_CHILDREN
+
+# ONLY_STRUCT: DW_TAG_compile_unit
+# ONLY_STRUCT-NOT: DW_TAG_namespace
+# ONLY_STRUCT-NOT: DW_TAG_structure_type
+
+# STRUCT_AND_NS: DW_TAG_compile_unit
+# STRUCT_AND_NS: DW_TAG_namespace
+# STRUCT_AND_NS: DW_TAG_structure_type
+# STRUCT_AND_NS: DW_TAG_structure_type
+
+# FOO_MEM: DW_TAG_structure_type
+# FOO_MEM: DW_TAG_member
+# FOO_MEM: DW_TAG_member
+# FOO_MEM: DW_TAG_member
+# FOO_MEM-NOT: DW_TAG_structure_type
+# FOO_MEM-NOT: DW_TAG_member
+
+# SINGLE_INVALID_TAG: DW_TAG_structure_type
+# SINGLE_INVALID_TAG: DW_TAG_member
+# SINGLE_INVALID_TAG: DW_TAG_member
+# SINGLE_INVALID_TAG: DW_TAG_member
+# SINGLE_INVALID_TAG-NOT: DW_TAG_structure_type
+# SINGLE_INVALID_TAG-NOT: DW_TAG_member
+
+# ONLY_INVALID_TAGS: DW_TAG_structure_type
+# ONLY_INVALID_TAGS-NOT: DW_TAG_structure_type
+
+# FOO_MEM_WITH_PARENT: DW_TAG_compile_unit
+# FOO_MEM_WITH_PARENT: DW_TAG_namespace
+# FOO_MEM_WITH_PARENT: DW_TAG_structure_type
+# FOO_MEM_WITH_PARENT: DW_TAG_member
+# FOO_MEM_WITH_PARENT: DW_TAG_member
+# FOO_MEM_WITH_PARENT: DW_TAG_member
+# FOO_MEM_WITH_PARENT-NOT: DW_TAG_structure_type
+# FOO_MEM_WITH_PARENT-NOT: DW_TAG_member
+
+# ERROR_NO_SHOW_CHILDREN: incompatible arguments: --child-tags requires --show-children
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+DWARF:
+ debug_abbrev:
+ - Table:
+ # 1
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ # 2
+ - Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ # 3
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ # 4
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ # 5
+ - Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ debug_info:
+ - Version: 5
+ UnitType: DW_UT_compile
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: handwritten
+ - AbbrCode: 2
+ Values:
+ - CStr: ns
+ - AbbrCode: 3
+ Values:
+ - CStr: Foo
+ - AbbrCode: 4
+ Values:
+ - CStr: mem1
+ - AbbrCode: 4
+ Values:
+ - CStr: mem2
+ - AbbrCode: 4
+ Values:
+ - CStr: mem3
+ - AbbrCode: 3
+ Values:
+ - CStr: NestedInFoo
+ - AbbrCode: 4
+ Values:
+ - CStr: NestedMem1
+ - AbbrCode: 4
+ Values:
+ - CStr: NestedMem2
+ - AbbrCode: 5
+ Values:
+ - CStr: NestedFunc
+ - AbbrCode: 0x0
+ - AbbrCode: 5
+ Values:
+ - CStr: FooFunc
+ - AbbrCode: 0x0
+ - AbbrCode: 0x0
+ - AbbrCode: 0x0
More information about the llvm-commits
mailing list