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