1 | //===- DWARFVerifier.h ----------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H |
10 | #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H |
11 | |
12 | #include "llvm/DebugInfo/DIContext.h" |
13 | #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" |
14 | #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" |
15 | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
16 | #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" |
17 | #include <cstdint> |
18 | #include <map> |
19 | #include <set> |
20 | |
21 | namespace llvm { |
22 | class raw_ostream; |
23 | struct DWARFAddressRange; |
24 | class DWARFUnit; |
25 | class DWARFUnitVector; |
26 | struct DWARFAttribute; |
27 | class DWARFContext; |
28 | class ; |
29 | class DWARFDebugAbbrev; |
30 | class ; |
31 | struct DWARFSection; |
32 | |
33 | class OutputCategoryAggregator { |
34 | private: |
35 | std::map<std::string, unsigned> Aggregation; |
36 | bool IncludeDetail; |
37 | |
38 | public: |
39 | OutputCategoryAggregator(bool includeDetail = false) |
40 | : IncludeDetail(includeDetail) {} |
41 | void ShowDetail(bool showDetail) { IncludeDetail = showDetail; } |
42 | size_t GetNumCategories() const { return Aggregation.size(); } |
43 | void Report(StringRef s, std::function<void()> detailCallback); |
44 | void EnumerateResults(std::function<void(StringRef, unsigned)> handleCounts); |
45 | }; |
46 | |
47 | /// A class that verifies DWARF debug information given a DWARF Context. |
48 | class DWARFVerifier { |
49 | public: |
50 | /// A class that keeps the address range information for a single DIE. |
51 | struct DieRangeInfo { |
52 | DWARFDie Die; |
53 | |
54 | /// Sorted DWARFAddressRanges. |
55 | std::vector<DWARFAddressRange> Ranges; |
56 | |
57 | /// Sorted DWARFAddressRangeInfo. |
58 | std::set<DieRangeInfo> Children; |
59 | |
60 | DieRangeInfo() = default; |
61 | DieRangeInfo(DWARFDie Die) : Die(Die) {} |
62 | |
63 | /// Used for unit testing. |
64 | DieRangeInfo(std::vector<DWARFAddressRange> Ranges) |
65 | : Ranges(std::move(Ranges)) {} |
66 | |
67 | typedef std::set<DieRangeInfo>::const_iterator die_range_info_iterator; |
68 | |
69 | /// Inserts the address range. If the range overlaps with an existing |
70 | /// range, the range that it overlaps with will be returned and the two |
71 | /// address ranges will be unioned together in "Ranges". |
72 | /// |
73 | /// This is used for finding overlapping ranges in the DW_AT_ranges |
74 | /// attribute of a DIE. It is also used as a set of address ranges that |
75 | /// children address ranges must all be contained in. |
76 | std::optional<DWARFAddressRange> insert(const DWARFAddressRange &R); |
77 | |
78 | /// Inserts the address range info. If any of its ranges overlaps with a |
79 | /// range in an existing range info, the range info is *not* added and an |
80 | /// iterator to the overlapping range info. |
81 | /// |
82 | /// This is used for finding overlapping children of the same DIE. |
83 | die_range_info_iterator insert(const DieRangeInfo &RI); |
84 | |
85 | /// Return true if ranges in this object contains all ranges within RHS. |
86 | bool contains(const DieRangeInfo &RHS) const; |
87 | |
88 | /// Return true if any range in this object intersects with any range in |
89 | /// RHS. |
90 | bool intersects(const DieRangeInfo &RHS) const; |
91 | }; |
92 | |
93 | private: |
94 | raw_ostream &OS; |
95 | DWARFContext &DCtx; |
96 | DIDumpOptions DumpOpts; |
97 | uint32_t NumDebugLineErrors = 0; |
98 | OutputCategoryAggregator ErrorCategory; |
99 | // Used to relax some checks that do not currently work portably |
100 | bool IsObjectFile; |
101 | bool IsMachOObject; |
102 | using ReferenceMap = std::map<uint64_t, std::set<uint64_t>>; |
103 | |
104 | raw_ostream &error() const; |
105 | raw_ostream &warn() const; |
106 | raw_ostream ¬e() const; |
107 | raw_ostream &dump(const DWARFDie &Die, unsigned indent = 0) const; |
108 | |
109 | /// Verifies the abbreviations section. |
110 | /// |
111 | /// This function currently checks that: |
112 | /// --No abbreviation declaration has more than one attributes with the same |
113 | /// name. |
114 | /// |
115 | /// \param Abbrev Pointer to the abbreviations section we are verifying |
116 | /// Abbrev can be a pointer to either .debug_abbrev or debug_abbrev.dwo. |
117 | /// |
118 | /// \returns The number of errors that occurred during verification. |
119 | unsigned verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev); |
120 | |
121 | /// Verifies the header of a unit in a .debug_info or .debug_types section. |
122 | /// |
123 | /// This function currently checks for: |
124 | /// - Unit is in 32-bit DWARF format. The function can be modified to |
125 | /// support 64-bit format. |
126 | /// - The DWARF version is valid |
127 | /// - The unit type is valid (if unit is in version >=5) |
128 | /// - The unit doesn't extend beyond the containing section |
129 | /// - The address size is valid |
130 | /// - The offset in the .debug_abbrev section is valid |
131 | /// |
132 | /// \param DebugInfoData The section data |
133 | /// \param Offset A reference to the offset start of the unit. The offset will |
134 | /// be updated to point to the next unit in the section |
135 | /// \param UnitIndex The index of the unit to be verified |
136 | /// \param UnitType A reference to the type of the unit |
137 | /// \param isUnitDWARF64 A reference to a flag that shows whether the unit is |
138 | /// in 64-bit format. |
139 | /// |
140 | /// \returns true if the header is verified successfully, false otherwise. |
141 | bool (const DWARFDataExtractor DebugInfoData, |
142 | uint64_t *Offset, unsigned UnitIndex, uint8_t &UnitType, |
143 | bool &isUnitDWARF64); |
144 | bool verifyName(const DWARFDie &Die); |
145 | |
146 | /// Verifies the header of a unit in a .debug_info or .debug_types section. |
147 | /// |
148 | /// This function currently verifies: |
149 | /// - The debug info attributes. |
150 | /// - The debug info form=s. |
151 | /// - The presence of a root DIE. |
152 | /// - That the root DIE is a unit DIE. |
153 | /// - If a unit type is provided, that the unit DIE matches the unit type. |
154 | /// - The DIE ranges. |
155 | /// - That call site entries are only nested within subprograms with a |
156 | /// DW_AT_call attribute. |
157 | /// |
158 | /// \param Unit The DWARF Unit to verify. |
159 | /// |
160 | /// \returns The number of errors that occurred during verification. |
161 | unsigned verifyUnitContents(DWARFUnit &Unit, |
162 | ReferenceMap &UnitLocalReferences, |
163 | ReferenceMap &CrossUnitReferences); |
164 | |
165 | /// Verifies the unit headers and contents in a .debug_info or .debug_types |
166 | /// section. |
167 | /// |
168 | /// \param S The DWARF Section to verify. |
169 | /// |
170 | /// \returns The number of errors that occurred during verification. |
171 | unsigned verifyUnitSection(const DWARFSection &S); |
172 | unsigned verifyUnits(const DWARFUnitVector &Units); |
173 | |
174 | unsigned verifyIndex(StringRef Name, DWARFSectionKind SectionKind, |
175 | StringRef Index); |
176 | |
177 | /// Verifies that a call site entry is nested within a subprogram with a |
178 | /// DW_AT_call attribute. |
179 | /// |
180 | /// \returns Number of errors that occurred during verification. |
181 | unsigned verifyDebugInfoCallSite(const DWARFDie &Die); |
182 | |
183 | /// Verify that all Die ranges are valid. |
184 | /// |
185 | /// This function currently checks for: |
186 | /// - cases in which lowPC >= highPC |
187 | /// |
188 | /// \returns Number of errors that occurred during verification. |
189 | unsigned verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI); |
190 | |
191 | /// Verifies the attribute's DWARF attribute and its value. |
192 | /// |
193 | /// This function currently checks for: |
194 | /// - DW_AT_ranges values is a valid .debug_ranges offset |
195 | /// - DW_AT_stmt_list is a valid .debug_line offset |
196 | /// |
197 | /// \param Die The DWARF DIE that owns the attribute value |
198 | /// \param AttrValue The DWARF attribute value to check |
199 | /// |
200 | /// \returns NumErrors The number of errors occurred during verification of |
201 | /// attributes' values in a unit |
202 | unsigned verifyDebugInfoAttribute(const DWARFDie &Die, |
203 | DWARFAttribute &AttrValue); |
204 | |
205 | /// Verifies the attribute's DWARF form. |
206 | /// |
207 | /// This function currently checks for: |
208 | /// - All DW_FORM_ref values that are CU relative have valid CU offsets |
209 | /// - All DW_FORM_ref_addr values have valid section offsets |
210 | /// - All DW_FORM_strp values have valid .debug_str offsets |
211 | /// |
212 | /// \param Die The DWARF DIE that owns the attribute value |
213 | /// \param AttrValue The DWARF attribute value to check |
214 | /// |
215 | /// \returns NumErrors The number of errors occurred during verification of |
216 | /// attributes' forms in a unit |
217 | unsigned verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue, |
218 | ReferenceMap &UnitLocalReferences, |
219 | ReferenceMap &CrossUnitReferences); |
220 | |
221 | /// Verifies the all valid references that were found when iterating through |
222 | /// all of the DIE attributes. |
223 | /// |
224 | /// This function will verify that all references point to DIEs whose DIE |
225 | /// offset matches. This helps to ensure if a DWARF link phase moved things |
226 | /// around, that it doesn't create invalid references by failing to relocate |
227 | /// CU relative and absolute references. |
228 | /// |
229 | /// \returns NumErrors The number of errors occurred during verification of |
230 | /// references for the .debug_info and .debug_types sections |
231 | unsigned verifyDebugInfoReferences( |
232 | const ReferenceMap &, |
233 | llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForDieOffset); |
234 | |
235 | /// Verify the DW_AT_stmt_list encoding and value and ensure that no |
236 | /// compile units that have the same DW_AT_stmt_list value. |
237 | void verifyDebugLineStmtOffsets(); |
238 | |
239 | /// Verify that all of the rows in the line table are valid. |
240 | /// |
241 | /// This function currently checks for: |
242 | /// - addresses within a sequence that decrease in value |
243 | /// - invalid file indexes |
244 | void verifyDebugLineRows(); |
245 | |
246 | /// Verify that an Apple-style accelerator table is valid. |
247 | /// |
248 | /// This function currently checks that: |
249 | /// - The fixed part of the header fits in the section |
250 | /// - The size of the section is as large as what the header describes |
251 | /// - There is at least one atom |
252 | /// - The form for each atom is valid |
253 | /// - The tag for each DIE in the table is valid |
254 | /// - The buckets have a valid index, or they are empty |
255 | /// - Each hashdata offset is valid |
256 | /// - Each DIE is valid |
257 | /// |
258 | /// \param AccelSection pointer to the section containing the acceleration table |
259 | /// \param StrData pointer to the string section |
260 | /// \param SectionName the name of the table we're verifying |
261 | /// |
262 | /// \returns The number of errors occurred during verification |
263 | unsigned (const DWARFSection *AccelSection, |
264 | DataExtractor *StrData, |
265 | const char *SectionName); |
266 | |
267 | unsigned verifyDebugNamesCULists(const DWARFDebugNames &AccelTable); |
268 | unsigned (const DWARFDebugNames::NameIndex &NI, |
269 | const DataExtractor &StrData); |
270 | unsigned verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI); |
271 | unsigned verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI, |
272 | const DWARFDebugNames::Abbrev &Abbr, |
273 | DWARFDebugNames::AttributeEncoding AttrEnc); |
274 | unsigned verifyNameIndexEntries(const DWARFDebugNames::NameIndex &NI, |
275 | const DWARFDebugNames::NameTableEntry &NTE); |
276 | unsigned verifyNameIndexCompleteness(const DWARFDie &Die, |
277 | const DWARFDebugNames::NameIndex &NI); |
278 | |
279 | /// Verify that the DWARF v5 accelerator table is valid. |
280 | /// |
281 | /// This function currently checks that: |
282 | /// - Headers individual Name Indices fit into the section and can be parsed. |
283 | /// - Abbreviation tables can be parsed and contain valid index attributes |
284 | /// with correct form encodings. |
285 | /// - The CU lists reference existing compile units. |
286 | /// - The buckets have a valid index, or they are empty. |
287 | /// - All names are reachable via the hash table (they have the correct hash, |
288 | /// and the hash is in the correct bucket). |
289 | /// - Information in the index entries is complete (all required entries are |
290 | /// present) and consistent with the debug_info section DIEs. |
291 | /// |
292 | /// \param AccelSection section containing the acceleration table |
293 | /// \param StrData string section |
294 | /// |
295 | /// \returns The number of errors occurred during verification |
296 | unsigned (const DWARFSection &AccelSection, |
297 | const DataExtractor &StrData); |
298 | |
299 | public: |
300 | DWARFVerifier(raw_ostream &S, DWARFContext &D, |
301 | DIDumpOptions DumpOpts = DIDumpOptions::getForSingleDIE()); |
302 | |
303 | /// Verify the information in any of the following sections, if available: |
304 | /// .debug_abbrev, debug_abbrev.dwo |
305 | /// |
306 | /// Any errors are reported to the stream that was this object was |
307 | /// constructed with. |
308 | /// |
309 | /// \returns true if .debug_abbrev and .debug_abbrev.dwo verify successfully, |
310 | /// false otherwise. |
311 | bool handleDebugAbbrev(); |
312 | |
313 | /// Verify the information in the .debug_info and .debug_types sections. |
314 | /// |
315 | /// Any errors are reported to the stream that this object was |
316 | /// constructed with. |
317 | /// |
318 | /// \returns true if all sections verify successfully, false otherwise. |
319 | bool handleDebugInfo(); |
320 | |
321 | /// Verify the information in the .debug_cu_index section. |
322 | /// |
323 | /// Any errors are reported to the stream that was this object was |
324 | /// constructed with. |
325 | /// |
326 | /// \returns true if the .debug_cu_index verifies successfully, false |
327 | /// otherwise. |
328 | bool handleDebugCUIndex(); |
329 | |
330 | /// Verify the information in the .debug_tu_index section. |
331 | /// |
332 | /// Any errors are reported to the stream that was this object was |
333 | /// constructed with. |
334 | /// |
335 | /// \returns true if the .debug_tu_index verifies successfully, false |
336 | /// otherwise. |
337 | bool handleDebugTUIndex(); |
338 | |
339 | /// Verify the information in the .debug_line section. |
340 | /// |
341 | /// Any errors are reported to the stream that was this object was |
342 | /// constructed with. |
343 | /// |
344 | /// \returns true if the .debug_line verifies successfully, false otherwise. |
345 | bool handleDebugLine(); |
346 | |
347 | /// Verify the information in accelerator tables, if they exist. |
348 | /// |
349 | /// Any errors are reported to the stream that was this object was |
350 | /// constructed with. |
351 | /// |
352 | /// \returns true if the existing Apple-style accelerator tables verify |
353 | /// successfully, false otherwise. |
354 | bool handleAccelTables(); |
355 | |
356 | /// Verify the information in the .debug_str_offsets[.dwo]. |
357 | /// |
358 | /// Any errors are reported to the stream that was this object was |
359 | /// constructed with. |
360 | /// |
361 | /// \returns true if the .debug_line verifies successfully, false otherwise. |
362 | bool handleDebugStrOffsets(); |
363 | bool verifyDebugStrOffsets(std::optional<dwarf::DwarfFormat> LegacyFormat, |
364 | StringRef SectionName, const DWARFSection &Section, |
365 | StringRef StrData); |
366 | |
367 | /// Emits any aggregate information collected, depending on the dump options |
368 | void summarize(); |
369 | }; |
370 | |
371 | static inline bool operator<(const DWARFVerifier::DieRangeInfo &LHS, |
372 | const DWARFVerifier::DieRangeInfo &RHS) { |
373 | return std::tie(args: LHS.Ranges, args: LHS.Die) < std::tie(args: RHS.Ranges, args: RHS.Die); |
374 | } |
375 | |
376 | } // end namespace llvm |
377 | |
378 | #endif // LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H |
379 | |