diff --git a/llvm/docs/CommandGuide/llvm-dwarfdump.rst b/llvm/docs/CommandGuide/llvm-dwarfdump.rst index 27ad4226e6cf9..79a90071c06b0 100644 --- a/llvm/docs/CommandGuide/llvm-dwarfdump.rst +++ b/llvm/docs/CommandGuide/llvm-dwarfdump.rst @@ -134,6 +134,15 @@ OPTIONS Abbreviate the description of type unit entries. +.. option:: -t, --filter-child-tag + + Only dump children whose DWARF tag is one of the specified tags. + Example usage: + + .. code-block:: c + + llvm-dwarfdump -t DW_TAG_structure_type -t DW_TAG_member -c + .. option:: -x, --regex Treat any strings as regular expressions when searching diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h index 0347f90c236d1..b72b027c5861c 100644 --- a/llvm/include/llvm/DebugInfo/DIContext.h +++ b/llvm/include/llvm/DebugInfo/DIContext.h @@ -210,6 +210,8 @@ struct DIDumpOptions { bool DumpNonSkeleton = false; bool ShowAggregateErrors = false; std::string JsonErrSummaryFile; + /// List of DWARF tags to filter children by. + llvm::SmallVector FilterChildTag; std::function GetNameForDWARFReg; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index edc69a36cdff2..d0684168c6b51 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -636,7 +636,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.FilterChildTag.empty() || + llvm::is_contained(DumpOpts.FilterChildTag, Child.getTag())) + Child.dump(OS, Indent + 2, ChildDumpOpts); Child = Child.getSibling(); } } diff --git a/llvm/test/tools/llvm-dwarfdump/X86/filter-child-tag.yaml b/llvm/test/tools/llvm-dwarfdump/X86/filter-child-tag.yaml new file mode 100644 index 0000000000000..2a8c37da80e64 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/filter-child-tag.yaml @@ -0,0 +1,136 @@ +## Tests the --filter-child-tag (-t) option. + +# RUN: yaml2obj %s -o %t.o + +# RUN: llvm-dwarfdump %t.o --filter-child-tag=DW_TAG_structure_type | FileCheck %s --check-prefix=ONLY_STRUCT + +# ONLY_STRUCT: DW_TAG_compile_unit +# ONLY_STRUCT-NOT: DW_TAG_namespace +# ONLY_STRUCT-NOT: DW_TAG_structure_type + +# RUN: llvm-dwarfdump %t.o -t DW_TAG_structure_type -t DW_TAG_namespace | \ +# RUN: FileCheck %s --check-prefix=STRUCT_AND_NS --implicit-check-not=DW_TAG_subprogram --implicit-check-not=DW_TAG_member + +# 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 + +# RUN: llvm-dwarfdump %t.o -c --name=Foo -t DW_TAG_member | \ +# RUN: 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 + +# 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 + +# RUN: llvm-dwarfdump %t.o -c --name=Foo -t not_a_tag -t DW_TAG_member | \ +# RUN: 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 + +# 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 + +# RUN: llvm-dwarfdump %t.o -c --name=Foo -t not_a_tag | \ +# RUN: 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 + +# ONLY_INVALID_TAGS: DW_TAG_structure_type +# ONLY_INVALID_TAGS-NOT: DW_TAG_structure_type + +# RUN: llvm-dwarfdump %t.o -c -p --name=Foo -t DW_TAG_member | \ +# RUN: FileCheck %s --check-prefix=FOO_MEM_WITH_PARENT --implicit-check-not=DW_TAG_subprogram + +# 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 + +## Not specifying --show-children ignores the --filter-child-tag option. +# RUN: llvm-dwarfdump %t.o --name=Foo -t DW_TAG_member 2>&1 | FileCheck %s --check-prefix=NO_SHOW_CHILDREN + +# NO_SHOW_CHILDREN: DW_TAG_structure_type + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Tag: DW_TAG_namespace + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - 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 diff --git a/llvm/tools/llvm-dwarfdump/CMakeLists.txt b/llvm/tools/llvm-dwarfdump/CMakeLists.txt index aeb1b8f14d830..7a0adf32e938c 100644 --- a/llvm/tools/llvm-dwarfdump/CMakeLists.txt +++ b/llvm/tools/llvm-dwarfdump/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + BinaryFormat DebugInfoDWARF DebugInfoDWARFLowLevel AllTargetsDescs diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 5749b19d7ad49..3c1adcc8bd689 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 cat(DwarfDumpCategory)); static alias ShowParentsAlias("p", desc("Alias for --show-parents."), aliasopt(ShowParents), cl::NotHidden); + +static list FilterChildTag( + "filter-child-tag", + desc("When --show-children is specified, show only DIEs with the " + "specified DWARF tags."), + value_desc("list of DWARF tags"), cat(DwarfDumpCategory)); +static alias FilterChildTagAlias("t", desc("Alias for --filter-child-tag."), + aliasopt(FilterChildTag), cl::NotHidden); + static opt ShowForm("show-form", desc("Show DWARF form types after the DWARF attribute types."), @@ -329,6 +339,13 @@ static cl::extrahelp /// @} //===----------------------------------------------------------------------===// +static llvm::SmallVector +makeTagVector(const list &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.FilterChildTag = makeTagVector(FilterChildTag); DumpOpts.ShowForm = ShowForm; DumpOpts.SummarizeTypes = SummarizeTypes; DumpOpts.Verbose = Verbose;