Skip to content

Commit a282463

Browse files
authored
[lldb/DWARF] Make sure bad abbreviation codes do not crash lldb (#93006)
We currently cannot represent abbreviation codes with more than 16 bits, and we were lldb-asserting if we ever ran into one. While I haven't seen any real DWARF with these kinds of abbreviations, it is possible to hit this with handcrafted evil dwarf, due some sort of corruptions, or just bugs (the addition of PeekDIEName makes these bugs more likely, as the function blindly dereferences offsets within the debug info section) . Missing abbreviations were already reporting an error. This patch turns sure that large abbreviations into an error as well, and adds a test for both cases.
1 parent 8930ba9 commit a282463

File tree

4 files changed

+70
-25
lines changed

4 files changed

+70
-25
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <cassert>
1212

1313
#include <algorithm>
14+
#include <limits>
1415
#include <optional>
1516

1617
#include "llvm/Support/LEB128.h"
@@ -41,13 +42,23 @@ extern int g_verbose;
4142
// Extract a debug info entry for a given DWARFUnit from the data
4243
// starting at the offset in offset_ptr
4344
bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data,
44-
const DWARFUnit *cu,
45+
const DWARFUnit &unit,
4546
lldb::offset_t *offset_ptr) {
4647
m_offset = *offset_ptr;
48+
auto report_error = [&](const char *fmt, const auto &...vals) {
49+
unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
50+
"[{0:x16}]: {1}, please file a bug and "
51+
"attach the file at the start of this error message",
52+
static_cast<uint64_t>(m_offset), llvm::formatv(fmt, vals...));
53+
*offset_ptr = std::numeric_limits<lldb::offset_t>::max();
54+
return false;
55+
};
56+
4757
m_parent_idx = 0;
4858
m_sibling_idx = 0;
4959
const uint64_t abbr_idx = data.GetULEB128(offset_ptr);
50-
lldbassert(abbr_idx <= UINT16_MAX);
60+
if (abbr_idx > std::numeric_limits<uint16_t>::max())
61+
return report_error("abbreviation code {0} too big", abbr_idx);
5162
m_abbr_idx = abbr_idx;
5263

5364
if (m_abbr_idx == 0) {
@@ -56,31 +67,18 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data,
5667
return true; // NULL debug tag entry
5768
}
5869

59-
const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu);
60-
if (abbrevDecl == nullptr) {
61-
cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
62-
"[{0:x16}]: invalid abbreviation code {1}, "
63-
"please file a bug and "
64-
"attach the file at the start of this error message",
65-
(uint64_t)m_offset, (unsigned)abbr_idx);
66-
// WE can't parse anymore if the DWARF is borked...
67-
*offset_ptr = UINT32_MAX;
68-
return false;
69-
}
70+
const auto *abbrevDecl = GetAbbreviationDeclarationPtr(&unit);
71+
if (abbrevDecl == nullptr)
72+
return report_error("invalid abbreviation code {0}", abbr_idx);
73+
7074
m_tag = abbrevDecl->getTag();
7175
m_has_children = abbrevDecl->hasChildren();
7276
// Skip all data in the .debug_info or .debug_types for the attributes
7377
for (const auto &attribute : abbrevDecl->attributes()) {
74-
if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, cu))
78+
if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, &unit))
7579
continue;
7680

77-
cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
78-
"[{0:x16}]: Unsupported DW_FORM_{1:x}, please file a bug "
79-
"and "
80-
"attach the file at the start of this error message",
81-
(uint64_t)m_offset, (unsigned)attribute.Form);
82-
*offset_ptr = m_offset;
83-
return false;
81+
return report_error("Unsupported DW_FORM_{1:x}", attribute.Form);
8482
}
8583
return true;
8684
}

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class DWARFDebugInfoEntry {
4949
void BuildFunctionAddressRangeTable(DWARFUnit *cu,
5050
DWARFDebugAranges *debug_aranges) const;
5151

52-
bool Extract(const DWARFDataExtractor &data, const DWARFUnit *cu,
52+
bool Extract(const DWARFDataExtractor &data, const DWARFUnit &cu,
5353
lldb::offset_t *offset_ptr);
5454

5555
using Recurse = DWARFBaseDIE::Recurse;

lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() {
6363
// parse
6464
const DWARFDataExtractor &data = GetData();
6565
if (offset < GetNextUnitOffset() &&
66-
m_first_die.Extract(data, this, &offset)) {
66+
m_first_die.Extract(data, *this, &offset)) {
6767
AddUnitDIE(m_first_die);
6868
return;
6969
}
@@ -242,7 +242,7 @@ void DWARFUnit::ExtractDIEsRWLocked() {
242242
die_index_stack.reserve(32);
243243
die_index_stack.push_back(0);
244244
bool prev_die_had_children = false;
245-
while (offset < next_cu_offset && die.Extract(data, this, &offset)) {
245+
while (offset < next_cu_offset && die.Extract(data, *this, &offset)) {
246246
const bool null_die = die.IsNULL();
247247
if (depth == 0) {
248248
assert(m_die_array.empty() && "Compile unit DIE already added");
@@ -670,7 +670,7 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) {
670670

671671
llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {
672672
DWARFDebugInfoEntry die;
673-
if (!die.Extract(GetData(), this, &die_offset))
673+
if (!die.Extract(GetData(), *this, &die_offset))
674674
return llvm::StringRef();
675675

676676
// Does die contain a DW_AT_Name?
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# REQUIRES: x86
2+
3+
# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s > %t
4+
# RUN: %lldb %t \
5+
# RUN: -o exit 2>&1 | FileCheck %s
6+
7+
# CHECK-DAG: error: {{.*}} [0x0000000000000022]: abbreviation code 65536 too big, please file a bug and attach the file at the start of this error message
8+
# CHECK-DAG: error: {{.*}} [0x0000000000000048]: invalid abbreviation code 47, please file a bug and attach the file at the start of this error message
9+
10+
11+
.section .debug_abbrev,"",@progbits
12+
.uleb128 65535 # Largest representable Abbreviation Code
13+
.byte 17 # DW_TAG_compile_unit
14+
.byte 1 # DW_CHILDREN_yes
15+
.byte 37 # DW_AT_producer
16+
.byte 8 # DW_FORM_string
17+
.byte 0 # EOM(1)
18+
.byte 0 # EOM(2)
19+
.byte 0 # EOM(3)
20+
21+
.section .debug_info,"",@progbits
22+
.Lcu_begin0:
23+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
24+
.Ldebug_info_start0:
25+
.short 5 # DWARF version number
26+
.byte 1 # DWARF Unit Type
27+
.byte 8 # Address Size (in bytes)
28+
.long .debug_abbrev # Offset Into Abbrev. Section
29+
.uleb128 65535 # DW_TAG_compile_unit
30+
.asciz "Hand-written DWARF" # DW_AT_producer
31+
.uleb128 65536 # Unrepresentable abbreviation
32+
.byte 0 # End Of Children Mark
33+
.Ldebug_info_end0:
34+
35+
.section .debug_info,"",@progbits
36+
.Lcu_begin1:
37+
.long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
38+
.Ldebug_info_start1:
39+
.short 5 # DWARF version number
40+
.byte 1 # DWARF Unit Type
41+
.byte 8 # Address Size (in bytes)
42+
.long .debug_abbrev # Offset Into Abbrev. Section
43+
.uleb128 65535 # DW_TAG_compile_unit
44+
.asciz "Hand-written DWARF" # DW_AT_producer
45+
.byte 47 # Missing abbreviation
46+
.byte 0 # End Of Children Mark
47+
.Ldebug_info_end1:

0 commit comments

Comments
 (0)