[llvm] r301984 - Add line table verification to lldb-dwarfdump --verify
Greg Clayton via llvm-commits
llvm-commits at lists.llvm.org
Tue May 2 15:48:52 PDT 2017
Author: gclayton
Date: Tue May 2 17:48:52 2017
New Revision: 301984
URL: http://llvm.org/viewvc/llvm-project?rev=301984&view=rev
Log:
Add line table verification to lldb-dwarfdump --verify
This patch verifies the .debug_line:
- verify all addresses in a line table sequence have ascending addresses
- verify that all line table file indexes are valid
Unit tests added for both cases.
Differential Revision: https://reviews.llvm.org/D32765
Modified:
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h?rev=301984&r1=301983&r2=301984&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h Tue May 2 17:48:52 2017
@@ -104,7 +104,7 @@ public:
void postAppend();
void reset(bool DefaultIsStmt);
void dump(raw_ostream &OS) const;
-
+ static void dumpTableHeader(raw_ostream &OS);
static bool orderByAddress(const Row &LHS, const Row &RHS) {
return LHS.Address < RHS.Address;
}
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp?rev=301984&r1=301983&r2=301984&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFContext.cpp Tue May 2 17:48:52 2017
@@ -445,6 +445,75 @@ public:
}
return Success;
}
+
+ bool HandleDebugLine() {
+ bool Success = true;
+ OS << "Verifying .debug_line...\n";
+ for (const auto &CU : DCtx.compile_units()) {
+ uint32_t LineTableOffset = 0;
+ auto StmtFormValue = CU->getUnitDIE().find(DW_AT_stmt_list);
+ if (!StmtFormValue) {
+ // No line table for this compile unit.
+ continue;
+ }
+ // Get the attribute value as a section offset. No need to produce an
+ // error here if the encoding isn't correct because we validate this in
+ // the .debug_info verifier.
+ if (auto StmtSectionOffset = toSectionOffset(StmtFormValue)) {
+ LineTableOffset = *StmtSectionOffset;
+ if (LineTableOffset >= DCtx.getLineSection().Data.size()) {
+ // Make sure we don't get a valid line table back if the offset
+ // is wrong.
+ assert(DCtx.getLineTableForUnit(CU.get()) == nullptr);
+ // Skip this line table as it isn't valid. No need to create an error
+ // here because we validate this in the .debug_info verifier.
+ continue;
+ }
+ }
+ auto LineTable = DCtx.getLineTableForUnit(CU.get());
+ if (!LineTable) {
+ Success = false;
+ OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+ << "] was not able to be parsed for CU:\n";
+ CU->getUnitDIE().dump(OS, 0);
+ OS << '\n';
+ continue;
+ }
+ uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
+ uint64_t PrevAddress = 0;
+ uint32_t RowIndex = 0;
+ for (const auto &Row : LineTable->Rows) {
+ if (Row.Address < PrevAddress) {
+ Success = false;
+ OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+ << "] row[" << RowIndex
+ << "] decreases in address from previous row:\n";
+
+ DWARFDebugLine::Row::dumpTableHeader(OS);
+ if (RowIndex > 0)
+ LineTable->Rows[RowIndex - 1].dump(OS);
+ Row.dump(OS);
+ OS << '\n';
+ }
+
+ if (Row.File > MaxFileIndex) {
+ Success = false;
+ OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+ << "][" << RowIndex << "] has invalid file index " << Row.File
+ << " (valid values are [1," << MaxFileIndex << "]):\n";
+ DWARFDebugLine::Row::dumpTableHeader(OS);
+ Row.dump(OS);
+ OS << '\n';
+ }
+ if (Row.EndSequence)
+ PrevAddress = 0;
+ else
+ PrevAddress = Row.Address;
+ ++RowIndex;
+ }
+ }
+ return Success;
+ }
};
} // anonymous namespace
@@ -456,6 +525,10 @@ bool DWARFContext::verify(raw_ostream &O
if (!verifier.HandleDebugInfo())
Success = false;
}
+ if (DumpType == DIDT_All || DumpType == DIDT_Line) {
+ if (!verifier.HandleDebugLine())
+ Success = false;
+ }
return Success;
}
const DWARFUnitIndex &DWARFContext::getCUIndex() {
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp?rev=301984&r1=301983&r2=301984&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp Tue May 2 17:48:52 2017
@@ -287,6 +287,12 @@ void DWARFDebugLine::Row::reset(bool Def
EpilogueBegin = false;
}
+void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) {
+ OS << "Address Line Column File ISA Discriminator Flags\n"
+ << "------------------ ------ ------ ------ --- ------------- "
+ "-------------\n";
+}
+
void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column)
<< format(" %6u %3u %13u ", File, Isa, Discriminator)
@@ -313,9 +319,7 @@ void DWARFDebugLine::LineTable::dump(raw
OS << '\n';
if (!Rows.empty()) {
- OS << "Address Line Column File ISA Discriminator Flags\n"
- << "------------------ ------ ------ ------ --- ------------- "
- "-------------\n";
+ Row::dumpTableHeader(OS);
for (const Row &R : Rows) {
R.dump(OS);
}
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp?rev=301984&r1=301983&r2=301984&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp Tue May 2 17:48:52 2017
@@ -10,6 +10,7 @@
#include "DwarfGenerator.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Config/llvm-config.h"
@@ -18,8 +19,8 @@
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Object/ObjectFile.h"
-#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/ObjectYAML/DWARFEmitter.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -1191,10 +1192,7 @@ TEST(DWARFDebugInfo, TestEmptyChildren)
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
-
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
// Verify the number of compile units is correct.
uint32_t NumCUs = DwarfContext.getNumCompileUnits();
@@ -1667,6 +1665,13 @@ TEST(DWARFDebugInfo, TestImplicitConstAb
EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
}
+void VerifyError(DWARFContext &DwarfContext, StringRef Error) {
+ SmallString<1024> Str;
+ raw_svector_ostream Strm(Str);
+ EXPECT_FALSE(DwarfContext.verify(Strm, DIDT_All));
+ EXPECT_TRUE(Str.str().contains(Error));
+}
+
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidCURef) {
// Create a single compile unit with a single function that has a DW_AT_type
// that is CU relative. The CU offset is not valid becuase it is larger than
@@ -1711,17 +1716,10 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInva
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
-
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
-
- std::string str;
- raw_string_ostream strm(str);
- EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
- const char *err = "error: DW_FORM_ref4 CU offset 0x00001234 is invalid "
- "(must be less than CU size of 0x0000001a):";
- EXPECT_TRUE(strm.str().find(err) != std::string::npos);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(DwarfContext, "error: DW_FORM_ref4 CU offset 0x00001234 is "
+ "invalid (must be less than CU size of "
+ "0x0000001a):");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddr) {
@@ -1766,17 +1764,9 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInva
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
-
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
-
- std::string str;
- raw_string_ostream strm(str);
- EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
- strm.flush();
- const char *err = "error: DW_FORM_ref_addr offset beyond .debug_info bounds:";
- EXPECT_TRUE(strm.str().find(err) != std::string::npos);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(DwarfContext,
+ "error: DW_FORM_ref_addr offset beyond .debug_info bounds:");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRanges) {
@@ -1810,18 +1800,9 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInva
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
-
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
-
- std::string str;
- raw_string_ostream strm(str);
- EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
- strm.flush();
- const char *err = "error: DW_AT_ranges offset is beyond .debug_ranges "
- "bounds:";
- EXPECT_TRUE(strm.str().find(err) != std::string::npos);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(DwarfContext,
+ "error: DW_AT_ranges offset is beyond .debug_ranges bounds:");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidStmtList) {
@@ -1855,18 +1836,10 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInva
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
-
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
-
- std::string str;
- raw_string_ostream strm(str);
- EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
- strm.flush();
- const char *err = "error: DW_AT_stmt_list offset is beyond .debug_line "
- "bounds: 0x00001000";
- EXPECT_TRUE(strm.str().find(err) != std::string::npos);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(
+ DwarfContext,
+ "error: DW_AT_stmt_list offset is beyond .debug_line bounds: 0x00001000");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidStrp) {
@@ -1895,17 +1868,9 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInva
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
-
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
-
- std::string str;
- raw_string_ostream strm(str);
- EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
- strm.flush();
- const char *err = "error: DW_FORM_strp offset beyond .debug_str bounds:";
- EXPECT_TRUE(strm.str().find(err) != std::string::npos);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(DwarfContext,
+ "error: DW_FORM_strp offset beyond .debug_str bounds:");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddrBetween) {
@@ -1950,18 +1915,150 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInva
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(
+ DwarfContext,
+ "error: invalid DIE reference 0x00000011. Offset is in between DIEs:");
+}
- auto &DebugSections = *ErrOrSections;
-
- DWARFContextInMemory DwarfContext(DebugSections, 8);
+TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineSequence) {
+ // Create a single compile unit whose line table has a sequence in it where
+ // the address decreases.
+ 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: 68
+ 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: 1
+ ModTime: 0
+ Length: 0
+ Opcodes:
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 9
+ SubOpcode: DW_LNE_set_address
+ Data: 4112
+ - Opcode: DW_LNS_advance_line
+ SData: 9
+ Data: 4112
+ - Opcode: DW_LNS_copy
+ Data: 4112
+ - Opcode: DW_LNS_advance_pc
+ Data: 18446744073709551600
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 1
+ SubOpcode: DW_LNE_end_sequence
+ Data: 18446744073709551600
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(DwarfContext, "error: .debug_line[0x00000000] row[1] decreases "
+ "in address from previous row:");
+}
- std::string str;
- raw_string_ostream strm(str);
- EXPECT_FALSE(DwarfContext.verify(strm, DIDT_All));
- strm.flush();
- const char *err = "error: invalid DIE reference 0x00000011. Offset is in "
- "between DIEs:";
- EXPECT_TRUE(strm.str().find(err) != std::string::npos);
+TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineFileIndex) {
+ // Create a single compile unit whose line table has a line table row with
+ // an invalid file 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: 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: 5
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 1
+ SubOpcode: DW_LNE_end_sequence
+ Data: 5
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ VerifyError(DwarfContext, "error: .debug_line[0x00000000][1] has invalid "
+ "file index 5 (valid values are [1,1]):");
}
-
+
} // end anonymous namespace
More information about the llvm-commits
mailing list