Index: include/llvm/DebugInfo/DWARF/DWARFVerifier.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -23,6 +23,8 @@ class DWARFAcceleratorTable; class DWARFDataExtractor; class DWARFDebugAbbrev; +class DataExtractor; +struct DWARFSection; /// A class that verifies DWARF debug information given a DWARF Context. class DWARFVerifier { @@ -33,7 +35,6 @@ /// lies between to valid DIEs. std::map> ReferenceToDIEOffsets; uint32_t NumDebugLineErrors = 0; - uint32_t NumAppleNamesErrors = 0; /// Verifies the abbreviations section. /// @@ -133,6 +134,25 @@ /// - invalid file indexes void verifyDebugLineRows(); + /// Verify that an Apple-style accelerator table is valid. + /// + /// This function currently checks that: + /// - The fixed part of the header fits in the section + /// - The size of the section is as large as what the header describes + /// - There is at least one atom + /// - The form for each atom is valid + /// - The buckets have a valid index, or they are empty + /// - Each hashdata offset is valid + /// - Each DIE is valid + /// + /// \param AccelSection pointer to the section containing the acceleration table + /// \param StrData pointer to the string section + /// \param SectionName the name of the table we're verifying + /// + /// \returns The number of errors occured during verification + unsigned verifyAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, const char *SectionName); + public: DWARFVerifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {} @@ -162,13 +182,14 @@ /// \returns true if the .debug_line verifies successfully, false otherwise. bool handleDebugLine(); - /// Verify the information in the .apple_names accelerator table. + /// Verify the information in accelerator tables, if they exist. /// /// Any errors are reported to the stream that was this object was /// constructed with. /// - /// \returns true if the .apple_names verifies successfully, false otherwise. - bool handleAppleNames(); + /// \returns true if the existing *Apple-style* accelerator tables verify + /// successfully, false otherwise. + bool handleAccelTables(); }; } // end namespace llvm Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -427,10 +427,7 @@ if (!verifier.handleDebugLine()) Success = false; } - if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) { - if (!verifier.handleAppleNames()) - Success = false; - } + Success &= verifier.handleAccelTables(); return Success; } Index: lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -464,61 +464,63 @@ return NumDebugLineErrors == 0; } -bool DWARFVerifier::handleAppleNames() { - NumAppleNamesErrors = 0; - const DWARFObject &D = DCtx.getDWARFObj(); - DWARFDataExtractor AppleNamesSection(D, D.getAppleNamesSection(), - DCtx.isLittleEndian(), 0); - DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0); - DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData); - - if (!AppleNames.extract()) { - return true; - } +unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, + const char *SectionName) { + unsigned NumErrors = 0; + DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, + DCtx.isLittleEndian(), 0); + DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData); - OS << "Verifying .apple_names...\n"; + OS << "Verifying " << SectionName << "...\n"; + // Verify that the fixed part of the header is not too short. + if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { + OS << "\terror: Section is too small to fit a section header.\n"; + return 1; + } + // Verify that the section is not too short. + // uint32_t Offset = 8; + if (!AccelTable.extract()) { + OS << "\terror: Section is smaller than size described in section header.\n"; + return 1; + } // Verify that all buckets have a valid hash index or are empty. - uint32_t NumBuckets = AppleNames.getNumBuckets(); - uint32_t NumHashes = AppleNames.getNumHashes(); + uint32_t NumBuckets = AccelTable.getNumBuckets(); + uint32_t NumHashes = AccelTable.getNumHashes(); uint32_t BucketsOffset = - AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength(); + AccelTable.getSizeHdr() + AccelTable.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); + uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { - OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx, + OS << format("\terror: Bucket[%d] has invalid hash index: %u.\n", BucketIdx, HashIdx); - ++NumAppleNamesErrors; + ++NumErrors; } } - - uint32_t NumAtoms = AppleNames.getAtomsDesc().size(); + uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); if (NumAtoms == 0) { - OS << "error: no atoms; failed to read HashData\n"; - ++NumAppleNamesErrors; - return false; + OS << "\terror: no atoms; failed to read HashData.\n"; + return 1; } - - if (!AppleNames.validateForms()) { - OS << "error: unsupported form; failed to read HashData\n"; - ++NumAppleNamesErrors; - return false; + if (!AccelTable.validateForms()) { + OS << "\terror: unsupported form; failed to read HashData.\n"; + return 1; } 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", + uint32_t Hash = AccelSectionData.getU32(&HashOffset); + uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset); + if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, + sizeof(uint64_t))) { + OS << format("\terror: Hash[%d] has invalid HashData offset: 0x%08x.\n", HashIdx, HashDataOffset); - ++NumAppleNamesErrors; + ++NumErrors; } uint32_t StrpOffset; @@ -526,32 +528,51 @@ uint32_t StringCount = 0; uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; - while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) { + while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { const uint32_t NumHashDataObjects = - AppleNamesSection.getU32(&HashDataOffset); + AccelSectionData.getU32(&HashDataOffset); for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; ++HashDataIdx) { - DieOffset = AppleNames.readAtoms(HashDataOffset); + DieOffset = AccelTable.readAtoms(HashDataOffset); if (!DCtx.getDIEForOffset(DieOffset)) { const uint32_t BucketIdx = NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; StringOffset = StrpOffset; - const char *Name = StrData.getCStr(&StringOffset); + const char *Name = StrData->getCStr(&StringOffset); if (!Name) Name = ""; OS << format( - "error: .apple_names Bucket[%d] Hash[%d] = 0x%08x " + "\terror: %s 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); + SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, + HashDataIdx, DieOffset, Name); - ++NumAppleNamesErrors; + ++NumErrors; } } ++StringCount; } } - return NumAppleNamesErrors == 0; + return NumErrors; +} + +bool DWARFVerifier::handleAccelTables() { + const DWARFObject &D = DCtx.getDWARFObj(); + DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0); + unsigned NumErrors = 0; + if (!D.getAppleNamesSection().Data.empty()) + NumErrors += + verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names"); + if (!D.getAppleTypesSection().Data.empty()) + NumErrors += + verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types"); + if (!D.getAppleNamespacesSection().Data.empty()) + NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData, + ".apple_namespaces"); + if (!D.getAppleObjCSection().Data.empty()) + NumErrors += + verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc"); + return NumErrors == 0; } Index: test/DebugInfo/dwarfdump-accel.test =================================================================== --- test/DebugInfo/dwarfdump-accel.test +++ test/DebugInfo/dwarfdump-accel.test @@ -1,5 +1,5 @@ RUN: llvm-dwarfdump %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s -RUN: llvm-dwarfdump -verify %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s --check-prefix=VERIFY +RUN: not llvm-dwarfdump -verify %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s --check-prefix=VERIFY Gather some DIE indexes to verify the accelerator table contents. CHECK: .debug_info contents @@ -66,5 +66,9 @@ CHECK: {Atom[0]: [[SETASSIGN]]} Verify the debug info in the apple_names accelerator table. -VERIFY: Verifying .apple_names -VERIFY-NEXT: No errors. +VERIFY: Verifying .apple_names... +VERIFY-NEXT: Verifying .apple_types... +VERIFY-NEXT: Verifying .apple_namespaces... +VERIFY-NEXT: error: Section is smaller than size described in section header. +VERIFY-NEXT: Verifying .apple_objc... +VERIFY-NEXT: Errors detected. Index: test/tools/llvm-dwarfdump/X86/apple_names_verify_data.s =================================================================== --- test/tools/llvm-dwarfdump/X86/apple_names_verify_data.s +++ test/tools/llvm-dwarfdump/X86/apple_names_verify_data.s @@ -3,9 +3,9 @@ # RUN: | FileCheck %s # CHECK: Verifying .apple_names... -# CHECK-NEXT: error: Bucket[0] has invalid hash index: 4294967294 -# CHECK-NEXT: error: Hash[0] has invalid HashData offset: 0x000000b4 -# CHECK-NEXT: error: .apple_names Bucket[1] Hash[1] = 0x0002b60f Str[0] = 0x0000005a DIE[0] = 0x00000001 is not a valid DIE offset for "j". +# CHECK-NEXT: error: Bucket[0] has invalid hash index: 4294967294. +# CHECK-NEXT: error: Hash[0] has invalid HashData offset: 0x000000b4. +# CHECK-NEXT: error: .apple_names Bucket[1] Hash[1] = 0x0002b60f Str[0] = 0x0000005a DIE[0] = 0x00000001 is not a valid DIE offset for "j". # This test is meant to verify that the -verify option # in llvm-dwarfdump, correctly identifies @@ -41,11 +41,11 @@ .long 1 ## HeaderData Atom Count .short 1 ## DW_ATOM_die_offset .short 25 ## DW_FORM_data4 -- error: .apple_names Bucket[1] Hash[1] = 0x0002b60f Str[0] = 0x0000005a DIE[0] = 0x00000001 is not a valid DIE offset for "j". - .long -2 ## Bucket 0 -- error: Bucket[0] has invalid hash index: 4294967294 + .long -2 ## Bucket 0 -- error: Bucket[0] has invalid hash index: 4294967294. .long 1 ## Bucket 1 .long 177678 ## Hash in Bucket 0 .long 177679 ## Hash in Bucket 1 - .long Lsection_line ## Offset in Bucket 0 -- error: Hash[0] has invalid HashData offset: 0x000000b4 + .long Lsection_line ## Offset in Bucket 0 -- error: Hash[0] has invalid HashData offset: 0x000000b4. .long LNames1-Lnames_begin ## Offset in Bucket 1 LNames0: .long 84 ## i Index: test/tools/llvm-dwarfdump/X86/apple_names_verify_form.s =================================================================== --- test/tools/llvm-dwarfdump/X86/apple_names_verify_form.s +++ test/tools/llvm-dwarfdump/X86/apple_names_verify_form.s @@ -3,7 +3,7 @@ # RUN: | FileCheck %s # CHECK: Verifying .apple_names... -# CHECK-NEXT: error: unsupported form; failed to read HashData +# CHECK-NEXT: error: unsupported form; failed to read HashData. # This test is meant to verify that the -verify option # in llvm-dwarfdump, correctly identifies that Atom[0].form is unsupported. @@ -34,7 +34,7 @@ .long 0 ## HeaderData Die Offset Base .long 1 ## HeaderData Atom Count .short 1 ## DW_ATOM_die_offset - .short 400 ## DW_FORM_data4 -- error: unsupported form; failed to read HashData + .short 400 ## DW_FORM_data4 -- error: unsupported form; failed to read HashData. .long 0 ## Bucket 0 .long 1 ## Bucket 1 .long 177678 ## Hash in Bucket 0 Index: test/tools/llvm-dwarfdump/X86/apple_names_verify_num_atoms.s =================================================================== --- test/tools/llvm-dwarfdump/X86/apple_names_verify_num_atoms.s +++ test/tools/llvm-dwarfdump/X86/apple_names_verify_num_atoms.s @@ -3,7 +3,7 @@ # RUN: | FileCheck %s # CHECK: Verifying .apple_names... -# CHECK-NEXT: error: no atoms; failed to read HashData +# CHECK-NEXT: error: no atoms; failed to read HashData. # This test is meant to verify that the -verify option # in llvm-dwarfdump, correctly identifies that there is not Atom. @@ -33,7 +33,7 @@ .long 2 ## Header Hash Count .long 12 ## Header Data Length .long 0 ## HeaderData Die Offset Base - .long 0 ## HeaderData Atom Count -- error: no atoms; failed to read HashData + .long 0 ## HeaderData Atom Count -- error: no atoms; failed to read HashData. .short 1 ## DW_ATOM_die_offset .short 6 ## DW_FORM_data4 .long 0 ## Bucket 0