mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-18 18:42:46 +02:00
[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 llvm-svn: 366762
This commit is contained in:
parent
901e1360c3
commit
d32db46951
@ -187,18 +187,24 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
|
||||
}
|
||||
|
||||
// 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 DWARFDataExtractor &DebugLineData, uint32_t
|
||||
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 DWARFDataExtractor &DebugLineData,
|
||||
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 DWARFDataExtractor &DebugLineData,
|
||||
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 DWARFDataExtractor &DebugLineData,
|
||||
}
|
||||
FileNames.push_back(FileEntry);
|
||||
}
|
||||
return true;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
|
||||
@ -343,14 +374,17 @@ Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
|
||||
}
|
||||
|
||||
if (getVersion() >= 5) {
|
||||
if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
|
||||
FormParams, Ctx, U, ContentTypes,
|
||||
IncludeDirectories, FileNames)) {
|
||||
return createStringError(errc::invalid_argument,
|
||||
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);
|
||||
PrologueOffset, (uint64_t)*OffsetPtr),
|
||||
std::move(e));
|
||||
}
|
||||
} else
|
||||
parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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, ErrorForInvalidV5IncludeDirTable) {
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user