diff options
Diffstat (limited to 'llvm/lib/DebugInfo')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 39 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 66 |
2 files changed, 102 insertions, 3 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 5c2254cb476..9ae7c9a07f7 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -62,6 +62,45 @@ uint32_t DWARFAcceleratorTable::getHeaderDataLength() { return Hdr.HeaderDataLength; } +ArrayRef<std::pair<DWARFAcceleratorTable::HeaderData::AtomType, + DWARFAcceleratorTable::HeaderData::Form>> +DWARFAcceleratorTable::getAtomsDesc() { + return HdrData.Atoms; +} + +bool DWARFAcceleratorTable::validateForms() { + for (auto Atom : getAtomsDesc()) { + DWARFFormValue FormValue(Atom.second); + switch (Atom.first) { + case dwarf::DW_ATOM_die_offset: + if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && + !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || + FormValue.getForm() == dwarf::DW_FORM_sdata) + return false; + default: + break; + } + } + return true; +} + +uint32_t DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { + uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; + + for (auto Atom : getAtomsDesc()) { + DWARFFormValue FormValue(Atom.second); + FormValue.extractValue(AccelSection, &HashDataOffset, NULL); + switch (Atom.first) { + case dwarf::DW_ATOM_die_offset: + DieOffset = *FormValue.getAsUnsignedConstant(); + break; + default: + break; + } + } + return DieOffset; +} + LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { // Dump the header. OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n' diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 488649ced13..0a10e6b7891 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -291,20 +291,80 @@ bool DWARFVerifier::handleAppleNames() { OS << "Verifying .apple_names...\n"; - // Verify that all buckets have a valid hash index or are empty + // Verify that all buckets have a valid hash index or are empty. uint32_t NumBuckets = AppleNames.getNumBuckets(); uint32_t NumHashes = AppleNames.getNumHashes(); uint32_t BucketsOffset = AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength(); + uint32_t HashesBase = BucketsOffset + NumBuckets * 4; + uint32_t OffsetsBase = HashesBase + NumHashes * 4; for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset); if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { - OS << format("error: Bucket[%d] has invalid hash index: [%d]\n", - BucketIdx, HashIdx); + OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx, + HashIdx); ++NumAppleNamesErrors; } } + + uint32_t NumAtoms = AppleNames.getAtomsDesc().size(); + if (NumAtoms == 0) { + OS << "error: no atoms; failed to read HashData\n"; + ++NumAppleNamesErrors; + return false; + } + + if (!AppleNames.validateForms()) { + OS << "error: unsupported form; failed to read HashData\n"; + ++NumAppleNamesErrors; + return false; + } + + for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) { + uint32_t HashOffset = HashesBase + 4 * HashIdx; + uint32_t DataOffset = OffsetsBase + 4 * HashIdx; + uint32_t Hash = AppleNamesSection.getU32(&HashOffset); + uint32_t HashDataOffset = AppleNamesSection.getU32(&DataOffset); + if (!AppleNamesSection.isValidOffsetForDataOfSize(HashDataOffset, + sizeof(uint64_t))) { + OS << format("error: Hash[%d] has invalid HashData offset: 0x%08x\n", + HashIdx, HashDataOffset); + ++NumAppleNamesErrors; + } + + uint32_t StrpOffset; + uint32_t StringOffset; + uint32_t StringCount = 0; + uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; + + while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) { + const uint32_t NumHashDataObjects = + AppleNamesSection.getU32(&HashDataOffset); + for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; + ++HashDataIdx) { + DieOffset = AppleNames.readAtoms(HashDataOffset); + if (!DCtx.getDIEForOffset(DieOffset)) { + const uint32_t BucketIdx = + NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; + StringOffset = StrpOffset; + const char *Name = StrData.getCStr(&StringOffset); + if (!Name) + Name = "<NULL>"; + + OS << format( + "error: .apple_names Bucket[%d] Hash[%d] = 0x%08x " + "Str[%u] = 0x%08x " + "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n", + BucketIdx, HashIdx, Hash, StringCount, StrpOffset, HashDataIdx, + DieOffset, Name); + + ++NumAppleNamesErrors; + } + } + ++StringCount; + } + } return NumAppleNamesErrors == 0; } |