void DWARFCompileUnit::setDIERelations() { if (DieArray.empty()) return; DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front(); DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back(); DWARFDebugInfoEntryMinimal *curr_die; // We purposely are skipping the last element in the array in the loop below // so that we can always have a valid next item for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) { // Since our loop doesn't include the last element, we can always // safely access the next die in the array. DWARFDebugInfoEntryMinimal *next_die = curr_die + 1; const DWARFAbbreviationDeclaration *curr_die_abbrev = curr_die->getAbbreviationDeclarationPtr(); if (curr_die_abbrev) { // Normal DIE if (curr_die_abbrev->hasChildren()) next_die->setParent(curr_die); else curr_die->setSibling(next_die); } else { // NULL DIE that terminates a sibling chain DWARFDebugInfoEntryMinimal *parent = curr_die->getParent(); if (parent) parent->setSibling(next_die); } } // Since we skipped the last element, we need to fix it up! if (die_array_begin < die_array_end) curr_die->setParent(die_array_begin); }
void DWARFUnit::setDIERelations() { if (DieArray.size() <= 1) return; std::vector<DWARFDebugInfoEntryMinimal *> ParentChain; DWARFDebugInfoEntryMinimal *SiblingChain = nullptr; for (auto &DIE : DieArray) { if (SiblingChain) { SiblingChain->setSibling(&DIE); } if (const DWARFAbbreviationDeclaration *AbbrDecl = DIE.getAbbreviationDeclarationPtr()) { // Normal DIE. if (AbbrDecl->hasChildren()) { ParentChain.push_back(&DIE); SiblingChain = nullptr; } else { SiblingChain = &DIE; } } else { // NULL entry terminates the sibling chain. SiblingChain = ParentChain.back(); ParentChain.pop_back(); } } assert(SiblingChain == nullptr || SiblingChain == &DieArray[0]); assert(ParentChain.empty()); }
void DWARFCompileUnit::extractDIEsToVector( bool AppendCUDie, bool AppendNonCUDies, std::vector<DWARFDebugInfoEntryMinimal> &Dies) const { if (!AppendCUDie && !AppendNonCUDies) return; // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. uint32_t Offset = getFirstDIEOffset(); uint32_t NextCUOffset = getNextCompileUnitOffset(); DWARFDebugInfoEntryMinimal DIE; uint32_t Depth = 0; const uint8_t *FixedFormSizes = DWARFFormValue::getFixedFormSizes(getAddressByteSize(), getVersion()); bool IsCUDie = true; while (Offset < NextCUOffset && DIE.extractFast(this, FixedFormSizes, &Offset)) { if (IsCUDie) { if (AppendCUDie) Dies.push_back(DIE); if (!AppendNonCUDies) break; // The average bytes per DIE entry has been seen to be // around 14-20 so let's pre-reserve the needed memory for // our DIE entries accordingly. Dies.reserve(Dies.size() + getDebugInfoSize() / 14); IsCUDie = false; } else { Dies.push_back(DIE); } const DWARFAbbreviationDeclaration *AbbrDecl = DIE.getAbbreviationDeclarationPtr(); if (AbbrDecl) { // Normal DIE if (AbbrDecl->hasChildren()) ++Depth; } else { // NULL DIE. if (Depth > 0) --Depth; if (Depth == 0) break; // We are done with this compile unit! } } // Give a little bit of info if we encounter corrupt DWARF (our offset // should always terminate at or before the start of the next compilation // unit header). if (Offset > NextCUOffset) fprintf(stderr, "warning: DWARF compile unit extends beyond its " "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), Offset); }
void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS, DWARFUnit *u, uint32_t *offset_ptr, uint16_t attr, uint16_t form, unsigned indent) const { const char BaseIndent[] = " "; OS << BaseIndent; OS.indent(indent+2); const char *attrString = AttributeString(attr); if (attrString) WithColor(OS, syntax::Attribute) << attrString; else WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", attr); const char *formString = FormEncodingString(form); if (formString) OS << " [" << formString << ']'; else OS << format(" [DW_FORM_Unknown_%x]", form); DWARFFormValue formValue(form); if (!formValue.extractValue(u->getDebugInfoExtractor(), offset_ptr, u)) return; OS << "\t("; const char *Name = nullptr; 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.c_str(); } } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant()) Name = AttributeValueString(attr, *Val); if (Name) WithColor(OS, Color) << Name; else if (attr == DW_AT_decl_line || attr == DW_AT_call_line) OS << *formValue.getAsUnsignedConstant(); else formValue.dump(OS, u); // 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) && // The signature references aren't handled. formValue.getForm() != DW_FORM_ref_sig8) { uint32_t Ref = formValue.getAsReference(u).getValue(); DWARFDebugInfoEntryMinimal DIE; if (const DWARFUnit *RefU = findUnitAndExtractFast(DIE, u, &Ref)) if (const char *Ref = DIE.getName(RefU, DINameKind::LinkageName)) OS << " \"" << Ref << '\"'; } 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, getAddressRanges(u), u->getAddressByteSize(), sizeof(BaseIndent)+indent+4); } OS << ")\n"; }
size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) { const size_t initial_die_array_size = DieArray.size(); if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) return 0; // Already parsed // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. uint32_t offset = getFirstDIEOffset(); uint32_t next_cu_offset = getNextCompileUnitOffset(); DWARFDebugInfoEntryMinimal die; // Keep a flat array of the DIE for binary lookup by DIE offset uint32_t depth = 0; // We are in our compile unit, parse starting at the offset // we were told to parse const uint8_t *fixed_form_sizes = DWARFFormValue::getFixedFormSizes(getAddressByteSize(), getVersion()); while (offset < next_cu_offset && die.extractFast(this, fixed_form_sizes, &offset)) { if (depth == 0) { uint64_t base_addr = die.getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U); if (base_addr == -1U) base_addr = die.getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0); setBaseAddress(base_addr); } if (cu_die_only) { addDIE(die); return 1; } else if (depth == 0 && initial_die_array_size == 1) // Don't append the CU die as we already did that ; else addDIE(die); const DWARFAbbreviationDeclaration *abbrDecl = die.getAbbreviationDeclarationPtr(); if (abbrDecl) { // Normal DIE if (abbrDecl->hasChildren()) ++depth; } else { // NULL DIE. if (depth > 0) --depth; if (depth == 0) break; // We are done with this compile unit! } } // Give a little bit of info if we encounter corrupt DWARF (our offset // should always terminate at or before the start of the next compilation // unit header). if (offset > next_cu_offset) fprintf(stderr, "warning: DWARF compile unit extends beyond its " "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), offset); setDIERelations(); return DieArray.size(); }