[llvm] r366762 - [DWARF] Add more error handling to debug line parser.
Jonas Devlieghere via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 22 16:23:34 PDT 2019
Author: jdevlieghere
Date: Mon Jul 22 16:23:34 2019
New Revision: 366762
URL: http://llvm.org/viewvc/llvm-project?rev=366762&view=rev
Log:
[DWARF] Add more error handling to debug line parser.
This patch exnteds the error handling in the debug line parser to get
rid of the existing MD5 assertion. I want to reuse the debug line parser
from LLVM in LLDB where we cannot crash on invalid input.
Differential revision: https://reviews.llvm.org/D64544
Modified:
llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s
llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test
llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp?rev=366762&r1=366761&r2=366762&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDebugLine.cpp Mon Jul 22 16:23:34 2019
@@ -187,18 +187,24 @@ parseV2DirFileTables(const DWARFDataExtr
}
// Parse v5 directory/file entry content descriptions.
-// Returns the descriptors, or an empty vector if we did not find a path or
-// ran off the end of the prologue.
-static ContentDescriptors
-parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t
- *OffsetPtr, uint64_t EndPrologueOffset, DWARFDebugLine::ContentTypeTracker
- *ContentTypes) {
+// Returns the descriptors, or an error if we did not find a path or ran off
+// the end of the prologue.
+static llvm::Expected<ContentDescriptors>
+parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
+ uint64_t EndPrologueOffset,
+ DWARFDebugLine::ContentTypeTracker *ContentTypes) {
ContentDescriptors Descriptors;
int FormatCount = DebugLineData.getU8(OffsetPtr);
bool HasPath = false;
for (int I = 0; I != FormatCount; ++I) {
if (*OffsetPtr >= EndPrologueOffset)
- return ContentDescriptors();
+ return createStringError(
+ errc::invalid_argument,
+ "failed to parse entry content descriptions at offset "
+ "0x%8.8" PRIx64
+ " because offset extends beyond the prologue end at offset "
+ "0x%8.8" PRIx64,
+ *OffsetPtr, EndPrologueOffset);
ContentDescriptor Descriptor;
Descriptor.Type =
dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
@@ -209,10 +215,15 @@ parseV5EntryFormat(const DWARFDataExtrac
ContentTypes->trackContentType(Descriptor.Type);
Descriptors.push_back(Descriptor);
}
- return HasPath ? Descriptors : ContentDescriptors();
+
+ if (!HasPath)
+ return createStringError(errc::invalid_argument,
+ "failed to parse entry content descriptions"
+ " because no path was found");
+ return Descriptors;
}
-static bool
+static Error
parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
uint32_t *OffsetPtr, uint64_t EndPrologueOffset,
const dwarf::FormParams &FormParams,
@@ -221,48 +232,65 @@ parseV5DirFileTables(const DWARFDataExtr
std::vector<DWARFFormValue> &IncludeDirectories,
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
// Get the directory entry description.
- ContentDescriptors DirDescriptors =
+ llvm::Expected<ContentDescriptors> DirDescriptors =
parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, nullptr);
- if (DirDescriptors.empty())
- return false;
+ if (!DirDescriptors)
+ return DirDescriptors.takeError();
// Get the directory entries, according to the format described above.
int DirEntryCount = DebugLineData.getU8(OffsetPtr);
for (int I = 0; I != DirEntryCount; ++I) {
if (*OffsetPtr >= EndPrologueOffset)
- return false;
- for (auto Descriptor : DirDescriptors) {
+ return createStringError(
+ errc::invalid_argument,
+ "failed to parse directory entry at offset "
+ "0x%8.8" PRIx64
+ " because offset extends beyond the prologue end at offset "
+ "0x%8.8" PRIx64,
+ *OffsetPtr, EndPrologueOffset);
+ for (auto Descriptor : *DirDescriptors) {
DWARFFormValue Value(Descriptor.Form);
switch (Descriptor.Type) {
case DW_LNCT_path:
if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
- return false;
+ return createStringError(errc::invalid_argument,
+ "failed to parse directory entry because "
+ "extracting the form value failed.");
IncludeDirectories.push_back(Value);
break;
default:
if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams))
- return false;
+ return createStringError(errc::invalid_argument,
+ "failed to parse directory entry because "
+ "skipping the form value failed.");
}
}
}
// Get the file entry description.
- ContentDescriptors FileDescriptors =
- parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset,
- &ContentTypes);
- if (FileDescriptors.empty())
- return false;
+ llvm::Expected<ContentDescriptors> FileDescriptors = parseV5EntryFormat(
+ DebugLineData, OffsetPtr, EndPrologueOffset, &ContentTypes);
+ if (!FileDescriptors)
+ return FileDescriptors.takeError();
// Get the file entries, according to the format described above.
int FileEntryCount = DebugLineData.getU8(OffsetPtr);
for (int I = 0; I != FileEntryCount; ++I) {
if (*OffsetPtr >= EndPrologueOffset)
- return false;
+ return createStringError(
+ errc::invalid_argument,
+ "failed to parse file entry at offset "
+ "0x%8.8" PRIx64
+ " because offset extends beyond the prologue end at offset "
+ "0x%8.8" PRIx64,
+ *OffsetPtr, EndPrologueOffset);
DWARFDebugLine::FileNameEntry FileEntry;
- for (auto Descriptor : FileDescriptors) {
+ for (auto Descriptor : *FileDescriptors) {
DWARFFormValue Value(Descriptor.Form);
if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
- return false;
+ return createStringError(errc::invalid_argument,
+ "failed to parse file entry because "
+ "extracting the form value failed.");
switch (Descriptor.Type) {
case DW_LNCT_path:
FileEntry.Name = Value;
@@ -280,7 +308,10 @@ parseV5DirFileTables(const DWARFDataExtr
FileEntry.Length = Value.getAsUnsignedConstant().getValue();
break;
case DW_LNCT_MD5:
- assert(Value.getAsBlock().getValue().size() == 16);
+ if (!Value.getAsBlock() || Value.getAsBlock().getValue().size() != 16)
+ return createStringError(
+ errc::invalid_argument,
+ "failed to parse file entry because the MD5 hash is invalid");
std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16,
FileEntry.Checksum.Bytes.begin());
break;
@@ -290,7 +321,7 @@ parseV5DirFileTables(const DWARFDataExtr
}
FileNames.push_back(FileEntry);
}
- return true;
+ return Error::success();
}
Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
@@ -343,14 +374,17 @@ Error DWARFDebugLine::Prologue::parse(co
}
if (getVersion() >= 5) {
- if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
- FormParams, Ctx, U, ContentTypes,
- IncludeDirectories, FileNames)) {
- return createStringError(errc::invalid_argument,
- "parsing line table prologue at 0x%8.8" PRIx64
- " found an invalid directory or file table description at"
- " 0x%8.8" PRIx64,
- PrologueOffset, (uint64_t)*OffsetPtr);
+ if (Error e = parseV5DirFileTables(
+ DebugLineData, OffsetPtr, EndPrologueOffset, FormParams, Ctx, U,
+ ContentTypes, IncludeDirectories, FileNames)) {
+ return joinErrors(
+ createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at 0x%8.8" PRIx64
+ " found an invalid directory or file table description at"
+ " 0x%8.8" PRIx64,
+ PrologueOffset, (uint64_t)*OffsetPtr),
+ std::move(e));
}
} else
parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
Modified: llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s?rev=366762&r1=366761&r2=366762&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s (original)
+++ llvm/trunk/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s Mon Jul 22 16:23:34 2019
@@ -162,6 +162,164 @@
.byte 1 # DW_LNS_copy
.Lunit_no_eos_end:
+# Invalid prologue length
+.long .Linvalid_description_end0-.Linvalid_description_start0 # Length of Unit
+.Linvalid_description_start0:
+.short 5 # DWARF version number
+.byte 8 # Address Size
+.byte 0 # Segment Selector Size
+.long 15 # Length of Prologue (invalid)
+.Linvalid_description_params0:
+.byte 1 # Minimum Instruction Length
+.byte 1 # Maximum Operations per Instruction
+.byte 1 # Default is_stmt
+.byte -5 # Line Base
+.byte 14 # Line Range
+.byte 13 # Opcode Base
+.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths
+# Directory table format
+.byte 1 # One element per directory entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+# Directory table entries
+.byte 1 # 1 directory
+.asciz "/tmp"
+# File table format
+.byte 2 # 2 elements per file entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+.byte 2 # DW_LNCT_directory_index
+.byte 0x0b # DW_FORM_data1
+# File table entries
+.byte 1 # 1 file
+.asciz "a.c"
+.byte 0
+.Linvalid_description_header_end0:
+.byte 0,2,4,1 # DW_LNE_set_discriminator 1
+.byte 1 # DW_LNS_copy
+.byte 33 # address += 1, line += 1
+.byte 0,1,1 # DW_LNE_end_sequence
+.Linvalid_description_end0:
+
+# Invalid file entry
+.long .Linvalid_file_end0-.Linvalid_file_start0 # Length of Unit
+.Linvalid_file_start0:
+.short 5 # DWARF version number
+.byte 8 # Address Size
+.byte 0 # Segment Selector Size
+.long .Linvalid_file_header_end0-.Linvalid_file_params0-7 # Length of Prologue (invalid)
+.Linvalid_file_params0:
+.byte 1 # Minimum Instruction Length
+.byte 1 # Maximum Operations per Instruction
+.byte 1 # Default is_stmt
+.byte -5 # Line Base
+.byte 14 # Line Range
+.byte 13 # Opcode Base
+.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths
+# Directory table format
+.byte 1 # One element per directory entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+# Directory table entries
+.byte 1 # 1 directory
+.asciz "/tmp"
+# File table format
+.byte 2 # 2 elements per file entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+.byte 2 # DW_LNCT_directory_index
+.byte 0x0b # DW_FORM_data1
+# File table entries
+.byte 1 # 1 file
+.asciz "a.c"
+.byte 0
+.Linvalid_file_header_end0:
+.byte 0,2,4,1 # DW_LNE_set_discriminator 1
+.byte 1 # DW_LNS_copy
+.byte 33 # address += 1, line += 1
+.byte 0,1,1 # DW_LNE_end_sequence
+.Linvalid_file_end0:
+
+# Invalid directory entry
+.long .Linvalid_dir_end0-.Linvalid_dir_start0 # Length of Unit
+.Linvalid_dir_start0:
+.short 5 # DWARF version number
+.byte 8 # Address Size
+.byte 0 # Segment Selector Size
+.long .Linvalid_dir_header_end0-.Linvalid_dir_params0-16 # Length of Prologue (invalid)
+.Linvalid_dir_params0:
+.byte 1 # Minimum Instruction Length
+.byte 1 # Maximum Operations per Instruction
+.byte 1 # Default is_stmt
+.byte -5 # Line Base
+.byte 14 # Line Range
+.byte 13 # Opcode Base
+.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths
+# Directory table format
+.byte 1 # One element per directory entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+# Directory table entries
+.byte 1 # 1 directory
+.asciz "/tmp"
+# File table format
+.byte 2 # 2 elements per file entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+.byte 2 # DW_LNCT_directory_index
+.byte 0x0b # DW_FORM_data1
+# File table entries
+.byte 1 # 1 file
+.asciz "a.c"
+.byte 0
+.Linvalid_dir_header_end0:
+.byte 0,2,4,1 # DW_LNE_set_discriminator 1
+.byte 1 # DW_LNS_copy
+.byte 33 # address += 1, line += 1
+.byte 0,1,1 # DW_LNE_end_sequence
+.Linvalid_dir_end0:
+
+# Invalid MD5 hash
+.long .Linvalid_md5_end0-.Linvalid_md5_start0 # Length of Unit
+.Linvalid_md5_start0:
+.short 5 # DWARF version number
+.byte 8 # Address Size
+.byte 0 # Segment Selector Size
+.long .Linvalid_md5_header_end0-.Linvalid_md5_params0 # Length of Prologue (invalid)
+.Linvalid_md5_params0:
+.byte 1 # Minimum Instruction Length
+.byte 1 # Maximum Operations per Instruction
+.byte 1 # Default is_stmt
+.byte -5 # Line Base
+.byte 14 # Line Range
+.byte 13 # Opcode Base
+.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths
+# Directory table format
+.byte 1 # One element per directory entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+# Directory table entries
+.byte 1 # 1 directory
+.asciz "/tmp"
+# File table format
+.byte 3 # 2 elements per file entry
+.byte 1 # DW_LNCT_path
+.byte 0x08 # DW_FORM_string
+.byte 2 # DW_LNCT_directory_index
+.byte 0x0b # DW_FORM_data1
+.byte 5 # DW_LNCT_MD5
+.byte 0x09 # DW_FORM_data1
+# File table entries
+.byte 1 # 1 file
+.asciz "a.c"
+.byte 0
+.Linvalid_md5_header_end0:
+.byte 0,2,4,1 # DW_LNE_set_discriminator 1
+.byte 1 # DW_LNS_copy
+.byte 33 # address += 1, line += 1
+.byte 0,1,1 # DW_LNE_end_sequence
+.Linvalid_md5_end0:
+
# Trailing good section
.long .Lunit_good_end - .Lunit_good_start # Length of Unit (DWARF-32 format)
.Lunit_good_start:
@@ -188,3 +346,4 @@
.quad 0xcafebabe
.byte 0, 1, 1 # DW_LNE_end_sequence
.Lunit_good_end:
+
Modified: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test?rev=366762&r1=366761&r2=366762&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test (original)
+++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test Mon Jul 22 16:23:34 2019
@@ -25,7 +25,7 @@
# RUN: FileCheck %s --input-file=%t-malformed-off-first.err --check-prefix=ALL
# Don't stop looking for the later unit if non-fatal issues are found.
-# RUN: llvm-dwarfdump -debug-line=0x183 %t-malformed.o 2> %t-malformed-off-last.err | FileCheck %s --check-prefixes=LASTONLY
+# RUN: llvm-dwarfdump -debug-line=0x271 %t-malformed.o 2> %t-malformed-off-last.err | FileCheck %s --check-prefixes=LASTONLY
# RUN: FileCheck %s --input-file=%t-malformed-off-last.err --check-prefix=ALL
# FIRST: debug_line[0x00000000]
@@ -69,23 +69,37 @@
# NONFATAL-NOT: debug_line[{{.*}}]
# NONFATAL: 0x00000000deadfade {{.*}}
# NONFATAL: debug_line[0x00000183]
+# NONFATAL-NEXT: Line table prologue
+# NONFATAL: debug_line[0x00000271]
# NONFATAL-NOT: debug_line[{{.*}}]
# NONFATAL: 0x00000000cafebabe {{.*}} end_sequence
# NONFATAL-NOT: debug_line[{{.*}}]
# LASTONLY-NOT: debug_line[{{.*}}]
-# LASTONLY: debug_line[0x00000183]
+# LASTONLY: debug_line[0x00000271]
# LASTONLY: 0x00000000cafebabe {{.*}} end_sequence
# RESERVED: warning: parsing line table prologue at offset 0x00000048 unsupported reserved unit length found of value 0xfffffffe
+# MD5: warning: parsing line table prologue at 0x00000000 found an invalid directory or file table description at 0x0000003b
+# MD5-NEXT: warning: failed to parse file entry because the MD5 hash is invalid
+
# ALL-NOT: warning:
# ALL: warning: parsing line table prologue at offset 0x00000048 found unsupported version 0x00
# ALL-NEXT: warning: parsing line table prologue at offset 0x0000004e found unsupported version 0x01
# ALL-NEXT: warning: parsing line table prologue at 0x00000054 found an invalid directory or file table description at 0x00000073
+# ALL-NEXT: warning: failed to parse entry content descriptions because no path was found
# FIXME - The latter offset in the next line should be 0xad. The filename parsing code does not notice a missing terminating byte.
# ALL-NEXT: warning: parsing line table prologue at 0x00000073 should have ended at 0x000000ab but it ended at 0x000000ac
# ALL-NEXT: warning: parsing line table prologue at 0x000000ad should have ended at 0x000000e8 but it ended at 0x000000e7
# OTHER-NEXT: warning: unexpected line op length at offset 0x0000012e expected 0x02 found 0x01
# OTHER-NEXT: warning: last sequence in debug line table is not terminated!
+# ALL-NEXT: warning: parsing line table prologue at 0x00000183 found an invalid directory or file table description at 0x000001a2
+# ALL-NEXT: warning: failed to parse entry content descriptions at offset 0x000001a2 because offset extends beyond the prologue end at offset 0x0000019e
+# ALL-NEXT: warning: parsing line table prologue at 0x000001be found an invalid directory or file table description at 0x000001eb
+# ALL-NEXT: warning: failed to parse file entry at offset 0x000001eb because offset extends beyond the prologue end at offset 0x000001e9
+# ALL-NEXT: warning: parsing line table prologue at 0x000001f9 found an invalid directory or file table description at 0x0000021b
+# ALL-NEXT: warning: failed to parse directory entry at offset 0x0000021b because offset extends beyond the prologue end at offset 0x0000021b
+# ALL-NEXT: warning: parsing line table prologue at 0x00000234 found an invalid directory or file table description at 0x00000269
+# ALL-NEXT: warning: failed to parse file entry because the MD5 hash is invalid
# ALL-NOT: warning:
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp?rev=366762&r1=366761&r2=366762&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp Mon Jul 22 16:23:34 2019
@@ -120,6 +120,16 @@ struct CommonFixture {
checkError(ExpectedMsg, ExpectedLineTable.takeError());
}
+ void checkGetOrParseLineTableEmitsError(ArrayRef<StringRef> ExpectedMsgs,
+ uint64_t Offset = 0) {
+ auto ExpectedLineTable = Line.getOrParseLineTable(
+ LineData, Offset, *Context, nullptr, RecordRecoverable);
+ EXPECT_FALSE(ExpectedLineTable);
+ EXPECT_FALSE(Recoverable);
+
+ checkError(ExpectedMsgs, ExpectedLineTable.takeError());
+ }
+
std::unique_ptr<Generator> Gen;
std::unique_ptr<DWARFContext> Context;
DWARFDataExtractor LineData;
@@ -344,8 +354,9 @@ TEST_F(DebugLineBasicFixture, ErrorForIn
generate();
checkGetOrParseLineTableEmitsError(
- "parsing line table prologue at 0x00000000 found an invalid directory or "
- "file table description at 0x00000014");
+ {"parsing line table prologue at 0x00000000 found an invalid directory "
+ "or file table description at 0x00000014",
+ "failed to parse entry content descriptions because no path was found"});
}
TEST_P(DebugLineParameterisedFixture, ErrorForTooLargePrologueLength) {
More information about the llvm-commits
mailing list