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 BreakpointResolver
*BreakpointResolverName::CreateFromStructuredData(
90 const BreakpointSP
&bkpt
, const StructuredData::Dictionary
&options_dict
,
92 LanguageType language
= eLanguageTypeUnknown
;
93 llvm::StringRef language_name
;
94 bool success
= options_dict
.GetValueForKeyAsString(
95 GetKey(OptionNames::LanguageName
), language_name
);
97 language
= Language::GetLanguageTypeFromString(language_name
);
98 if (language
== eLanguageTypeUnknown
) {
99 error
.SetErrorStringWithFormatv("BRN::CFSD: Unknown language: {0}.",
105 lldb::offset_t offset
= 0;
107 options_dict
.GetValueForKeyAsInteger(GetKey(OptionNames::Offset
), offset
);
109 error
.SetErrorString("BRN::CFSD: Missing offset entry.");
114 success
= options_dict
.GetValueForKeyAsBoolean(
115 GetKey(OptionNames::SkipPrologue
), skip_prologue
);
117 error
.SetErrorString("BRN::CFSD: Missing Skip prologue entry.");
121 llvm::StringRef regex_text
;
122 success
= options_dict
.GetValueForKeyAsString(
123 GetKey(OptionNames::RegexString
), regex_text
);
125 return new BreakpointResolverName(bkpt
, RegularExpression(regex_text
),
126 language
, offset
, skip_prologue
);
128 StructuredData::Array
*names_array
;
129 success
= options_dict
.GetValueForKeyAsArray(
130 GetKey(OptionNames::SymbolNameArray
), names_array
);
132 error
.SetErrorString("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
.SetErrorString("BRN::CFSD: Missing symbol names mask entry.");
143 size_t num_elem
= names_array
->GetSize();
144 if (num_elem
!= names_mask_array
->GetSize()) {
145 error
.SetErrorString(
146 "BRN::CFSD: names and names mask arrays have different sizes.");
151 error
.SetErrorString(
152 "BRN::CFSD: no name entry in a breakpoint by name breakpoint.");
155 std::vector
<std::string
> names
;
156 std::vector
<FunctionNameType
> name_masks
;
157 for (size_t i
= 0; i
< num_elem
; i
++) {
158 llvm::StringRef name
;
160 success
= names_array
->GetItemAtIndexAsString(i
, name
);
162 error
.SetErrorString("BRN::CFSD: name entry is not a string.");
165 std::underlying_type
<FunctionNameType
>::type fnt
;
166 success
= names_mask_array
->GetItemAtIndexAsInteger(i
, fnt
);
168 error
.SetErrorString("BRN::CFSD: name mask entry is not an integer.");
171 names
.push_back(std::string(name
));
172 name_masks
.push_back(static_cast<FunctionNameType
>(fnt
));
175 BreakpointResolverName
*resolver
= new BreakpointResolverName(
176 bkpt
, names
[0].c_str(), name_masks
[0], language
,
177 Breakpoint::MatchType::Exact
, offset
, skip_prologue
);
178 for (size_t i
= 1; i
< num_elem
; i
++) {
179 resolver
->AddNameLookup(ConstString(names
[i
]), name_masks
[i
]);
185 StructuredData::ObjectSP
BreakpointResolverName::SerializeToStructuredData() {
186 StructuredData::DictionarySP
options_dict_sp(
187 new StructuredData::Dictionary());
189 if (m_regex
.IsValid()) {
190 options_dict_sp
->AddStringItem(GetKey(OptionNames::RegexString
),
193 StructuredData::ArraySP
names_sp(new StructuredData::Array());
194 StructuredData::ArraySP
name_masks_sp(new StructuredData::Array());
195 for (auto lookup
: m_lookups
) {
196 names_sp
->AddItem(StructuredData::StringSP(
197 new StructuredData::String(lookup
.GetName().GetStringRef())));
198 name_masks_sp
->AddItem(StructuredData::UnsignedIntegerSP(
199 new StructuredData::UnsignedInteger(lookup
.GetNameTypeMask())));
201 options_dict_sp
->AddItem(GetKey(OptionNames::SymbolNameArray
), names_sp
);
202 options_dict_sp
->AddItem(GetKey(OptionNames::NameMaskArray
), name_masks_sp
);
204 if (m_language
!= eLanguageTypeUnknown
)
205 options_dict_sp
->AddStringItem(
206 GetKey(OptionNames::LanguageName
),
207 Language::GetNameForLanguageType(m_language
));
208 options_dict_sp
->AddBooleanItem(GetKey(OptionNames::SkipPrologue
),
211 return WrapOptionsDict(options_dict_sp
);
214 void BreakpointResolverName::AddNameLookup(ConstString name
,
215 FunctionNameType name_type_mask
) {
217 Module::LookupInfo
lookup(name
, name_type_mask
, m_language
);
218 m_lookups
.emplace_back(lookup
);
220 auto add_variant_funcs
= [&](Language
*lang
) {
221 for (Language::MethodNameVariant variant
:
222 lang
->GetMethodNameVariants(name
)) {
223 // FIXME: Should we be adding variants that aren't of type Full?
224 if (variant
.GetType() & lldb::eFunctionNameTypeFull
) {
225 Module::LookupInfo
variant_lookup(name
, variant
.GetType(),
226 lang
->GetLanguageType());
227 variant_lookup
.SetLookupName(variant
.GetName());
228 m_lookups
.emplace_back(variant_lookup
);
234 if (Language
*lang
= Language::FindPlugin(m_language
)) {
235 add_variant_funcs(lang
);
237 // Most likely m_language is eLanguageTypeUnknown. We check each language for
238 // possible variants or more qualified names and create lookups for those as
240 Language::ForEach(add_variant_funcs
);
244 // FIXME: Right now we look at the module level, and call the module's
246 // Greg says he will add function tables, maybe at the CompileUnit level to
247 // accelerate function lookup. At that point, we should switch the depth to
248 // CompileUnit, and look in these tables.
250 Searcher::CallbackReturn
251 BreakpointResolverName::SearchCallback(SearchFilter
&filter
,
252 SymbolContext
&context
, Address
*addr
) {
253 Log
*log
= GetLog(LLDBLog::Breakpoints
);
257 log
->Warning("Class/method function specification not supported yet.\n");
258 return Searcher::eCallbackReturnStop
;
261 SymbolContextList func_list
;
263 (filter
.GetFilterRequiredItems() & eSymbolContextCompUnit
) != 0;
264 bool filter_by_language
= (m_language
!= eLanguageTypeUnknown
);
266 ModuleFunctionSearchOptions function_options
;
267 function_options
.include_symbols
= !filter_by_cu
;
268 function_options
.include_inlines
= true;
270 switch (m_match_type
) {
271 case Breakpoint::Exact
:
272 if (context
.module_sp
) {
273 for (const auto &lookup
: m_lookups
) {
274 const size_t start_func_idx
= func_list
.GetSize();
275 context
.module_sp
->FindFunctions(lookup
, CompilerDeclContext(),
276 function_options
, func_list
);
278 const size_t end_func_idx
= func_list
.GetSize();
280 if (start_func_idx
< end_func_idx
)
281 lookup
.Prune(func_list
, start_func_idx
);
285 case Breakpoint::Regexp
:
286 if (context
.module_sp
) {
287 context
.module_sp
->FindFunctions(m_regex
, function_options
, func_list
);
290 case Breakpoint::Glob
:
292 log
->Warning("glob is not supported yet.");
296 // If the filter specifies a Compilation Unit, remove the ones that don't
297 // pass at this point.
298 if (filter_by_cu
|| filter_by_language
) {
299 uint32_t num_functions
= func_list
.GetSize();
301 for (size_t idx
= 0; idx
< num_functions
; idx
++) {
302 bool remove_it
= false;
304 func_list
.GetContextAtIndex(idx
, sc
);
306 if (!sc
.comp_unit
|| !filter
.CompUnitPasses(*sc
.comp_unit
))
310 if (filter_by_language
) {
311 LanguageType sym_language
= sc
.GetLanguage();
312 if ((Language::GetPrimaryLanguage(sym_language
) !=
313 Language::GetPrimaryLanguage(m_language
)) &&
314 (sym_language
!= eLanguageTypeUnknown
)) {
320 func_list
.RemoveContextAtIndex(idx
);
327 BreakpointSP breakpoint_sp
= GetBreakpoint();
328 Breakpoint
&breakpoint
= *breakpoint_sp
;
331 // Remove any duplicates between the function list and the symbol list
332 for (const SymbolContext
&sc
: func_list
) {
333 bool is_reexported
= false;
335 if (sc
.block
&& sc
.block
->GetInlinedFunctionInfo()) {
336 if (!sc
.block
->GetStartAddress(break_addr
))
338 } else if (sc
.function
) {
339 break_addr
= sc
.function
->GetAddressRange().GetBaseAddress();
340 if (m_skip_prologue
&& break_addr
.IsValid()) {
341 const uint32_t prologue_byte_size
= sc
.function
->GetPrologueByteSize();
342 if (prologue_byte_size
)
343 break_addr
.SetOffset(break_addr
.GetOffset() + prologue_byte_size
);
345 } else if (sc
.symbol
) {
346 if (sc
.symbol
->GetType() == eSymbolTypeReExported
) {
347 const Symbol
*actual_symbol
=
348 sc
.symbol
->ResolveReExportedSymbol(breakpoint
.GetTarget());
350 is_reexported
= true;
351 break_addr
= actual_symbol
->GetAddress();
354 break_addr
= sc
.symbol
->GetAddress();
357 if (m_skip_prologue
&& break_addr
.IsValid()) {
358 const uint32_t prologue_byte_size
= sc
.symbol
->GetPrologueByteSize();
359 if (prologue_byte_size
)
360 break_addr
.SetOffset(break_addr
.GetOffset() + prologue_byte_size
);
362 const Architecture
*arch
=
363 breakpoint
.GetTarget().GetArchitecturePlugin();
365 arch
->AdjustBreakpointAddress(*sc
.symbol
, break_addr
);
370 if (!break_addr
.IsValid())
373 if (!filter
.AddressPasses(break_addr
))
377 BreakpointLocationSP
bp_loc_sp(AddLocation(break_addr
, &new_location
));
378 bp_loc_sp
->SetIsReExported(is_reexported
);
379 if (bp_loc_sp
&& new_location
&& !breakpoint
.IsInternal()) {
382 bp_loc_sp
->GetDescription(&s
, lldb::eDescriptionLevelVerbose
);
383 LLDB_LOGF(log
, "Added location: %s\n", s
.GetData());
388 return Searcher::eCallbackReturnContinue
;
391 lldb::SearchDepth
BreakpointResolverName::GetDepth() {
392 return lldb::eSearchDepthModule
;
395 void BreakpointResolverName::GetDescription(Stream
*s
) {
396 if (m_match_type
== Breakpoint::Regexp
)
397 s
->Printf("regex = '%s'", m_regex
.GetText().str().c_str());
399 size_t num_names
= m_lookups
.size();
401 s
->Printf("name = '%s'", m_lookups
[0].GetName().GetCString());
403 s
->Printf("names = {");
404 for (size_t i
= 0; i
< num_names
; i
++) {
405 s
->Printf("%s'%s'", (i
== 0 ? "" : ", "),
406 m_lookups
[i
].GetName().GetCString());
411 if (m_language
!= eLanguageTypeUnknown
) {
412 s
->Printf(", language = %s", Language::GetNameForLanguageType(m_language
));
416 void BreakpointResolverName::Dump(Stream
*s
) const {}
418 lldb::BreakpointResolverSP
419 BreakpointResolverName::CopyForBreakpoint(BreakpointSP
&breakpoint
) {
420 lldb::BreakpointResolverSP
ret_sp(new BreakpointResolverName(*this));
421 ret_sp
->SetBreakpoint(breakpoint
);