void ObjectLoadListener::extractLocalLocations( const DWARFUnit *CU, const DWARFDebugInfoEntryMinimal *DebugEntry, std::vector<uint64_t> &Offsets) { if (DebugEntry->isNULL()) return; if (DebugEntry->getTag() == dwarf::DW_TAG_formal_parameter || DebugEntry->getTag() == dwarf::DW_TAG_variable) { uint64_t Offset; // Extract offset for each local found DWARFFormValue FormValue; if (DebugEntry->getAttributeValue(CU, dwarf::DW_AT_location, FormValue)) { Optional<ArrayRef<uint8_t>> FormValues = FormValue.getAsBlock(); Offset = FormValues->back(); } Offsets.push_back(Offset); } const DWARFDebugInfoEntryMinimal *Child = DebugEntry->getFirstChild(); // Extract info for DebugEntry's child and its child's siblings. while (Child) { extractLocalLocations(CU, Child, Offsets); Child = Child->getSibling(); } }
void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { const DWARFDebugInfoEntryMinimal *TD = getDIEForOffset(TypeOffset + getOffset()); DWARFFormValue NameVal; const char *Name = ""; if (TD->getAttributeValue(this, llvm::dwarf::DW_AT_name, NameVal)) if (auto ON = NameVal.getAsCString(this)) Name = *ON; if (SummarizeTypes) { OS << "name = '" << Name << "'" << " type_signature = " << format("0x%16" PRIx64, TypeHash) << " length = " << format("0x%08x", getLength()) << '\n'; return; } OS << format("0x%08x", getOffset()) << ": Type Unit:" << " length = " << format("0x%08x", getLength()) << " version = " << format("0x%04x", getVersion()) << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) << " addr_size = " << format("0x%02x", getAddressByteSize()) << " name = '" << Name << "'" << " type_signature = " << format("0x%16" PRIx64, TypeHash) << " type_offset = " << format("0x%04x", TypeOffset) << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; if (const DWARFDebugInfoEntryMinimal *TU = getUnitDIE(false)) TU->dump(OS, this, -1U); else OS << "<type unit can't be parsed!>\n\n"; }
uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSectionOffset( const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { DWARFFormValue FormValue; if (!getAttributeValue(U, Attr, FormValue)) return FailValue; Optional<uint64_t> Result = FormValue.getAsSectionOffset(); return Result.hasValue() ? Result.getValue() : FailValue; }
const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString( const DWARFUnit *U, const uint16_t Attr, const char *FailValue) const { DWARFFormValue FormValue; if (!getAttributeValue(U, Attr, FormValue)) return FailValue; Optional<const char *> Result = FormValue.getAsCString(U); return Result.hasValue() ? Result.getValue() : FailValue; }
DIERef::DIERef(const DWARFFormValue &form_value) : cu_offset(DW_INVALID_OFFSET), die_offset(DW_INVALID_OFFSET) { if (form_value.IsValid()) { const DWARFUnit *dwarf_cu = form_value.GetCompileUnit(); if (dwarf_cu) { if (dwarf_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) cu_offset = dwarf_cu->GetBaseObjOffset(); else cu_offset = dwarf_cu->GetOffset(); } die_offset = form_value.Reference(); } }
uint32_t DWARFDebugInfoEntryMinimal::getAttributeValue(const DWARFCompileUnit *cu, const uint16_t attr, DWARFFormValue &form_value, uint32_t *end_attr_offset_ptr) const { if (AbbrevDecl) { uint32_t attr_idx = AbbrevDecl->findAttributeIndex(attr); if (attr_idx != -1U) { uint32_t offset = getOffset(); DataExtractor debug_info_data = cu->getDebugInfoExtractor(); // Skip the abbreviation code so we are at the data for the attributes debug_info_data.getULEB128(&offset); uint32_t idx = 0; while (idx < attr_idx) DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(idx++), debug_info_data, &offset, cu); const uint32_t attr_offset = offset; form_value = DWARFFormValue(AbbrevDecl->getFormByIndex(idx)); if (form_value.extractValue(debug_info_data, &offset, cu)) { if (end_attr_offset_ptr) *end_attr_offset_ptr = offset; return attr_offset; } } } return 0; }
static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, DWARFUnit *U, unsigned Indent, DIDumpOptions DumpOpts) { DWARFContext &Ctx = U->getContext(); const DWARFObject &Obj = Ctx.getDWARFObj(); const MCRegisterInfo *MRI = Ctx.getRegisterInfo(); if (FormValue.isFormClass(DWARFFormValue::FC_Block) || FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) { ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), Ctx.isLittleEndian(), 0); DWARFExpression(Data, U->getVersion(), U->getAddressByteSize()) .print(OS, MRI); return; } FormValue.dump(OS, DumpOpts); if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { const DWARFSection &LocSection = Obj.getLocSection(); const DWARFSection &LocDWOSection = Obj.getLocDWOSection(); uint32_t Offset = *FormValue.getAsSectionOffset(); if (!LocSection.Data.empty()) { DWARFDebugLoc DebugLoc; DWARFDataExtractor Data(Obj, LocSection, Ctx.isLittleEndian(), Obj.getAddressSize()); auto LL = DebugLoc.parseOneLocationList(Data, &Offset); if (LL) { uint64_t BaseAddr = 0; if (Optional<BaseAddress> BA = U->getBaseAddress()) BaseAddr = BA->Address; LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, BaseAddr, Indent); } else OS << "error extracting location list."; } else if (!LocDWOSection.Data.empty()) { DataExtractor Data(LocDWOSection.Data, Ctx.isLittleEndian(), 0); auto LL = DWARFDebugLocDWO::parseOneLocationList(Data, &Offset); if (LL) LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent); else OS << "error extracting location list."; } } }
bool DWARFDebugInfoEntryMinimal::getAttributeValue( const DWARFUnit *U, const uint16_t Attr, DWARFFormValue &FormValue) const { if (!AbbrevDecl) return false; uint32_t AttrIdx = AbbrevDecl->findAttributeIndex(Attr); if (AttrIdx == -1U) return false; DataExtractor DebugInfoData = U->getDebugInfoExtractor(); uint32_t DebugInfoOffset = getOffset(); // Skip the abbreviation code so we are at the data for the attributes DebugInfoData.getULEB128(&DebugInfoOffset); // Skip preceding attribute values. for (uint32_t i = 0; i < AttrIdx; ++i) { DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(i), DebugInfoData, &DebugInfoOffset, U); } FormValue = DWARFFormValue(AbbrevDecl->getFormByIndex(AttrIdx)); return FormValue.extractValue(DebugInfoData, &DebugInfoOffset, U); }
void ObjectLoadListener::getDebugInfoForLocals( DWARFContextInMemory &DwarfContext, uint64_t Addr, uint64_t Size) { for (const auto &CU : DwarfContext.compile_units()) { const DWARFDebugInfoEntryMinimal *UnitDIE = CU->getUnitDIE(false); const DWARFDebugInfoEntryMinimal *SubprogramDIE = getSubprogramDIE(UnitDIE); ICorDebugInfo::RegNum FrameBaseRegister = ICorDebugInfo::REGNUM_COUNT; DWARFFormValue FormValue; // Find the frame_base register value if (SubprogramDIE->getAttributeValue(CU.get(), dwarf::DW_AT_frame_base, FormValue)) { Optional<ArrayRef<uint8_t>> FormValues = FormValue.getAsBlock(); FrameBaseRegister = mapDwarfRegisterToRegNum(FormValues->back()); } if (SubprogramDIE->getAttributeValue(CU.get(), dwarf::DW_AT_low_pc, FormValue)) { Optional<uint64_t> FormAddress = FormValue.getAsAddress(CU.get()); // If the Form address doesn't match the address for the function passed // do not collect debug for locals since they do not go with the current // function being processed if (FormAddress.getValue() != Addr) { return; } } std::vector<uint64_t> Offsets; extractLocalLocations(CU.get(), SubprogramDIE, Offsets); // Allocate the array of NativeVarInfo objects that will be sent to the EE ICorDebugInfo::NativeVarInfo *LocalVars; unsigned SizeOfArray = Offsets.size() * sizeof(ICorDebugInfo::NativeVarInfo); if (SizeOfArray > 0) { LocalVars = (ICorDebugInfo::NativeVarInfo *)Context->JitInfo->allocateArray( SizeOfArray); unsigned CurrentDebugEntry = 0; for (auto &Offset : Offsets) { LocalVars[CurrentDebugEntry].startOffset = Addr; LocalVars[CurrentDebugEntry].endOffset = Addr + Size; LocalVars[CurrentDebugEntry].varNumber = CurrentDebugEntry; // Assume all locals are on the stack ICorDebugInfo::VarLoc VarLoc; VarLoc.vlType = ICorDebugInfo::VLT_STK; VarLoc.vlStk.vlsBaseReg = FrameBaseRegister; VarLoc.vlStk.vlsOffset = Offset; LocalVars[CurrentDebugEntry].loc = VarLoc; CurrentDebugEntry++; } CORINFO_METHOD_INFO *MethodInfo = Context->MethodInfo; CORINFO_METHOD_HANDLE MethodHandle = MethodInfo->ftn; Context->JitInfo->setVars(MethodHandle, Offsets.size(), LocalVars); } } }
static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, DWARFUnit *U, unsigned Indent, DIDumpOptions DumpOpts) { DWARFContext &Ctx = U->getContext(); const DWARFObject &Obj = Ctx.getDWARFObj(); const MCRegisterInfo *MRI = Ctx.getRegisterInfo(); if (FormValue.isFormClass(DWARFFormValue::FC_Block) || FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) { ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), Ctx.isLittleEndian(), 0); DWARFExpression(Data, U->getVersion(), U->getAddressByteSize()) .print(OS, MRI, U); return; } FormValue.dump(OS, DumpOpts); if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { uint32_t Offset = *FormValue.getAsSectionOffset(); if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) { DWARFDebugLoc DebugLoc; DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(), Obj.getAddressSize()); auto LL = DebugLoc.parseOneLocationList(Data, &Offset); if (LL) { uint64_t BaseAddr = 0; if (Optional<object::SectionedAddress> BA = U->getBaseAddress()) BaseAddr = BA->Address; LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, U, BaseAddr, Indent); } else OS << "error extracting location list."; return; } bool UseLocLists = !U->isDWOUnit(); StringRef LoclistsSectionData = UseLocLists ? Obj.getLoclistsSection().Data : U->getLocSectionData(); if (!LoclistsSectionData.empty()) { DataExtractor Data(LoclistsSectionData, Ctx.isLittleEndian(), Obj.getAddressSize()); // Old-style location list were used in DWARF v4 (.debug_loc.dwo section). // Modern locations list (.debug_loclists) are used starting from v5. // Ideally we should take the version from the .debug_loclists section // header, but using CU's version for simplicity. auto LL = DWARFDebugLoclists::parseOneLocationList( Data, &Offset, UseLocLists ? U->getVersion() : 4); uint64_t BaseAddr = 0; if (Optional<object::SectionedAddress> BA = U->getBaseAddress()) BaseAddr = BA->Address; if (LL) LL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, U, Indent); else OS << "error extracting location list."; } } }
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"; }
int DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DWARFDataExtractor* debug_str_data_ptr) { dw_form_t a_form = a_value.Form(); dw_form_t b_form = b_value.Form(); if (a_form < b_form) return -1; if (a_form > b_form) return 1; switch (a_form) { case DW_FORM_addr: case DW_FORM_flag: case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_udata: case DW_FORM_ref_addr: case DW_FORM_sec_offset: case DW_FORM_flag_present: case DW_FORM_ref_sig8: { uint64_t a = a_value.Unsigned(); uint64_t b = b_value.Unsigned(); if (a < b) return -1; if (a > b) return 1; return 0; } case DW_FORM_sdata: { int64_t a = a_value.Signed(); int64_t b = b_value.Signed(); if (a < b) return -1; if (a > b) return 1; return 0; } case DW_FORM_string: case DW_FORM_strp: { const char *a_string = a_value.AsCString(debug_str_data_ptr); const char *b_string = b_value.AsCString(debug_str_data_ptr); if (a_string == b_string) return 0; else if (a_string && b_string) return strcmp(a_string, b_string); else if (a_string == NULL) return -1; // A string is NULL, and B is valid else return 1; // A string valid, and B is NULL } case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: case DW_FORM_exprloc: { uint64_t a_len = a_value.Unsigned(); uint64_t b_len = b_value.Unsigned(); if (a_len < b_len) return -1; if (a_len > b_len) return 1; // The block lengths are the same return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned()); } break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: { uint64_t a = a_value.Reference(a_cu); uint64_t b = b_value.Reference(b_cu); if (a < b) return -1; if (a > b) return 1; return 0; } case DW_FORM_indirect: assert(!"This shouldn't happen after the form has been extracted..."); break; default: assert(!"Unhandled DW_FORM"); break; } return -1; }