Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback ( SearchFilter &filter, SymbolContext &context, Address *addr, bool containing ) { assert (m_breakpoint != NULL); if (!context.target_sp) return eCallbackReturnContinue; CompileUnit *cu = context.comp_unit; FileSpec cu_file_spec = *(static_cast<FileSpec *>(cu)); std::vector<uint32_t> line_matches; context.target_sp->GetSourceManager().FindLinesMatchingRegex(cu_file_spec, m_regex, 1, UINT32_MAX, line_matches); uint32_t num_matches = line_matches.size(); for (uint32_t i = 0; i < num_matches; i++) { SymbolContextList sc_list; const bool search_inlines = false; const bool exact = false; cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, exact, eSymbolContextEverything, sc_list); const bool skip_prologue = true; BreakpointResolver::SetSCMatchesByLine (filter, sc_list, skip_prologue, m_regex.GetText()); } assert (m_breakpoint != NULL); return Searcher::eCallbackReturnContinue; }
Searcher::CallbackReturn FileLineResolver::SearchCallback(SearchFilter &filter, SymbolContext &context, Address *addr, bool containing) { CompileUnit *cu = context.comp_unit; if (m_inlines || m_file_spec.Compare(*cu, m_file_spec, (bool)m_file_spec.GetDirectory())) { uint32_t start_file_idx = 0; uint32_t file_idx = cu->GetSupportFiles().FindFileIndex(start_file_idx, m_file_spec, false); if (file_idx != UINT32_MAX) { LineTable *line_table = cu->GetLineTable(); if (line_table) { if (m_line_number == 0) { // Match all lines in a file... const bool append = true; while (file_idx != UINT32_MAX) { line_table->FineLineEntriesForFileIndex(file_idx, append, m_sc_list); // Get the next file index in case we have multiple file // entries for the same file file_idx = cu->GetSupportFiles().FindFileIndex(file_idx + 1, m_file_spec, false); } } else { // Match a specific line in a file... } } } } return Searcher::eCallbackReturnContinue; }
/// Check if the DIE at \p Idx is in the scope of a function. static bool inFunctionScope(CompileUnit &U, unsigned Idx) { while (Idx) { if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram) return true; Idx = U.getInfo(Idx).ParentIdx; } return false; }
Searcher::CallbackReturn AddressResolverFileLine::SearchCallback ( SearchFilter &filter, SymbolContext &context, Address *addr, bool containing ) { SymbolContextList sc_list; uint32_t sc_list_size; CompileUnit *cu = context.comp_unit; Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); sc_list_size = cu->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); for (uint32_t i = 0; i < sc_list_size; i++) { SymbolContext sc; if (sc_list.GetContextAtIndex(i, sc)) { Address line_start = sc.line_entry.range.GetBaseAddress(); addr_t byte_size = sc.line_entry.range.GetByteSize(); if (line_start.IsValid()) { AddressRange new_range (line_start, byte_size); m_address_ranges.push_back (new_range); if (log) { StreamString s; //new_bp_loc->GetDescription (&s, lldb::eDescriptionLevelVerbose); //log->Printf ("Added address: %s\n", s.GetData()); } } else { if (log) log->Printf ("error: Unable to resolve address at file address 0x%llx for %s:%d\n", line_start.GetFileAddress(), m_file_spec.GetFilename().AsCString("<Unknown>"), m_line_number); } } } return Searcher::eCallbackReturnContinue; }
/// Emit location lists for \p Unit and update attributes to point to the new /// entries. void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf) { const auto &Attributes = Unit.getLocationAttributes(); if (Attributes.empty()) return; MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection()); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); const DWARFSection &InputSec = Dwarf.getDWARFObj().getLocSection(); DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize); DWARFUnit &OrigUnit = Unit.getOrigUnit(); auto OrigUnitDie = OrigUnit.getUnitDIE(false); int64_t UnitPcOffset = 0; if (auto OrigLowPc = dwarf::toAddress(OrigUnitDie.find(dwarf::DW_AT_low_pc))) UnitPcOffset = int64_t(*OrigLowPc) - Unit.getLowPc(); for (const auto &Attr : Attributes) { uint32_t Offset = Attr.first.get(); Attr.first.set(LocSectionSize); // This is the quantity to add to the old location address to get // the correct address for the new one. int64_t LocPcOffset = Attr.second + UnitPcOffset; while (Data.isValidOffset(Offset)) { uint64_t Low = Data.getUnsigned(&Offset, AddressSize); uint64_t High = Data.getUnsigned(&Offset, AddressSize); LocSectionSize += 2 * AddressSize; if (Low == 0 && High == 0) { Asm->OutStreamer->EmitIntValue(0, AddressSize); Asm->OutStreamer->EmitIntValue(0, AddressSize); break; } Asm->OutStreamer->EmitIntValue(Low + LocPcOffset, AddressSize); Asm->OutStreamer->EmitIntValue(High + LocPcOffset, AddressSize); uint64_t Length = Data.getU16(&Offset); Asm->OutStreamer->EmitIntValue(Length, 2); // Just copy the bytes over. Asm->OutStreamer->EmitBytes( StringRef(InputSec.Data.substr(Offset, Length))); Offset += Length; LocSectionSize += Length + 2; } } }
bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) { bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit, false) != UINT32_MAX; if (in_cu_list) { ModuleSP module_sp(compUnit.GetModule()); if (module_sp) { bool module_passes = SearchFilterByModuleList::ModulePasses(module_sp); return module_passes; } else return true; } else return false; }
/// Emit the pubnames or pubtypes section contribution for \p /// Unit into \p Sec. The data is provided in \p Names. void DwarfStreamer::emitPubSectionForUnit( MCSection *Sec, StringRef SecName, const CompileUnit &Unit, const std::vector<CompileUnit::AccelInfo> &Names) { if (Names.empty()) return; // Start the dwarf pubnames section. Asm->OutStreamer->SwitchSection(Sec); MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin"); MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end"); bool HeaderEmitted = false; // Emit the pubnames for this compilation unit. for (const auto &Name : Names) { if (Name.SkipPubSection) continue; if (!HeaderEmitted) { // Emit the header. Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length Asm->OutStreamer->EmitLabel(BeginLabel); Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); // Version Asm->emitInt32(Unit.getStartOffset()); // Unit offset Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size HeaderEmitted = true; } Asm->emitInt32(Name.Die->getOffset()); // Emit the string itself. Asm->OutStreamer->EmitBytes(Name.Name.getString()); // Emit a null terminator. Asm->emitInt8(0); } if (!HeaderEmitted) return; Asm->emitInt32(0); // End marker. Asm->OutStreamer->EmitLabel(EndLabel); }
/// Emit the compilation unit header for \p Unit in the debug_info section. /// /// A Dwarf section header is encoded as: /// uint32_t Unit length (omitting this field) /// uint16_t Version /// uint32_t Abbreviation table offset /// uint8_t Address size /// /// Leading to a total of 11 bytes. void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) { unsigned Version = Unit.getOrigUnit().getVersion(); switchToDebugInfoSection(Version); /// The start of the unit within its section. Unit.setLabelBegin(Asm->createTempSymbol("cu_begin")); Asm->OutStreamer->EmitLabel(Unit.getLabelBegin()); // Emit size of content not including length itself. The size has already // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to // account for the length field. Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4); Asm->emitInt16(Version); // We share one abbreviations table across all units so it's always at the // start of the section. Asm->emitInt32(0); Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize()); }
Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback ( SearchFilter &filter, SymbolContext &context, Address *addr, bool containing ) { assert (m_breakpoint != NULL); if (!context.target_sp) return eCallbackReturnContinue; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); CompileUnit *cu = context.comp_unit; FileSpec cu_file_spec = *(static_cast<FileSpec *>(cu)); std::vector<uint32_t> line_matches; context.target_sp->GetSourceManager().FindLinesMatchingRegex(cu_file_spec, m_regex, 1, UINT32_MAX, line_matches); uint32_t num_matches = line_matches.size(); for (uint32_t i = 0; i < num_matches; i++) { uint32_t start_idx = 0; bool exact = false; while (1) { LineEntry line_entry; // Cycle through all the line entries that might match this one: start_idx = cu->FindLineEntry (start_idx, line_matches[i], NULL, exact, &line_entry); if (start_idx == UINT32_MAX) break; exact = true; start_idx++; Address line_start = line_entry.range.GetBaseAddress(); if (line_start.IsValid()) { if (filter.AddressPasses(line_start)) { BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start)); if (log && bp_loc_sp && !m_breakpoint->IsInternal()) { StreamString s; bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose); log->Printf ("Added location: %s\n", s.GetData()); } } else if (log) { log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass filter.\n", line_start.GetFileAddress(), cu_file_spec.GetFilename().AsCString("<Unknown>"), line_matches[i]); } } else { if (log) log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n", line_start.GetFileAddress(), cu_file_spec.GetFilename().AsCString("<Unknown>"), line_matches[i]); } } } assert (m_breakpoint != NULL); return Searcher::eCallbackReturnContinue; }
/// Emit .debug_pubtypes for \p Unit. void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) { emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(), "types", Unit, Unit.getPubtypes()); }
/// Emit the debug_aranges contribution of a unit and /// if \p DoDebugRanges is true the debug_range contents for a /// compile_unit level DW_AT_ranges attribute (Which are basically the /// same thing with a different base address). /// Just aggregate all the ranges gathered inside that unit. void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit, bool DoDebugRanges) { unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); // Gather the ranges in a vector, so that we can simplify them. The // IntervalMap will have coalesced the non-linked ranges, but here // we want to coalesce the linked addresses. std::vector<std::pair<uint64_t, uint64_t>> Ranges; const auto &FunctionRanges = Unit.getFunctionRanges(); for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end(); Range != End; ++Range) Ranges.push_back(std::make_pair(Range.start() + Range.value(), Range.stop() + Range.value())); // The object addresses where sorted, but again, the linked // addresses might end up in a different order. llvm::sort(Ranges.begin(), Ranges.end()); if (!Ranges.empty()) { MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); MCSymbol *BeginLabel = Asm->createTempSymbol("Barange"); MCSymbol *EndLabel = Asm->createTempSymbol("Earange"); unsigned HeaderSize = sizeof(int32_t) + // Size of contents (w/o this field sizeof(int16_t) + // DWARF ARange version number sizeof(int32_t) + // Offset of CU in the .debug_info section sizeof(int8_t) + // Pointer Size (in bytes) sizeof(int8_t); // Segment Size (in bytes) unsigned TupleSize = AddressSize * 2; unsigned Padding = OffsetToAlignment(HeaderSize, TupleSize); Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Arange length Asm->OutStreamer->EmitLabel(BeginLabel); Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset Asm->emitInt8(AddressSize); // Address size Asm->emitInt8(0); // Segment size Asm->OutStreamer->emitFill(Padding, 0x0); for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { uint64_t RangeStart = Range->first; MS->EmitIntValue(RangeStart, AddressSize); while ((Range + 1) != End && Range->second == (Range + 1)->first) ++Range; MS->EmitIntValue(Range->second - RangeStart, AddressSize); } // Emit terminator Asm->OutStreamer->EmitIntValue(0, AddressSize); Asm->OutStreamer->EmitIntValue(0, AddressSize); Asm->OutStreamer->EmitLabel(EndLabel); } if (!DoDebugRanges) return; MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); // Offset each range by the right amount. int64_t PcOffset = -Unit.getLowPc(); // Emit coalesced ranges. for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { MS->EmitIntValue(Range->first + PcOffset, AddressSize); while (Range + 1 != End && Range->second == (Range + 1)->first) ++Range; MS->EmitIntValue(Range->second + PcOffset, AddressSize); RangesSectionSize += 2 * AddressSize; } // Add the terminator entry. MS->EmitIntValue(0, AddressSize); MS->EmitIntValue(0, AddressSize); RangesSectionSize += 2 * AddressSize; }