Skip to content

Commit

Permalink
DWARFAcceleratorTable: fix equal_range iterators
Browse files Browse the repository at this point in the history
Summary:
Both (Apple and DWARF5) implementations of the iterators had bugs which
resulted in crashes if one attempted to iterate through the accelerator
tables all the way.

For the Apple tables, the issue was that we did not clear the DataOffset
field when we reached the end, which made our iterator compare unequal
to the "end" iterator. For the Dwarf5 tables, the problem was that we
incremented the CurrentIndex pointer and then used the incremented
(possibly invalid) pointer to check whether we have reached the end of
the index list.

The reason these bugs went undetected is because their only user
(dwarfdump) only ever searched for the first match. Besides allowing us
to test this fix, changing llvm-dwarfdump --find to display all matches
seems like a good improvement (it makes the behavior consistent with the
--name option), so I change llvm-dwarfdump to do that.

The existing tests would be sufficient to test this fix with the new
llvm-dwarfdump behavior, but I add a special test that demonstrates that
the tool indeed displays multiple results. The find.test test needed to
be tweaked a bit as the tool now does not print the ".debug_info
contents" header (also consistent with how --name works).

Reviewers: JDevlieghere, aprantl, dblaikie

Subscribers: mgrang, llvm-commits

Differential Revision: https://reviews.llvm.org/D47543

llvm-svn: 333635
  • Loading branch information
labath committed May 31, 2018
1 parent 2e09995 commit 59870af
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 33 deletions.
5 changes: 3 additions & 2 deletions llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
Expand Up @@ -312,6 +312,7 @@ void AppleAcceleratorTable::ValueIterator::Next() {
if (Data >= NumData ||
!AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
NumData = 0;
DataOffset = 0;
return;
}
Current.extract(*AccelTable, &DataOffset);
Expand Down Expand Up @@ -849,8 +850,8 @@ void DWARFDebugNames::ValueIterator::next() {
if (getEntryAtCurrentOffset())
return;

// If we're a local iterator, we're done.
if (IsLocal) {
// If we're a local iterator or we have reached the last Index, we're done.
if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) {
setEnd();
return;
}
Expand Down
92 changes: 92 additions & 0 deletions llvm/test/tools/llvm-dwarfdump/X86/debug-names-multi-find.s
@@ -0,0 +1,92 @@
# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj -o %t
# RUN: llvm-dwarfdump -find=foo - <%t | FileCheck %s

# CHECK: 12: DW_TAG_subprogram
# CHECK-NEXT: DW_AT_name ("foo")
# CHECK-NEXT: DW_AT_external
# CHECK: 17: DW_TAG_subprogram
# CHECK-NEXT: DW_AT_name ("foo")
# CHECK-NEXT: DW_AT_external

.section .debug_str,"MS",@progbits,1
.Lstring_foo:
.asciz "foo"
.Lstring_producer:
.asciz "Hand-written dwarf"

.section .debug_abbrev,"",@progbits
.Lsection_abbrev:
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 14 # DW_FORM_strp
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)

.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Lcu_end0-.Lcu_start0 # Length of Unit
.Lcu_start0:
.short 4 # DWARF version number
.long .Lsection_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] DW_TAG_compile_unit
.long .Lstring_producer # DW_AT_producer
.short 12 # DW_AT_language
.Ldie_foo:
.byte 2 # Abbrev [2] DW_TAG_subprogram
.long .Lstring_foo # DW_AT_name
# DW_AT_external
.Ldie_foo2:
.byte 2 # Abbrev [2] DW_TAG_subprogram
.long .Lstring_foo # DW_AT_name
# DW_AT_external
.byte 0 # End Of Children Mark
.Lcu_end0:

.section .debug_names,"",@progbits
.long .Lnames_end0-.Lnames_start0 # Header: contribution length
.Lnames_start0:
.short 5 # Header: version
.short 0 # Header: padding
.long 1 # Header: compilation unit count
.long 0 # Header: local type unit count
.long 0 # Header: foreign type unit count
.long 0 # Header: bucket count
.long 1 # Header: name count
.long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
.long 0 # Header: augmentation length
.long .Lcu_begin0 # Compilation unit 0
.long .Lstring_foo # String in Bucket 0: foo
.long .Lnames0-.Lnames_entries0 # Offset in Bucket 0
.Lnames_abbrev_start0:
.byte 46 # Abbrev code
.byte 46 # DW_TAG_subprogram
.byte 3 # DW_IDX_die_offset
.byte 19 # DW_FORM_ref4
.byte 0 # End of abbrev
.byte 0 # End of abbrev
.byte 0 # End of abbrev list
.Lnames_abbrev_end0:
.Lnames_entries0:
.Lnames0:
.byte 46 # Abbrev code
.long .Ldie_foo-.Lcu_begin0 # DW_IDX_die_offset
.byte 46 # Abbrev code
.long .Ldie_foo2-.Lcu_begin0 # DW_IDX_die_offset
.long 0 # End of list: foo
.p2align 2
.Lnames_end0:
8 changes: 2 additions & 6 deletions llvm/test/tools/llvm-dwarfdump/X86/find.test
Expand Up @@ -5,8 +5,6 @@ EMPTY: {{^$}}

RUN: llvm-mc %S/brief.s -filetype obj -triple x86_64-apple-darwin -o - \
RUN: | llvm-dwarfdump -find=main - | FileCheck %s
CHECK: .debug_info contents:
CHECK-NOT: {{:}}
CHECK: : DW_TAG_subprogram
CHECK-NOT: {{:}}
CHECK: DW_AT_name ("main")
Expand All @@ -15,22 +13,20 @@ CHECK-NOT: {{:}}
RUN: llvm-dwarfdump %S/../../dsymutil/Inputs/libfat-test.a \
RUN: -find=x86_64h_var -find=i386_var \
RUN: | FileCheck %s --check-prefix=MULTI
MULTI: .debug_info contents:
MULTI: libfat-test.a(i386)
MULTI-NOT: {{: DW}}
MULTI: : DW_TAG_variable
MULTI-NOT: {{: DW}}
MULTI: DW_AT_name ("i386_var")
MULTI: libfat-test.a(x86_64h)
MULTI-NOT: {{: DW}}
MULTI: .debug_info contents:
MULTI: : DW_TAG_variable
MULTI-NOT: {{: DW}}
MULTI: DW_AT_name ("x86_64h_var")
MULTI-NOT: {{: DW}}

RUN: llvm-mc %S/brief.s -filetype obj -triple x86_64-apple-darwin -o - \
RUN: | llvm-dwarfdump -find=int - | FileCheck %s --check-prefix=TYPES
TYPES: .debug_info contents:
TYPES-NOT: {{:}}
TYPES: : DW_TAG_base_type
TYPES-NOT: {{:}}
TYPES: DW_AT_name ("int")
Expand Down
54 changes: 29 additions & 25 deletions llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
Expand Up @@ -309,6 +309,33 @@ static void filterByName(const StringSet<> &Names,

}

template <typename AccelTable>
static void getDIEOffset(const AccelTable &Accel, StringRef Name,
SmallVectorImpl<uint64_t> &Offsets) {
for (const auto &Entry : Accel.equal_range(Name))
if (llvm::Optional<uint64_t> Off = Entry.getDIESectionOffset())
Offsets.push_back(*Off);
}

/// Print only DIEs that have a certain name.
static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx,
raw_ostream &OS) {
SmallVector<uint64_t, 4> Offsets;
for (const auto &Name : Names) {
getDIEOffset(DICtx.getAppleNames(), Name, Offsets);
getDIEOffset(DICtx.getAppleTypes(), Name, Offsets);
getDIEOffset(DICtx.getAppleNamespaces(), Name, Offsets);
getDIEOffset(DICtx.getDebugNames(), Name, Offsets);
}
llvm::sort(Offsets.begin(), Offsets.end());
Offsets.erase(std::unique(Offsets.begin(), Offsets.end()), Offsets.end());

for (uint64_t Off: Offsets) {
DWARFDie Die = DICtx.getDIEForOffset(Off);
Die.dump(OS, 0, getDumpOpts());
}
}

/// Handle the --lookup option and dump the DIEs and line info for the given
/// address.
static bool lookup(DWARFContext &DICtx, uint64_t Address, raw_ostream &OS) {
Expand All @@ -335,15 +362,6 @@ static bool lookup(DWARFContext &DICtx, uint64_t Address, raw_ostream &OS) {
bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
Twine Filename, raw_ostream &OS);

template <typename AccelTable>
static llvm::Optional<uint64_t> getDIEOffset(const AccelTable &Accel,
StringRef Name) {
for (const auto &Entry : Accel.equal_range(Name))
if (llvm::Optional<uint64_t> Off = Entry.getDIESectionOffset())
return *Off;
return None;
}

static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
raw_ostream &OS) {
logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
Expand All @@ -369,22 +387,8 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,

// Handle the --find option and lower it to --debug-info=<offset>.
if (!Find.empty()) {
DumpOffsets[DIDT_ID_DebugInfo] = [&]() -> llvm::Optional<uint64_t> {
for (auto Name : Find) {
if (auto Offset = getDIEOffset(DICtx.getAppleNames(), Name))
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
if (auto Offset = getDIEOffset(DICtx.getAppleTypes(), Name))
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
if (auto Offset = getDIEOffset(DICtx.getAppleNamespaces(), Name))
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
if (auto Offset = getDIEOffset(DICtx.getDebugNames(), Name))
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
}
return None;
}();
// Early exit if --find was specified but the current file doesn't have it.
if (!DumpOffsets[DIDT_ID_DebugInfo])
return true;
filterByAccelName(Find, DICtx, OS);
return true;
}

// Dump the complete DWARF structure.
Expand Down

0 comments on commit 59870af

Please sign in to comment.