forked from OSchip/llvm-project
Add verification for DW_AT_decl_file and DW_AT_call_file.
LTO builds have been creating invalid DWARF and one of the errors was a file index that was out of bounds. "llvm-dwarfdump --verify" will check all file indexes for line tables already, but there are no checks for the validity of file indexes in attributes. The verification will verify if there is a DW_AT_decl_file/DW_AT_call_file that: - there is a line table for the compile unit - the file index is valid - the encoding is appropriate Tests are added that test all of the above conditions. Differential Revision: https://reviews.llvm.org/D84817
This commit is contained in:
parent
31137b87ef
commit
e1de85f9f4
|
@ -121,6 +121,8 @@ public:
|
|||
|
||||
bool hasFileAtIndex(uint64_t FileIndex) const;
|
||||
|
||||
Optional<uint64_t> getLastValidFileIndex() const;
|
||||
|
||||
bool
|
||||
getFileNameByIndex(uint64_t FileIndex, StringRef CompDir,
|
||||
DILineInfoSpecifier::FileLineInfoKind Kind,
|
||||
|
@ -251,6 +253,10 @@ public:
|
|||
return Prologue.hasFileAtIndex(FileIndex);
|
||||
}
|
||||
|
||||
Optional<uint64_t> getLastValidFileIndex() const {
|
||||
return Prologue.getLastValidFileIndex();
|
||||
}
|
||||
|
||||
/// Extracts filename by its index in filename table in prologue.
|
||||
/// In Dwarf 4, the files are 1-indexed and the current compilation file
|
||||
/// name is not represented in the list. In DWARF v5, the files are
|
||||
|
|
|
@ -79,6 +79,18 @@ bool DWARFDebugLine::Prologue::hasFileAtIndex(uint64_t FileIndex) const {
|
|||
return FileIndex != 0 && FileIndex <= FileNames.size();
|
||||
}
|
||||
|
||||
Optional<uint64_t> DWARFDebugLine::Prologue::getLastValidFileIndex() const {
|
||||
if (FileNames.empty())
|
||||
return None;
|
||||
uint16_t DwarfVersion = getVersion();
|
||||
assert(DwarfVersion != 0 &&
|
||||
"line table prologue has no dwarf version information");
|
||||
// In DWARF v5 the file names are 0-indexed.
|
||||
if (DwarfVersion >= 5)
|
||||
return FileNames.size() - 1;
|
||||
return FileNames.size();
|
||||
}
|
||||
|
||||
const llvm::DWARFDebugLine::FileNameEntry &
|
||||
DWARFDebugLine::Prologue::getFileNameEntry(uint64_t Index) const {
|
||||
uint16_t DwarfVersion = getVersion();
|
||||
|
|
|
@ -538,6 +538,39 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DW_AT_call_file:
|
||||
case DW_AT_decl_file: {
|
||||
if (auto FileIdx = AttrValue.Value.getAsUnsignedConstant()) {
|
||||
DWARFUnit *U = Die.getDwarfUnit();
|
||||
const auto *LT = U->getContext().getLineTableForUnit(U);
|
||||
if (LT) {
|
||||
if (!LT->hasFileAtIndex(*FileIdx)) {
|
||||
bool IsZeroIndexed = LT->Prologue.getVersion() >= 5;
|
||||
if (Optional<uint64_t> LastFileIdx = LT->getLastValidFileIndex()) {
|
||||
ReportError("DIE has " + AttributeString(Attr) +
|
||||
" with an invalid file index " +
|
||||
llvm::formatv("{0}", *FileIdx) +
|
||||
" (valid values are [" + (IsZeroIndexed ? "0-" : "1-") +
|
||||
llvm::formatv("{0}", *LastFileIdx) + "])");
|
||||
} else {
|
||||
ReportError("DIE has " + AttributeString(Attr) +
|
||||
" with an invalid file index " +
|
||||
llvm::formatv("{0}", *FileIdx) +
|
||||
" (the file table in the prologue is empty)");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ReportError("DIE has " + AttributeString(Attr) +
|
||||
" that references a file with index " +
|
||||
llvm::formatv("{0}", *FileIdx) +
|
||||
" and the compile unit has no line table");
|
||||
}
|
||||
} else {
|
||||
ReportError("DIE has " + AttributeString(Attr) +
|
||||
" with invalid encoding");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: error: DIE has DW_AT_decl_file with an invalid file index 2 (valid values are [1-1]){{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000001e: DW_TAG_subprogram
|
||||
# CHECK-NEXT: DW_AT_name ("main")
|
||||
# CHECK-NEXT: DW_AT_low_pc (0x0000000000001000)
|
||||
# CHECK-NEXT: DW_AT_high_pc (0x0000000000002000)
|
||||
# CHECK-NEXT: DW_AT_decl_file (0x02)
|
||||
# CHECK-NEXT: DW_AT_call_line (5){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: DIE has DW_AT_call_file with an invalid file index 3 (valid values are [1-1]){{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x00000035: DW_TAG_inlined_subroutine
|
||||
# CHECK-NEXT: DW_AT_name ("inline1")
|
||||
# CHECK-NEXT: DW_AT_low_pc (0x0000000000001100)
|
||||
# CHECK-NEXT: DW_AT_high_pc (0x0000000000001200)
|
||||
# CHECK-NEXT: DW_AT_call_file (0x03)
|
||||
# CHECK-NEXT: DW_AT_call_line (10){{[[:space:]]}}
|
||||
|
||||
# CHECK: Errors detected.
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
DWARF:
|
||||
debug_str:
|
||||
- ''
|
||||
- '/tmp/main.c'
|
||||
- main
|
||||
- inline1
|
||||
debug_abbrev:
|
||||
- Code: 0x0000000000000001
|
||||
Tag: DW_TAG_compile_unit
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_language
|
||||
Form: DW_FORM_data2
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_stmt_list
|
||||
Form: DW_FORM_sec_offset
|
||||
- Code: 0x0000000000000002
|
||||
Tag: DW_TAG_subprogram
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_decl_file
|
||||
Form: DW_FORM_data1
|
||||
- Attribute: DW_AT_call_line
|
||||
Form: DW_FORM_data1
|
||||
- Code: 0x0000000000000003
|
||||
Tag: DW_TAG_inlined_subroutine
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data4
|
||||
- Attribute: DW_AT_call_file
|
||||
Form: DW_FORM_data1
|
||||
- Attribute: DW_AT_call_line
|
||||
Form: DW_FORM_data1
|
||||
debug_info:
|
||||
- Length: 0x0000000000000046
|
||||
Version: 4
|
||||
AbbrOffset: 0x0000000000000000
|
||||
AddrSize: 8
|
||||
Entries:
|
||||
- AbbrCode: 0x00000001
|
||||
Values:
|
||||
- Value: 0x0000000000000001
|
||||
- Value: 0x0000000000000002
|
||||
- Value: 0x0000000000000000
|
||||
- Value: 0x0000000000000000
|
||||
- AbbrCode: 0x00000002
|
||||
Values:
|
||||
- Value: 0x000000000000000D
|
||||
- Value: 0x0000000000001000
|
||||
- Value: 0x0000000000002000
|
||||
- Value: 0x0000000000000002
|
||||
- Value: 0x0000000000000005
|
||||
- AbbrCode: 0x00000003
|
||||
Values:
|
||||
- Value: 0x0000000000000012
|
||||
- Value: 0x0000000000001100
|
||||
- Value: 0x0000000000000100
|
||||
- Value: 0x0000000000000003
|
||||
- Value: 0x000000000000000A
|
||||
- AbbrCode: 0x00000000
|
||||
Values: []
|
||||
- AbbrCode: 0x00000000
|
||||
Values: []
|
||||
debug_line:
|
||||
- Length: 40
|
||||
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: []
|
||||
...
|
|
@ -0,0 +1,117 @@
|
|||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: error: DIE has DW_AT_decl_file with an invalid file index 2 (the file table in the prologue is empty){{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000001e: DW_TAG_subprogram
|
||||
# CHECK-NEXT: DW_AT_name ("main")
|
||||
# CHECK-NEXT: DW_AT_low_pc (0x0000000000001000)
|
||||
# CHECK-NEXT: DW_AT_high_pc (0x0000000000002000)
|
||||
# CHECK-NEXT: DW_AT_decl_file (0x02)
|
||||
# CHECK-NEXT: DW_AT_call_line (5){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: DIE has DW_AT_call_file with an invalid file index 3 (the file table in the prologue is empty){{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x00000035: DW_TAG_inlined_subroutine
|
||||
# CHECK-NEXT: DW_AT_name ("inline1")
|
||||
# CHECK-NEXT: DW_AT_low_pc (0x0000000000001100)
|
||||
# CHECK-NEXT: DW_AT_high_pc (0x0000000000001200)
|
||||
# CHECK-NEXT: DW_AT_call_file (0x03)
|
||||
# CHECK-NEXT: DW_AT_call_line (10){{[[:space:]]}}
|
||||
|
||||
# CHECK: Errors detected.
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
DWARF:
|
||||
debug_str:
|
||||
- ''
|
||||
- '/tmp/main.c'
|
||||
- main
|
||||
- inline1
|
||||
debug_abbrev:
|
||||
- Code: 0x0000000000000001
|
||||
Tag: DW_TAG_compile_unit
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_language
|
||||
Form: DW_FORM_data2
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_stmt_list
|
||||
Form: DW_FORM_sec_offset
|
||||
- Code: 0x0000000000000002
|
||||
Tag: DW_TAG_subprogram
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_decl_file
|
||||
Form: DW_FORM_data1
|
||||
- Attribute: DW_AT_call_line
|
||||
Form: DW_FORM_data1
|
||||
- Code: 0x0000000000000003
|
||||
Tag: DW_TAG_inlined_subroutine
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data4
|
||||
- Attribute: DW_AT_call_file
|
||||
Form: DW_FORM_data1
|
||||
- Attribute: DW_AT_call_line
|
||||
Form: DW_FORM_data1
|
||||
debug_info:
|
||||
- Length: 0x0000000000000046
|
||||
Version: 4
|
||||
AbbrOffset: 0x0000000000000000
|
||||
AddrSize: 8
|
||||
Entries:
|
||||
- AbbrCode: 0x00000001
|
||||
Values:
|
||||
- Value: 0x0000000000000001
|
||||
- Value: 0x0000000000000002
|
||||
- Value: 0x0000000000000000
|
||||
- Value: 0x0000000000000000
|
||||
- AbbrCode: 0x00000002
|
||||
Values:
|
||||
- Value: 0x000000000000000D
|
||||
- Value: 0x0000000000001000
|
||||
- Value: 0x0000000000002000
|
||||
- Value: 0x0000000000000002
|
||||
- Value: 0x0000000000000005
|
||||
- AbbrCode: 0x00000003
|
||||
Values:
|
||||
- Value: 0x0000000000000012
|
||||
- Value: 0x0000000000001100
|
||||
- Value: 0x0000000000000100
|
||||
- Value: 0x0000000000000003
|
||||
- Value: 0x000000000000000A
|
||||
- AbbrCode: 0x00000000
|
||||
Values: []
|
||||
- AbbrCode: 0x00000000
|
||||
Values: []
|
||||
debug_line:
|
||||
- Length: 30
|
||||
Version: 2
|
||||
PrologueLength: 24
|
||||
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:
|
||||
Opcodes: []
|
||||
...
|
|
@ -11,6 +11,17 @@
|
|||
# CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x0000003f] = "/Users/sgravani/Development/tests")
|
||||
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
|
||||
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000016){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: DIE has DW_AT_decl_file that references a file with index 1 and the compile unit has no line table{{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000002b: DW_TAG_subprogram [2] *
|
||||
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
|
||||
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000016)
|
||||
# CHECK-NEXT: DW_AT_frame_base [DW_FORM_exprloc] (DW_OP_reg6)
|
||||
# CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000061] = "main")
|
||||
# CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] (0x01)
|
||||
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] (1)
|
||||
# CHECK-NEXT: DW_AT_prototyped [DW_FORM_flag_present] (true)
|
||||
# CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0052 => {0x00000052} "")
|
||||
# CHECK-NEXT: DW_AT_external [DW_FORM_flag_present] (true){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: DIE has DW_AT_type with incompatible tag DW_TAG_null{{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000002b: DW_TAG_subprogram [2] *
|
||||
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
|
||||
|
@ -22,6 +33,13 @@
|
|||
# CHECK-NEXT: DW_AT_prototyped [DW_FORM_flag_present] (true)
|
||||
# CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x0052 => {0x00000052} "")
|
||||
# CHECK-NEXT: DW_AT_external [DW_FORM_flag_present] (true){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: DIE has DW_AT_decl_file that references a file with index 1 and the compile unit has no line table{{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x00000044: DW_TAG_variable [3]
|
||||
# CHECK-NEXT: DW_AT_location [DW_FORM_exprloc] (DW_OP_fbreg -8)
|
||||
# CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000006a] = "a")
|
||||
# CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] (0x01)
|
||||
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] (2)
|
||||
# CHECK-NEXT: DW_AT_use_location [DW_FORM_ref4] (cu + 0x0053 => {0x00000053}){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: Compilation unit root DIE is not a unit DIE: DW_TAG_null.
|
||||
# CHECK-NEXT: error: Compilation unit type (DW_UT_compile) and root DIE (DW_TAG_null) do not match.
|
||||
# CHECK-NEXT: error: Units[2] - start offset: 0x00000068
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: error: DIE has DW_AT_decl_file with invalid encoding{{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000001a: DW_TAG_subprogram
|
||||
# CHECK-NEXT: DW_AT_name ("main")
|
||||
# CHECK-NEXT: DW_AT_low_pc (0x0000000000001000)
|
||||
# CHECK-NEXT: DW_AT_high_pc (0x0000000000002000)
|
||||
# CHECK-NEXT: DW_AT_decl_file ("")
|
||||
# CHECK-NEXT: DW_AT_call_line (5){{[[:space:]]}}
|
||||
# CHECK-NEXT: error: DIE has DW_AT_call_file with invalid encoding{{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x00000034: DW_TAG_inlined_subroutine
|
||||
# CHECK-NEXT: DW_AT_name ("inline1")
|
||||
# CHECK-NEXT: DW_AT_low_pc (0x0000000000001100)
|
||||
# CHECK-NEXT: DW_AT_high_pc (0x0000000000001200)
|
||||
# CHECK-NEXT: DW_AT_call_file ("")
|
||||
# CHECK-NEXT: DW_AT_call_line (10){{[[:space:]]}}
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
DWARF:
|
||||
debug_str:
|
||||
- ''
|
||||
- '/tmp/main.c'
|
||||
- main
|
||||
- ''
|
||||
- inline1
|
||||
debug_abbrev:
|
||||
- Code: 0x0000000000000001
|
||||
Tag: DW_TAG_compile_unit
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_language
|
||||
Form: DW_FORM_data2
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Code: 0x0000000000000002
|
||||
Tag: DW_TAG_subprogram
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_decl_file
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_call_line
|
||||
Form: DW_FORM_data1
|
||||
- Code: 0x0000000000000003
|
||||
Tag: DW_TAG_inlined_subroutine
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data4
|
||||
- Attribute: DW_AT_call_file
|
||||
Form: DW_FORM_strp
|
||||
- Attribute: DW_AT_call_line
|
||||
Form: DW_FORM_data1
|
||||
debug_info:
|
||||
- Length: 0x0000000000000048
|
||||
Version: 4
|
||||
AbbrOffset: 0x0000000000000000
|
||||
AddrSize: 8
|
||||
Entries:
|
||||
- AbbrCode: 0x00000001
|
||||
Values:
|
||||
- Value: 0x0000000000000001
|
||||
- Value: 0x0000000000000002
|
||||
- Value: 0x0000000000000000
|
||||
- AbbrCode: 0x00000002
|
||||
Values:
|
||||
- Value: 0x000000000000000D
|
||||
- Value: 0x0000000000001000
|
||||
- Value: 0x0000000000002000
|
||||
- Value: 0x0000000000000012
|
||||
- Value: 0x0000000000000005
|
||||
- AbbrCode: 0x00000003
|
||||
Values:
|
||||
- Value: 0x0000000000000013
|
||||
- Value: 0x0000000000001100
|
||||
- Value: 0x0000000000000100
|
||||
- Value: 0x0000000000000012
|
||||
- Value: 0x000000000000000A
|
||||
- AbbrCode: 0x00000000
|
||||
Values: []
|
||||
- AbbrCode: 0x00000000
|
||||
Values: []
|
||||
...
|
Loading…
Reference in New Issue