171 lines · cpp
1//===-- BreakpointResolverFileRegex.cpp -----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"10 11#include "lldb/Breakpoint/BreakpointLocation.h"12#include "lldb/Core/SourceManager.h"13#include "lldb/Symbol/CompileUnit.h"14#include "lldb/Target/Target.h"15#include "lldb/Utility/Log.h"16#include "lldb/Utility/StreamString.h"17 18using namespace lldb;19using namespace lldb_private;20 21// BreakpointResolverFileRegex:22BreakpointResolverFileRegex::BreakpointResolverFileRegex(23 const lldb::BreakpointSP &bkpt, RegularExpression regex,24 const std::unordered_set<std::string> &func_names, bool exact_match)25 : BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver),26 m_regex(std::move(regex)), m_exact_match(exact_match),27 m_function_names(func_names) {}28 29BreakpointResolverSP BreakpointResolverFileRegex::CreateFromStructuredData(30 const StructuredData::Dictionary &options_dict, Status &error) {31 bool success;32 33 llvm::StringRef regex_string;34 success = options_dict.GetValueForKeyAsString(35 GetKey(OptionNames::RegexString), regex_string);36 if (!success) {37 error = Status::FromErrorString("BRFR::CFSD: Couldn't find regex entry.");38 return nullptr;39 }40 RegularExpression regex(regex_string);41 42 bool exact_match;43 success = options_dict.GetValueForKeyAsBoolean(44 GetKey(OptionNames::ExactMatch), exact_match);45 if (!success) {46 error =47 Status::FromErrorString("BRFL::CFSD: Couldn't find exact match entry.");48 return nullptr;49 }50 51 // The names array is optional:52 std::unordered_set<std::string> names_set;53 StructuredData::Array *names_array;54 success = options_dict.GetValueForKeyAsArray(55 GetKey(OptionNames::SymbolNameArray), names_array);56 if (success && names_array) {57 size_t num_names = names_array->GetSize();58 for (size_t i = 0; i < num_names; i++) {59 std::optional<llvm::StringRef> maybe_name =60 names_array->GetItemAtIndexAsString(i);61 if (!maybe_name) {62 error = Status::FromErrorStringWithFormatv(63 "BRFR::CFSD: Malformed element {0} in the names array.", i);64 return nullptr;65 }66 names_set.insert(std::string(*maybe_name));67 }68 }69 70 return std::make_shared<BreakpointResolverFileRegex>(71 nullptr, std::move(regex), names_set, exact_match);72}73 74StructuredData::ObjectSP75BreakpointResolverFileRegex::SerializeToStructuredData() {76 StructuredData::DictionarySP options_dict_sp(77 new StructuredData::Dictionary());78 79 options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),80 m_regex.GetText());81 options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),82 m_exact_match);83 if (!m_function_names.empty()) {84 StructuredData::ArraySP names_array_sp(new StructuredData::Array());85 for (std::string name : m_function_names) {86 StructuredData::StringSP item(new StructuredData::String(name));87 names_array_sp->AddItem(item);88 }89 options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp);90 }91 92 return WrapOptionsDict(options_dict_sp);93}94 95Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback(96 SearchFilter &filter, SymbolContext &context, Address *addr) {97 98 if (!context.target_sp)99 return eCallbackReturnContinue;100 101 CompileUnit *cu = context.comp_unit;102 FileSpec cu_file_spec = cu->GetPrimaryFile();103 std::vector<uint32_t> line_matches;104 context.target_sp->GetSourceManager().FindLinesMatchingRegex(105 std::make_shared<SupportFile>(cu_file_spec), m_regex, 1, UINT32_MAX,106 line_matches);107 108 uint32_t num_matches = line_matches.size();109 for (uint32_t i = 0; i < num_matches; i++) {110 SymbolContextList sc_list;111 // TODO: Handle SourceLocationSpec column information112 SourceLocationSpec location_spec(cu_file_spec, line_matches[i],113 /*column=*/std::nullopt,114 /*check_inlines=*/false, m_exact_match);115 cu->ResolveSymbolContext(location_spec, eSymbolContextEverything, sc_list);116 // Find all the function names:117 if (!m_function_names.empty()) {118 std::vector<size_t> sc_to_remove;119 for (size_t i = 0; i < sc_list.GetSize(); i++) {120 SymbolContext sc_ctx;121 sc_list.GetContextAtIndex(i, sc_ctx);122 std::string name(123 sc_ctx124 .GetFunctionName(125 Mangled::NamePreference::ePreferDemangledWithoutArguments)126 .AsCString());127 if (!m_function_names.count(name)) {128 sc_to_remove.push_back(i);129 }130 }131 132 if (!sc_to_remove.empty()) {133 std::vector<size_t>::reverse_iterator iter;134 std::vector<size_t>::reverse_iterator rend = sc_to_remove.rend();135 for (iter = sc_to_remove.rbegin(); iter != rend; iter++) {136 sc_list.RemoveContextAtIndex(*iter);137 }138 }139 }140 141 const bool skip_prologue = true;142 143 BreakpointResolver::SetSCMatchesByLine(filter, sc_list, skip_prologue,144 m_regex.GetText());145 }146 147 return Searcher::eCallbackReturnContinue;148}149 150lldb::SearchDepth BreakpointResolverFileRegex::GetDepth() {151 return lldb::eSearchDepthCompUnit;152}153 154void BreakpointResolverFileRegex::GetDescription(Stream *s) {155 s->Printf("source regex = \"%s\", exact_match = %d",156 m_regex.GetText().str().c_str(), m_exact_match);157}158 159void BreakpointResolverFileRegex::Dump(Stream *s) const {}160 161lldb::BreakpointResolverSP162BreakpointResolverFileRegex::CopyForBreakpoint(BreakpointSP &breakpoint) {163 lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(164 breakpoint, m_regex, m_function_names, m_exact_match));165 return ret_sp;166}167 168void BreakpointResolverFileRegex::AddFunctionName(const char *func_name) {169 m_function_names.insert(func_name);170}171