1 //===-- BreakpointResolverFileRegex.cpp -----------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
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"
19 using namespace lldb_private
;
21 // BreakpointResolverFileRegex:
22 BreakpointResolverFileRegex::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
) {}
29 BreakpointResolverSP
BreakpointResolverFileRegex::CreateFromStructuredData(
30 const StructuredData::Dictionary
&options_dict
, Status
&error
) {
33 llvm::StringRef regex_string
;
34 success
= options_dict
.GetValueForKeyAsString(
35 GetKey(OptionNames::RegexString
), regex_string
);
37 error
.SetErrorString("BRFR::CFSD: Couldn't find regex entry.");
40 RegularExpression
regex(regex_string
);
43 success
= options_dict
.GetValueForKeyAsBoolean(
44 GetKey(OptionNames::ExactMatch
), exact_match
);
46 error
.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
50 // The names array is optional:
51 std::unordered_set
<std::string
> names_set
;
52 StructuredData::Array
*names_array
;
53 success
= options_dict
.GetValueForKeyAsArray(
54 GetKey(OptionNames::SymbolNameArray
), names_array
);
55 if (success
&& names_array
) {
56 size_t num_names
= names_array
->GetSize();
57 for (size_t i
= 0; i
< num_names
; i
++) {
58 std::optional
<llvm::StringRef
> maybe_name
=
59 names_array
->GetItemAtIndexAsString(i
);
61 error
.SetErrorStringWithFormat(
62 "BRFR::CFSD: Malformed element %zu in the names array.", i
);
65 names_set
.insert(std::string(*maybe_name
));
69 return std::make_shared
<BreakpointResolverFileRegex
>(
70 nullptr, std::move(regex
), names_set
, exact_match
);
73 StructuredData::ObjectSP
74 BreakpointResolverFileRegex::SerializeToStructuredData() {
75 StructuredData::DictionarySP
options_dict_sp(
76 new StructuredData::Dictionary());
78 options_dict_sp
->AddStringItem(GetKey(OptionNames::RegexString
),
80 options_dict_sp
->AddBooleanItem(GetKey(OptionNames::ExactMatch
),
82 if (!m_function_names
.empty()) {
83 StructuredData::ArraySP
names_array_sp(new StructuredData::Array());
84 for (std::string name
: m_function_names
) {
85 StructuredData::StringSP
item(new StructuredData::String(name
));
86 names_array_sp
->AddItem(item
);
88 options_dict_sp
->AddItem(GetKey(OptionNames::LineNumber
), names_array_sp
);
91 return WrapOptionsDict(options_dict_sp
);
94 Searcher::CallbackReturn
BreakpointResolverFileRegex::SearchCallback(
95 SearchFilter
&filter
, SymbolContext
&context
, Address
*addr
) {
97 if (!context
.target_sp
)
98 return eCallbackReturnContinue
;
100 CompileUnit
*cu
= context
.comp_unit
;
101 FileSpec cu_file_spec
= cu
->GetPrimaryFile();
102 std::vector
<uint32_t> line_matches
;
103 context
.target_sp
->GetSourceManager().FindLinesMatchingRegex(
104 cu_file_spec
, m_regex
, 1, UINT32_MAX
, line_matches
);
106 uint32_t num_matches
= line_matches
.size();
107 for (uint32_t i
= 0; i
< num_matches
; i
++) {
108 SymbolContextList sc_list
;
109 // TODO: Handle SourceLocationSpec column information
110 SourceLocationSpec
location_spec(cu_file_spec
, line_matches
[i
],
111 /*column=*/std::nullopt
,
112 /*check_inlines=*/false, m_exact_match
);
113 cu
->ResolveSymbolContext(location_spec
, eSymbolContextEverything
, sc_list
);
114 // Find all the function names:
115 if (!m_function_names
.empty()) {
116 std::vector
<size_t> sc_to_remove
;
117 for (size_t i
= 0; i
< sc_list
.GetSize(); i
++) {
118 SymbolContext sc_ctx
;
119 sc_list
.GetContextAtIndex(i
, sc_ctx
);
123 Mangled::NamePreference::ePreferDemangledWithoutArguments
)
125 if (!m_function_names
.count(name
)) {
126 sc_to_remove
.push_back(i
);
130 if (!sc_to_remove
.empty()) {
131 std::vector
<size_t>::reverse_iterator iter
;
132 std::vector
<size_t>::reverse_iterator rend
= sc_to_remove
.rend();
133 for (iter
= sc_to_remove
.rbegin(); iter
!= rend
; iter
++) {
134 sc_list
.RemoveContextAtIndex(*iter
);
139 const bool skip_prologue
= true;
141 BreakpointResolver::SetSCMatchesByLine(filter
, sc_list
, skip_prologue
,
145 return Searcher::eCallbackReturnContinue
;
148 lldb::SearchDepth
BreakpointResolverFileRegex::GetDepth() {
149 return lldb::eSearchDepthCompUnit
;
152 void BreakpointResolverFileRegex::GetDescription(Stream
*s
) {
153 s
->Printf("source regex = \"%s\", exact_match = %d",
154 m_regex
.GetText().str().c_str(), m_exact_match
);
157 void BreakpointResolverFileRegex::Dump(Stream
*s
) const {}
159 lldb::BreakpointResolverSP
160 BreakpointResolverFileRegex::CopyForBreakpoint(BreakpointSP
&breakpoint
) {
161 lldb::BreakpointResolverSP
ret_sp(new BreakpointResolverFileRegex(
162 breakpoint
, m_regex
, m_function_names
, m_exact_match
));
166 void BreakpointResolverFileRegex::AddFunctionName(const char *func_name
) {
167 m_function_names
.insert(func_name
);