static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { Optional<DWARFFormValue> Location = Die.findRecursively(DW_AT_location); if (!Location) return false; auto ContainsInterestingOperators = [&](StringRef D) { DWARFUnit *U = Die.getDwarfUnit(); DataExtractor Data(D, DCtx.isLittleEndian(), U->getAddressByteSize()); DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); return any_of(Expression, [](DWARFExpression::Operation &Op) { return !Op.isError() && (Op.getCode() == DW_OP_addr || Op.getCode() == DW_OP_form_tls_address || Op.getCode() == DW_OP_GNU_push_tls_address); }); }; if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) { // Inlined location. if (ContainsInterestingOperators(toStringRef(*Expr))) return true; } else if (Optional<uint64_t> Offset = Location->getAsSectionOffset()) { // Location list. if (const DWARFDebugLoc *DebugLoc = DCtx.getDebugLoc()) { if (const DWARFDebugLoc::LocationList *LocList = DebugLoc->getLocationListAtOffset(*Offset)) { if (any_of(LocList->Entries, [&](const DWARFDebugLoc::Entry &E) { return ContainsInterestingOperators({E.Loc.data(), E.Loc.size()}); })) return true; } } } return false; }
DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint32_t Offset) { DWARFUnit *U = nullptr; auto It = LineToUnit.find(Offset); if (It != LineToUnit.end()) U = It->second; DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0); return U; }
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; }
size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( const DWARFUnit &U) const { size_t ByteSize = NumBytes; if (NumAddrs) ByteSize += NumAddrs * U.getAddressByteSize(); if (NumRefAddrs) ByteSize += NumRefAddrs * U.getRefAddrByteSize(); if (NumDwarfOffsets) ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize(); return ByteSize; }
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; }
static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, uint32_t *OffsetPtr, dwarf::Attribute Attr, dwarf::Form Form, unsigned Indent) { if (!Die.isValid()) return; const char BaseIndent[] = " "; OS << BaseIndent; OS.indent(Indent+2); auto attrString = AttributeString(Attr); if (!attrString.empty()) WithColor(OS, syntax::Attribute) << attrString; else WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", Attr); auto formString = FormEncodingString(Form); if (!formString.empty()) OS << " [" << formString << ']'; else OS << format(" [DW_FORM_Unknown_%x]", Form); DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue formValue(Form); if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U)) return; OS << "\t("; StringRef Name; std::string File; auto Color = syntax::Enumerator; if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { Color = syntax::String; if (const auto *LT = U->getContext().getLineTableForUnit(U)) if (LT->getFileNameByIndex(formValue.getAsUnsignedConstant().getValue(), U->getCompilationDir(), DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { File = '"' + File + '"'; Name = File; } } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant()) Name = AttributeValueString(Attr, *Val); if (!Name.empty()) WithColor(OS, Color) << Name; else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) OS << *formValue.getAsUnsignedConstant(); else formValue.dump(OS); // We have dumped the attribute raw value. For some attributes // having both the raw value and the pretty-printed value is // interesting. These attributes are handled below. if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) { if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName(DINameKind::LinkageName)) OS << " \"" << Name << '\"'; } else if (Attr == DW_AT_APPLE_property_attribute) { if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant()) dumpApplePropertyAttribute(OS, *OptVal); } else if (Attr == DW_AT_ranges) { dumpRanges(OS, Die.getAddressRanges(), U->getAddressByteSize(), sizeof(BaseIndent)+Indent+4); } OS << ")\n"; }
static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, uint32_t *OffsetPtr, dwarf::Attribute Attr, dwarf::Form Form, unsigned Indent, DIDumpOptions DumpOpts) { if (!Die.isValid()) return; const char BaseIndent[] = " "; OS << BaseIndent; OS.indent(Indent + 2); WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr); if (DumpOpts.Verbose || DumpOpts.ShowForm) OS << formatv(" [{0}]", Form); DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue FormValue = DWARFFormValue::createFromUnit(Form, U, OffsetPtr); OS << "\t("; StringRef Name; std::string File; auto Color = HighlightColor::Enumerator; if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { Color = HighlightColor::String; if (const auto *LT = U->getContext().getLineTableForUnit(U)) if (LT->getFileNameByIndex( FormValue.getAsUnsignedConstant().getValue(), U->getCompilationDir(), DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { File = '"' + File + '"'; Name = File; } } else if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) Name = AttributeValueString(Attr, *Val); if (!Name.empty()) WithColor(OS, Color) << Name; else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) OS << *FormValue.getAsUnsignedConstant(); else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose && FormValue.getAsUnsignedConstant()) { if (DumpOpts.ShowAddresses) { // Print the actual address rather than the offset. uint64_t LowPC, HighPC, Index; if (Die.getLowAndHighPC(LowPC, HighPC, Index)) OS << format("0x%016" PRIx64, HighPC); else FormValue.dump(OS, DumpOpts); } } else if (DWARFAttribute::mayHaveLocationDescription(Attr)) dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); else FormValue.dump(OS, DumpOpts); std::string Space = DumpOpts.ShowAddresses ? " " : ""; // We have dumped the attribute raw value. For some attributes // having both the raw value and the pretty-printed value is // interesting. These attributes are handled below. if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) { if (const char *Name = Die.getAttributeValueAsReferencedDie(FormValue).getName( DINameKind::LinkageName)) OS << Space << "\"" << Name << '\"'; } else if (Attr == DW_AT_type) { OS << Space << "\""; dumpTypeName(OS, Die.getAttributeValueAsReferencedDie(FormValue)); OS << '"'; } else if (Attr == DW_AT_APPLE_property_attribute) { if (Optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant()) dumpApplePropertyAttribute(OS, *OptVal); } else if (Attr == DW_AT_ranges) { const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); // For DW_FORM_rnglistx we need to dump the offset separately, since // we have only dumped the index so far. if (FormValue.getForm() == DW_FORM_rnglistx) if (auto RangeListOffset = U->getRnglistOffset(*FormValue.getAsSectionOffset())) { DWARFFormValue FV = DWARFFormValue::createFromUValue( dwarf::DW_FORM_sec_offset, *RangeListOffset); FV.dump(OS, DumpOpts); } if (auto RangesOrError = Die.getAddressRanges()) dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(), sizeof(BaseIndent) + Indent + 4, DumpOpts); else WithColor::error() << "decoding address ranges: " << toString(RangesOrError.takeError()) << '\n'; } OS << ")\n"; }
static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, uint32_t *OffsetPtr, dwarf::Attribute Attr, dwarf::Form Form, unsigned Indent, DIDumpOptions DumpOpts) { if (!Die.isValid()) return; const char BaseIndent[] = " "; OS << BaseIndent; OS.indent(Indent + 2); auto attrString = AttributeString(Attr); if (!attrString.empty()) WithColor(OS, HighlightColor::Attribute) << attrString; else WithColor(OS, HighlightColor::Attribute).get() << format("DW_AT_Unknown_%x", Attr); if (DumpOpts.Verbose || DumpOpts.ShowForm) { auto formString = FormEncodingString(Form); if (!formString.empty()) OS << " [" << formString << ']'; else OS << format(" [DW_FORM_Unknown_%x]", Form); } DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue formValue(Form); if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U->getFormParams(), U)) return; OS << "\t("; StringRef Name; std::string File; auto Color = HighlightColor::Enumerator; if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { Color = HighlightColor::String; if (const auto *LT = U->getContext().getLineTableForUnit(U)) if (LT->getFileNameByIndex( formValue.getAsUnsignedConstant().getValue(), U->getCompilationDir(), DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { File = '"' + File + '"'; Name = File; } } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant()) Name = AttributeValueString(Attr, *Val); if (!Name.empty()) WithColor(OS, Color) << Name; else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) OS << *formValue.getAsUnsignedConstant(); else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose && formValue.getAsUnsignedConstant()) { if (DumpOpts.ShowAddresses) { // Print the actual address rather than the offset. uint64_t LowPC, HighPC, Index; if (Die.getLowAndHighPC(LowPC, HighPC, Index)) OS << format("0x%016" PRIx64, HighPC); else formValue.dump(OS, DumpOpts); } } else if (Attr == DW_AT_location || Attr == DW_AT_frame_base || Attr == DW_AT_data_member_location || Attr == DW_AT_GNU_call_site_value) dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); else formValue.dump(OS, DumpOpts); // We have dumped the attribute raw value. For some attributes // having both the raw value and the pretty-printed value is // interesting. These attributes are handled below. if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) { if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName( DINameKind::LinkageName)) OS << " \"" << Name << '\"'; } else if (Attr == DW_AT_type) { OS << " \""; dumpTypeName(OS, Die); OS << '"'; } else if (Attr == DW_AT_APPLE_property_attribute) { if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant()) dumpApplePropertyAttribute(OS, *OptVal); } else if (Attr == DW_AT_ranges) { const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(), sizeof(BaseIndent) + Indent + 4, DumpOpts); } OS << ")\n"; }