| //===-- BreakpointResolverFileRegex.cpp -----------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lldb/Breakpoint/BreakpointResolverFileRegex.h" | |
| #include "lldb/Breakpoint/BreakpointLocation.h" | |
| #include "lldb/Core/SourceManager.h" | |
| #include "lldb/Symbol/CompileUnit.h" | |
| #include "lldb/Target/Target.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "lldb/Utility/StreamString.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| // BreakpointResolverFileRegex: | |
| BreakpointResolverFileRegex::BreakpointResolverFileRegex( | |
| const lldb::BreakpointSP &bkpt, RegularExpression regex, | |
| const std::unordered_set<std::string> &func_names, bool exact_match) | |
| : BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver), | |
| m_regex(std::move(regex)), m_exact_match(exact_match), | |
| m_function_names(func_names) {} | |
| BreakpointResolverSP BreakpointResolverFileRegex::CreateFromStructuredData( | |
| const StructuredData::Dictionary &options_dict, Status &error) { | |
| bool success; | |
| llvm::StringRef regex_string; | |
| success = options_dict.GetValueForKeyAsString( | |
| GetKey(OptionNames::RegexString), regex_string); | |
| if (!success) { | |
| error = Status::FromErrorString("BRFR::CFSD: Couldn't find regex entry."); | |
| return nullptr; | |
| } | |
| RegularExpression regex(regex_string); | |
| bool exact_match; | |
| success = options_dict.GetValueForKeyAsBoolean( | |
| GetKey(OptionNames::ExactMatch), exact_match); | |
| if (!success) { | |
| error = | |
| Status::FromErrorString("BRFL::CFSD: Couldn't find exact match entry."); | |
| return nullptr; | |
| } | |
| // The names array is optional: | |
| std::unordered_set<std::string> names_set; | |
| StructuredData::Array *names_array; | |
| success = options_dict.GetValueForKeyAsArray( | |
| GetKey(OptionNames::SymbolNameArray), names_array); | |
| if (success && names_array) { | |
| size_t num_names = names_array->GetSize(); | |
| for (size_t i = 0; i < num_names; i++) { | |
| std::optional<llvm::StringRef> maybe_name = | |
| names_array->GetItemAtIndexAsString(i); | |
| if (!maybe_name) { | |
| error = Status::FromErrorStringWithFormatv( | |
| "BRFR::CFSD: Malformed element {0} in the names array.", i); | |
| return nullptr; | |
| } | |
| names_set.insert(std::string(*maybe_name)); | |
| } | |
| } | |
| return std::make_shared<BreakpointResolverFileRegex>( | |
| nullptr, std::move(regex), names_set, exact_match); | |
| } | |
| StructuredData::ObjectSP | |
| BreakpointResolverFileRegex::SerializeToStructuredData() { | |
| StructuredData::DictionarySP options_dict_sp( | |
| new StructuredData::Dictionary()); | |
| options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString), | |
| m_regex.GetText()); | |
| options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch), | |
| m_exact_match); | |
| if (!m_function_names.empty()) { | |
| StructuredData::ArraySP names_array_sp(new StructuredData::Array()); | |
| for (std::string name : m_function_names) { | |
| StructuredData::StringSP item(new StructuredData::String(name)); | |
| names_array_sp->AddItem(item); | |
| } | |
| options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp); | |
| } | |
| return WrapOptionsDict(options_dict_sp); | |
| } | |
| Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback( | |
| SearchFilter &filter, SymbolContext &context, Address *addr) { | |
| if (!context.target_sp) | |
| return eCallbackReturnContinue; | |
| CompileUnit *cu = context.comp_unit; | |
| if (!cu) | |
| return eCallbackReturnContinue; | |
| FileSpec cu_file_spec = cu->GetPrimaryFile(); | |
| std::vector<uint32_t> line_matches; | |
| context.target_sp->GetSourceManager().FindLinesMatchingRegex( | |
| std::make_shared<SupportFile>(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; | |
| // TODO: Handle SourceLocationSpec column information | |
| SourceLocationSpec location_spec(cu_file_spec, line_matches[i], | |
| /*column=*/std::nullopt, | |
| /*check_inlines=*/false, m_exact_match); | |
| cu->ResolveSymbolContext(location_spec, eSymbolContextEverything, sc_list); | |
| // Find all the function names: | |
| if (!m_function_names.empty()) { | |
| std::vector<size_t> sc_to_remove; | |
| for (size_t i = 0; i < sc_list.GetSize(); i++) { | |
| SymbolContext sc_ctx; | |
| sc_list.GetContextAtIndex(i, sc_ctx); | |
| std::string name = | |
| sc_ctx | |
| .GetFunctionName( | |
| Mangled::NamePreference::ePreferDemangledWithoutArguments) | |
| .GetString(); | |
| if (!m_function_names.count(name)) { | |
| sc_to_remove.push_back(i); | |
| } | |
| } | |
| if (!sc_to_remove.empty()) { | |
| std::vector<size_t>::reverse_iterator iter; | |
| std::vector<size_t>::reverse_iterator rend = sc_to_remove.rend(); | |
| for (iter = sc_to_remove.rbegin(); iter != rend; iter++) { | |
| sc_list.RemoveContextAtIndex(*iter); | |
| } | |
| } | |
| } | |
| const bool skip_prologue = true; | |
| BreakpointResolver::SetSCMatchesByLine(filter, sc_list, skip_prologue, | |
| m_regex.GetText()); | |
| } | |
| return Searcher::eCallbackReturnContinue; | |
| } | |
| lldb::SearchDepth BreakpointResolverFileRegex::GetDepth() { | |
| return lldb::eSearchDepthCompUnit; | |
| } | |
| void BreakpointResolverFileRegex::GetDescription(Stream *s) { | |
| s->Printf("source regex = \"%s\", exact_match = %d", | |
| m_regex.GetText().str().c_str(), m_exact_match); | |
| } | |
| void BreakpointResolverFileRegex::Dump(Stream *s) const {} | |
| lldb::BreakpointResolverSP | |
| BreakpointResolverFileRegex::CopyForBreakpoint(BreakpointSP &breakpoint) { | |
| lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex( | |
| breakpoint, m_regex, m_function_names, m_exact_match)); | |
| return ret_sp; | |
| } | |
| void BreakpointResolverFileRegex::AddFunctionName(const char *func_name) { | |
| m_function_names.insert(func_name); | |
| } |