llvm.org GIT mirror llvm / edadbde
Verify that all references point to actual DIEs in "llvm-dwarfdump --verify" LTO and other fancy linking previously led to DWARF that contained invalid references. We already validate that CU relative references fall into the CU, and the DW_FORM_ref_addr references fall inside the .debug_info section, but we didn't validate that the references pointed to correct DIE offsets. This new verification will ensure that all references refer to actual DIEs and not an offset in between. This caught a bug in DWARFUnit::getDIEForOffset() where if you gave it any offset, it would match the DIE that mathes the offset _or_ the next DIE. This has been fixed. Differential Revision: https://reviews.llvm.org/D32722 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301971 91177308-0d34-0410-b5e6-96231b3b80d8 Greg Clayton 3 years ago
4 changed file(s) with 207 addition(s) and 87 deletion(s). Raw diff Collapse all Expand all
171171 return DWOCUs[index].get();
172172 }
173173
174 /// Get a DIE given an exact offset.
175 DWARFDie getDIEForOffset(uint32_t Offset);
176
174177 const DWARFUnitIndex &getCUIndex();
175178 DWARFGdbIndex &getGdbIndex();
176179 const DWARFUnitIndex &getTUIndex();
311311 [](const DWARFDebugInfoEntry &LHS, uint32_t Offset) {
312312 return LHS.getOffset() < Offset;
313313 });
314 if (it == DieArray.end())
315 return DWARFDie();
316 return DWARFDie(this, &*it);
314 if (it != DieArray.end() && it->getOffset() == Offset)
315 return DWARFDie(this, &*it);
316 return DWARFDie();
317317 }
318318
319319 uint32_t getLineTableOffset() const {
4141 #include "llvm/Support/raw_ostream.h"
4242 #include
4343 #include
44 #include
45 #include
4446 #include
4547 #include
4648 #include
283285 getStringSection(), isLittleEndian());
284286 }
285287
286 bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
287 bool Success = true;
288 if (DumpType == DIDT_All || DumpType == DIDT_Info) {
288 DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
289 parseCompileUnits();
290 if (auto *CU = CUs.getUnitForOffset(Offset))
291 return CU->getDIEForOffset(Offset);
292 return DWARFDie();
293 }
294
295 namespace {
296
297 class Verifier {
298 raw_ostream &OS;
299 DWARFContext &DCtx;
300 public:
301 Verifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {}
302
303 bool HandleDebugInfo() {
304 bool Success = true;
305 // A map that tracks all references (converted absolute references) so we
306 // can verify each reference points to a valid DIE and not an offset that
307 // lies between to valid DIEs.
308 std::map> ReferenceToDIEOffsets;
309
289310 OS << "Verifying .debug_info...\n";
290 for (const auto &CU : compile_units()) {
311 for (const auto &CU : DCtx.compile_units()) {
291312 unsigned NumDies = CU->getNumDIEs();
292313 for (unsigned I = 0; I < NumDies; ++I) {
293314 auto Die = CU->getDIEAtIndex(I);
298319 const auto Attr = AttrValue.Attr;
299320 const auto Form = AttrValue.Value.getForm();
300321 switch (Attr) {
301 case DW_AT_ranges:
302 // Make sure the offset in the DW_AT_ranges attribute is valid.
303 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
304 if (*SectionOffset >= getRangeSection().Data.size()) {
322 case DW_AT_ranges:
323 // Make sure the offset in the DW_AT_ranges attribute is valid.
324 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
325 if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
326 Success = false;
327 OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
328 "bounds:\n";
329 Die.dump(OS, 0);
330 OS << "\n";
331 }
332 } else {
305333 Success = false;
306 OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
307 "bounds:\n";
334 OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
308335 Die.dump(OS, 0);
309336 OS << "\n";
310337 }
311 } else {
312 Success = false;
313 OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
314 Die.dump(OS, 0);
315 OS << "\n";
316 }
317 break;
318 case DW_AT_stmt_list:
319 // Make sure the offset in the DW_AT_stmt_list attribute is valid.
320 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
321 if (*SectionOffset >= getLineSection().Data.size()) {
338 break;
339 case DW_AT_stmt_list:
340 // Make sure the offset in the DW_AT_stmt_list attribute is valid.
341 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
342 if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
343 Success = false;
344 OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
345 "bounds: "
346 << format("0x%08" PRIx32, *SectionOffset) << "\n";
347 CU->getUnitDIE().dump(OS, 0);
348 OS << "\n";
349 }
350 } else {
322351 Success = false;
323 OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
324 "bounds: "
325 << format("0x%08" PRIx32, *SectionOffset) << "\n";
326 CU->getUnitDIE().dump(OS, 0);
327 OS << "\n";
328 }
329 } else {
330 Success = false;
331 OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
332 Die.dump(OS, 0);
333 OS << "\n";
334 }
335 break;
336
337 default:
338 break;
339 }
340 switch (Form) {
341 case DW_FORM_ref1:
342 case DW_FORM_ref2:
343 case DW_FORM_ref4:
344 case DW_FORM_ref8:
345 case DW_FORM_ref_udata: {
346 // Verify all CU relative references are valid CU offsets.
347 Optional RefVal = AttrValue.Value.getAsReference();
348 assert(RefVal);
349 if (RefVal) {
350 auto DieCU = Die.getDwarfUnit();
351 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
352 auto CUOffset = AttrValue.Value.getRawUValue();
353 if (CUOffset >= CUSize) {
354 Success = false;
355 OS << "error: " << FormEncodingString(Form) << " CU offset "
356 << format("0x%08" PRIx32, CUOffset)
357 << " is invalid (must be less than CU size of "
358 << format("0x%08" PRIx32, CUSize) << "):\n";
352 OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
359353 Die.dump(OS, 0);
360354 OS << "\n";
361355 }
356 break;
357
358 default:
359 break;
360 }
361 switch (Form) {
362 case DW_FORM_ref1:
363 case DW_FORM_ref2:
364 case DW_FORM_ref4:
365 case DW_FORM_ref8:
366 case DW_FORM_ref_udata: {
367 // Verify all CU relative references are valid CU offsets.
368 Optional RefVal = AttrValue.Value.getAsReference();
369 assert(RefVal);
370 if (RefVal) {
371 auto DieCU = Die.getDwarfUnit();
372 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
373 auto CUOffset = AttrValue.Value.getRawUValue();
374 if (CUOffset >= CUSize) {
375 Success = false;
376 OS << "error: " << FormEncodingString(Form) << " CU offset "
377 << format("0x%08" PRIx32, CUOffset)
378 << " is invalid (must be less than CU size of "
379 << format("0x%08" PRIx32, CUSize) << "):\n";
380 Die.dump(OS, 0);
381 OS << "\n";
382 } else {
383 // Valid reference, but we will verify it points to an actual
384 // DIE later.
385 ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
386 }
387 }
388 break;
362389 }
363 break;
364 }
365 case DW_FORM_ref_addr: {
366 // Verify all absolute DIE references have valid offsets in the
367 // .debug_info section.
368 Optional RefVal = AttrValue.Value.getAsReference();
369 assert(RefVal);
370 if (RefVal && *RefVal >= getInfoSection().Data.size()) {
371 Success = false;
372 OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
373 "bounds:\n";
374 Die.dump(OS, 0);
375 OS << "\n";
390 case DW_FORM_ref_addr: {
391 // Verify all absolute DIE references have valid offsets in the
392 // .debug_info section.
393 Optional RefVal = AttrValue.Value.getAsReference();
394 assert(RefVal);
395 if (RefVal) {
396 if(*RefVal >= DCtx.getInfoSection().Data.size()) {
397 Success = false;
398 OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
399 "bounds:\n";
400 Die.dump(OS, 0);
401 OS << "\n";
402 } else {
403 // Valid reference, but we will verify it points to an actual
404 // DIE later.
405 ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
406 }
407 }
408 break;
376409 }
377 break;
378 }
379 case DW_FORM_strp: {
380 auto SecOffset = AttrValue.Value.getAsSectionOffset();
381 assert(SecOffset); // DW_FORM_strp is a section offset.
382 if (SecOffset && *SecOffset >= getStringSection().size()) {
383 Success = false;
384 OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
385 Die.dump(OS, 0);
386 OS << "\n";
410 case DW_FORM_strp: {
411 auto SecOffset = AttrValue.Value.getAsSectionOffset();
412 assert(SecOffset); // DW_FORM_strp is a section offset.
413 if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
414 Success = false;
415 OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
416 Die.dump(OS, 0);
417 OS << "\n";
418 }
419 break;
387420 }
388 break;
389 }
390 default:
391 break;
421 default:
422 break;
392423 }
393424 }
394425 }
395426 }
427
428 // Take all references and make sure they point to an actual DIE by
429 // getting the DIE by offset and emitting an error
430 OS << "Verifying .debug_info references...\n";
431 for (auto Pair: ReferenceToDIEOffsets) {
432 auto Die = DCtx.getDIEForOffset(Pair.first);
433 if (Die)
434 continue;
435 Success = false;
436 OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
437 << ". Offset is in between DIEs:\n";
438 for (auto Offset: Pair.second) {
439 auto ReferencingDie = DCtx.getDIEForOffset(Offset);
440 ReferencingDie.dump(OS, 0);
441 OS << "\n";
442 }
443 OS << "\n";
444 }
445 return Success;
446 }
447 };
448
449 } // anonymous namespace
450
451 bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
452 bool Success = true;
453 Verifier verifier(OS, *this);
454 if (DumpType == DIDT_All || DumpType == DIDT_Info) {
455 if (!verifier.HandleDebugInfo())
456 Success = false;
396457 }
397458 return Success;
398459 }
19071907 EXPECT_TRUE(strm.str().find(err) != std::string::npos);
19081908 }
19091909
1910 TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddrBetween) {
1911 // Create a single compile unit with a single function that has a DW_AT_type
1912 // with a valid .debug_info offset, but the offset is between two DIEs.
1913 const char *yamldata = R"(
1914 debug_str:
1915 - ''
1916 - /tmp/main.c
1917 - main
1918 debug_abbrev:
1919 - Code: 0x00000001
1920 Tag: DW_TAG_compile_unit
1921 Children: DW_CHILDREN_yes
1922 Attributes:
1923 - Attribute: DW_AT_name
1924 Form: DW_FORM_strp
1925 - Code: 0x00000002
1926 Tag: DW_TAG_subprogram
1927 Children: DW_CHILDREN_no
1928 Attributes:
1929 - Attribute: DW_AT_name
1930 Form: DW_FORM_strp
1931 - Attribute: DW_AT_type
1932 Form: DW_FORM_ref_addr
1933 debug_info:
1934 - Length:
1935 TotalLength: 22
1936 Version: 4
1937 AbbrOffset: 0
1938 AddrSize: 8
1939 Entries:
1940 - AbbrCode: 0x00000001
1941 Values:
1942 - Value: 0x0000000000000001
1943 - AbbrCode: 0x00000002
1944 Values:
1945 - Value: 0x000000000000000D
1946 - Value: 0x0000000000000011
1947 - AbbrCode: 0x00000000
1948 Values:
1949 )";
1950 auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
1951 ASSERT_TRUE((bool)ErrOrSections);
1952
1953 auto &DebugSections = *ErrOrSections;
1954
1955 DWARFContextInMemory DwarfContext(DebugSections, 8);
1956
1957 std::string str;
1958 raw_string_ostream strm(str);
1959 EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
1960 strm.flush();
1961 const char *err = "error: invalid DIE reference 0x00000011. Offset is in "
1962 "between DIEs:";
1963 EXPECT_TRUE(strm.str().find(err) != std::string::npos);
1964 }
1965
19101966 } // end anonymous namespace