mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 02:52:53 +02:00
Adds initial llvm-dwarfdump --verify support with unit tests.
lldb-dwarfdump gets a new "--verify" option that will verify a single file's DWARF debug info and will print out any errors that it finds. It will return an non-zero exit status if verification fails, and a zero exit status if verification succeeds. Adding the --quiet option will suppress any output the STDOUT or STDERR. The first part of the verify does the following: - verifies that all CU relative references (DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata) have valid CU offsets - verifies that all DW_FORM_ref_addr references have valid .debug_info offsets - verifies that all DW_AT_ranges attributes have valid .debug_ranges offsets - verifies that all DW_AT_stmt_list attributes have valid .debug_line offsets - verifies that all DW_FORM_strp attributes have valid .debug_str offsets Unit tests were added for each of the above cases. Differential Revision: https://reviews.llvm.org/D32707 llvm-svn: 301844
This commit is contained in:
parent
3a58d4ac26
commit
5e0a89ef4f
@ -161,6 +161,10 @@ public:
|
|||||||
virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||||
bool DumpEH = false, bool SummarizeTypes = false) = 0;
|
bool DumpEH = false, bool SummarizeTypes = false) = 0;
|
||||||
|
|
||||||
|
virtual bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) {
|
||||||
|
// No verifier? Just say things went well.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
virtual DILineInfo getLineInfoForAddress(uint64_t Address,
|
virtual DILineInfo getLineInfoForAddress(uint64_t Address,
|
||||||
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
|
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0;
|
||||||
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address,
|
virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address,
|
||||||
|
@ -106,6 +106,8 @@ public:
|
|||||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||||
bool DumpEH = false, bool SummarizeTypes = false) override;
|
bool DumpEH = false, bool SummarizeTypes = false) override;
|
||||||
|
|
||||||
|
bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override;
|
||||||
|
|
||||||
typedef DWARFUnitSection<DWARFCompileUnit>::iterator_range cu_iterator_range;
|
typedef DWARFUnitSection<DWARFCompileUnit>::iterator_range cu_iterator_range;
|
||||||
typedef DWARFUnitSection<DWARFTypeUnit>::iterator_range tu_iterator_range;
|
typedef DWARFUnitSection<DWARFTypeUnit>::iterator_range tu_iterator_range;
|
||||||
typedef iterator_range<decltype(TUs)::iterator> tu_section_iterator_range;
|
typedef iterator_range<decltype(TUs)::iterator> tu_section_iterator_range;
|
||||||
|
@ -59,6 +59,7 @@ public:
|
|||||||
DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {}
|
DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {}
|
||||||
|
|
||||||
dwarf::Form getForm() const { return Form; }
|
dwarf::Form getForm() const { return Form; }
|
||||||
|
uint64_t getRawUValue() const { return Value.uval; }
|
||||||
void setForm(dwarf::Form F) { Form = F; }
|
void setForm(dwarf::Form F) { Form = F; }
|
||||||
void setUValue(uint64_t V) { Value.uval = V; }
|
void setUValue(uint64_t V) { Value.uval = V; }
|
||||||
void setSValue(int64_t V) { Value.sval = V; }
|
void setSValue(int64_t V) { Value.sval = V; }
|
||||||
|
@ -284,6 +284,119 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH,
|
|||||||
getStringSection(), isLittleEndian());
|
getStringSection(), isLittleEndian());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
|
||||||
|
bool Success = true;
|
||||||
|
if (DumpType == DIDT_All || DumpType == DIDT_Info) {
|
||||||
|
OS << "Verifying .debug_info...\n";
|
||||||
|
for (const auto &CU : compile_units()) {
|
||||||
|
unsigned NumDies = CU->getNumDIEs();
|
||||||
|
for (unsigned I = 0; I < NumDies; ++I) {
|
||||||
|
auto Die = CU->getDIEAtIndex(I);
|
||||||
|
const auto Tag = Die.getTag();
|
||||||
|
if (Tag == DW_TAG_null)
|
||||||
|
continue;
|
||||||
|
for (auto AttrValue : Die.attributes()) {
|
||||||
|
const auto Attr = AttrValue.Attr;
|
||||||
|
const auto Form = AttrValue.Value.getForm();
|
||||||
|
switch (Attr) {
|
||||||
|
case DW_AT_ranges:
|
||||||
|
// Make sure the offset in the DW_AT_ranges attribute is valid.
|
||||||
|
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||||
|
if (*SectionOffset >= getRangeSection().Data.size()) {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
|
||||||
|
"bounds:\n";
|
||||||
|
Die.dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
|
||||||
|
Die.dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DW_AT_stmt_list:
|
||||||
|
// Make sure the offset in the DW_AT_stmt_list attribute is valid.
|
||||||
|
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||||
|
if (*SectionOffset >= getLineSection().Data.size()) {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
|
||||||
|
"bounds: "
|
||||||
|
<< format("0x%08" PRIx32, *SectionOffset) << "\n";
|
||||||
|
CU->getUnitDIE().dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
|
||||||
|
Die.dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (Form) {
|
||||||
|
case DW_FORM_ref1:
|
||||||
|
case DW_FORM_ref2:
|
||||||
|
case DW_FORM_ref4:
|
||||||
|
case DW_FORM_ref8:
|
||||||
|
case DW_FORM_ref_udata: {
|
||||||
|
// Verify all CU relative references are valid CU offsets.
|
||||||
|
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||||
|
assert(RefVal);
|
||||||
|
if (RefVal) {
|
||||||
|
auto DieCU = Die.getDwarfUnit();
|
||||||
|
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
|
||||||
|
auto CUOffset = AttrValue.Value.getRawUValue();
|
||||||
|
if (CUOffset >= CUSize) {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: " << FormEncodingString(Form) << " CU offset "
|
||||||
|
<< format("0x%08" PRIx32, CUOffset)
|
||||||
|
<< " is invalid (must be less than CU size of "
|
||||||
|
<< format("0x%08" PRIx32, CUSize) << "):\n";
|
||||||
|
Die.dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_FORM_ref_addr: {
|
||||||
|
// Verify all absolute DIE references have valid offsets in the
|
||||||
|
// .debug_info section.
|
||||||
|
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||||
|
assert(RefVal);
|
||||||
|
if (RefVal && *RefVal >= getInfoSection().Data.size()) {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
|
||||||
|
"bounds:\n";
|
||||||
|
Die.dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_FORM_strp: {
|
||||||
|
auto SecOffset = AttrValue.Value.getAsSectionOffset();
|
||||||
|
assert(SecOffset); // DW_FORM_strp is a section offset.
|
||||||
|
if (SecOffset && *SecOffset >= getStringSection().size()) {
|
||||||
|
Success = false;
|
||||||
|
OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
|
||||||
|
Die.dump(OS, 0);
|
||||||
|
OS << "\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
const DWARFUnitIndex &DWARFContext::getCUIndex() {
|
const DWARFUnitIndex &DWARFContext::getCUIndex() {
|
||||||
if (CUIndex)
|
if (CUIndex)
|
||||||
return *CUIndex;
|
return *CUIndex;
|
||||||
|
@ -309,8 +309,10 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
|
|||||||
}
|
}
|
||||||
// In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset.
|
// In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset.
|
||||||
// Don't check for DWARF version here, as some producers may still do this
|
// Don't check for DWARF version here, as some producers may still do this
|
||||||
// by mistake.
|
// by mistake. Also accept DW_FORM_strp since this is .debug_str section
|
||||||
return (Form == DW_FORM_data4 || Form == DW_FORM_data8) &&
|
// offset.
|
||||||
|
return (Form == DW_FORM_data4 || Form == DW_FORM_data8 ||
|
||||||
|
Form == DW_FORM_strp) &&
|
||||||
FC == FC_SectionOffset;
|
FC == FC_SectionOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,11 @@ static cl::opt<bool>
|
|||||||
SummarizeTypes("summarize-types",
|
SummarizeTypes("summarize-types",
|
||||||
cl::desc("Abbreviate the description of type unit entries"));
|
cl::desc("Abbreviate the description of type unit entries"));
|
||||||
|
|
||||||
|
static cl::opt<bool> Verify("verify", cl::desc("Verify the DWARF debug info"));
|
||||||
|
|
||||||
|
static cl::opt<bool> Quiet("quiet",
|
||||||
|
cl::desc("Use with -verify to not emit to STDOUT."));
|
||||||
|
|
||||||
static void error(StringRef Filename, std::error_code EC) {
|
static void error(StringRef Filename, std::error_code EC) {
|
||||||
if (!EC)
|
if (!EC)
|
||||||
return;
|
return;
|
||||||
@ -116,6 +121,46 @@ static void DumpInput(StringRef Filename) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool VerifyObjectFile(ObjectFile &Obj, Twine Filename) {
|
||||||
|
std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj));
|
||||||
|
|
||||||
|
// Verify the DWARF and exit with non-zero exit status if verification
|
||||||
|
// fails.
|
||||||
|
raw_ostream &stream = Quiet ? nulls() : outs();
|
||||||
|
stream << "Verifying " << Filename.str() << ":\tfile format "
|
||||||
|
<< Obj.getFileFormatName() << "\n";
|
||||||
|
bool Result = DICtx->verify(stream, DumpType);
|
||||||
|
if (Result)
|
||||||
|
stream << "No errors.\n";
|
||||||
|
else
|
||||||
|
stream << "Errors detected.\n";
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool VerifyInput(StringRef Filename) {
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
|
||||||
|
MemoryBuffer::getFileOrSTDIN(Filename);
|
||||||
|
error(Filename, BuffOrErr.getError());
|
||||||
|
std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
|
||||||
|
|
||||||
|
Expected<std::unique_ptr<Binary>> BinOrErr =
|
||||||
|
object::createBinary(Buff->getMemBufferRef());
|
||||||
|
if (!BinOrErr)
|
||||||
|
error(Filename, errorToErrorCode(BinOrErr.takeError()));
|
||||||
|
|
||||||
|
bool Result = true;
|
||||||
|
if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get()))
|
||||||
|
Result = VerifyObjectFile(*Obj, Filename);
|
||||||
|
else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
|
||||||
|
for (auto &ObjForArch : Fat->objects()) {
|
||||||
|
auto MachOOrErr = ObjForArch.getAsObjectFile();
|
||||||
|
error(Filename, errorToErrorCode(MachOOrErr.takeError()));
|
||||||
|
if (!VerifyObjectFile(**MachOOrErr, Filename + " (" + ObjForArch.getArchFlagName() + ")"))
|
||||||
|
Result = false;
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
|
/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
|
||||||
/// replace it with individual entries for each of the object files inside the
|
/// replace it with individual entries for each of the object files inside the
|
||||||
/// bundle otherwise return the input path.
|
/// bundle otherwise return the input path.
|
||||||
@ -168,7 +213,13 @@ int main(int argc, char **argv) {
|
|||||||
Objects.insert(Objects.end(), Objs.begin(), Objs.end());
|
Objects.insert(Objects.end(), Objs.begin(), Objs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::for_each(Objects.begin(), Objects.end(), DumpInput);
|
if (Verify) {
|
||||||
|
// If we encountered errors during verify, exit with a non-zero exit status.
|
||||||
|
if (!std::all_of(Objects.begin(), Objects.end(), VerifyInput))
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
std::for_each(Objects.begin(), Objects.end(), DumpInput);
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1667,4 +1667,245 @@ TEST(DWARFDebugInfo, TestImplicitConstAbbrevs) {
|
|||||||
EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
|
EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// the compile unit itself.
|
||||||
|
|
||||||
|
const char *yamldata = R"(
|
||||||
|
debug_str:
|
||||||
|
- ''
|
||||||
|
- /tmp/main.c
|
||||||
|
- main
|
||||||
|
debug_abbrev:
|
||||||
|
- Code: 0x00000001
|
||||||
|
Tag: DW_TAG_compile_unit
|
||||||
|
Children: DW_CHILDREN_yes
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Code: 0x00000002
|
||||||
|
Tag: DW_TAG_subprogram
|
||||||
|
Children: DW_CHILDREN_no
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Attribute: DW_AT_type
|
||||||
|
Form: DW_FORM_ref4
|
||||||
|
debug_info:
|
||||||
|
- Length:
|
||||||
|
TotalLength: 22
|
||||||
|
Version: 4
|
||||||
|
AbbrOffset: 0
|
||||||
|
AddrSize: 8
|
||||||
|
Entries:
|
||||||
|
- AbbrCode: 0x00000001
|
||||||
|
Values:
|
||||||
|
- Value: 0x0000000000000001
|
||||||
|
- AbbrCode: 0x00000002
|
||||||
|
Values:
|
||||||
|
- Value: 0x000000000000000D
|
||||||
|
- Value: 0x0000000000001234
|
||||||
|
- AbbrCode: 0x00000000
|
||||||
|
Values:
|
||||||
|
)";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddr) {
|
||||||
|
// Create a single compile unit with a single function that has an invalid
|
||||||
|
// DW_AT_type with an invalid .debug_info offset in its DW_FORM_ref_addr.
|
||||||
|
const char *yamldata = R"(
|
||||||
|
debug_str:
|
||||||
|
- ''
|
||||||
|
- /tmp/main.c
|
||||||
|
- main
|
||||||
|
debug_abbrev:
|
||||||
|
- Code: 0x00000001
|
||||||
|
Tag: DW_TAG_compile_unit
|
||||||
|
Children: DW_CHILDREN_yes
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Code: 0x00000002
|
||||||
|
Tag: DW_TAG_subprogram
|
||||||
|
Children: DW_CHILDREN_no
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
- Attribute: DW_AT_type
|
||||||
|
Form: DW_FORM_ref_addr
|
||||||
|
debug_info:
|
||||||
|
- Length:
|
||||||
|
TotalLength: 22
|
||||||
|
Version: 4
|
||||||
|
AbbrOffset: 0
|
||||||
|
AddrSize: 8
|
||||||
|
Entries:
|
||||||
|
- AbbrCode: 0x00000001
|
||||||
|
Values:
|
||||||
|
- Value: 0x0000000000000001
|
||||||
|
- AbbrCode: 0x00000002
|
||||||
|
Values:
|
||||||
|
- Value: 0x000000000000000D
|
||||||
|
- Value: 0x0000000000001234
|
||||||
|
- AbbrCode: 0x00000000
|
||||||
|
Values:
|
||||||
|
)";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRanges) {
|
||||||
|
// Create a single compile unit with a DW_AT_ranges whose section offset
|
||||||
|
// isn't valid.
|
||||||
|
const char *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_ranges
|
||||||
|
Form: DW_FORM_sec_offset
|
||||||
|
debug_info:
|
||||||
|
- Length:
|
||||||
|
TotalLength: 16
|
||||||
|
Version: 4
|
||||||
|
AbbrOffset: 0
|
||||||
|
AddrSize: 8
|
||||||
|
Entries:
|
||||||
|
- AbbrCode: 0x00000001
|
||||||
|
Values:
|
||||||
|
- Value: 0x0000000000000001
|
||||||
|
- Value: 0x0000000000001000
|
||||||
|
|
||||||
|
)";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidStmtList) {
|
||||||
|
// Create a single compile unit with a DW_AT_stmt_list whose section offset
|
||||||
|
// isn't valid.
|
||||||
|
const char *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: 0x0000000000001000
|
||||||
|
|
||||||
|
)";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidStrp) {
|
||||||
|
// Create a single compile unit with a single function that has an invalid
|
||||||
|
// DW_FORM_strp for the DW_AT_name.
|
||||||
|
const char *yamldata = R"(
|
||||||
|
debug_str:
|
||||||
|
- ''
|
||||||
|
debug_abbrev:
|
||||||
|
- Code: 0x00000001
|
||||||
|
Tag: DW_TAG_compile_unit
|
||||||
|
Children: DW_CHILDREN_no
|
||||||
|
Attributes:
|
||||||
|
- Attribute: DW_AT_name
|
||||||
|
Form: DW_FORM_strp
|
||||||
|
debug_info:
|
||||||
|
- Length:
|
||||||
|
TotalLength: 12
|
||||||
|
Version: 4
|
||||||
|
AbbrOffset: 0
|
||||||
|
AddrSize: 8
|
||||||
|
Entries:
|
||||||
|
- AbbrCode: 0x00000001
|
||||||
|
Values:
|
||||||
|
- Value: 0x0000000000001234
|
||||||
|
)";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user