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
= Status::FromErrorString("BRFR::CFSD: Couldn't find regex entry.");
40 RegularExpression
regex(regex_string
);
43 success
= options_dict
.GetValueForKeyAsBoolean(
44 GetKey(OptionNames::ExactMatch
), exact_match
);
47 Status::FromErrorString("BRFL::CFSD: Couldn't find exact match entry.");
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
);
62 error
= Status::FromErrorStringWithFormatv(
63 "BRFR::CFSD: Malformed element {0} in the names array.", i
);
66 names_set
.insert(std::string(*maybe_name
));
70 return std::make_shared
<BreakpointResolverFileRegex
>(
71 nullptr, std::move(regex
), names_set
, exact_match
);
74 StructuredData::ObjectSP
75 BreakpointResolverFileRegex::SerializeToStructuredData() {
76 StructuredData::DictionarySP
options_dict_sp(
77 new StructuredData::Dictionary());
79 options_dict_sp
->AddStringItem(GetKey(OptionNames::RegexString
),
81 options_dict_sp
->AddBooleanItem(GetKey(OptionNames::ExactMatch
),
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
);
89 options_dict_sp
->AddItem(GetKey(OptionNames::LineNumber
), names_array_sp
);
92 return WrapOptionsDict(options_dict_sp
);
95 Searcher::CallbackReturn
BreakpointResolverFileRegex::SearchCallback(
96 SearchFilter
&filter
, SymbolContext
&context
, Address
*addr
) {
98 if (!context
.target_sp
)
99 return eCallbackReturnContinue
;
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
,
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 information
112 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
);
125 Mangled::NamePreference::ePreferDemangledWithoutArguments
)
127 if (!m_function_names
.count(name
)) {
128 sc_to_remove
.push_back(i
);
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
);
141 const bool skip_prologue
= true;
143 BreakpointResolver::SetSCMatchesByLine(filter
, sc_list
, skip_prologue
,
147 return Searcher::eCallbackReturnContinue
;
150 lldb::SearchDepth
BreakpointResolverFileRegex::GetDepth() {
151 return lldb::eSearchDepthCompUnit
;
154 void BreakpointResolverFileRegex::GetDescription(Stream
*s
) {
155 s
->Printf("source regex = \"%s\", exact_match = %d",
156 m_regex
.GetText().str().c_str(), m_exact_match
);
159 void BreakpointResolverFileRegex::Dump(Stream
*s
) const {}
161 lldb::BreakpointResolverSP
162 BreakpointResolverFileRegex::CopyForBreakpoint(BreakpointSP
&breakpoint
) {
163 lldb::BreakpointResolverSP
ret_sp(new BreakpointResolverFileRegex(
164 breakpoint
, m_regex
, m_function_names
, m_exact_match
));
168 void BreakpointResolverFileRegex::AddFunctionName(const char *func_name
) {
169 m_function_names
.insert(func_name
);