/// Print only DIEs that have a certain name. static void filterByName(const StringSet<> &Names, DWARFContext::cu_iterator_range CUs, raw_ostream &OS) { for (const auto &CU : CUs) for (const auto &Entry : CU->dies()) { DWARFDie Die = {CU.get(), &Entry}; if (const char *NamePtr = Die.getName(DINameKind::ShortName)) { std::string Name = (IgnoreCase && !UseRegex) ? StringRef(NamePtr).lower() : NamePtr; // Match regular expression. if (UseRegex) for (auto Pattern : Names.keys()) { Regex RE(Pattern, IgnoreCase ? Regex::IgnoreCase : Regex::NoFlags); std::string Error; if (!RE.isValid(Error)) { errs() << "error in regular expression: " << Error << "\n"; exit(1); } if (RE.match(Name)) Die.dump(OS, 0, getDumpOpts()); } // Match full text. else if (Names.count(Name)) Die.dump(OS, 0, getDumpOpts()); } } }
unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI) { unsigned NumErrors = 0; if (!Die.isValid()) return NumErrors; DWARFAddressRangesVector Ranges = Die.getAddressRanges(); // Build RI for this DIE and check that ranges within this DIE do not // overlap. DieRangeInfo RI(Die); for (auto Range : Ranges) { if (!Range.valid()) { ++NumErrors; error() << "Invalid address range " << Range << "\n"; continue; } // Verify that ranges don't intersect. const auto IntersectingRange = RI.insert(Range); if (IntersectingRange != RI.Ranges.end()) { ++NumErrors; error() << "DIE has overlapping address ranges: " << Range << " and " << *IntersectingRange << "\n"; break; } } // Verify that children don't intersect. const auto IntersectingChild = ParentRI.insert(RI); if (IntersectingChild != ParentRI.Children.end()) { ++NumErrors; error() << "DIEs have overlapping address ranges:"; Die.dump(OS, 0); IntersectingChild->Die.dump(OS, 0); OS << "\n"; } // Verify that ranges are contained within their parent. bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() && !(Die.getTag() == DW_TAG_subprogram && ParentRI.Die.getTag() == DW_TAG_subprogram); if (ShouldBeContained && !ParentRI.contains(RI)) { ++NumErrors; error() << "DIE address ranges are not " "contained in its parent's ranges:"; Die.dump(OS, 0); ParentRI.Die.dump(OS, 0); OS << "\n"; } // Recursively check children. for (DWARFDie Child : Die) NumErrors += verifyDieRanges(Child, RI); return NumErrors; }
unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue) { const DWARFObject &DObj = DCtx.getDWARFObj(); unsigned NumErrors = 0; const auto Attr = AttrValue.Attr; 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 >= DObj.getRangeSection().Data.size()) { ++NumErrors; OS << "error: DW_AT_ranges offset is beyond .debug_ranges " "bounds:\n"; Die.dump(OS, 0); OS << "\n"; } } else { ++NumErrors; 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 >= DObj.getLineSection().Data.size()) { ++NumErrors; OS << "error: DW_AT_stmt_list offset is beyond .debug_line " "bounds: " << format("0x%08" PRIx64, *SectionOffset) << "\n"; Die.dump(OS, 0); OS << "\n"; } } else { ++NumErrors; OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n"; Die.dump(OS, 0); OS << "\n"; } break; default: break; } return NumErrors; }
/// Helper to dump a DIE with all of its parents, but no siblings. static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, DIDumpOptions DumpOpts) { if (!Die) return Indent; Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts); Die.dump(OS, Indent, DumpOpts); return Indent + 2; }
unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue) { unsigned NumErrors = 0; auto ReportError = [&](const Twine &TitleMsg) { ++NumErrors; error() << TitleMsg << '\n'; Die.dump(OS, 0, DumpOpts); OS << "\n"; }; const DWARFObject &DObj = DCtx.getDWARFObj(); const auto Attr = AttrValue.Attr; 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 >= DObj.getRangeSection().Data.size()) ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:"); break; } ReportError("DIE has invalid DW_AT_ranges encoding:"); 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 >= DObj.getLineSection().Data.size()) ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); break; } ReportError("DIE has invalid DW_AT_stmt_list encoding:"); break; case DW_AT_location: { Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock(); if (!Expr) { ReportError("DIE has invalid DW_AT_location encoding:"); break; } DWARFUnit *U = Die.getDwarfUnit(); DataExtractor Data( StringRef(reinterpret_cast<const char *>(Expr->data()), Expr->size()), DCtx.isLittleEndian(), 0); DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { return Op.isError(); }); if (Error) ReportError("DIE contains invalid DWARF expression:"); break; } default: break; } return NumErrors; }
void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent) const { if (!isValid()) return; DataExtractor debug_info_data = U->getDebugInfoExtractor(); const uint32_t Offset = getOffset(); uint32_t offset = Offset; if (debug_info_data.isValidOffset(offset)) { uint32_t abbrCode = debug_info_data.getULEB128(&offset); WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset); if (abbrCode) { auto AbbrevDecl = getAbbreviationDeclarationPtr(); if (AbbrevDecl) { auto tagString = TagString(getTag()); if (!tagString.empty()) WithColor(OS, syntax::Tag).get().indent(Indent) << tagString; else WithColor(OS, syntax::Tag).get().indent(Indent) << format("DW_TAG_Unknown_%x", getTag()); OS << format(" [%u] %c\n", abbrCode, AbbrevDecl->hasChildren() ? '*' : ' '); // Dump all data in the DIE for the attributes. for (const auto &AttrSpec : AbbrevDecl->attributes()) { if (AttrSpec.Form == DW_FORM_implicit_const) { // We are dumping .debug_info section , // implicit_const attribute values are not really stored here, // but in .debug_abbrev section. So we just skip such attrs. continue; } dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, Indent); } DWARFDie child = getFirstChild(); if (RecurseDepth > 0 && child) { while (child) { child.dump(OS, RecurseDepth-1, Indent+2); child = child.getSibling(); } } } else { OS << "Abbreviation code not found in 'debug_abbrev' class for code: " << abbrCode << '\n'; } } else { OS.indent(Indent) << "NULL\n"; } } }
/// Print only DIEs that have a certain name. static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx, raw_ostream &OS) { SmallVector<uint64_t, 4> Offsets; for (const auto &Name : Names) { getDIEOffset(DICtx.getAppleNames(), Name, Offsets); getDIEOffset(DICtx.getAppleTypes(), Name, Offsets); getDIEOffset(DICtx.getAppleNamespaces(), Name, Offsets); getDIEOffset(DICtx.getDebugNames(), Name, Offsets); } llvm::sort(Offsets.begin(), Offsets.end()); Offsets.erase(std::unique(Offsets.begin(), Offsets.end()), Offsets.end()); for (uint64_t Off: Offsets) { DWARFDie Die = DICtx.getDIEForOffset(Off); Die.dump(OS, 0, getDumpOpts()); } }
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::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue) { unsigned NumErrors = 0; auto ReportError = [&](const Twine &TitleMsg) { ++NumErrors; error() << TitleMsg << '\n'; Die.dump(OS, 0, DumpOpts); OS << "\n"; }; const DWARFObject &DObj = DCtx.getDWARFObj(); const auto Attr = AttrValue.Attr; 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 >= DObj.getRangeSection().Data.size()) ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:"); break; } ReportError("DIE has invalid DW_AT_ranges encoding:"); 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 >= DObj.getLineSection().Data.size()) ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); break; } ReportError("DIE has invalid DW_AT_stmt_list encoding:"); break; case DW_AT_location: { auto VerifyLocation = [&](StringRef D) { DWARFUnit *U = Die.getDwarfUnit(); DataExtractor Data(D, DCtx.isLittleEndian(), 0); DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { return Op.isError(); }); if (Error) ReportError("DIE contains invalid DWARF expression:"); }; if (Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock()) { // Verify inlined location. VerifyLocation(llvm::toStringRef(*Expr)); } else if (auto LocOffset = AttrValue.Value.getAsUnsignedConstant()) { // Verify location list. if (auto DebugLoc = DCtx.getDebugLoc()) if (auto LocList = DebugLoc->getLocationListAtOffset(*LocOffset)) for (const auto &Entry : LocList->Entries) VerifyLocation({Entry.Loc.data(), Entry.Loc.size()}); } break; } default: break; } return NumErrors; }
std::shared_ptr<TypeInfo> DwarfVariableFinder::makeType(const DWARFDie &die) { if (!die.isValid()) { return std::make_shared<TypeInfo>("", ~0u); } auto opSize = die.find(dwarf::DW_AT_byte_size); unsigned size = 1; if(opSize.hasValue()) { size = opSize.getValue().getAsUnsignedConstant().getValue(); } std::string type_encoding = ""; raw_string_ostream SS(type_encoding); switch (die.getTag()) { case dwarf::DW_TAG_base_type: { auto opForm = die.find(dwarf::DW_AT_encoding); auto opEnc = opForm->getAsUnsignedConstant(); assert(opEnc < HANDLE_DW_ATE_SIZE); SS << HANDLE_DW_ATE[*opEnc]; opForm = die.find(dwarf::DW_AT_name); opForm->dump(SS); return std::make_shared<TypeInfo>(SS.str(), size); } case dwarf::DW_TAG_reference_type: case dwarf::DW_TAG_rvalue_reference_type: case dwarf::DW_TAG_pointer_type: { auto baseType = getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); SS << "*" << baseType->getName(); return std::make_shared<TypeInfo>(SS.str(), size); } case dwarf::DW_TAG_array_type: { auto baseType = getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); SS << baseType->getName(); size *= baseType->getSize(); for (auto childDie = die.getFirstChild(); childDie && childDie.getTag(); childDie = childDie.getSibling()) { std::shared_ptr<TypeInfo> rangeInfo = makeType(childDie); SS << "["; SS << rangeInfo->getName(); SS << "]"; size *= rangeInfo->getSize(); } return std::make_shared<TypeInfo>(SS.str(), size); } case dwarf::DW_TAG_subrange_type: { uint64_t count = 0; auto opCount = die.find(dwarf::DW_AT_count); if(opCount.hasValue()) { count = opCount.getValue().getAsUnsignedConstant().getValue(); } else { opCount = die.find(dwarf::DW_AT_upper_bound); assert(opCount.hasValue()); count = opCount.getValue().getAsUnsignedConstant().getValue() +1; } return std::make_shared<TypeInfo>(std::to_string(count), count); } case dwarf::DW_TAG_typedef: { return getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); } case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_class_type: case dwarf::DW_TAG_union_type: { SS << "struct" << dwarf::toString(die.find(dwarf::DW_AT_name), "None"); auto structType = std::make_shared<TypeInfo>(SS.str(), size); // Add subentries for various pieces of the struct. for (auto childDie = die.getFirstChild(); childDie && childDie.getTag(); childDie = childDie.getSibling()) { if (childDie.getTag() != dwarf::DW_TAG_inheritance && childDie.getTag() != dwarf::DW_TAG_member) { continue; } uint64_t dataMemOffset = dwarf::toUnsigned(childDie.find(dwarf::DW_AT_data_member_location), ~0U); structType->getFields().emplace_back(makeType(childDie), dataMemOffset); } return structType; } case dwarf::DW_TAG_inheritance: case dwarf::DW_TAG_member: { return getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type)); } default: { auto tagString = TagString(die.getTag()); if (tagString.empty()) { llvm::errs() << format("DW_TAG_Unknown_%x", die.getTag()); } die.dump(llvm::errs(), 10); return std::make_shared<TypeInfo>("", ~0u); } } }
void DWARFDie::dump(raw_ostream &OS, unsigned Indent, DIDumpOptions DumpOpts) const { if (!isValid()) return; DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); const uint32_t Offset = getOffset(); uint32_t offset = Offset; if (DumpOpts.ShowParents) { DIDumpOptions ParentDumpOpts = DumpOpts; ParentDumpOpts.ShowParents = false; ParentDumpOpts.ShowChildren = false; Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts); } if (debug_info_data.isValidOffset(offset)) { uint32_t abbrCode = debug_info_data.getULEB128(&offset); if (DumpOpts.ShowAddresses) WithColor(OS, HighlightColor::Address).get() << format("\n0x%8.8x: ", Offset); if (abbrCode) { auto AbbrevDecl = getAbbreviationDeclarationPtr(); if (AbbrevDecl) { WithColor(OS, HighlightColor::Tag).get().indent(Indent) << formatv("{0}", getTag()); if (DumpOpts.Verbose) OS << format(" [%u] %c", abbrCode, AbbrevDecl->hasChildren() ? '*' : ' '); OS << '\n'; // Dump all data in the DIE for the attributes. for (const auto &AttrSpec : AbbrevDecl->attributes()) { if (AttrSpec.Form == DW_FORM_implicit_const) { // We are dumping .debug_info section , // implicit_const attribute values are not really stored here, // but in .debug_abbrev section. So we just skip such attrs. continue; } dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, Indent, DumpOpts); } DWARFDie child = getFirstChild(); if (DumpOpts.ShowChildren && DumpOpts.RecurseDepth > 0 && child) { DumpOpts.RecurseDepth--; DIDumpOptions ChildDumpOpts = DumpOpts; ChildDumpOpts.ShowParents = false; while (child) { child.dump(OS, Indent + 2, ChildDumpOpts); child = child.getSibling(); } } } else { OS << "Abbreviation code not found in 'debug_abbrev' class for code: " << abbrCode << '\n'; } } else { OS.indent(Indent) << "NULL\n"; } } }