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