1 //===-- BreakpointResolverName.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/BreakpointResolverName.h"
11 #include "lldb/Breakpoint/BreakpointLocation.h"
12 #include "lldb/Core/Architecture.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Symbol/Block.h"
15 #include "lldb/Symbol/Function.h"
16 #include "lldb/Symbol/Symbol.h"
17 #include "lldb/Symbol/SymbolContext.h"
18 #include "lldb/Target/Language.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Utility/LLDBLog.h"
21 #include "lldb/Utility/Log.h"
22 #include "lldb/Utility/StreamString.h"
25 using namespace lldb_private
;
27 BreakpointResolverName::BreakpointResolverName(const BreakpointSP
&bkpt
,
28 const char *name_cstr
, FunctionNameType name_type_mask
,
29 LanguageType language
, Breakpoint::MatchType type
, lldb::addr_t offset
,
31 : BreakpointResolver(bkpt
, BreakpointResolver::NameResolver
, offset
),
32 m_match_type(type
), m_language(language
), m_skip_prologue(skip_prologue
) {
33 if (m_match_type
== Breakpoint::Regexp
) {
34 m_regex
= RegularExpression(name_cstr
);
35 if (!m_regex
.IsValid()) {
36 Log
*log
= GetLog(LLDBLog::Breakpoints
);
39 log
->Warning("function name regexp: \"%s\" did not compile.",
43 AddNameLookup(ConstString(name_cstr
), name_type_mask
);
47 BreakpointResolverName::BreakpointResolverName(
48 const BreakpointSP
&bkpt
, const char *names
[], size_t num_names
,
49 FunctionNameType name_type_mask
, LanguageType language
, lldb::addr_t offset
,
51 : BreakpointResolver(bkpt
, BreakpointResolver::NameResolver
, offset
),
52 m_match_type(Breakpoint::Exact
), m_language(language
),
53 m_skip_prologue(skip_prologue
) {
54 for (size_t i
= 0; i
< num_names
; i
++) {
55 AddNameLookup(ConstString(names
[i
]), name_type_mask
);
59 BreakpointResolverName::BreakpointResolverName(
60 const BreakpointSP
&bkpt
, const std::vector
<std::string
> &names
,
61 FunctionNameType name_type_mask
, LanguageType language
, lldb::addr_t offset
,
63 : BreakpointResolver(bkpt
, BreakpointResolver::NameResolver
, offset
),
64 m_match_type(Breakpoint::Exact
), m_language(language
),
65 m_skip_prologue(skip_prologue
) {
66 for (const std::string
&name
: names
) {
67 AddNameLookup(ConstString(name
.c_str(), name
.size()), name_type_mask
);
71 BreakpointResolverName::BreakpointResolverName(const BreakpointSP
&bkpt
,
72 RegularExpression func_regex
,
73 lldb::LanguageType language
,
76 : BreakpointResolver(bkpt
, BreakpointResolver::NameResolver
, offset
),
77 m_class_name(nullptr), m_regex(std::move(func_regex
)),
78 m_match_type(Breakpoint::Regexp
), m_language(language
),
79 m_skip_prologue(skip_prologue
) {}
81 BreakpointResolverName::BreakpointResolverName(
82 const BreakpointResolverName
&rhs
)
83 : BreakpointResolver(rhs
.GetBreakpoint(), BreakpointResolver::NameResolver
,
85 m_lookups(rhs
.m_lookups
), m_class_name(rhs
.m_class_name
),
86 m_regex(rhs
.m_regex
), m_match_type(rhs
.m_match_type
),
87 m_language(rhs
.m_language
), m_skip_prologue(rhs
.m_skip_prologue
) {}
89 BreakpointResolverSP
BreakpointResolverName::CreateFromStructuredData(
90 const StructuredData::Dictionary
&options_dict
, Status
&error
) {
91 LanguageType language
= eLanguageTypeUnknown
;
92 llvm::StringRef language_name
;
93 bool success
= options_dict
.GetValueForKeyAsString(
94 GetKey(OptionNames::LanguageName
), language_name
);
96 language
= Language::GetLanguageTypeFromString(language_name
);
97 if (language
== eLanguageTypeUnknown
) {
98 error
= Status::FromErrorStringWithFormatv(
99 "BRN::CFSD: Unknown language: {0}.", language_name
);
104 lldb::offset_t offset
= 0;
106 options_dict
.GetValueForKeyAsInteger(GetKey(OptionNames::Offset
), offset
);
108 error
= Status::FromErrorString("BRN::CFSD: Missing offset entry.");
113 success
= options_dict
.GetValueForKeyAsBoolean(
114 GetKey(OptionNames::SkipPrologue
), skip_prologue
);
116 error
= Status::FromErrorString("BRN::CFSD: Missing Skip prologue entry.");
120 llvm::StringRef regex_text
;
121 success
= options_dict
.GetValueForKeyAsString(
122 GetKey(OptionNames::RegexString
), regex_text
);
124 return std::make_shared
<BreakpointResolverName
>(
125 nullptr, RegularExpression(regex_text
), language
, offset
,
128 StructuredData::Array
*names_array
;
129 success
= options_dict
.GetValueForKeyAsArray(
130 GetKey(OptionNames::SymbolNameArray
), names_array
);
132 error
= Status::FromErrorString("BRN::CFSD: Missing symbol names entry.");
135 StructuredData::Array
*names_mask_array
;
136 success
= options_dict
.GetValueForKeyAsArray(
137 GetKey(OptionNames::NameMaskArray
), names_mask_array
);
139 error
= Status::FromErrorString(
140 "BRN::CFSD: Missing symbol names mask entry.");
144 size_t num_elem
= names_array
->GetSize();
145 if (num_elem
!= names_mask_array
->GetSize()) {
146 error
= Status::FromErrorString(
147 "BRN::CFSD: names and names mask arrays have different sizes.");
152 error
= Status::FromErrorString(
153 "BRN::CFSD: no name entry in a breakpoint by name breakpoint.");
156 std::vector
<std::string
> names
;
157 std::vector
<FunctionNameType
> name_masks
;
158 for (size_t i
= 0; i
< num_elem
; i
++) {
159 std::optional
<llvm::StringRef
> maybe_name
=
160 names_array
->GetItemAtIndexAsString(i
);
163 Status::FromErrorString("BRN::CFSD: name entry is not a string.");
166 auto maybe_fnt
= names_mask_array
->GetItemAtIndexAsInteger
<
167 std::underlying_type
<FunctionNameType
>::type
>(i
);
169 error
= Status::FromErrorString(
170 "BRN::CFSD: name mask entry is not an integer.");
173 names
.push_back(std::string(*maybe_name
));
174 name_masks
.push_back(static_cast<FunctionNameType
>(*maybe_fnt
));
177 std::shared_ptr
<BreakpointResolverName
> resolver_sp
=
178 std::make_shared
<BreakpointResolverName
>(
179 nullptr, names
[0].c_str(), name_masks
[0], language
,
180 Breakpoint::MatchType::Exact
, offset
, skip_prologue
);
181 for (size_t i
= 1; i
< num_elem
; i
++) {
182 resolver_sp
->AddNameLookup(ConstString(names
[i
]), name_masks
[i
]);
188 StructuredData::ObjectSP
BreakpointResolverName::SerializeToStructuredData() {
189 StructuredData::DictionarySP
options_dict_sp(
190 new StructuredData::Dictionary());
192 if (m_regex
.IsValid()) {
193 options_dict_sp
->AddStringItem(GetKey(OptionNames::RegexString
),
196 StructuredData::ArraySP
names_sp(new StructuredData::Array());
197 StructuredData::ArraySP
name_masks_sp(new StructuredData::Array());
198 for (auto lookup
: m_lookups
) {
199 names_sp
->AddItem(StructuredData::StringSP(
200 new StructuredData::String(lookup
.GetName().GetStringRef())));
201 name_masks_sp
->AddItem(StructuredData::UnsignedIntegerSP(
202 new StructuredData::UnsignedInteger(lookup
.GetNameTypeMask())));
204 options_dict_sp
->AddItem(GetKey(OptionNames::SymbolNameArray
), names_sp
);
205 options_dict_sp
->AddItem(GetKey(OptionNames::NameMaskArray
), name_masks_sp
);
207 if (m_language
!= eLanguageTypeUnknown
)
208 options_dict_sp
->AddStringItem(
209 GetKey(OptionNames::LanguageName
),
210 Language::GetNameForLanguageType(m_language
));
211 options_dict_sp
->AddBooleanItem(GetKey(OptionNames::SkipPrologue
),
214 return WrapOptionsDict(options_dict_sp
);
217 void BreakpointResolverName::AddNameLookup(ConstString name
,
218 FunctionNameType name_type_mask
) {
220 Module::LookupInfo
lookup(name
, name_type_mask
, m_language
);
221 m_lookups
.emplace_back(lookup
);
223 auto add_variant_funcs
= [&](Language
*lang
) {
224 for (Language::MethodNameVariant variant
:
225 lang
->GetMethodNameVariants(name
)) {
226 // FIXME: Should we be adding variants that aren't of type Full?
227 if (variant
.GetType() & lldb::eFunctionNameTypeFull
) {
228 Module::LookupInfo
variant_lookup(name
, variant
.GetType(),
229 lang
->GetLanguageType());
230 variant_lookup
.SetLookupName(variant
.GetName());
231 m_lookups
.emplace_back(variant_lookup
);
237 if (Language
*lang
= Language::FindPlugin(m_language
)) {
238 add_variant_funcs(lang
);
240 // Most likely m_language is eLanguageTypeUnknown. We check each language for
241 // possible variants or more qualified names and create lookups for those as
243 Language::ForEach(add_variant_funcs
);
247 // FIXME: Right now we look at the module level, and call the module's
249 // Greg says he will add function tables, maybe at the CompileUnit level to
250 // accelerate function lookup. At that point, we should switch the depth to
251 // CompileUnit, and look in these tables.
253 Searcher::CallbackReturn
254 BreakpointResolverName::SearchCallback(SearchFilter
&filter
,
255 SymbolContext
&context
, Address
*addr
) {
256 Log
*log
= GetLog(LLDBLog::Breakpoints
);
260 log
->Warning("Class/method function specification not supported yet.\n");
261 return Searcher::eCallbackReturnStop
;
264 SymbolContextList func_list
;
266 (filter
.GetFilterRequiredItems() & eSymbolContextCompUnit
) != 0;
267 bool filter_by_language
= (m_language
!= eLanguageTypeUnknown
);
269 ModuleFunctionSearchOptions function_options
;
270 function_options
.include_symbols
= !filter_by_cu
;
271 function_options
.include_inlines
= true;
273 switch (m_match_type
) {
274 case Breakpoint::Exact
:
275 if (context
.module_sp
) {
276 for (const auto &lookup
: m_lookups
) {
277 const size_t start_func_idx
= func_list
.GetSize();
278 context
.module_sp
->FindFunctions(lookup
, CompilerDeclContext(),
279 function_options
, func_list
);
281 const size_t end_func_idx
= func_list
.GetSize();
283 if (start_func_idx
< end_func_idx
)
284 lookup
.Prune(func_list
, start_func_idx
);
288 case Breakpoint::Regexp
:
289 if (context
.module_sp
) {
290 context
.module_sp
->FindFunctions(m_regex
, function_options
, func_list
);
293 case Breakpoint::Glob
:
295 log
->Warning("glob is not supported yet.");
299 // If the filter specifies a Compilation Unit, remove the ones that don't
300 // pass at this point.
301 if (filter_by_cu
|| filter_by_language
) {
302 uint32_t num_functions
= func_list
.GetSize();
304 for (size_t idx
= 0; idx
< num_functions
; idx
++) {
305 bool remove_it
= false;
307 func_list
.GetContextAtIndex(idx
, sc
);
309 if (!sc
.comp_unit
|| !filter
.CompUnitPasses(*sc
.comp_unit
))
313 if (filter_by_language
) {
314 LanguageType sym_language
= sc
.GetLanguage();
315 if ((Language::GetPrimaryLanguage(sym_language
) !=
316 Language::GetPrimaryLanguage(m_language
)) &&
317 (sym_language
!= eLanguageTypeUnknown
)) {
323 func_list
.RemoveContextAtIndex(idx
);
330 BreakpointSP breakpoint_sp
= GetBreakpoint();
331 Breakpoint
&breakpoint
= *breakpoint_sp
;
334 // Remove any duplicates between the function list and the symbol list
335 for (const SymbolContext
&sc
: func_list
) {
336 bool is_reexported
= false;
338 if (sc
.block
&& sc
.block
->GetInlinedFunctionInfo()) {
339 if (!sc
.block
->GetStartAddress(break_addr
))
341 } else if (sc
.function
) {
342 break_addr
= sc
.function
->GetAddressRange().GetBaseAddress();
343 if (m_skip_prologue
&& break_addr
.IsValid()) {
344 const uint32_t prologue_byte_size
= sc
.function
->GetPrologueByteSize();
345 if (prologue_byte_size
)
346 break_addr
.SetOffset(break_addr
.GetOffset() + prologue_byte_size
);
348 } else if (sc
.symbol
) {
349 if (sc
.symbol
->GetType() == eSymbolTypeReExported
) {
350 const Symbol
*actual_symbol
=
351 sc
.symbol
->ResolveReExportedSymbol(breakpoint
.GetTarget());
353 is_reexported
= true;
354 break_addr
= actual_symbol
->GetAddress();
357 break_addr
= sc
.symbol
->GetAddress();
360 if (m_skip_prologue
&& break_addr
.IsValid()) {
361 const uint32_t prologue_byte_size
= sc
.symbol
->GetPrologueByteSize();
362 if (prologue_byte_size
)
363 break_addr
.SetOffset(break_addr
.GetOffset() + prologue_byte_size
);
365 const Architecture
*arch
=
366 breakpoint
.GetTarget().GetArchitecturePlugin();
368 arch
->AdjustBreakpointAddress(*sc
.symbol
, break_addr
);
373 if (!break_addr
.IsValid())
376 if (!filter
.AddressPasses(break_addr
))
380 BreakpointLocationSP
bp_loc_sp(AddLocation(break_addr
, &new_location
));
381 bp_loc_sp
->SetIsReExported(is_reexported
);
382 if (bp_loc_sp
&& new_location
&& !breakpoint
.IsInternal()) {
385 bp_loc_sp
->GetDescription(&s
, lldb::eDescriptionLevelVerbose
);
386 LLDB_LOGF(log
, "Added location: %s\n", s
.GetData());
391 return Searcher::eCallbackReturnContinue
;
394 lldb::SearchDepth
BreakpointResolverName::GetDepth() {
395 return lldb::eSearchDepthModule
;
398 void BreakpointResolverName::GetDescription(Stream
*s
) {
399 if (m_match_type
== Breakpoint::Regexp
)
400 s
->Printf("regex = '%s'", m_regex
.GetText().str().c_str());
402 size_t num_names
= m_lookups
.size();
404 s
->Printf("name = '%s'", m_lookups
[0].GetName().GetCString());
406 s
->Printf("names = {");
407 for (size_t i
= 0; i
< num_names
; i
++) {
408 s
->Printf("%s'%s'", (i
== 0 ? "" : ", "),
409 m_lookups
[i
].GetName().GetCString());
414 if (m_language
!= eLanguageTypeUnknown
) {
415 s
->Printf(", language = %s", Language::GetNameForLanguageType(m_language
));
419 void BreakpointResolverName::Dump(Stream
*s
) const {}
421 lldb::BreakpointResolverSP
422 BreakpointResolverName::CopyForBreakpoint(BreakpointSP
&breakpoint
) {
423 lldb::BreakpointResolverSP
ret_sp(new BreakpointResolverName(*this));
424 ret_sp
->SetBreakpoint(breakpoint
);