1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
//===- DWARFVerifier.cpp --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <set>
#include <vector>
using namespace llvm;
using namespace dwarf;
using namespace object;
void DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
DWARFAttribute &AttrValue) {
const auto Attr = AttrValue.Attr;
switch (Attr) {
case DW_AT_ranges:
// Make sure the offset in the DW_AT_ranges attribute is valid.
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
++NumDebugInfoErrors;
OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
"bounds:\n";
Die.dump(OS, 0);
OS << "\n";
}
} else {
++NumDebugInfoErrors;
OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
Die.dump(OS, 0);
OS << "\n";
}
break;
case DW_AT_stmt_list:
// Make sure the offset in the DW_AT_stmt_list attribute is valid.
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
++NumDebugInfoErrors;
OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
"bounds: "
<< format("0x%08" PRIx32, *SectionOffset) << "\n";
Die.dump(OS, 0);
OS << "\n";
}
} else {
++NumDebugInfoErrors;
OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
Die.dump(OS, 0);
OS << "\n";
}
break;
default:
break;
}
}
void DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
DWARFAttribute &AttrValue) {
const auto Form = AttrValue.Value.getForm();
switch (Form) {
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata: {
// Verify all CU relative references are valid CU offsets.
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
assert(RefVal);
if (RefVal) {
auto DieCU = Die.getDwarfUnit();
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
auto CUOffset = AttrValue.Value.getRawUValue();
if (CUOffset >= CUSize) {
++NumDebugInfoErrors;
OS << "error: " << FormEncodingString(Form) << " CU offset "
<< format("0x%08" PRIx32, CUOffset)
<< " is invalid (must be less than CU size of "
<< format("0x%08" PRIx32, CUSize) << "):\n";
Die.dump(OS, 0);
OS << "\n";
} else {
// Valid reference, but we will verify it points to an actual
// DIE later.
ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
}
}
break;
}
case DW_FORM_ref_addr: {
// Verify all absolute DIE references have valid offsets in the
// .debug_info section.
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
assert(RefVal);
if (RefVal) {
if (*RefVal >= DCtx.getInfoSection().Data.size()) {
++NumDebugInfoErrors;
OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
"bounds:\n";
Die.dump(OS, 0);
OS << "\n";
} else {
// Valid reference, but we will verify it points to an actual
// DIE later.
ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
}
}
break;
}
case DW_FORM_strp: {
auto SecOffset = AttrValue.Value.getAsSectionOffset();
assert(SecOffset); // DW_FORM_strp is a section offset.
if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
++NumDebugInfoErrors;
OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
Die.dump(OS, 0);
OS << "\n";
}
break;
}
default:
break;
}
}
void DWARFVerifier::verifyDebugInfoReferences() {
// Take all references and make sure they point to an actual DIE by
// getting the DIE by offset and emitting an error
OS << "Verifying .debug_info references...\n";
for (auto Pair : ReferenceToDIEOffsets) {
auto Die = DCtx.getDIEForOffset(Pair.first);
if (Die)
continue;
++NumDebugInfoErrors;
OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
<< ". Offset is in between DIEs:\n";
for (auto Offset : Pair.second) {
auto ReferencingDie = DCtx.getDIEForOffset(Offset);
ReferencingDie.dump(OS, 0);
OS << "\n";
}
OS << "\n";
}
}
bool DWARFVerifier::handleDebugInfo() {
NumDebugInfoErrors = 0;
OS << "Verifying .debug_info...\n";
for (const auto &CU : DCtx.compile_units()) {
unsigned NumDies = CU->getNumDIEs();
for (unsigned I = 0; I < NumDies; ++I) {
auto Die = CU->getDIEAtIndex(I);
const auto Tag = Die.getTag();
if (Tag == DW_TAG_null)
continue;
for (auto AttrValue : Die.attributes()) {
verifyDebugInfoAttribute(Die, AttrValue);
verifyDebugInfoForm(Die, AttrValue);
}
}
}
verifyDebugInfoReferences();
return NumDebugInfoErrors == 0;
}
void DWARFVerifier::verifyDebugLineStmtOffsets() {
std::map<uint64_t, DWARFDie> StmtListToDie;
for (const auto &CU : DCtx.compile_units()) {
auto Die = CU->getUnitDIE();
// Get the attribute value as a section offset. No need to produce an
// error here if the encoding isn't correct because we validate this in
// the .debug_info verifier.
auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
if (!StmtSectionOffset)
continue;
const uint32_t LineTableOffset = *StmtSectionOffset;
auto LineTable = DCtx.getLineTableForUnit(CU.get());
if (LineTableOffset < DCtx.getLineSection().Data.size()) {
if (!LineTable) {
++NumDebugLineErrors;
OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
<< "] was not able to be parsed for CU:\n";
Die.dump(OS, 0);
OS << '\n';
continue;
}
} else {
// Make sure we don't get a valid line table back if the offset is wrong.
assert(LineTable == nullptr);
// Skip this line table as it isn't valid. No need to create an error
// here because we validate this in the .debug_info verifier.
continue;
}
auto Iter = StmtListToDie.find(LineTableOffset);
if (Iter != StmtListToDie.end()) {
++NumDebugLineErrors;
OS << "error: two compile unit DIEs, "
<< format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
<< format("0x%08" PRIx32, Die.getOffset())
<< ", have the same DW_AT_stmt_list section offset:\n";
Iter->second.dump(OS, 0);
Die.dump(OS, 0);
OS << '\n';
// Already verified this line table before, no need to do it again.
continue;
}
StmtListToDie[LineTableOffset] = Die;
}
}
void DWARFVerifier::verifyDebugLineRows() {
for (const auto &CU : DCtx.compile_units()) {
auto Die = CU->getUnitDIE();
auto LineTable = DCtx.getLineTableForUnit(CU.get());
// If there is no line table we will have created an error in the
// .debug_info verifier or in verifyDebugLineStmtOffsets().
if (!LineTable)
continue;
uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
uint64_t PrevAddress = 0;
uint32_t RowIndex = 0;
for (const auto &Row : LineTable->Rows) {
if (Row.Address < PrevAddress) {
++NumDebugLineErrors;
OS << "error: .debug_line["
<< format("0x%08" PRIx32,
*toSectionOffset(Die.find(DW_AT_stmt_list)))
<< "] row[" << RowIndex
<< "] decreases in address from previous row:\n";
DWARFDebugLine::Row::dumpTableHeader(OS);
if (RowIndex > 0)
LineTable->Rows[RowIndex - 1].dump(OS);
Row.dump(OS);
OS << '\n';
}
if (Row.File > MaxFileIndex) {
++NumDebugLineErrors;
OS << "error: .debug_line["
<< format("0x%08" PRIx32,
*toSectionOffset(Die.find(DW_AT_stmt_list)))
<< "][" << RowIndex << "] has invalid file index " << Row.File
<< " (valid values are [1," << MaxFileIndex << "]):\n";
DWARFDebugLine::Row::dumpTableHeader(OS);
Row.dump(OS);
OS << '\n';
}
if (Row.EndSequence)
PrevAddress = 0;
else
PrevAddress = Row.Address;
++RowIndex;
}
}
}
bool DWARFVerifier::handleDebugLine() {
NumDebugLineErrors = 0;
OS << "Verifying .debug_line...\n";
verifyDebugLineStmtOffsets();
verifyDebugLineRows();
return NumDebugLineErrors == 0;
}
bool DWARFVerifier::handleAppleNames() {
NumAppleNamesErrors = 0;
OS << "Verifying .apple_names...\n";
DataExtractor AppleNamesSection(DCtx.getAppleNamesSection().Data,
DCtx.isLittleEndian(), 0);
DataExtractor StrData(DCtx.getStringSection(), DCtx.isLittleEndian(), 0);
DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData,
DCtx.getAppleNamesSection().Relocs);
if (!AppleNames.extract()) {
OS << "error: cannot extract .apple_names accelerator table\n";
return false;
}
// Verify that all buckets have a valid hash index or are empty
uint32_t NumBuckets = AppleNames.getNumBuckets();
uint32_t NumHashes = AppleNames.getNumHashes();
uint32_t BucketsOffset =
AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength();
for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset);
if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
OS << format("error: Bucket[%d] has invalid hash index: [%d]\n",
BucketIdx, HashIdx);
++NumAppleNamesErrors;
}
}
return NumAppleNamesErrors == 0;
}
|