diff --git a/llvm/docs/CommandGuide/llvm-dwarfdump.rst b/llvm/docs/CommandGuide/llvm-dwarfdump.rst index 137830259eb64..87920741f26dd 100644 --- a/llvm/docs/CommandGuide/llvm-dwarfdump.rst +++ b/llvm/docs/CommandGuide/llvm-dwarfdump.rst @@ -134,6 +134,12 @@ 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: + `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 e7e87bbfebf38..39f5ab5b9298d 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 FilterChildTag; 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 6c78ef05e1b61..7496c5a084da4 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -704,7 +704,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..145791cc8ea51 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/filter-child-tag.yaml @@ -0,0 +1,127 @@ +# 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 +# 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: --filter-child-tag 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 diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 11eb58ea911df..8b829ec1e0225 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" @@ -242,6 +243,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."), @@ -330,6 +340,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; @@ -356,6 +373,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; @@ -899,6 +917,12 @@ int main(int argc, char **argv) { Find.empty() && !FindAllApple) ShowChildren = true; + if (!ShowChildren && !FilterChildTag.empty()) { + WithColor::error() << "incompatible arguments: --filter-child-tag requires " + "--show-children"; + return 1; + } + // Defaults to a.out if no filenames specified. if (InputFilenames.empty()) InputFilenames.push_back("a.out");