1cfca06d7SDimitry Andric //===-- BreakpointResolverFileRegex.cpp -----------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f034231aSEd Maste #include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
10f034231aSEd Maste
11f034231aSEd Maste #include "lldb/Breakpoint/BreakpointLocation.h"
1214f1b3e8SDimitry Andric #include "lldb/Core/SourceManager.h"
13f034231aSEd Maste #include "lldb/Symbol/CompileUnit.h"
14f034231aSEd Maste #include "lldb/Target/Target.h"
1574a628f7SDimitry Andric #include "lldb/Utility/Log.h"
1674a628f7SDimitry Andric #include "lldb/Utility/StreamString.h"
17f034231aSEd Maste
18f034231aSEd Maste using namespace lldb;
19f034231aSEd Maste using namespace lldb_private;
20f034231aSEd Maste
21f034231aSEd Maste // BreakpointResolverFileRegex:
BreakpointResolverFileRegex(const lldb::BreakpointSP & bkpt,RegularExpression regex,const std::unordered_set<std::string> & func_names,bool exact_match)2214f1b3e8SDimitry Andric BreakpointResolverFileRegex::BreakpointResolverFileRegex(
23cfca06d7SDimitry Andric const lldb::BreakpointSP &bkpt, RegularExpression regex,
2414f1b3e8SDimitry Andric const std::unordered_set<std::string> &func_names, bool exact_match)
2514f1b3e8SDimitry Andric : BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver),
26ead24645SDimitry Andric m_regex(std::move(regex)), m_exact_match(exact_match),
27ead24645SDimitry Andric m_function_names(func_names) {}
28f034231aSEd Maste
CreateFromStructuredData(const StructuredData::Dictionary & options_dict,Status & error)29b1c73532SDimitry Andric BreakpointResolverSP BreakpointResolverFileRegex::CreateFromStructuredData(
30b1c73532SDimitry Andric const StructuredData::Dictionary &options_dict, Status &error) {
3114f1b3e8SDimitry Andric bool success;
3214f1b3e8SDimitry Andric
33b76161e4SDimitry Andric llvm::StringRef regex_string;
3414f1b3e8SDimitry Andric success = options_dict.GetValueForKeyAsString(
3514f1b3e8SDimitry Andric GetKey(OptionNames::RegexString), regex_string);
3614f1b3e8SDimitry Andric if (!success) {
3714f1b3e8SDimitry Andric error.SetErrorString("BRFR::CFSD: Couldn't find regex entry.");
3814f1b3e8SDimitry Andric return nullptr;
3914f1b3e8SDimitry Andric }
4014f1b3e8SDimitry Andric RegularExpression regex(regex_string);
4114f1b3e8SDimitry Andric
4214f1b3e8SDimitry Andric bool exact_match;
4314f1b3e8SDimitry Andric success = options_dict.GetValueForKeyAsBoolean(
4414f1b3e8SDimitry Andric GetKey(OptionNames::ExactMatch), exact_match);
4514f1b3e8SDimitry Andric if (!success) {
4614f1b3e8SDimitry Andric error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
4714f1b3e8SDimitry Andric return nullptr;
4814f1b3e8SDimitry Andric }
4914f1b3e8SDimitry Andric
5014f1b3e8SDimitry Andric // The names array is optional:
5114f1b3e8SDimitry Andric std::unordered_set<std::string> names_set;
5214f1b3e8SDimitry Andric StructuredData::Array *names_array;
5314f1b3e8SDimitry Andric success = options_dict.GetValueForKeyAsArray(
5414f1b3e8SDimitry Andric GetKey(OptionNames::SymbolNameArray), names_array);
5514f1b3e8SDimitry Andric if (success && names_array) {
5614f1b3e8SDimitry Andric size_t num_names = names_array->GetSize();
5714f1b3e8SDimitry Andric for (size_t i = 0; i < num_names; i++) {
58b1c73532SDimitry Andric std::optional<llvm::StringRef> maybe_name =
59b1c73532SDimitry Andric names_array->GetItemAtIndexAsString(i);
60b1c73532SDimitry Andric if (!maybe_name) {
6114f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
6214f1b3e8SDimitry Andric "BRFR::CFSD: Malformed element %zu in the names array.", i);
6314f1b3e8SDimitry Andric return nullptr;
6414f1b3e8SDimitry Andric }
65b1c73532SDimitry Andric names_set.insert(std::string(*maybe_name));
6614f1b3e8SDimitry Andric }
6714f1b3e8SDimitry Andric }
6814f1b3e8SDimitry Andric
69312c0ed1SDimitry Andric return std::make_shared<BreakpointResolverFileRegex>(
70312c0ed1SDimitry Andric nullptr, std::move(regex), names_set, exact_match);
7114f1b3e8SDimitry Andric }
7214f1b3e8SDimitry Andric
7314f1b3e8SDimitry Andric StructuredData::ObjectSP
SerializeToStructuredData()7414f1b3e8SDimitry Andric BreakpointResolverFileRegex::SerializeToStructuredData() {
7514f1b3e8SDimitry Andric StructuredData::DictionarySP options_dict_sp(
7614f1b3e8SDimitry Andric new StructuredData::Dictionary());
7714f1b3e8SDimitry Andric
7814f1b3e8SDimitry Andric options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
7914f1b3e8SDimitry Andric m_regex.GetText());
8014f1b3e8SDimitry Andric options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
8114f1b3e8SDimitry Andric m_exact_match);
8214f1b3e8SDimitry Andric if (!m_function_names.empty()) {
8314f1b3e8SDimitry Andric StructuredData::ArraySP names_array_sp(new StructuredData::Array());
8414f1b3e8SDimitry Andric for (std::string name : m_function_names) {
8514f1b3e8SDimitry Andric StructuredData::StringSP item(new StructuredData::String(name));
8614f1b3e8SDimitry Andric names_array_sp->AddItem(item);
8714f1b3e8SDimitry Andric }
8814f1b3e8SDimitry Andric options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp);
8914f1b3e8SDimitry Andric }
9014f1b3e8SDimitry Andric
9114f1b3e8SDimitry Andric return WrapOptionsDict(options_dict_sp);
92f034231aSEd Maste }
93f034231aSEd Maste
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)94ead24645SDimitry Andric Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback(
95ead24645SDimitry Andric SearchFilter &filter, SymbolContext &context, Address *addr) {
96f034231aSEd Maste
97f034231aSEd Maste if (!context.target_sp)
98f034231aSEd Maste return eCallbackReturnContinue;
99f034231aSEd Maste
100f034231aSEd Maste CompileUnit *cu = context.comp_unit;
101706b4fc4SDimitry Andric FileSpec cu_file_spec = cu->GetPrimaryFile();
102f034231aSEd Maste std::vector<uint32_t> line_matches;
10314f1b3e8SDimitry Andric context.target_sp->GetSourceManager().FindLinesMatchingRegex(
10414f1b3e8SDimitry Andric cu_file_spec, m_regex, 1, UINT32_MAX, line_matches);
105f21a844fSEd Maste
106f034231aSEd Maste uint32_t num_matches = line_matches.size();
10714f1b3e8SDimitry Andric for (uint32_t i = 0; i < num_matches; i++) {
108f21a844fSEd Maste SymbolContextList sc_list;
109344a3780SDimitry Andric // TODO: Handle SourceLocationSpec column information
110344a3780SDimitry Andric SourceLocationSpec location_spec(cu_file_spec, line_matches[i],
111e3b55780SDimitry Andric /*column=*/std::nullopt,
1126f8fc217SDimitry Andric /*check_inlines=*/false, m_exact_match);
113344a3780SDimitry Andric cu->ResolveSymbolContext(location_spec, eSymbolContextEverything, sc_list);
114f3fbd1c0SDimitry Andric // Find all the function names:
11514f1b3e8SDimitry Andric if (!m_function_names.empty()) {
116f3fbd1c0SDimitry Andric std::vector<size_t> sc_to_remove;
11714f1b3e8SDimitry Andric for (size_t i = 0; i < sc_list.GetSize(); i++) {
118f3fbd1c0SDimitry Andric SymbolContext sc_ctx;
119f3fbd1c0SDimitry Andric sc_list.GetContextAtIndex(i, sc_ctx);
12014f1b3e8SDimitry Andric std::string name(
12114f1b3e8SDimitry Andric sc_ctx
12214f1b3e8SDimitry Andric .GetFunctionName(
12314f1b3e8SDimitry Andric Mangled::NamePreference::ePreferDemangledWithoutArguments)
12414f1b3e8SDimitry Andric .AsCString());
12514f1b3e8SDimitry Andric if (!m_function_names.count(name)) {
126f3fbd1c0SDimitry Andric sc_to_remove.push_back(i);
127f3fbd1c0SDimitry Andric }
128f3fbd1c0SDimitry Andric }
129f3fbd1c0SDimitry Andric
13014f1b3e8SDimitry Andric if (!sc_to_remove.empty()) {
131f3fbd1c0SDimitry Andric std::vector<size_t>::reverse_iterator iter;
132f3fbd1c0SDimitry Andric std::vector<size_t>::reverse_iterator rend = sc_to_remove.rend();
13314f1b3e8SDimitry Andric for (iter = sc_to_remove.rbegin(); iter != rend; iter++) {
134f3fbd1c0SDimitry Andric sc_list.RemoveContextAtIndex(*iter);
135f3fbd1c0SDimitry Andric }
136f3fbd1c0SDimitry Andric }
137f3fbd1c0SDimitry Andric }
138f3fbd1c0SDimitry Andric
139f21a844fSEd Maste const bool skip_prologue = true;
140f034231aSEd Maste
14114f1b3e8SDimitry Andric BreakpointResolver::SetSCMatchesByLine(filter, sc_list, skip_prologue,
14214f1b3e8SDimitry Andric m_regex.GetText());
143f034231aSEd Maste }
144f034231aSEd Maste
145f034231aSEd Maste return Searcher::eCallbackReturnContinue;
146f034231aSEd Maste }
147f034231aSEd Maste
GetDepth()14894994d37SDimitry Andric lldb::SearchDepth BreakpointResolverFileRegex::GetDepth() {
14994994d37SDimitry Andric return lldb::eSearchDepthCompUnit;
150f034231aSEd Maste }
151f034231aSEd Maste
GetDescription(Stream * s)15214f1b3e8SDimitry Andric void BreakpointResolverFileRegex::GetDescription(Stream *s) {
15314f1b3e8SDimitry Andric s->Printf("source regex = \"%s\", exact_match = %d",
15414f1b3e8SDimitry Andric m_regex.GetText().str().c_str(), m_exact_match);
155f034231aSEd Maste }
156f034231aSEd Maste
Dump(Stream * s) const15714f1b3e8SDimitry Andric void BreakpointResolverFileRegex::Dump(Stream *s) const {}
158f034231aSEd Maste
159205afe67SEd Maste lldb::BreakpointResolverSP
CopyForBreakpoint(BreakpointSP & breakpoint)160cfca06d7SDimitry Andric BreakpointResolverFileRegex::CopyForBreakpoint(BreakpointSP &breakpoint) {
16114f1b3e8SDimitry Andric lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(
162cfca06d7SDimitry Andric breakpoint, m_regex, m_function_names, m_exact_match));
163205afe67SEd Maste return ret_sp;
164205afe67SEd Maste }
165205afe67SEd Maste
AddFunctionName(const char * func_name)16614f1b3e8SDimitry Andric void BreakpointResolverFileRegex::AddFunctionName(const char *func_name) {
167f3fbd1c0SDimitry Andric m_function_names.insert(func_name);
168f3fbd1c0SDimitry Andric }
169