Index: lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -417,10 +417,50 @@ // .debug_info verifier or in verifyDebugLineStmtOffsets(). if (!LineTable) continue; + + // Verify prologue. uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size(); + uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); + uint32_t FileIndex = 1; + StringMap FullPathMap; + for (const auto &FileName : LineTable->Prologue.FileNames) { + // Verify directory index. + if (FileName.DirIdx > MaxDirIndex) { + ++NumDebugLineErrors; + OS << "error: .debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "].prologue.file_names[" << FileIndex + << "].dir_idx contains an invalid index: " << FileName.DirIdx + << "\n"; + } + + // Check file paths for duplicates. + std::string FullPath; + const bool HasFullPath = LineTable->getFileNameByIndex( + FileIndex, CU->getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); + assert(HasFullPath && "Invalid index?"); + (void)HasFullPath; + auto It = FullPathMap.find(FullPath); + if (It == FullPathMap.end()) + FullPathMap[FullPath] = FileIndex; + else if (It->second != FileIndex) { + OS << "warning: .debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "].prologue.file_names[" << FileIndex + << "] is a duplicate of file_names[" << It->second << "]\n"; + } + + FileIndex++; + } + + // Verify rows. uint64_t PrevAddress = 0; uint32_t RowIndex = 0; for (const auto &Row : LineTable->Rows) { + // Verify row address. if (Row.Address < PrevAddress) { ++NumDebugLineErrors; OS << "error: .debug_line[" @@ -436,6 +476,7 @@ OS << '\n'; } + // Verify file index. if (Row.File > MaxFileIndex) { ++NumDebugLineErrors; OS << "error: .debug_line[" Index: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -1658,6 +1658,13 @@ EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2); } +void VerifyWarning(DWARFContext &DwarfContext, StringRef Error) { + SmallString<1024> Str; + raw_svector_ostream Strm(Str); + EXPECT_TRUE(DwarfContext.verify(Strm, DIDT_All)); + EXPECT_TRUE(Str.str().contains(Error)); +} + void VerifyError(DWARFContext &DwarfContext, StringRef Error) { SmallString<1024> Str; raw_svector_ostream Strm(Str); @@ -2062,6 +2069,156 @@ "file index 5 (valid values are [1,1]):"); } +TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineTablePorlogueDirIndex) { + // Create a single compile unit whose line table has a prologue with an + // invalid dir index. + StringRef yamldata = R"( + debug_str: + - '' + - /tmp/main.c + debug_abbrev: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_stmt_list + Form: DW_FORM_sec_offset + debug_info: + - Length: + TotalLength: 16 + Version: 4 + AbbrOffset: 0 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x0000000000000001 + - Value: 0x0000000000000000 + debug_line: + - Length: + TotalLength: 61 + Version: 2 + PrologueLength: 34 + MinInstLength: 1 + DefaultIsStmt: 1 + LineBase: 251 + LineRange: 14 + OpcodeBase: 13 + StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] + IncludeDirs: + - /tmp + Files: + - Name: main.c + DirIdx: 2 + ModTime: 0 + Length: 0 + Opcodes: + - Opcode: DW_LNS_extended_op + ExtLen: 9 + SubOpcode: DW_LNE_set_address + Data: 4096 + - Opcode: DW_LNS_advance_line + SData: 9 + Data: 4096 + - Opcode: DW_LNS_copy + Data: 4096 + - Opcode: DW_LNS_advance_pc + Data: 16 + - Opcode: DW_LNS_set_file + Data: 1 + - Opcode: DW_LNS_extended_op + ExtLen: 1 + SubOpcode: DW_LNE_end_sequence + Data: 1 + )"; + auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata); + ASSERT_TRUE((bool)ErrOrSections); + std::unique_ptr DwarfContext = + DWARFContext::create(*ErrOrSections, 8); + VerifyError(*DwarfContext, + "error: .debug_line[0x00000000].prologue." + "file_names[1].dir_idx contains an invalid index: 2"); +} + +TEST(DWARFDebugInfo, TestDwarfVerifyDuplicateFileWarning) { + // Create a single compile unit whose line table has a prologue with an + // invalid dir index. + StringRef yamldata = R"( + debug_str: + - '' + - /tmp/main.c + debug_abbrev: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_stmt_list + Form: DW_FORM_sec_offset + debug_info: + - Length: + TotalLength: 16 + Version: 4 + AbbrOffset: 0 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x0000000000000001 + - Value: 0x0000000000000000 + debug_line: + - Length: + TotalLength: 71 + Version: 2 + PrologueLength: 44 + MinInstLength: 1 + DefaultIsStmt: 1 + LineBase: 251 + LineRange: 14 + OpcodeBase: 13 + StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] + IncludeDirs: + - /tmp + Files: + - Name: main.c + DirIdx: 1 + ModTime: 0 + Length: 0 + - Name: main.c + DirIdx: 1 + ModTime: 0 + Length: 0 + Opcodes: + - Opcode: DW_LNS_extended_op + ExtLen: 9 + SubOpcode: DW_LNE_set_address + Data: 4096 + - Opcode: DW_LNS_advance_line + SData: 9 + Data: 4096 + - Opcode: DW_LNS_copy + Data: 4096 + - Opcode: DW_LNS_advance_pc + Data: 16 + - Opcode: DW_LNS_set_file + Data: 1 + - Opcode: DW_LNS_extended_op + ExtLen: 1 + SubOpcode: DW_LNE_end_sequence + Data: 2 + )"; + auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata); + ASSERT_TRUE((bool)ErrOrSections); + std::unique_ptr DwarfContext = + DWARFContext::create(*ErrOrSections, 8); + VerifyWarning(*DwarfContext, + "warning: .debug_line[0x00000000].prologue.file_names[2] is " + "a duplicate of file_names[1]"); +} + TEST(DWARFDebugInfo, TestDwarfVerifyCUDontShareLineTable) { // Create a two compile units where both compile units share the same // DW_AT_stmt_list value and verify we report the error correctly.