DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) : Die(D), AttrValue(0), Index(0) { auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); assert(AbbrDecl && "Must have abbreviation declaration"); if (End) { // This is the end iterator so we set the index to the attribute count. Index = AbbrDecl->getNumAttributes(); } else { // This is the begin iterator so we extract the value for this->Index. AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); updateForIndex(*AbbrDecl, 0); } }
std::shared_ptr<TypeInfo> DwarfVariableFinder::getType(const DWARFDie &die) { if (!die.isValid()) { assert(0); return std::make_shared<TypeInfo>("", ~0u); } auto die_offset = die.getOffset(); if(typeDict.count(die_offset)) { return typeDict[die_offset]; } auto result = makeType(die); typeDict[die_offset] = result; return result; }
unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue) { const DWARFObject &DObj = DCtx.getDWARFObj(); unsigned NumErrors = 0; const auto Form = AttrValue.Value.getForm(); 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) { ++NumErrors; error() << FormEncodingString(Form) << " CU offset " << format("0x%08" PRIx64, CUOffset) << " is invalid (must be less than CU size of " << format("0x%08" PRIx32, CUSize) << "):\n"; Die.dump(OS, 0, DumpOpts); OS << "\n"; } else { // Valid reference, but we will verify it points to an actual // DIE later. ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); } } 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) { if (*RefVal >= DObj.getInfoSection().Data.size()) { ++NumErrors; error() << "DW_FORM_ref_addr offset beyond .debug_info " "bounds:\n"; Die.dump(OS, 0, DumpOpts); OS << "\n"; } else { // Valid reference, but we will verify it points to an actual // DIE later. ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); } } break; } case DW_FORM_strp: { auto SecOffset = AttrValue.Value.getAsSectionOffset(); assert(SecOffset); // DW_FORM_strp is a section offset. if (SecOffset && *SecOffset >= DObj.getStringSection().size()) { ++NumErrors; error() << "DW_FORM_strp offset beyond .debug_str bounds:\n"; Die.dump(OS, 0, DumpOpts); OS << "\n"; } break; } default: break; } return NumErrors; }
unsigned DWARFVerifier::verifyNameIndexCompleteness( const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) { // First check, if the Die should be indexed. The code follows the DWARF v5 // wording as closely as possible. // "All non-defining declarations (that is, debugging information entries // with a DW_AT_declaration attribute) are excluded." if (Die.find(DW_AT_declaration)) return 0; // "DW_TAG_namespace debugging information entries without a DW_AT_name // attribute are included with the name “(anonymous namespace)”. // All other debugging information entries without a DW_AT_name attribute // are excluded." // "If a subprogram or inlined subroutine is included, and has a // DW_AT_linkage_name attribute, there will be an additional index entry for // the linkage name." auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram || Die.getTag() == DW_TAG_inlined_subroutine; auto EntryNames = getNames(Die, IncludeLinkageName); if (EntryNames.empty()) return 0; // We deviate from the specification here, which says: // "The name index must contain an entry for each debugging information entry // that defines a named subprogram, label, variable, type, or namespace, // subject to ..." // Instead whitelisting all TAGs representing a "type" or a "subprogram", to // make sure we catch any missing items, we instead blacklist all TAGs that we // know shouldn't be indexed. switch (Die.getTag()) { // Compile units and modules have names but shouldn't be indexed. case DW_TAG_compile_unit: case DW_TAG_module: return 0; // Function and template parameters are not globally visible, so we shouldn't // index them. case DW_TAG_formal_parameter: case DW_TAG_template_value_parameter: case DW_TAG_template_type_parameter: case DW_TAG_GNU_template_parameter_pack: case DW_TAG_GNU_template_template_param: return 0; // Object members aren't globally visible. case DW_TAG_member: return 0; // According to a strict reading of the specification, enumerators should not // be indexed (and LLVM currently does not do that). However, this causes // problems for the debuggers, so we may need to reconsider this. case DW_TAG_enumerator: return 0; // Imported declarations should not be indexed according to the specification // and LLVM currently does not do that. case DW_TAG_imported_declaration: return 0; // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging // information entries without an address attribute (DW_AT_low_pc, // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded." case DW_TAG_subprogram: case DW_TAG_inlined_subroutine: case DW_TAG_label: if (Die.findRecursively( {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc})) break; return 0; // "DW_TAG_variable debugging information entries with a DW_AT_location // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are // included; otherwise, they are excluded." // // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list. case DW_TAG_variable: if (isVariableIndexable(Die, DCtx)) break; return 0; default: break; } // Now we know that our Die should be present in the Index. Let's check if // that's the case. unsigned NumErrors = 0; uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset(); for (StringRef Name : EntryNames) { if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) { return E.getDIEUnitOffset() == DieUnitOffset; })) { error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with " "name {3} missing.\n", NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name); ++NumErrors; } } return NumErrors; }