Skip to content
6 changes: 6 additions & 0 deletions llvm/docs/CommandGuide/llvm-dwarfdump.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you have a local docs build? How does this render in the output? What it be better using .. code-block:: c?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yea confirmed with the code-block it looks nicer. Fixed


.. 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 @@ -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, 0> FilterChildTag;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: this list is sorted by type, so this belongs near the end, probably next to the JsonErrSummaryFile entry.

bool ShowForm = false;
bool SummarizeTypes = false;
bool Verbose = false;
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
127 changes: 127 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,127 @@
# Tests the --filter-child-tag (-t) option.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I don't know if this has been adopted in llvm-dwarfdump tests at all yet, but in many other LLVM binary utils and related code, we've been adopting a policy of ## for comment markers (or otherwise double-comment markers) to indicate true comments and to distinguish them from the lit/FileCheck commands. I find it really helps test readability. Example:

## Tests the --filter-child-tag (-t) option.
# RUN: ...

# 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!

# 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
Copy link
Collaborator

Choose a reason for hiding this comment

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

What are these comments for?

Copy link
Member Author

Choose a reason for hiding this comment

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

Abbreviation codes, but mostly for myself when writing the test. Will remove them

- 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
24 changes: 24 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 Expand Up @@ -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 "
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd be tempted to just silently do nothing in this case, rather than emitting an error.

Copy link
Member Author

Choose a reason for hiding this comment

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

yea I don't mind doing that. Other non-composable options already behave that way anyway (like --name and --debug-info=).

"--show-children";
return 1;
}

// Defaults to a.out if no filenames specified.
if (InputFilenames.empty())
InputFilenames.push_back("a.out");
Expand Down