/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Breakpoint/BreakpointResolverName.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- BreakpointResolverName.cpp ----------------------------------------===// |
2 | | // |
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 |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "lldb/Breakpoint/BreakpointResolverName.h" |
10 | | |
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" |
23 | | |
24 | | using namespace lldb; |
25 | | using namespace lldb_private; |
26 | | |
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, |
30 | | bool skip_prologue) |
31 | 5.75k | : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset), |
32 | 5.75k | m_match_type(type), m_language(language), m_skip_prologue(skip_prologue) { |
33 | 5.75k | if (m_match_type == Breakpoint::Regexp) { |
34 | 0 | m_regex = RegularExpression(name_cstr); |
35 | 0 | if (!m_regex.IsValid()) { |
36 | 0 | Log *log = GetLog(LLDBLog::Breakpoints); |
37 | |
|
38 | 0 | if (log) |
39 | 0 | log->Warning("function name regexp: \"%s\" did not compile.", |
40 | 0 | name_cstr); |
41 | 0 | } |
42 | 5.75k | } else { |
43 | 5.75k | AddNameLookup(ConstString(name_cstr), name_type_mask); |
44 | 5.75k | } |
45 | 5.75k | } |
46 | | |
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, |
50 | | bool skip_prologue) |
51 | 2.09k | : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset), |
52 | 2.09k | m_match_type(Breakpoint::Exact), m_language(language), |
53 | 2.09k | m_skip_prologue(skip_prologue) { |
54 | 8.36k | for (size_t i = 0; i < num_names; i++6.27k ) { |
55 | 6.27k | AddNameLookup(ConstString(names[i]), name_type_mask); |
56 | 6.27k | } |
57 | 2.09k | } |
58 | | |
59 | | BreakpointResolverName::BreakpointResolverName( |
60 | | const BreakpointSP &bkpt, const std::vector<std::string> &names, |
61 | | FunctionNameType name_type_mask, LanguageType language, lldb::addr_t offset, |
62 | | bool skip_prologue) |
63 | 163 | : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset), |
64 | 163 | m_match_type(Breakpoint::Exact), m_language(language), |
65 | 163 | m_skip_prologue(skip_prologue) { |
66 | 168 | for (const std::string &name : names) { |
67 | 168 | AddNameLookup(ConstString(name.c_str(), name.size()), name_type_mask); |
68 | 168 | } |
69 | 163 | } |
70 | | |
71 | | BreakpointResolverName::BreakpointResolverName(const BreakpointSP &bkpt, |
72 | | RegularExpression func_regex, |
73 | | lldb::LanguageType language, |
74 | | lldb::addr_t offset, |
75 | | bool skip_prologue) |
76 | 15 | : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset), |
77 | 15 | m_class_name(nullptr), m_regex(std::move(func_regex)), |
78 | 15 | m_match_type(Breakpoint::Regexp), m_language(language), |
79 | 15 | m_skip_prologue(skip_prologue) {} |
80 | | |
81 | | BreakpointResolverName::BreakpointResolverName( |
82 | | const BreakpointResolverName &rhs) |
83 | 1 | : BreakpointResolver(rhs.GetBreakpoint(), BreakpointResolver::NameResolver, |
84 | 1 | rhs.GetOffset()), |
85 | 1 | m_lookups(rhs.m_lookups), m_class_name(rhs.m_class_name), |
86 | 1 | m_regex(rhs.m_regex), m_match_type(rhs.m_match_type), |
87 | 1 | m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {} |
88 | | |
89 | | BreakpointResolverSP BreakpointResolverName::CreateFromStructuredData( |
90 | | const BreakpointSP &bkpt, const StructuredData::Dictionary &options_dict, |
91 | 9 | Status &error) { |
92 | 9 | LanguageType language = eLanguageTypeUnknown; |
93 | 9 | llvm::StringRef language_name; |
94 | 9 | bool success = options_dict.GetValueForKeyAsString( |
95 | 9 | GetKey(OptionNames::LanguageName), language_name); |
96 | 9 | if (success) { |
97 | 0 | language = Language::GetLanguageTypeFromString(language_name); |
98 | 0 | if (language == eLanguageTypeUnknown) { |
99 | 0 | error.SetErrorStringWithFormatv("BRN::CFSD: Unknown language: {0}.", |
100 | 0 | language_name); |
101 | 0 | return nullptr; |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 9 | lldb::offset_t offset = 0; |
106 | 9 | success = |
107 | 9 | options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Offset), offset); |
108 | 9 | if (!success) { |
109 | 0 | error.SetErrorString("BRN::CFSD: Missing offset entry."); |
110 | 0 | return nullptr; |
111 | 0 | } |
112 | | |
113 | 9 | bool skip_prologue; |
114 | 9 | success = options_dict.GetValueForKeyAsBoolean( |
115 | 9 | GetKey(OptionNames::SkipPrologue), skip_prologue); |
116 | 9 | if (!success) { |
117 | 0 | error.SetErrorString("BRN::CFSD: Missing Skip prologue entry."); |
118 | 0 | return nullptr; |
119 | 0 | } |
120 | | |
121 | 9 | llvm::StringRef regex_text; |
122 | 9 | success = options_dict.GetValueForKeyAsString( |
123 | 9 | GetKey(OptionNames::RegexString), regex_text); |
124 | 9 | if (success) { |
125 | 0 | return std::make_shared<BreakpointResolverName>( |
126 | 0 | bkpt, RegularExpression(regex_text), language, offset, skip_prologue); |
127 | 9 | } else { |
128 | 9 | StructuredData::Array *names_array; |
129 | 9 | success = options_dict.GetValueForKeyAsArray( |
130 | 9 | GetKey(OptionNames::SymbolNameArray), names_array); |
131 | 9 | if (!success) { |
132 | 0 | error.SetErrorString("BRN::CFSD: Missing symbol names entry."); |
133 | 0 | return nullptr; |
134 | 0 | } |
135 | 9 | StructuredData::Array *names_mask_array; |
136 | 9 | success = options_dict.GetValueForKeyAsArray( |
137 | 9 | GetKey(OptionNames::NameMaskArray), names_mask_array); |
138 | 9 | if (!success) { |
139 | 0 | error.SetErrorString("BRN::CFSD: Missing symbol names mask entry."); |
140 | 0 | return nullptr; |
141 | 0 | } |
142 | | |
143 | 9 | size_t num_elem = names_array->GetSize(); |
144 | 9 | if (num_elem != names_mask_array->GetSize()) { |
145 | 0 | error.SetErrorString( |
146 | 0 | "BRN::CFSD: names and names mask arrays have different sizes."); |
147 | 0 | return nullptr; |
148 | 0 | } |
149 | | |
150 | 9 | if (num_elem == 0) { |
151 | 0 | error.SetErrorString( |
152 | 0 | "BRN::CFSD: no name entry in a breakpoint by name breakpoint."); |
153 | 0 | return nullptr; |
154 | 0 | } |
155 | 9 | std::vector<std::string> names; |
156 | 9 | std::vector<FunctionNameType> name_masks; |
157 | 18 | for (size_t i = 0; i < num_elem; i++9 ) { |
158 | 9 | std::optional<llvm::StringRef> maybe_name = |
159 | 9 | names_array->GetItemAtIndexAsString(i); |
160 | 9 | if (!maybe_name) { |
161 | 0 | error.SetErrorString("BRN::CFSD: name entry is not a string."); |
162 | 0 | return nullptr; |
163 | 0 | } |
164 | 9 | std::underlying_type<FunctionNameType>::type fnt; |
165 | 9 | success = names_mask_array->GetItemAtIndexAsInteger(i, fnt); |
166 | 9 | if (!success) { |
167 | 0 | error.SetErrorString("BRN::CFSD: name mask entry is not an integer."); |
168 | 0 | return nullptr; |
169 | 0 | } |
170 | 9 | names.push_back(std::string(*maybe_name)); |
171 | 9 | name_masks.push_back(static_cast<FunctionNameType>(fnt)); |
172 | 9 | } |
173 | | |
174 | 9 | std::shared_ptr<BreakpointResolverName> resolver_sp = |
175 | 9 | std::make_shared<BreakpointResolverName>( |
176 | 9 | bkpt, names[0].c_str(), name_masks[0], language, |
177 | 9 | Breakpoint::MatchType::Exact, offset, skip_prologue); |
178 | 9 | for (size_t i = 1; i < num_elem; i++0 ) { |
179 | 0 | resolver_sp->AddNameLookup(ConstString(names[i]), name_masks[i]); |
180 | 0 | } |
181 | 9 | return resolver_sp; |
182 | 9 | } |
183 | 9 | } |
184 | | |
185 | 29 | StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() { |
186 | 29 | StructuredData::DictionarySP options_dict_sp( |
187 | 29 | new StructuredData::Dictionary()); |
188 | | |
189 | 29 | if (m_regex.IsValid()) { |
190 | 0 | options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString), |
191 | 0 | m_regex.GetText()); |
192 | 29 | } else { |
193 | 29 | StructuredData::ArraySP names_sp(new StructuredData::Array()); |
194 | 29 | StructuredData::ArraySP name_masks_sp(new StructuredData::Array()); |
195 | 41 | for (auto lookup : m_lookups) { |
196 | 41 | names_sp->AddItem(StructuredData::StringSP( |
197 | 41 | new StructuredData::String(lookup.GetName().GetStringRef()))); |
198 | 41 | name_masks_sp->AddItem(StructuredData::UnsignedIntegerSP( |
199 | 41 | new StructuredData::UnsignedInteger(lookup.GetNameTypeMask()))); |
200 | 41 | } |
201 | 29 | options_dict_sp->AddItem(GetKey(OptionNames::SymbolNameArray), names_sp); |
202 | 29 | options_dict_sp->AddItem(GetKey(OptionNames::NameMaskArray), name_masks_sp); |
203 | 29 | } |
204 | 29 | if (m_language != eLanguageTypeUnknown) |
205 | 0 | options_dict_sp->AddStringItem( |
206 | 0 | GetKey(OptionNames::LanguageName), |
207 | 0 | Language::GetNameForLanguageType(m_language)); |
208 | 29 | options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue), |
209 | 29 | m_skip_prologue); |
210 | | |
211 | 29 | return WrapOptionsDict(options_dict_sp); |
212 | 29 | } |
213 | | |
214 | | void BreakpointResolverName::AddNameLookup(ConstString name, |
215 | 12.1k | FunctionNameType name_type_mask) { |
216 | | |
217 | 12.1k | Module::LookupInfo lookup(name, name_type_mask, m_language); |
218 | 12.1k | m_lookups.emplace_back(lookup); |
219 | | |
220 | 97.4k | auto add_variant_funcs = [&](Language *lang) { |
221 | 97.4k | for (Language::MethodNameVariant variant : |
222 | 97.4k | lang->GetMethodNameVariants(name)) { |
223 | | // FIXME: Should we be adding variants that aren't of type Full? |
224 | 43 | if (variant.GetType() & lldb::eFunctionNameTypeFull) { |
225 | 12 | Module::LookupInfo variant_lookup(name, variant.GetType(), |
226 | 12 | lang->GetLanguageType()); |
227 | 12 | variant_lookup.SetLookupName(variant.GetName()); |
228 | 12 | m_lookups.emplace_back(variant_lookup); |
229 | 12 | } |
230 | 43 | } |
231 | 97.4k | return true; |
232 | 97.4k | }; |
233 | | |
234 | 12.1k | if (Language *lang = Language::FindPlugin(m_language)) { |
235 | 12 | add_variant_funcs(lang); |
236 | 12.1k | } else { |
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 |
239 | | // well. |
240 | 12.1k | Language::ForEach(add_variant_funcs); |
241 | 12.1k | } |
242 | 12.1k | } |
243 | | |
244 | | // FIXME: Right now we look at the module level, and call the module's |
245 | | // "FindFunctions". |
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. |
249 | | |
250 | | Searcher::CallbackReturn |
251 | | BreakpointResolverName::SearchCallback(SearchFilter &filter, |
252 | 42.5k | SymbolContext &context, Address *addr) { |
253 | 42.5k | Log *log = GetLog(LLDBLog::Breakpoints); |
254 | | |
255 | 42.5k | if (m_class_name) { |
256 | 0 | if (log) |
257 | 0 | log->Warning("Class/method function specification not supported yet.\n"); |
258 | 0 | return Searcher::eCallbackReturnStop; |
259 | 0 | } |
260 | | |
261 | 42.5k | SymbolContextList func_list; |
262 | 42.5k | bool filter_by_cu = |
263 | 42.5k | (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0; |
264 | 42.5k | bool filter_by_language = (m_language != eLanguageTypeUnknown); |
265 | | |
266 | 42.5k | ModuleFunctionSearchOptions function_options; |
267 | 42.5k | function_options.include_symbols = !filter_by_cu; |
268 | 42.5k | function_options.include_inlines = true; |
269 | | |
270 | 42.5k | switch (m_match_type) { |
271 | 42.1k | case Breakpoint::Exact: |
272 | 42.1k | if (context.module_sp) { |
273 | 54.0k | for (const auto &lookup : m_lookups) { |
274 | 54.0k | const size_t start_func_idx = func_list.GetSize(); |
275 | 54.0k | context.module_sp->FindFunctions(lookup, CompilerDeclContext(), |
276 | 54.0k | function_options, func_list); |
277 | | |
278 | 54.0k | const size_t end_func_idx = func_list.GetSize(); |
279 | | |
280 | 54.0k | if (start_func_idx < end_func_idx) |
281 | 9.76k | lookup.Prune(func_list, start_func_idx); |
282 | 54.0k | } |
283 | 42.1k | } |
284 | 42.1k | break; |
285 | 381 | case Breakpoint::Regexp: |
286 | 381 | if (context.module_sp) { |
287 | 381 | context.module_sp->FindFunctions(m_regex, function_options, func_list); |
288 | 381 | } |
289 | 381 | break; |
290 | 0 | case Breakpoint::Glob: |
291 | 0 | if (log) |
292 | 0 | log->Warning("glob is not supported yet."); |
293 | 0 | break; |
294 | 42.5k | } |
295 | | |
296 | | // If the filter specifies a Compilation Unit, remove the ones that don't |
297 | | // pass at this point. |
298 | 42.5k | if (filter_by_cu || filter_by_language42.2k ) { |
299 | 297 | uint32_t num_functions = func_list.GetSize(); |
300 | | |
301 | 379 | for (size_t idx = 0; idx < num_functions; idx++82 ) { |
302 | 82 | bool remove_it = false; |
303 | 82 | SymbolContext sc; |
304 | 82 | func_list.GetContextAtIndex(idx, sc); |
305 | 82 | if (filter_by_cu) { |
306 | 38 | if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit)) |
307 | 1 | remove_it = true; |
308 | 38 | } |
309 | | |
310 | 82 | if (filter_by_language) { |
311 | 44 | LanguageType sym_language = sc.GetLanguage(); |
312 | 44 | if ((Language::GetPrimaryLanguage(sym_language) != |
313 | 44 | Language::GetPrimaryLanguage(m_language)) && |
314 | 44 | (sym_language != eLanguageTypeUnknown)28 ) { |
315 | 28 | remove_it = true; |
316 | 28 | } |
317 | 44 | } |
318 | | |
319 | 82 | if (remove_it) { |
320 | 29 | func_list.RemoveContextAtIndex(idx); |
321 | 29 | num_functions--; |
322 | 29 | idx--; |
323 | 29 | } |
324 | 82 | } |
325 | 297 | } |
326 | | |
327 | 42.5k | BreakpointSP breakpoint_sp = GetBreakpoint(); |
328 | 42.5k | Breakpoint &breakpoint = *breakpoint_sp; |
329 | 42.5k | Address break_addr; |
330 | | |
331 | | // Remove any duplicates between the function list and the symbol list |
332 | 42.5k | for (const SymbolContext &sc : func_list) { |
333 | 10.9k | bool is_reexported = false; |
334 | | |
335 | 10.9k | if (sc.block && sc.block->GetInlinedFunctionInfo()15 ) { |
336 | 15 | if (!sc.block->GetStartAddress(break_addr)) |
337 | 0 | break_addr.Clear(); |
338 | 10.9k | } else if (sc.function) { |
339 | 574 | break_addr = sc.function->GetAddressRange().GetBaseAddress(); |
340 | 574 | if (m_skip_prologue && break_addr.IsValid()549 ) { |
341 | 549 | const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); |
342 | 549 | if (prologue_byte_size) |
343 | 541 | break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); |
344 | 549 | } |
345 | 10.3k | } else if (sc.symbol) { |
346 | 10.3k | if (sc.symbol->GetType() == eSymbolTypeReExported) { |
347 | 2 | const Symbol *actual_symbol = |
348 | 2 | sc.symbol->ResolveReExportedSymbol(breakpoint.GetTarget()); |
349 | 2 | if (actual_symbol) { |
350 | 2 | is_reexported = true; |
351 | 2 | break_addr = actual_symbol->GetAddress(); |
352 | 2 | } |
353 | 10.3k | } else { |
354 | 10.3k | break_addr = sc.symbol->GetAddress(); |
355 | 10.3k | } |
356 | | |
357 | 10.3k | if (m_skip_prologue && break_addr.IsValid()1.26k ) { |
358 | 1.26k | const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize(); |
359 | 1.26k | if (prologue_byte_size) |
360 | 44 | break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); |
361 | 1.22k | else { |
362 | 1.22k | const Architecture *arch = |
363 | 1.22k | breakpoint.GetTarget().GetArchitecturePlugin(); |
364 | 1.22k | if (arch) |
365 | 0 | arch->AdjustBreakpointAddress(*sc.symbol, break_addr); |
366 | 1.22k | } |
367 | 1.26k | } |
368 | 10.3k | } |
369 | | |
370 | 10.9k | if (!break_addr.IsValid()) |
371 | 0 | continue; |
372 | | |
373 | 10.9k | if (!filter.AddressPasses(break_addr)) |
374 | 0 | continue; |
375 | | |
376 | 10.9k | bool new_location; |
377 | 10.9k | BreakpointLocationSP bp_loc_sp(AddLocation(break_addr, &new_location)); |
378 | 10.9k | bp_loc_sp->SetIsReExported(is_reexported); |
379 | 10.9k | if (bp_loc_sp && new_location && !breakpoint.IsInternal()10.9k ) { |
380 | 1.88k | if (log) { |
381 | 0 | StreamString s; |
382 | 0 | bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); |
383 | 0 | LLDB_LOGF(log, "Added location: %s\n", s.GetData()); |
384 | 0 | } |
385 | 1.88k | } |
386 | 10.9k | } |
387 | | |
388 | 42.5k | return Searcher::eCallbackReturnContinue; |
389 | 42.5k | } |
390 | | |
391 | 71.4k | lldb::SearchDepth BreakpointResolverName::GetDepth() { |
392 | 71.4k | return lldb::eSearchDepthModule; |
393 | 71.4k | } |
394 | | |
395 | 92 | void BreakpointResolverName::GetDescription(Stream *s) { |
396 | 92 | if (m_match_type == Breakpoint::Regexp) |
397 | 6 | s->Printf("regex = '%s'", m_regex.GetText().str().c_str()); |
398 | 86 | else { |
399 | 86 | size_t num_names = m_lookups.size(); |
400 | 86 | if (num_names == 1) |
401 | 86 | s->Printf("name = '%s'", m_lookups[0].GetName().GetCString()); |
402 | 0 | else { |
403 | 0 | s->Printf("names = {"); |
404 | 0 | for (size_t i = 0; i < num_names; i++) { |
405 | 0 | s->Printf("%s'%s'", (i == 0 ? "" : ", "), |
406 | 0 | m_lookups[i].GetName().GetCString()); |
407 | 0 | } |
408 | 0 | s->Printf("}"); |
409 | 0 | } |
410 | 86 | } |
411 | 92 | if (m_language != eLanguageTypeUnknown) { |
412 | 0 | s->Printf(", language = %s", Language::GetNameForLanguageType(m_language)); |
413 | 0 | } |
414 | 92 | } |
415 | | |
416 | 0 | void BreakpointResolverName::Dump(Stream *s) const {} |
417 | | |
418 | | lldb::BreakpointResolverSP |
419 | 1 | BreakpointResolverName::CopyForBreakpoint(BreakpointSP &breakpoint) { |
420 | 1 | lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this)); |
421 | 1 | ret_sp->SetBreakpoint(breakpoint); |
422 | 1 | return ret_sp; |
423 | 1 | } |