Optional<DWARFFormValue> DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { std::vector<DWARFDie> Worklist; Worklist.push_back(*this); // Keep track if DIEs already seen to prevent infinite recursion. // Empirically we rarely see a depth of more than 3 when dealing with valid // DWARF. This corresponds to following the DW_AT_abstract_origin and // DW_AT_specification just once. SmallSet<DWARFDie, 3> Seen; Seen.insert(*this); while (!Worklist.empty()) { DWARFDie Die = Worklist.back(); Worklist.pop_back(); if (!Die.isValid()) continue; if (auto Value = Die.find(Attrs)) return Value; if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) if (Seen.insert(D).second) Worklist.push_back(D); if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification)) if (Seen.insert(D).second) Worklist.push_back(D); } return None; }
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; }
/// Recursively dump the DIE type name when applicable. static void dumpTypeName(raw_ostream &OS, const DWARFDie &Die) { DWARFDie D = Die.getAttributeValueAsReferencedDie(DW_AT_type); if (!D.isValid()) return; if (const char *Name = D.getName(DINameKind::LinkageName)) { OS << Name; return; } // FIXME: We should have pretty printers per language. Currently we print // everything as if it was C++ and fall back to the TAG type name. const dwarf::Tag T = D.getTag(); switch (T) { case DW_TAG_array_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: case DW_TAG_reference_type: case DW_TAG_rvalue_reference_type: break; default: dumpTypeTagName(OS, T); } // Follow the DW_AT_type if possible. dumpTypeName(OS, D); switch (T) { case DW_TAG_array_type: OS << "[]"; break; case DW_TAG_pointer_type: OS << '*'; break; case DW_TAG_ptr_to_member_type: OS << '*'; break; case DW_TAG_reference_type: OS << '&'; break; case DW_TAG_rvalue_reference_type: OS << "&&"; break; default: break; } }
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; }
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"; }
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); } } }
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"; }
/// Recursively dump the DIE type name when applicable. static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) { if (!D.isValid()) return; if (const char *Name = D.getName(DINameKind::LinkageName)) { OS << Name; return; } // FIXME: We should have pretty printers per language. Currently we print // everything as if it was C++ and fall back to the TAG type name. const dwarf::Tag T = D.getTag(); switch (T) { case DW_TAG_array_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: case DW_TAG_reference_type: case DW_TAG_rvalue_reference_type: case DW_TAG_subroutine_type: break; default: dumpTypeTagName(OS, T); } // Follow the DW_AT_type if possible. DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type); dumpTypeName(OS, TypeDie); switch (T) { case DW_TAG_subroutine_type: { if (!TypeDie) OS << "void"; OS << '('; bool First = true; for (const DWARFDie &C : D.children()) { if (C.getTag() == DW_TAG_formal_parameter) { if (!First) OS << ", "; First = false; dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type)); } } OS << ')'; break; } case DW_TAG_array_type: { dumpArrayType(OS, D); break; } case DW_TAG_pointer_type: OS << '*'; break; case DW_TAG_ptr_to_member_type: if (DWARFDie Cont = D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) { dumpTypeName(OS << ' ', Cont); OS << "::"; } OS << '*'; break; case DW_TAG_reference_type: OS << '&'; break; case DW_TAG_rvalue_reference_type: OS << "&&"; break; default: break; } }
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"; }