Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback ( SearchFilter &filter, SymbolContext &context, Address *addr, bool containing ) { assert (m_breakpoint != NULL); if (filter.AddressPasses (m_addr)) { BreakpointLocationSP bp_loc_sp(m_breakpoint->AddLocation(m_addr)); if (bp_loc_sp && !m_breakpoint->IsInternal()) { StreamString s; bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("Added location: %s\n", s.GetData()); } } return Searcher::eCallbackReturnStop; }
void BreakpointResolver::AddLocation(SearchFilter &filter, const SymbolContext &sc, bool skip_prologue, llvm::StringRef log_ident) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); Address line_start = sc.line_entry.range.GetBaseAddress(); if (!line_start.IsValid()) { if (log) log->Printf("error: Unable to set breakpoint %s at file address " "0x%" PRIx64 "\n", log_ident.str().c_str(), line_start.GetFileAddress()); return; } if (!filter.AddressPasses(line_start)) { if (log) log->Printf("Breakpoint %s at file address 0x%" PRIx64 " didn't pass the filter.\n", log_ident.str().c_str(), line_start.GetFileAddress()); } // If the line number is before the prologue end, move it there... bool skipped_prologue = false; if (skip_prologue && sc.function) { Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress()); if (prologue_addr.IsValid() && (line_start == prologue_addr)) { const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); if (prologue_byte_size) { prologue_addr.Slide(prologue_byte_size); if (filter.AddressPasses(prologue_addr)) { skipped_prologue = true; line_start = prologue_addr; } } } } BreakpointLocationSP bp_loc_sp(AddLocation(line_start)); if (log && bp_loc_sp && !m_breakpoint->IsInternal()) { StreamString s; bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); log->Printf("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData()); } }
Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback ( SearchFilter &filter, SymbolContext &context, Address *addr, bool containing ) { SymbolContextList sc_list; assert (m_breakpoint != NULL); // There is a tricky bit here. You can have two compilation units that #include the same file, and // in one of them the function at m_line_number is used (and so code and a line entry for it is generated) but in the // other it isn't. If we considered the CU's independently, then in the second inclusion, we'd move the breakpoint // to the next function that actually generated code in the header file. That would end up being confusing. // So instead, we do the CU iterations by hand here, then scan through the complete list of matches, and figure out // the closest line number match, and only set breakpoints on that match. // Note also that if file_spec only had a file name and not a directory, there may be many different file spec's in // the resultant list. The closest line match for one will not be right for some totally different file. // So we go through the match list and pull out the sets that have the same file spec in their line_entry // and treat each set separately. const size_t num_comp_units = context.module_sp->GetNumCompileUnits(); for (size_t i = 0; i < num_comp_units; i++) { CompUnitSP cu_sp (context.module_sp->GetCompileUnitAtIndex (i)); if (cu_sp) { if (filter.CompUnitPasses(*cu_sp)) cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); } } StreamString s; s.Printf ("for %s:%d ", m_file_spec.GetFilename().AsCString("<Unknown>"), m_line_number); SetSCMatchesByLine (filter, sc_list, m_skip_prologue, s.GetData()); return Searcher::eCallbackReturnContinue; }
Searcher::CallbackReturn BreakpointResolverName::SearchCallback(SearchFilter &filter, SymbolContext &context, Address *addr, bool containing) { SymbolContextList func_list; // SymbolContextList sym_list; uint32_t i; bool new_location; Address break_addr; assert(m_breakpoint != nullptr); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); if (m_class_name) { if (log) log->Warning("Class/method function specification not supported yet.\n"); return Searcher::eCallbackReturnStop; } bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0; bool filter_by_language = (m_language != eLanguageTypeUnknown); const bool include_symbols = !filter_by_cu; const bool include_inlines = true; const bool append = true; switch (m_match_type) { case Breakpoint::Exact: if (context.module_sp) { for (const auto &lookup : m_lookups) { const size_t start_func_idx = func_list.GetSize(); context.module_sp->FindFunctions( lookup.GetLookupName(), nullptr, lookup.GetNameTypeMask(), include_symbols, include_inlines, append, func_list); const size_t end_func_idx = func_list.GetSize(); if (start_func_idx < end_func_idx) lookup.Prune(func_list, start_func_idx); } } break; case Breakpoint::Regexp: if (context.module_sp) { context.module_sp->FindFunctions( m_regex, !filter_by_cu, // include symbols only if we aren't filtering by CU include_inlines, append, func_list); } break; case Breakpoint::Glob: if (log) log->Warning("glob is not supported yet."); break; } // If the filter specifies a Compilation Unit, remove the ones that don't // pass at this point. if (filter_by_cu || filter_by_language) { uint32_t num_functions = func_list.GetSize(); for (size_t idx = 0; idx < num_functions; idx++) { bool remove_it = false; SymbolContext sc; func_list.GetContextAtIndex(idx, sc); if (filter_by_cu) { if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit)) remove_it = true; } if (filter_by_language) { LanguageType sym_language = sc.GetLanguage(); if ((Language::GetPrimaryLanguage(sym_language) != Language::GetPrimaryLanguage(m_language)) && (sym_language != eLanguageTypeUnknown)) { remove_it = true; } } if (remove_it) { func_list.RemoveContextAtIndex(idx); num_functions--; idx--; } } } // Remove any duplicates between the function list and the symbol list SymbolContext sc; if (func_list.GetSize()) { for (i = 0; i < func_list.GetSize(); i++) { if (func_list.GetContextAtIndex(i, sc)) { bool is_reexported = false; if (sc.block && sc.block->GetInlinedFunctionInfo()) { if (!sc.block->GetStartAddress(break_addr)) break_addr.Clear(); } else if (sc.function) { break_addr = sc.function->GetAddressRange().GetBaseAddress(); if (m_skip_prologue && break_addr.IsValid()) { const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); if (prologue_byte_size) break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); } } else if (sc.symbol) { if (sc.symbol->GetType() == eSymbolTypeReExported) { const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget()); if (actual_symbol) { is_reexported = true; break_addr = actual_symbol->GetAddress(); } } else { break_addr = sc.symbol->GetAddress(); } if (m_skip_prologue && break_addr.IsValid()) { const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize(); if (prologue_byte_size) break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); else { const Architecture *arch = m_breakpoint->GetTarget().GetArchitecturePlugin(); if (arch) arch->AdjustBreakpointAddress(*sc.symbol, break_addr); } } } if (break_addr.IsValid()) { if (filter.AddressPasses(break_addr)) { BreakpointLocationSP bp_loc_sp( AddLocation(break_addr, &new_location)); bp_loc_sp->SetIsReExported(is_reexported); if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) { if (log) { StreamString s; bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); log->Printf("Added location: %s\n", s.GetData()); } } } } } } } return Searcher::eCallbackReturnContinue; }
void BreakpointResolver::SetSCMatchesByLine (SearchFilter &filter, SymbolContextList &sc_list, bool skip_prologue, const char *log_ident) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); while (sc_list.GetSize() > 0) { SymbolContextList tmp_sc_list; unsigned current_idx = 0; SymbolContext sc; bool first_entry = true; FileSpec match_file_spec; FileSpec match_original_file_spec; uint32_t closest_line_number = UINT32_MAX; // Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list. while (current_idx < sc_list.GetSize()) { bool matches; sc_list.GetContextAtIndex (current_idx, sc); if (first_entry) { match_file_spec = sc.line_entry.file; match_original_file_spec = sc.line_entry.original_file; matches = true; first_entry = false; } else matches = ((sc.line_entry.file == match_file_spec) || (sc.line_entry.original_file == match_original_file_spec)); if (matches) { tmp_sc_list.Append (sc); sc_list.RemoveContextAtIndex(current_idx); // ResolveSymbolContext will always return a number that is >= the line number you pass in. // So the smaller line number is always better. if (sc.line_entry.line < closest_line_number) closest_line_number = sc.line_entry.line; } else current_idx++; } // Okay, we've found the closest line number match, now throw away all the others: current_idx = 0; while (current_idx < tmp_sc_list.GetSize()) { if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) { if (sc.line_entry.line != closest_line_number) tmp_sc_list.RemoveContextAtIndex(current_idx); else current_idx++; } } // Next go through and see if there are line table entries that are contiguous, and if so keep only the // first of the contiguous range: current_idx = 0; std::map<Block *, lldb::addr_t> blocks_with_breakpoints; while (current_idx < tmp_sc_list.GetSize()) { if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) { if (blocks_with_breakpoints.find (sc.block) != blocks_with_breakpoints.end()) tmp_sc_list.RemoveContextAtIndex(current_idx); else { blocks_with_breakpoints.insert (std::pair<Block *, lldb::addr_t>(sc.block, sc.line_entry.range.GetBaseAddress().GetFileAddress())); current_idx++; } } } // and make breakpoints out of the closest line number match. uint32_t tmp_sc_list_size = tmp_sc_list.GetSize(); for (uint32_t i = 0; i < tmp_sc_list_size; i++) { if (tmp_sc_list.GetContextAtIndex(i, sc)) { Address line_start = sc.line_entry.range.GetBaseAddress(); if (line_start.IsValid()) { if (filter.AddressPasses(line_start)) { // If the line number is before the prologue end, move it there... bool skipped_prologue = false; if (skip_prologue) { if (sc.function) { Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress()); if (prologue_addr.IsValid() && (line_start == prologue_addr)) { const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); if (prologue_byte_size) { prologue_addr.Slide(prologue_byte_size); if (filter.AddressPasses(prologue_addr)) { skipped_prologue = true; line_start = prologue_addr; } } } } } BreakpointLocationSP bp_loc_sp (AddLocation(line_start)); if (log && bp_loc_sp && !m_breakpoint->IsInternal()) { StreamString s; bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose); log->Printf ("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData()); } } else if (log) { log->Printf ("Breakpoint %s at file address 0x%" PRIx64 " didn't pass the filter.\n", log_ident ? log_ident : "", line_start.GetFileAddress()); } } else { if (log) log->Printf ("error: Unable to set breakpoint %s at file address 0x%" PRIx64 "\n", log_ident ? log_ident : "", line_start.GetFileAddress()); } } } } }
void BreakpointResolver::ResolveBreakpoint (SearchFilter &filter) { filter.Search (*this); }
void BreakpointResolver::ResolveBreakpointInModules (SearchFilter &filter, ModuleList &modules) { filter.SearchInModuleList(*this, modules); }
Searcher::CallbackReturn AddressResolverName::SearchCallback ( SearchFilter &filter, SymbolContext &context, Address *addr, bool containing ) { SymbolContextList func_list; SymbolContextList sym_list; bool skip_prologue = true; uint32_t i; SymbolContext sc; Address func_addr; LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (m_class_name) { if (log) log->Warning ("Class/method function specification not supported yet.\n"); return Searcher::eCallbackReturnStop; } const bool include_symbols = false; const bool append = false; switch (m_match_type) { case AddressResolver::Exact: if (context.module_sp) { context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list); context.module_sp->FindFunctions (m_func_name, eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeMethod | eFunctionNameTypeSelector, include_symbols, append, func_list); } break; case AddressResolver::Regexp: if (context.module_sp) { context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list); context.module_sp->FindFunctions (m_regex, include_symbols, append, func_list); } break; case AddressResolver::Glob: if (log) log->Warning ("glob is not supported yet."); break; } // Remove any duplicates between the funcion list and the symbol list if (func_list.GetSize()) { for (i = 0; i < func_list.GetSize(); i++) { if (func_list.GetContextAtIndex(i, sc) == false) continue; if (sc.function == NULL) continue; uint32_t j = 0; while (j < sym_list.GetSize()) { SymbolContext symbol_sc; if (sym_list.GetContextAtIndex(j, symbol_sc)) { if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr()) { if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress()) { sym_list.RemoveContextAtIndex(j); continue; // Don't increment j } } } j++; } } for (i = 0; i < func_list.GetSize(); i++) { if (func_list.GetContextAtIndex(i, sc)) { if (sc.function) { func_addr = sc.function->GetAddressRange().GetBaseAddress(); addr_t byte_size = sc.function->GetAddressRange().GetByteSize(); if (skip_prologue) { const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); if (prologue_byte_size) { func_addr.SetOffset (func_addr.GetOffset() + prologue_byte_size); byte_size -= prologue_byte_size; } } if (filter.AddressPasses (func_addr)) { AddressRange new_range (func_addr, byte_size); m_address_ranges.push_back (new_range); } } } } } for (i = 0; i < sym_list.GetSize(); i++) { if (sym_list.GetContextAtIndex(i, sc)) { if (sc.symbol && sc.symbol->GetAddressRangePtr()) { func_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress(); addr_t byte_size = sc.symbol->GetAddressRangePtr()->GetByteSize(); if (skip_prologue) { const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize(); if (prologue_byte_size) { func_addr.SetOffset (func_addr.GetOffset() + prologue_byte_size); byte_size -= prologue_byte_size; } } if (filter.AddressPasses (func_addr)) { AddressRange new_range (func_addr, byte_size); m_address_ranges.push_back (new_range); } } } } return Searcher::eCallbackReturnContinue; }
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; }
void AddressResolver::ResolveAddress(SearchFilter &filter) { filter.Search(*this); }
void AddressResolver::ResolveAddressInModules(SearchFilter &filter, ModuleList &modules) { filter.SearchInModuleList(*this, modules); }