Skip to content
Merged
9 changes: 9 additions & 0 deletions llvm/docs/CommandGuide/llvm-dwarfdump.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <name> strings as regular expressions when searching
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/DebugInfo/DIContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ struct DIDumpOptions {
bool ShowAggregateErrors = false;
bool PrintRegisterOnly = false;
std::string JsonErrSummaryFile;
/// List of DWARF tags to filter children by.
llvm::SmallVector<unsigned, 0> FilterChildTag;
std::function<llvm::StringRef(uint64_t DwarfRegNum, bool IsEH)>
GetNameForDWARFReg;

Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand Down
136 changes: 136 additions & 0 deletions llvm/test/tools/llvm-dwarfdump/X86/filter-child-tag.yaml
Original file line number Diff line number Diff line change
@@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would find it easier to follow the test if you did something like:

# RUN: ... | FileCheck --check-prefix=APREFIX
# APREFIX: ...

# RUN: ... | FileCheck --check-prefix=ANOTHER_PREFIX
# ANOTHER_PREFIX: ...

# RUN: llvm-dwarfdump %t.o --option --option \
# RUN:                                     --option --option | \
# RUN:   FileCheck --check-prefix=LONG_PREFIX

etc.

You should also break up your longer lines over multiple lines using \ as the line continuation character (see last example).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!


# 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
18 changes: 18 additions & 0 deletions llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -242,6 +243,15 @@ static opt<bool>
cat(DwarfDumpCategory));
static alias ShowParentsAlias("p", desc("Alias for --show-parents."),
aliasopt(ShowParents), cl::NotHidden);

static list<std::string> 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<bool>
ShowForm("show-form",
desc("Show DWARF form types after the DWARF attribute types."),
Expand Down Expand Up @@ -330,6 +340,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;
Expand All @@ -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;
Expand Down