DWARFDIE DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { DWARFCompileUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); if (cu) return cu->GetDIE(die_offset); return DWARFDIE(); }
DWARFDIE DWARFDIE::LookupDeepestBlock (lldb::addr_t file_addr) const { if (IsValid()) { SymbolFileDWARF *dwarf= GetDWARF(); DWARFCompileUnit *cu = GetCU(); DWARFDebugInfoEntry* function_die = nullptr; DWARFDebugInfoEntry* block_die = nullptr; if (m_die->LookupAddress (file_addr, dwarf, cu, &function_die, &block_die)) { if (block_die && block_die != function_die) { if (cu->ContainsDIEOffset(block_die->GetOffset())) return DWARFDIE(cu, block_die); else return DWARFDIE(dwarf->DebugInfo()->GetCompileUnitContainingDIE(DIERef(cu->GetOffset(), block_die->GetOffset())), block_die); } } } return DWARFDIE(); }
static dw_offset_t DWARFDebugInfo_ParseCallback ( SymbolFileDWARF* dwarf2Data, DWARFCompileUnitSP& cu_sp, DWARFDebugInfoEntry* die, const dw_offset_t next_offset, const uint32_t curr_depth, void* userData ) { DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData; DWARFCompileUnit* cu = cu_sp.get(); if (die) { cu->AddDIE(*die); } else if (cu) { debug_info->AddCompileUnit(cu_sp); } // Just return the current offset to parse the next CU or DIE entry return next_offset; }
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Spec) { DIInliningInfo InliningInfo; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return InliningInfo; const DWARFLineTable *LineTable = nullptr; SmallVector<DWARFDie, 4> InlinedChain; CU->getInlinedChainForAddress(Address, InlinedChain); if (InlinedChain.size() == 0) { // If there is no DIE for address (e.g. it is in unavailable .dwo file), // try to at least get file/line info from symbol table. if (Spec.FLIKind != FileLineInfoKind::None) { DILineInfo Frame; LineTable = getLineTableForUnit(CU); if (LineTable && LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), Spec.FLIKind, Frame)) InliningInfo.addFrame(Frame); } return InliningInfo; } uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) { DWARFDie &FunctionDIE = InlinedChain[i]; DILineInfo Frame; // Get function name if necessary. if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind)) Frame.FunctionName = Name; if (Spec.FLIKind != FileLineInfoKind::None) { if (i == 0) { // For the topmost frame, initialize the line table of this // compile unit and fetch file/line info from it. LineTable = getLineTableForUnit(CU); // For the topmost routine, get file/line info from line table. if (LineTable) LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), Spec.FLIKind, Frame); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. if (LineTable) LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(), Spec.FLIKind, Frame.FileName); Frame.Line = CallLine; Frame.Column = CallColumn; } // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn); } } InliningInfo.addFrame(Frame); } return InliningInfo; }
DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return DILineInfo(); std::string FileName = "<invalid>"; std::string FunctionName = "<invalid>"; uint32_t Line = 0; uint32_t Column = 0; if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the // name of the topmost function in it. const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.size() > 0) { const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0]; if (const char *Name = TopFunctionDIE.getSubroutineName(CU)) FunctionName = Name; } } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, FileName, Line, Column); } return DILineInfo(StringRef(FileName), StringRef(FunctionName), Line, Column); }
//---------------------------------------------------------------------- // GetDIE() // // Get the DIE (Debug Information Entry) with the specified offset. //---------------------------------------------------------------------- DWARFDIE DWARFDebugInfo::GetDIE(const DIERef &die_ref) { DWARFCompileUnit *cu = GetCompileUnit(die_ref); if (cu) return cu->GetDIE(die_ref.die_offset); return DWARFDIE(); // Not found }
DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address, DILineInfoSpecifier specifier) { // First, get the offset of the compile unit. uint32_t cuOffset = getDebugAranges()->findAddress(address); // Retrieve the compile unit. DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset); if (!cu) return DILineInfo(); SmallString<16> fileName("<invalid>"); SmallString<16> functionName("<invalid>"); uint32_t line = 0; uint32_t column = 0; if (specifier.needs(DILineInfoSpecifier::FunctionName)) { const DWARFDebugInfoEntryMinimal *function_die = cu->getFunctionDIEForAddress(address); if (function_die) { if (const char *name = function_die->getSubprogramName(cu)) functionName = name; } } if (specifier.needs(DILineInfoSpecifier::FileLineInfo)) { // Get the line table for this compile unit. const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu); if (lineTable) { // Get the index of the row we're looking for in the line table. uint32_t rowIndex = lineTable->lookupAddress(address); if (rowIndex != -1U) { const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex]; // Take file/line info from the line table. const DWARFDebugLine::FileNameEntry &fileNameEntry = lineTable->Prologue.FileNames[row.File - 1]; fileName = fileNameEntry.Name; if (specifier.needs(DILineInfoSpecifier::AbsoluteFilePath) && sys::path::is_relative(fileName.str())) { // Append include directory of file (if it is present in line table) // and compilation directory of compile unit to make path absolute. const char *includeDir = 0; if (uint64_t includeDirIndex = fileNameEntry.DirIdx) { includeDir = lineTable->Prologue .IncludeDirectories[includeDirIndex - 1]; } SmallString<16> absFileName; if (includeDir == 0 || sys::path::is_relative(includeDir)) { if (const char *compilationDir = cu->getCompilationDir()) sys::path::append(absFileName, compilationDir); } if (includeDir) { sys::path::append(absFileName, includeDir); } sys::path::append(absFileName, fileName.str()); fileName = absFileName; } line = row.Line; column = row.Column; } } } return DILineInfo(fileName, functionName, line, column); }
DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier) { DILineInfoTable Lines; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Lines; std::string FunctionName = "<invalid>"; if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the // name of the topmost function in it. const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.size() > 0) { const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0]; if (const char *Name = TopFunctionDIE.getSubroutineName(CU)) FunctionName = Name; } } StringRef FuncNameRef = StringRef(FunctionName); // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (!Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { Lines.push_back(std::make_pair(Address, DILineInfo(StringRef("<invalid>"), FuncNameRef, 0, 0))); return Lines; } const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); // Get the index of row we're looking for in the line table. std::vector<uint32_t> RowVector; if (!LineTable->lookupAddressRange(Address, Size, RowVector)) return Lines; uint32_t NumRows = RowVector.size(); for (uint32_t i = 0; i < NumRows; ++i) { uint32_t RowIndex = RowVector[i]; // Take file number and line/column from the row. const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; std::string FileName = "<invalid>"; getFileNameForCompileUnit(CU, LineTable, Row.File, NeedsAbsoluteFilePath, FileName); Lines.push_back(std::make_pair(Row.Address, DILineInfo(StringRef(FileName), FuncNameRef, Row.Line, Row.Column))); } return Lines; }
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return DIInliningInfo(); const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.DIEs.size() == 0) return DIInliningInfo(); DIInliningInfo InliningInfo; uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; const DWARFLineTable *LineTable = 0; for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; std::string FileName = "<invalid>"; std::string FunctionName = "<invalid>"; uint32_t Line = 0; uint32_t Column = 0; // Get function name if necessary. if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.U)) FunctionName = Name; } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); if (i == 0) { // For the topmost frame, initialize the line table of this // compile unit and fetch file/line info from it. LineTable = getLineTableForCompileUnit(CU); // For the topmost routine, get file/line info from line table. getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, FileName, Line, Column); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. getFileNameForCompileUnit(CU, LineTable, CallFile, NeedsAbsoluteFilePath, FileName); Line = CallLine; Column = CallColumn; } // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, CallColumn); } } DILineInfo Frame(StringRef(FileName), StringRef(FunctionName), Line, Column); InliningInfo.addFrame(Frame); } return InliningInfo; }
DWARFDebugAranges & DWARFDebugInfo::GetCompileUnitAranges () { if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) { Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); m_cu_aranges_ap.reset (new DWARFDebugAranges()); const DWARFDataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data(); if (debug_aranges_data.GetByteSize() > 0) { if (log) log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from .debug_aranges", m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); m_cu_aranges_ap->Extract (debug_aranges_data); } // Make a list of all CUs represented by the arange data in the file. std::set<dw_offset_t> cus_with_data; for (size_t n=0;n<m_cu_aranges_ap.get()->GetNumRanges();n++) { dw_offset_t offset = m_cu_aranges_ap.get()->OffsetAtIndex(n); if (offset != DW_INVALID_OFFSET) cus_with_data.insert (offset); } // Manually build arange data for everything that wasn't in the .debug_aranges table. bool printed = false; const size_t num_compile_units = GetNumCompileUnits(); const bool clear_dies_if_already_not_parsed = true; for (size_t idx = 0; idx < num_compile_units; ++idx) { DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx); dw_offset_t offset = cu->GetOffset(); if (cus_with_data.find(offset) == cus_with_data.end()) { if (log) { if (!printed) log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing", m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); printed = true; } cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed); } } const bool minimize = true; m_cu_aranges_ap->Sort (minimize); } return *m_cu_aranges_ap.get(); }
bool DWARFDebugAranges::generate(DWARFContext *ctx) { clear(); if (ctx) { const uint32_t num_compile_units = ctx->getNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { DWARFCompileUnit *cu = ctx->getCompileUnitAtIndex(cu_idx); if (cu) cu->buildAddressRangeTable(this, true); } } return !isEmpty(); }
void DWARFContext::dump(raw_ostream &OS) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); OS << "\n.debug_info contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) getCompileUnitAtIndex(i)->dump(OS); OS << "\n.debug_aranges contents:\n"; DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); uint32_t offset = 0; DWARFDebugArangeSet set; while (set.extract(arangesData, &offset)) set.dump(OS); uint8_t savedAddressByteSize = 0; OS << "\n.debug_lines contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { DWARFCompileUnit *cu = getCompileUnitAtIndex(i); savedAddressByteSize = cu->getAddressByteSize(); unsigned stmtOffset = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, -1U); if (stmtOffset != -1U) { DataExtractor lineData(getLineSection(), isLittleEndian(), savedAddressByteSize); DWARFDebugLine::DumpingState state(OS); DWARFDebugLine::parseStatementTable(lineData, &stmtOffset, state); } } OS << "\n.debug_str contents:\n"; DataExtractor strData(getStringSection(), isLittleEndian(), 0); offset = 0; uint32_t lastOffset = 0; while (const char *s = strData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", lastOffset, s); lastOffset = offset; } OS << "\n.debug_ranges contents:\n"; // In fact, different compile units may have different address byte // sizes, but for simplicity we just use the address byte size of the last // compile unit (there is no easy and fast way to associate address range // list and the compile unit it describes). DataExtractor rangesData(getRangeSection(), isLittleEndian(), savedAddressByteSize); offset = 0; DWARFDebugRangeList rangeList; while (rangeList.extract(rangesData, &offset)) rangeList.dump(OS); }
//---------------------------------------------------------------------- // Generate //---------------------------------------------------------------------- bool DWARFDebugAranges::Generate(SymbolFileDWARF *dwarf2Data) { Clear(); DWARFDebugInfo *debug_info = dwarf2Data->DebugInfo(); if (debug_info) { uint32_t cu_idx = 0; const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (cu) cu->BuildAddressRangeTable(dwarf2Data, this); } } return !IsEmpty(); }
DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Spec) { DILineInfo Result; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Result; getFunctionNameForAddress(CU, Address, Spec.FNKind, Result.FunctionName); if (Spec.FLIKind != FileLineInfoKind::None) { if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), Spec.FLIKind, Result); } return Result; }
//---------------------------------------------------------------------- // Dump // // Dump the contents of this DWARFDebugInfo object as has been parsed // and/or modified after it has been parsed. //---------------------------------------------------------------------- void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset, const uint32_t recurse_depth) { DumpInfo dumpInfo(s, die_offset, recurse_depth); s->PutCString("Dumping .debug_info section from internal representation\n"); CompileUnitColl::const_iterator pos; uint32_t curr_depth = 0; ParseCompileUnitHeadersIfNeeded(); for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { DWARFCompileUnit *cu = pos->get(); DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); const DWARFDIE die = cu->DIE(); if (die) die.Dump(s, recurse_depth); } }
DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Spec) { DILineInfoTable Lines; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Lines; std::string FunctionName = "<invalid>"; getFunctionNameForAddress(CU, Address, Spec.FNKind, FunctionName); // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (Spec.FLIKind == FileLineInfoKind::None) { DILineInfo Result; Result.FunctionName = FunctionName; Lines.push_back(std::make_pair(Address, Result)); return Lines; } const DWARFLineTable *LineTable = getLineTableForUnit(CU); // Get the index of row we're looking for in the line table. std::vector<uint32_t> RowVector; if (!LineTable->lookupAddressRange(Address, Size, RowVector)) return Lines; for (uint32_t RowIndex : RowVector) { // Take file number and line/column from the row. const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; DILineInfo Result; LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(), Spec.FLIKind, Result.FileName); Result.FunctionName = FunctionName; Result.Line = Row.Line; Result.Column = Row.Column; Lines.push_back(std::make_pair(Row.Address, Result)); } return Lines; }
DWARFDebugAranges & DWARFDebugInfo::GetCompileUnitAranges () { if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) { LogSP log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); m_cu_aranges_ap.reset (new DWARFDebugAranges()); const DataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data(); if (debug_aranges_data.GetByteSize() > 0) { if (log) log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s/%s\" from .debug_aranges", m_dwarf2Data->GetObjectFile()->GetFileSpec().GetDirectory().GetCString(), m_dwarf2Data->GetObjectFile()->GetFileSpec().GetFilename().GetCString()); m_cu_aranges_ap->Extract (debug_aranges_data); } else { if (log) log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s/%s\" by parsing", m_dwarf2Data->GetObjectFile()->GetFileSpec().GetDirectory().GetCString(), m_dwarf2Data->GetObjectFile()->GetFileSpec().GetFilename().GetCString()); const uint32_t num_compile_units = GetNumCompileUnits(); uint32_t idx; const bool clear_dies_if_already_not_parsed = true; for (idx = 0; idx < num_compile_units; ++idx) { DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx); if (cu) cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed); } } const bool minimize = true; m_cu_aranges_ap->Sort (minimize); } return *m_cu_aranges_ap.get(); }
void DWARFContext::dump(raw_ostream &OS) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); OS << "\n.debug_info contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) getCompileUnitAtIndex(i)->dump(OS); OS << "\n.debug_aranges contents:\n"; DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); uint32_t offset = 0; DWARFDebugArangeSet set; while (set.extract(arangesData, &offset)) set.dump(OS); OS << "\n.debug_lines contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { DWARFCompileUnit *cu = getCompileUnitAtIndex(i); unsigned stmtOffset = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, -1U); if (stmtOffset != -1U) { DataExtractor lineData(getLineSection(), isLittleEndian(), cu->getAddressByteSize()); DWARFDebugLine::DumpingState state(OS); DWARFDebugLine::parseStatementTable(lineData, &stmtOffset, state); } } OS << "\n.debug_str contents:\n"; DataExtractor strData(getStringSection(), isLittleEndian(), 0); offset = 0; uint32_t lastOffset = 0; while (const char *s = strData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", lastOffset, s); lastOffset = offset; } }
DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address, DILineInfoSpecifier specifier) { // First, get the offset of the compile unit. uint32_t cuOffset = getDebugAranges()->findAddress(address); // Retrieve the compile unit. DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset); if (!cu) return DILineInfo(); const char *fileName = "<invalid>"; const char *functionName = "<invalid>"; uint32_t line = 0; uint32_t column = 0; if (specifier.needs(DILineInfoSpecifier::FunctionName)) { const DWARFDebugInfoEntryMinimal *function_die = cu->getFunctionDIEForAddress(address); if (function_die) functionName = function_die->getSubprogramName(cu); } if (specifier.needs(DILineInfoSpecifier::FileLineInfo)) { // Get the line table for this compile unit. const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu); if (lineTable) { // Get the index of the row we're looking for in the line table. uint64_t hiPC = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned( cu, DW_AT_high_pc, -1ULL); uint32_t rowIndex = lineTable->lookupAddress(address, hiPC); if (rowIndex != -1U) { const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex]; // Take file/line info from the line table. fileName = lineTable->Prologue.FileNames[row.File - 1].Name.c_str(); line = row.Line; column = row.Column; } } } return DILineInfo(fileName, functionName, line, column); }
bool DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data) { m_sets.clear(); DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); if (debug_info) { uint32_t cu_idx = 0; const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); DWARFDIECollection dies; const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies); dw_offset_t cu_offset = cu->GetOffset(); DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); size_t die_idx; for (die_idx = 0; die_idx < die_count; ++die_idx) { const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL); if (name) { pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name); } } if (pubnames_set.NumDescriptors() > 0) { m_sets.push_back(pubnames_set); } } } return !m_sets.empty(); }
//---------------------------------------------------------------------- // LookupAddress //---------------------------------------------------------------------- DWARFDIE DWARFDebugInfo::LookupAddress (const dw_addr_t address, const dw_offset_t hint_die_offset) { DWARFDIE die; DWARFCompileUnit *cu = nullptr; if (hint_die_offset != DW_INVALID_OFFSET) { cu = GetCompileUnit(hint_die_offset); } else { DWARFDebugAranges &cu_aranges = GetCompileUnitAranges (); const dw_offset_t cu_offset = cu_aranges.FindAddress (address); cu = GetCompileUnit(cu_offset); } if (cu) { die = cu->LookupAddress(address); } else { // The hint_die_offset may have been a pointer to the actual item that // we are looking for die = GetDIE(hint_die_offset); if (die) { DWARFDebugInfoEntry* function_die = nullptr; if (die.GetDIE()->LookupAddress (address, die.GetDWARF(), die.GetCU(), &function_die, nullptr)) die.Set (die.GetCU(), function_die); } } return die; }
DIInliningInfo DWARFContext::getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { DIInliningInfo InliningInfo; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return InliningInfo; const DWARFLineTable *LineTable = nullptr; const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); const DWARFDebugInfoEntryInlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.DIEs.size() == 0) { // If there is no DIE for address (e.g. it is in unavailable .dwo file), // try to at least get file/line info from symbol table. if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { DILineInfo Frame; LineTable = getLineTableForCompileUnit(CU); if (getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, Frame)) { InliningInfo.addFrame(Frame); } } return InliningInfo; } uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; DILineInfo Frame; // Get function name if necessary. if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { if (const char *Name = FunctionDIE.getSubroutineName(InlinedChain.U)) Frame.FunctionName = Name; } if (Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { if (i == 0) { // For the topmost frame, initialize the line table of this // compile unit and fetch file/line info from it. LineTable = getLineTableForCompileUnit(CU); // For the topmost routine, get file/line info from line table. getFileLineInfoForCompileUnit(CU, LineTable, Address, NeedsAbsoluteFilePath, Frame); } else { // Otherwise, use call file, call line and call column from // previous DIE in inlined chain. getFileNameForCompileUnit(CU, LineTable, CallFile, NeedsAbsoluteFilePath, Frame.FileName); Frame.Line = CallLine; Frame.Column = CallColumn; } // Get call file/line/column of a current DIE. if (i + 1 < n) { FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, CallColumn); } } InliningInfo.addFrame(Frame); } return InliningInfo; }
void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Info) { OS << "\n.debug_info contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) getCompileUnitAtIndex(i)->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Frames) { OS << "\n.debug_frame contents:\n"; getDebugFrame()->dump(OS); } uint32_t offset = 0; if (DumpType == DIDT_All || DumpType == DIDT_Aranges) { OS << "\n.debug_aranges contents:\n"; DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); DWARFDebugArangeSet set; while (set.extract(arangesData, &offset)) set.dump(OS); } uint8_t savedAddressByteSize = 0; if (DumpType == DIDT_All || DumpType == DIDT_Line) { OS << "\n.debug_line contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { DWARFCompileUnit *cu = getCompileUnitAtIndex(i); savedAddressByteSize = cu->getAddressByteSize(); unsigned stmtOffset = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_stmt_list, -1U); if (stmtOffset != -1U) { DataExtractor lineData(getLineSection(), isLittleEndian(), savedAddressByteSize); DWARFDebugLine::DumpingState state(OS); DWARFDebugLine::parseStatementTable(lineData, &lineRelocMap(), &stmtOffset, state); } } } if (DumpType == DIDT_All || DumpType == DIDT_Str) { OS << "\n.debug_str contents:\n"; DataExtractor strData(getStringSection(), isLittleEndian(), 0); offset = 0; uint32_t strOffset = 0; while (const char *s = strData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", strOffset, s); strOffset = offset; } } if (DumpType == DIDT_All || DumpType == DIDT_Ranges) { OS << "\n.debug_ranges contents:\n"; // In fact, different compile units may have different address byte // sizes, but for simplicity we just use the address byte size of the last // compile unit (there is no easy and fast way to associate address range // list and the compile unit it describes). DataExtractor rangesData(getRangeSection(), isLittleEndian(), savedAddressByteSize); offset = 0; DWARFDebugRangeList rangeList; while (rangeList.extract(rangesData, &offset)) rangeList.dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Pubnames) { OS << "\n.debug_pubnames contents:\n"; DataExtractor pubNames(getPubNamesSection(), isLittleEndian(), 0); offset = 0; OS << "Length: " << pubNames.getU32(&offset) << "\n"; OS << "Version: " << pubNames.getU16(&offset) << "\n"; OS << "Offset in .debug_info: " << pubNames.getU32(&offset) << "\n"; OS << "Size: " << pubNames.getU32(&offset) << "\n"; OS << "\n Offset Name\n"; while (offset < getPubNamesSection().size()) { uint32_t n = pubNames.getU32(&offset); if (n == 0) break; OS << format("%8x ", n); OS << pubNames.getCStr(&offset) << "\n"; } } if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo) { OS << "\n.debug_abbrev.dwo contents:\n"; getDebugAbbrevDWO()->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_InfoDwo) { OS << "\n.debug_info.dwo contents:\n"; for (unsigned i = 0, e = getNumDWOCompileUnits(); i != e; ++i) getDWOCompileUnitAtIndex(i)->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_StrDwo) { OS << "\n.debug_str.dwo contents:\n"; DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0); offset = 0; uint32_t strDWOOffset = 0; while (const char *s = strDWOData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s); strDWOOffset = offset; } } if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) { OS << "\n.debug_str_offsets.dwo contents:\n"; DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(), 0); offset = 0; while (offset < getStringOffsetDWOSection().size()) { OS << format("0x%8.8x: ", offset); OS << format("%8.8x\n", strOffsetExt.getU32(&offset)); } } }
bool DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data) { Timer scoped_timer (__PRETTY_FUNCTION__, "DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data); LogSP log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); if (log) log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data); m_sets.clear(); DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); if (debug_info) { const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data(); uint32_t cu_idx = 0; const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize()); bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1; DWARFDIECollection dies; const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) + cu->AppendDIEsWithTag (DW_TAG_variable, dies); dw_offset_t cu_offset = cu->GetOffset(); DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); size_t die_idx; for (die_idx = 0; die_idx < die_count; ++die_idx) { const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); DWARFDebugInfoEntry::Attributes attributes; const char *name = NULL; const char *mangled = NULL; bool add_die = false; bool is_variable = false; const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes); if (num_attributes > 0) { uint32_t i; dw_tag_t tag = die->Tag(); is_variable = tag == DW_TAG_variable; for (i=0; i<num_attributes; ++i) { dw_attr_t attr = attributes.AttributeAtIndex(i); DWARFFormValue form_value; switch (attr) { case DW_AT_name: if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) name = form_value.AsCString(debug_str); break; case DW_AT_MIPS_linkage_name: if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) mangled = form_value.AsCString(debug_str); break; case DW_AT_low_pc: case DW_AT_ranges: case DW_AT_entry_pc: if (tag == DW_TAG_subprogram) add_die = true; break; case DW_AT_location: if (tag == DW_TAG_variable) { const DWARFDebugInfoEntry* parent_die = die->GetParent(); while ( parent_die != NULL ) { switch (parent_die->Tag()) { case DW_TAG_subprogram: case DW_TAG_lexical_block: case DW_TAG_inlined_subroutine: // Even if this is a function level static, we don't add it. We could theoretically // add these if we wanted to by introspecting into the DW_AT_location and seeing // if the location describes a hard coded address, but we don't want the performance // penalty of that right now. add_die = false; // if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) // { // // If we have valid block data, then we have location expression bytes // // that are fixed (not a location list). // const uint8_t *block_data = form_value.BlockData(); // if (block_data) // { // uint32_t block_length = form_value.Unsigned(); // if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) // { // if (block_data[0] == DW_OP_addr) // add_die = true; // } // } // } parent_die = NULL; // Terminate the while loop. break; case DW_TAG_compile_unit: add_die = true; parent_die = NULL; // Terminate the while loop. break; default: parent_die = parent_die->GetParent(); // Keep going in the while loop. break; } } } break; } } } if (add_die && (name || mangled)) { pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name); } } if (pubnames_set.NumDescriptors() > 0) { m_sets.push_back(pubnames_set); } // Keep memory down by clearing DIEs if this generate function // caused them to be parsed if (clear_dies) cu->ClearDIEs (true); } } if (m_sets.empty()) return false; if (log) Dump (log.get()); return true; }
void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo) if (const DWARFDebugAbbrev *D = getDebugAbbrevDWO()) { OS << "\n.debug_abbrev.dwo contents:\n"; D->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Info) { OS << "\n.debug_info contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) getCompileUnitAtIndex(i)->dump(OS); } if ((DumpType == DIDT_All || DumpType == DIDT_InfoDwo) && getNumDWOCompileUnits()) { OS << "\n.debug_info.dwo contents:\n"; for (unsigned i = 0, e = getNumDWOCompileUnits(); i != e; ++i) getDWOCompileUnitAtIndex(i)->dump(OS); } if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) { OS << "\n.debug_types contents:\n"; for (unsigned i = 0, e = getNumTypeUnits(); i != e; ++i) getTypeUnitAtIndex(i)->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_TypesDwo) if (getNumDWOTypeUnits()) { OS << "\n.debug_types.dwo contents:\n"; for (unsigned i = 0, e = getNumDWOTypeUnits(); i != e; ++i) getDWOTypeUnitAtIndex(i)->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Loc) { OS << "\n.debug_loc contents:\n"; getDebugLoc()->dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Frames) { OS << "\n.debug_frame contents:\n"; getDebugFrame()->dump(OS); } uint32_t offset = 0; if (DumpType == DIDT_All || DumpType == DIDT_Aranges) { OS << "\n.debug_aranges contents:\n"; DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); DWARFDebugArangeSet set; while (set.extract(arangesData, &offset)) set.dump(OS); } uint8_t savedAddressByteSize = 0; if (DumpType == DIDT_All || DumpType == DIDT_Line) { OS << "\n.debug_line contents:\n"; for (unsigned i = 0, e = getNumCompileUnits(); i != e; ++i) { DWARFCompileUnit *cu = getCompileUnitAtIndex(i); savedAddressByteSize = cu->getAddressByteSize(); unsigned stmtOffset = cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset( cu, DW_AT_stmt_list, -1U); if (stmtOffset != -1U) { DataExtractor lineData(getLineSection().Data, isLittleEndian(), savedAddressByteSize); DWARFDebugLine::DumpingState state(OS); DWARFDebugLine::parseStatementTable(lineData, &getLineSection().Relocs, &stmtOffset, state); } } } if (DumpType == DIDT_All || DumpType == DIDT_Str) { OS << "\n.debug_str contents:\n"; DataExtractor strData(getStringSection(), isLittleEndian(), 0); offset = 0; uint32_t strOffset = 0; while (const char *s = strData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", strOffset, s); strOffset = offset; } } if ((DumpType == DIDT_All || DumpType == DIDT_StrDwo) && !getStringDWOSection().empty()) { OS << "\n.debug_str.dwo contents:\n"; DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0); offset = 0; uint32_t strDWOOffset = 0; while (const char *s = strDWOData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s); strDWOOffset = offset; } } if (DumpType == DIDT_All || DumpType == DIDT_Ranges) { OS << "\n.debug_ranges contents:\n"; // In fact, different compile units may have different address byte // sizes, but for simplicity we just use the address byte size of the last // compile unit (there is no easy and fast way to associate address range // list and the compile unit it describes). DataExtractor rangesData(getRangeSection(), isLittleEndian(), savedAddressByteSize); offset = 0; DWARFDebugRangeList rangeList; while (rangeList.extract(rangesData, &offset)) rangeList.dump(OS); } if (DumpType == DIDT_All || DumpType == DIDT_Pubnames) dumpPubSection(OS, "debug_pubnames", getPubNamesSection(), isLittleEndian(), false); if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes) dumpPubSection(OS, "debug_pubtypes", getPubTypesSection(), isLittleEndian(), false); if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames) dumpPubSection(OS, "debug_gnu_pubnames", getGnuPubNamesSection(), isLittleEndian(), true /* GnuStyle */); if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes) dumpPubSection(OS, "debug_gnu_pubtypes", getGnuPubTypesSection(), isLittleEndian(), true /* GnuStyle */); if ((DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) && !getStringOffsetDWOSection().empty()) { OS << "\n.debug_str_offsets.dwo contents:\n"; DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(), 0); offset = 0; uint64_t size = getStringOffsetDWOSection().size(); while (offset < size) { OS << format("0x%8.8x: ", offset); OS << format("%8.8x\n", strOffsetExt.getU32(&offset)); } } }