1 | //===-- SearchFilter.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/Core/SearchFilter.h" |
10 | |
11 | #include "lldb/Breakpoint/Breakpoint.h" |
12 | #include "lldb/Core/Module.h" |
13 | #include "lldb/Core/ModuleList.h" |
14 | #include "lldb/Symbol/CompileUnit.h" |
15 | #include "lldb/Symbol/SymbolContext.h" |
16 | #include "lldb/Symbol/SymbolFile.h" |
17 | #include "lldb/Target/Target.h" |
18 | #include "lldb/Utility/ConstString.h" |
19 | #include "lldb/Utility/Status.h" |
20 | #include "lldb/Utility/Stream.h" |
21 | #include "lldb/lldb-enumerations.h" |
22 | |
23 | #include "llvm/ADT/StringRef.h" |
24 | #include "llvm/Support/ErrorHandling.h" |
25 | |
26 | #include <memory> |
27 | #include <mutex> |
28 | #include <string> |
29 | |
30 | #include <cinttypes> |
31 | #include <cstring> |
32 | |
33 | namespace lldb_private { |
34 | class Address; |
35 | } |
36 | namespace lldb_private { |
37 | class Function; |
38 | } |
39 | |
40 | using namespace lldb; |
41 | using namespace lldb_private; |
42 | |
43 | const char *SearchFilter::g_ty_to_name[] = {"Unconstrained" , "Exception" , |
44 | "Module" , "Modules" , |
45 | "ModulesAndCU" , "Unknown" }; |
46 | |
47 | const char |
48 | *SearchFilter::g_option_names[SearchFilter::OptionNames::LastOptionName] = { |
49 | "ModuleList" , "CUList" }; |
50 | |
51 | const char *SearchFilter::FilterTyToName(enum FilterTy type) { |
52 | if (type > LastKnownFilterType) |
53 | return g_ty_to_name[UnknownFilter]; |
54 | |
55 | return g_ty_to_name[type]; |
56 | } |
57 | |
58 | SearchFilter::FilterTy SearchFilter::NameToFilterTy(llvm::StringRef name) { |
59 | for (size_t i = 0; i <= LastKnownFilterType; i++) { |
60 | if (name == g_ty_to_name[i]) |
61 | return (FilterTy)i; |
62 | } |
63 | return UnknownFilter; |
64 | } |
65 | |
66 | Searcher::Searcher() = default; |
67 | |
68 | Searcher::~Searcher() = default; |
69 | |
70 | void Searcher::GetDescription(Stream *s) {} |
71 | |
72 | SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType) |
73 | : m_target_sp(target_sp), SubclassID(filterType) {} |
74 | |
75 | SearchFilter::~SearchFilter() = default; |
76 | |
77 | SearchFilterSP SearchFilter::CreateFromStructuredData( |
78 | const lldb::TargetSP& target_sp, |
79 | const StructuredData::Dictionary &filter_dict, |
80 | Status &error) { |
81 | SearchFilterSP result_sp; |
82 | if (!filter_dict.IsValid()) { |
83 | error = Status::FromErrorString( |
84 | str: "Can't deserialize from an invalid data object." ); |
85 | return result_sp; |
86 | } |
87 | |
88 | llvm::StringRef subclass_name; |
89 | |
90 | bool success = filter_dict.GetValueForKeyAsString( |
91 | key: GetSerializationSubclassKey(), result&: subclass_name); |
92 | if (!success) { |
93 | error = Status::FromErrorString(str: "Filter data missing subclass key" ); |
94 | return result_sp; |
95 | } |
96 | |
97 | FilterTy filter_type = NameToFilterTy(name: subclass_name); |
98 | if (filter_type == UnknownFilter) { |
99 | error = Status::FromErrorStringWithFormatv(format: "Unknown filter type: {0}." , |
100 | args&: subclass_name); |
101 | return result_sp; |
102 | } |
103 | |
104 | StructuredData::Dictionary *subclass_options = nullptr; |
105 | success = filter_dict.GetValueForKeyAsDictionary( |
106 | key: GetSerializationSubclassOptionsKey(), result&: subclass_options); |
107 | if (!success || !subclass_options || !subclass_options->IsValid()) { |
108 | error = |
109 | Status::FromErrorString(str: "Filter data missing subclass options key." ); |
110 | return result_sp; |
111 | } |
112 | |
113 | switch (filter_type) { |
114 | case Unconstrained: |
115 | result_sp = SearchFilterForUnconstrainedSearches::CreateFromStructuredData( |
116 | target_sp, data_dict: *subclass_options, error); |
117 | break; |
118 | case ByModule: |
119 | result_sp = SearchFilterByModule::CreateFromStructuredData( |
120 | target_sp, data_dict: *subclass_options, error); |
121 | break; |
122 | case ByModules: |
123 | result_sp = SearchFilterByModuleList::CreateFromStructuredData( |
124 | target_sp, data_dict: *subclass_options, error); |
125 | break; |
126 | case ByModulesAndCU: |
127 | result_sp = SearchFilterByModuleListAndCU::CreateFromStructuredData( |
128 | target_sp, data_dict: *subclass_options, error); |
129 | break; |
130 | case Exception: |
131 | error = |
132 | Status::FromErrorString(str: "Can't serialize exception breakpoints yet." ); |
133 | break; |
134 | default: |
135 | llvm_unreachable("Should never get an uresolvable filter type." ); |
136 | } |
137 | |
138 | return result_sp; |
139 | } |
140 | |
141 | bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; } |
142 | |
143 | bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; } |
144 | |
145 | bool SearchFilter::AddressPasses(Address &address) { return true; } |
146 | |
147 | bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; } |
148 | |
149 | bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; } |
150 | |
151 | bool SearchFilter::FunctionPasses(Function &function) { |
152 | // This is a slightly cheesy job, but since we don't have finer grained |
153 | // filters yet, just checking that the start address passes is probably |
154 | // good enough for the base class behavior. |
155 | Address addr = function.GetAddress(); |
156 | return AddressPasses(address&: addr); |
157 | } |
158 | |
159 | |
160 | uint32_t SearchFilter::GetFilterRequiredItems() { |
161 | return (lldb::SymbolContextItem)0; |
162 | } |
163 | |
164 | void SearchFilter::GetDescription(Stream *s) {} |
165 | |
166 | void SearchFilter::Dump(Stream *s) const {} |
167 | |
168 | lldb::SearchFilterSP SearchFilter::CreateCopy(lldb::TargetSP& target_sp) { |
169 | SearchFilterSP ret_sp = DoCreateCopy(); |
170 | ret_sp->SetTarget(target_sp); |
171 | return ret_sp; |
172 | } |
173 | |
174 | // Helper functions for serialization. |
175 | |
176 | StructuredData::DictionarySP |
177 | SearchFilter::WrapOptionsDict(StructuredData::DictionarySP options_dict_sp) { |
178 | if (!options_dict_sp || !options_dict_sp->IsValid()) |
179 | return StructuredData::DictionarySP(); |
180 | |
181 | auto type_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
182 | type_dict_sp->AddStringItem(key: GetSerializationSubclassKey(), value: GetFilterName()); |
183 | type_dict_sp->AddItem(key: GetSerializationSubclassOptionsKey(), value_sp: options_dict_sp); |
184 | |
185 | return type_dict_sp; |
186 | } |
187 | |
188 | void SearchFilter::SerializeFileSpecList( |
189 | StructuredData::DictionarySP &options_dict_sp, OptionNames name, |
190 | FileSpecList &file_list) { |
191 | size_t num_modules = file_list.GetSize(); |
192 | |
193 | // Don't serialize empty lists. |
194 | if (num_modules == 0) |
195 | return; |
196 | |
197 | auto module_array_sp = std::make_shared<StructuredData::Array>(); |
198 | for (size_t i = 0; i < num_modules; i++) { |
199 | module_array_sp->AddItem(item: std::make_shared<StructuredData::String>( |
200 | args: file_list.GetFileSpecAtIndex(idx: i).GetPath())); |
201 | } |
202 | options_dict_sp->AddItem(key: GetKey(enum_value: name), value_sp: module_array_sp); |
203 | } |
204 | |
205 | // UTILITY Functions to help iterate down through the elements of the |
206 | // SymbolContext. |
207 | |
208 | void SearchFilter::Search(Searcher &searcher) { |
209 | SymbolContext empty_sc; |
210 | |
211 | if (!m_target_sp) |
212 | return; |
213 | empty_sc.target_sp = m_target_sp; |
214 | |
215 | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
216 | searcher.SearchCallback(filter&: *this, context&: empty_sc, addr: nullptr); |
217 | return; |
218 | } |
219 | |
220 | DoModuleIteration(context: empty_sc, searcher); |
221 | } |
222 | |
223 | void SearchFilter::SearchInModuleList(Searcher &searcher, ModuleList &modules) { |
224 | SymbolContext empty_sc; |
225 | |
226 | if (!m_target_sp) |
227 | return; |
228 | empty_sc.target_sp = m_target_sp; |
229 | |
230 | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
231 | searcher.SearchCallback(filter&: *this, context&: empty_sc, addr: nullptr); |
232 | return; |
233 | } |
234 | |
235 | for (ModuleSP module_sp : modules.Modules()) { |
236 | if (!ModulePasses(module_sp)) |
237 | continue; |
238 | if (DoModuleIteration(module_sp, searcher) == Searcher::eCallbackReturnStop) |
239 | return; |
240 | } |
241 | } |
242 | |
243 | Searcher::CallbackReturn |
244 | SearchFilter::DoModuleIteration(const lldb::ModuleSP &module_sp, |
245 | Searcher &searcher) { |
246 | SymbolContext matchingContext(m_target_sp, module_sp); |
247 | return DoModuleIteration(context: matchingContext, searcher); |
248 | } |
249 | |
250 | Searcher::CallbackReturn |
251 | SearchFilter::DoModuleIteration(const SymbolContext &context, |
252 | Searcher &searcher) { |
253 | if (searcher.GetDepth() < lldb::eSearchDepthModule) |
254 | return Searcher::eCallbackReturnContinue; |
255 | |
256 | if (context.module_sp) { |
257 | if (searcher.GetDepth() != lldb::eSearchDepthModule) |
258 | return DoCUIteration(module_sp: context.module_sp, context, searcher); |
259 | |
260 | SymbolContext matchingContext(context.module_sp.get()); |
261 | searcher.SearchCallback(filter&: *this, context&: matchingContext, addr: nullptr); |
262 | return Searcher::eCallbackReturnContinue; |
263 | } |
264 | |
265 | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
266 | // If this is the last level supplied, then call the callback directly, |
267 | // otherwise descend. |
268 | if (!ModulePasses(module_sp)) |
269 | continue; |
270 | |
271 | if (searcher.GetDepth() == lldb::eSearchDepthModule) { |
272 | SymbolContext matchingContext(m_target_sp, module_sp); |
273 | |
274 | Searcher::CallbackReturn shouldContinue = |
275 | searcher.SearchCallback(filter&: *this, context&: matchingContext, addr: nullptr); |
276 | if (shouldContinue == Searcher::eCallbackReturnStop || |
277 | shouldContinue == Searcher::eCallbackReturnPop) |
278 | return shouldContinue; |
279 | } else { |
280 | Searcher::CallbackReturn shouldContinue = |
281 | DoCUIteration(module_sp, context, searcher); |
282 | if (shouldContinue == Searcher::eCallbackReturnStop) |
283 | return shouldContinue; |
284 | else if (shouldContinue == Searcher::eCallbackReturnPop) |
285 | continue; |
286 | } |
287 | } |
288 | |
289 | return Searcher::eCallbackReturnContinue; |
290 | } |
291 | |
292 | Searcher::CallbackReturn |
293 | SearchFilter::DoCUIteration(const ModuleSP &module_sp, |
294 | const SymbolContext &context, Searcher &searcher) { |
295 | Searcher::CallbackReturn shouldContinue; |
296 | if (context.comp_unit != nullptr) { |
297 | if (CompUnitPasses(compUnit&: *context.comp_unit)) { |
298 | SymbolContext matchingContext(m_target_sp, module_sp, context.comp_unit); |
299 | return searcher.SearchCallback(filter&: *this, context&: matchingContext, addr: nullptr); |
300 | } |
301 | return Searcher::eCallbackReturnContinue; |
302 | } |
303 | |
304 | const size_t num_comp_units = module_sp->GetNumCompileUnits(); |
305 | for (size_t i = 0; i < num_comp_units; i++) { |
306 | CompUnitSP cu_sp(module_sp->GetCompileUnitAtIndex(idx: i)); |
307 | if (!cu_sp) |
308 | continue; |
309 | if (!CompUnitPasses(compUnit&: *(cu_sp.get()))) |
310 | continue; |
311 | |
312 | if (searcher.GetDepth() == lldb::eSearchDepthCompUnit) { |
313 | SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get()); |
314 | |
315 | shouldContinue = searcher.SearchCallback(filter&: *this, context&: matchingContext, addr: nullptr); |
316 | |
317 | if (shouldContinue == Searcher::eCallbackReturnPop) |
318 | return Searcher::eCallbackReturnContinue; |
319 | else if (shouldContinue == Searcher::eCallbackReturnStop) |
320 | return shouldContinue; |
321 | continue; |
322 | } |
323 | |
324 | // First make sure this compile unit's functions are parsed |
325 | // since CompUnit::ForeachFunction only iterates over already |
326 | // parsed functions. |
327 | SymbolFile *sym_file = module_sp->GetSymbolFile(); |
328 | if (!sym_file) |
329 | continue; |
330 | if (!sym_file->ParseFunctions(comp_unit&: *cu_sp)) |
331 | continue; |
332 | // If we got any functions, use ForeachFunction to do the iteration. |
333 | cu_sp->ForeachFunction(lambda: [&](const FunctionSP &func_sp) { |
334 | if (!FunctionPasses(function&: *func_sp.get())) |
335 | return false; // Didn't pass the filter, just keep going. |
336 | if (searcher.GetDepth() == lldb::eSearchDepthFunction) { |
337 | SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get(), |
338 | func_sp.get()); |
339 | shouldContinue = |
340 | searcher.SearchCallback(filter&: *this, context&: matchingContext, addr: nullptr); |
341 | } else { |
342 | shouldContinue = DoFunctionIteration(function: func_sp.get(), context, searcher); |
343 | } |
344 | return shouldContinue != Searcher::eCallbackReturnContinue; |
345 | }); |
346 | } |
347 | return Searcher::eCallbackReturnContinue; |
348 | } |
349 | |
350 | Searcher::CallbackReturn SearchFilter::DoFunctionIteration( |
351 | Function *function, const SymbolContext &context, Searcher &searcher) { |
352 | // FIXME: Implement... |
353 | return Searcher::eCallbackReturnContinue; |
354 | } |
355 | |
356 | // SearchFilterForUnconstrainedSearches: |
357 | // Selects a shared library matching a given file spec, consulting the targets |
358 | // "black list". |
359 | SearchFilterSP SearchFilterForUnconstrainedSearches::CreateFromStructuredData( |
360 | const lldb::TargetSP& target_sp, |
361 | const StructuredData::Dictionary &data_dict, |
362 | Status &error) { |
363 | // No options for an unconstrained search. |
364 | return std::make_shared<SearchFilterForUnconstrainedSearches>(args: target_sp); |
365 | } |
366 | |
367 | StructuredData::ObjectSP |
368 | SearchFilterForUnconstrainedSearches::SerializeToStructuredData() { |
369 | // The options dictionary is an empty dictionary: |
370 | auto result_sp = std::make_shared<StructuredData::Dictionary>(); |
371 | return WrapOptionsDict(options_dict_sp: result_sp); |
372 | } |
373 | |
374 | bool SearchFilterForUnconstrainedSearches::ModulePasses( |
375 | const FileSpec &module_spec) { |
376 | return !m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec); |
377 | } |
378 | |
379 | bool SearchFilterForUnconstrainedSearches::ModulePasses( |
380 | const lldb::ModuleSP &module_sp) { |
381 | if (!module_sp) |
382 | return true; |
383 | else if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_sp)) |
384 | return false; |
385 | return true; |
386 | } |
387 | |
388 | SearchFilterSP SearchFilterForUnconstrainedSearches::DoCreateCopy() { |
389 | return std::make_shared<SearchFilterForUnconstrainedSearches>(args&: *this); |
390 | } |
391 | |
392 | // SearchFilterByModule: |
393 | // Selects a shared library matching a given file spec |
394 | |
395 | SearchFilterByModule::SearchFilterByModule(const lldb::TargetSP &target_sp, |
396 | const FileSpec &module) |
397 | : SearchFilter(target_sp, FilterTy::ByModule), m_module_spec(module) {} |
398 | |
399 | SearchFilterByModule::~SearchFilterByModule() = default; |
400 | |
401 | bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) { |
402 | return (module_sp && |
403 | FileSpec::Match(pattern: m_module_spec, file: module_sp->GetFileSpec())); |
404 | } |
405 | |
406 | bool SearchFilterByModule::ModulePasses(const FileSpec &spec) { |
407 | return FileSpec::Match(pattern: m_module_spec, file: spec); |
408 | } |
409 | |
410 | bool SearchFilterByModule::AddressPasses(Address &address) { |
411 | // FIXME: Not yet implemented |
412 | return true; |
413 | } |
414 | |
415 | void SearchFilterByModule::Search(Searcher &searcher) { |
416 | if (!m_target_sp) |
417 | return; |
418 | |
419 | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
420 | SymbolContext empty_sc; |
421 | empty_sc.target_sp = m_target_sp; |
422 | searcher.SearchCallback(filter&: *this, context&: empty_sc, addr: nullptr); |
423 | } |
424 | |
425 | // If the module file spec is a full path, then we can just find the one |
426 | // filespec that passes. Otherwise, we need to go through all modules and |
427 | // find the ones that match the file name. |
428 | |
429 | const ModuleList &target_modules = m_target_sp->GetImages(); |
430 | std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); |
431 | |
432 | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
433 | if (FileSpec::Match(pattern: m_module_spec, file: module_sp->GetFileSpec())) { |
434 | SymbolContext matchingContext(m_target_sp, module_sp); |
435 | Searcher::CallbackReturn shouldContinue; |
436 | |
437 | shouldContinue = DoModuleIteration(context: matchingContext, searcher); |
438 | if (shouldContinue == Searcher::eCallbackReturnStop) |
439 | return; |
440 | } |
441 | } |
442 | } |
443 | |
444 | void SearchFilterByModule::GetDescription(Stream *s) { |
445 | s->PutCString(cstr: ", module = " ); |
446 | s->PutCString(cstr: m_module_spec.GetFilename().AsCString(value_if_empty: "<Unknown>" )); |
447 | } |
448 | |
449 | uint32_t SearchFilterByModule::GetFilterRequiredItems() { |
450 | return eSymbolContextModule; |
451 | } |
452 | |
453 | void SearchFilterByModule::Dump(Stream *s) const {} |
454 | |
455 | SearchFilterSP SearchFilterByModule::DoCreateCopy() { |
456 | return std::make_shared<SearchFilterByModule>(args&: *this); |
457 | } |
458 | |
459 | SearchFilterSP SearchFilterByModule::CreateFromStructuredData( |
460 | const lldb::TargetSP& target_sp, |
461 | const StructuredData::Dictionary &data_dict, |
462 | Status &error) { |
463 | StructuredData::Array *modules_array; |
464 | bool success = data_dict.GetValueForKeyAsArray(key: GetKey(enum_value: OptionNames::ModList), |
465 | result&: modules_array); |
466 | if (!success) { |
467 | error = Status::FromErrorString( |
468 | str: "SFBM::CFSD: Could not find the module list key." ); |
469 | return nullptr; |
470 | } |
471 | |
472 | size_t num_modules = modules_array->GetSize(); |
473 | if (num_modules > 1) { |
474 | error = Status::FromErrorString( |
475 | str: "SFBM::CFSD: Only one modules allowed for SearchFilterByModule." ); |
476 | return nullptr; |
477 | } |
478 | |
479 | std::optional<llvm::StringRef> maybe_module = |
480 | modules_array->GetItemAtIndexAsString(idx: 0); |
481 | if (!maybe_module) { |
482 | error = |
483 | Status::FromErrorString(str: "SFBM::CFSD: filter module item not a string." ); |
484 | return nullptr; |
485 | } |
486 | FileSpec module_spec(*maybe_module); |
487 | |
488 | return std::make_shared<SearchFilterByModule>(args: target_sp, args&: module_spec); |
489 | } |
490 | |
491 | StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() { |
492 | auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
493 | auto module_array_sp = std::make_shared<StructuredData::Array>(); |
494 | module_array_sp->AddItem( |
495 | item: std::make_shared<StructuredData::String>(args: m_module_spec.GetPath())); |
496 | options_dict_sp->AddItem(key: GetKey(enum_value: OptionNames::ModList), value_sp: module_array_sp); |
497 | return WrapOptionsDict(options_dict_sp); |
498 | } |
499 | |
500 | // SearchFilterByModuleList: |
501 | // Selects a shared library matching a given file spec |
502 | |
503 | SearchFilterByModuleList::SearchFilterByModuleList( |
504 | const lldb::TargetSP &target_sp, const FileSpecList &module_list) |
505 | : SearchFilter(target_sp, FilterTy::ByModules), |
506 | m_module_spec_list(module_list) {} |
507 | |
508 | SearchFilterByModuleList::SearchFilterByModuleList( |
509 | const lldb::TargetSP &target_sp, const FileSpecList &module_list, |
510 | enum FilterTy filter_ty) |
511 | : SearchFilter(target_sp, filter_ty), m_module_spec_list(module_list) {} |
512 | |
513 | SearchFilterByModuleList::~SearchFilterByModuleList() = default; |
514 | |
515 | bool SearchFilterByModuleList::ModulePasses(const ModuleSP &module_sp) { |
516 | if (m_module_spec_list.GetSize() == 0) |
517 | return true; |
518 | |
519 | return module_sp && m_module_spec_list.FindFileIndex( |
520 | idx: 0, file: module_sp->GetFileSpec(), full: false) != UINT32_MAX; |
521 | } |
522 | |
523 | bool SearchFilterByModuleList::ModulePasses(const FileSpec &spec) { |
524 | if (m_module_spec_list.GetSize() == 0) |
525 | return true; |
526 | |
527 | return m_module_spec_list.FindFileIndex(idx: 0, file: spec, full: true) != UINT32_MAX; |
528 | } |
529 | |
530 | bool SearchFilterByModuleList::AddressPasses(Address &address) { |
531 | // FIXME: Not yet implemented |
532 | return true; |
533 | } |
534 | |
535 | void SearchFilterByModuleList::Search(Searcher &searcher) { |
536 | if (!m_target_sp) |
537 | return; |
538 | |
539 | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
540 | SymbolContext empty_sc; |
541 | empty_sc.target_sp = m_target_sp; |
542 | searcher.SearchCallback(filter&: *this, context&: empty_sc, addr: nullptr); |
543 | } |
544 | |
545 | // If the module file spec is a full path, then we can just find the one |
546 | // filespec that passes. Otherwise, we need to go through all modules and |
547 | // find the ones that match the file name. |
548 | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
549 | if (m_module_spec_list.FindFileIndex(idx: 0, file: module_sp->GetFileSpec(), full: false) == |
550 | UINT32_MAX) |
551 | continue; |
552 | SymbolContext matchingContext(m_target_sp, module_sp); |
553 | Searcher::CallbackReturn shouldContinue; |
554 | |
555 | shouldContinue = DoModuleIteration(context: matchingContext, searcher); |
556 | if (shouldContinue == Searcher::eCallbackReturnStop) |
557 | return; |
558 | } |
559 | } |
560 | |
561 | void SearchFilterByModuleList::GetDescription(Stream *s) { |
562 | size_t num_modules = m_module_spec_list.GetSize(); |
563 | if (num_modules == 1) { |
564 | s->Printf(format: ", module = " ); |
565 | s->PutCString( |
566 | cstr: m_module_spec_list.GetFileSpecAtIndex(idx: 0).GetFilename().AsCString( |
567 | value_if_empty: "<Unknown>" )); |
568 | return; |
569 | } |
570 | |
571 | s->Printf(format: ", modules(%" PRIu64 ") = " , (uint64_t)num_modules); |
572 | for (size_t i = 0; i < num_modules; i++) { |
573 | s->PutCString( |
574 | cstr: m_module_spec_list.GetFileSpecAtIndex(idx: i).GetFilename().AsCString( |
575 | value_if_empty: "<Unknown>" )); |
576 | if (i != num_modules - 1) |
577 | s->PutCString(cstr: ", " ); |
578 | } |
579 | } |
580 | |
581 | uint32_t SearchFilterByModuleList::GetFilterRequiredItems() { |
582 | return eSymbolContextModule; |
583 | } |
584 | |
585 | void SearchFilterByModuleList::Dump(Stream *s) const {} |
586 | |
587 | lldb::SearchFilterSP SearchFilterByModuleList::DoCreateCopy() { |
588 | return std::make_shared<SearchFilterByModuleList>(args&: *this); |
589 | } |
590 | |
591 | SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData( |
592 | const lldb::TargetSP& target_sp, |
593 | const StructuredData::Dictionary &data_dict, |
594 | Status &error) { |
595 | StructuredData::Array *modules_array; |
596 | bool success = data_dict.GetValueForKeyAsArray(key: GetKey(enum_value: OptionNames::ModList), |
597 | result&: modules_array); |
598 | |
599 | if (!success) |
600 | return std::make_shared<SearchFilterByModuleList>(args: target_sp, |
601 | args: FileSpecList{}); |
602 | FileSpecList modules; |
603 | size_t num_modules = modules_array->GetSize(); |
604 | for (size_t i = 0; i < num_modules; i++) { |
605 | std::optional<llvm::StringRef> maybe_module = |
606 | modules_array->GetItemAtIndexAsString(idx: i); |
607 | if (!maybe_module) { |
608 | error = Status::FromErrorStringWithFormat( |
609 | format: "SFBM::CFSD: filter module item %zu not a string." , i); |
610 | return nullptr; |
611 | } |
612 | modules.EmplaceBack(args&: *maybe_module); |
613 | } |
614 | return std::make_shared<SearchFilterByModuleList>(args: target_sp, args&: modules); |
615 | } |
616 | |
617 | void SearchFilterByModuleList::SerializeUnwrapped( |
618 | StructuredData::DictionarySP &options_dict_sp) { |
619 | SerializeFileSpecList(options_dict_sp, name: OptionNames::ModList, |
620 | file_list&: m_module_spec_list); |
621 | } |
622 | |
623 | StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() { |
624 | auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
625 | SerializeUnwrapped(options_dict_sp); |
626 | return WrapOptionsDict(options_dict_sp); |
627 | } |
628 | |
629 | // SearchFilterByModuleListAndCU: |
630 | // Selects a shared library matching a given file spec |
631 | |
632 | SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU( |
633 | const lldb::TargetSP &target_sp, const FileSpecList &module_list, |
634 | const FileSpecList &cu_list) |
635 | : SearchFilterByModuleList(target_sp, module_list, |
636 | FilterTy::ByModulesAndCU), |
637 | m_cu_spec_list(cu_list) {} |
638 | |
639 | SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default; |
640 | |
641 | lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( |
642 | const lldb::TargetSP& target_sp, |
643 | const StructuredData::Dictionary &data_dict, |
644 | Status &error) { |
645 | StructuredData::Array *modules_array = nullptr; |
646 | SearchFilterSP result_sp; |
647 | bool success = data_dict.GetValueForKeyAsArray(key: GetKey(enum_value: OptionNames::ModList), |
648 | result&: modules_array); |
649 | FileSpecList modules; |
650 | if (success) { |
651 | size_t num_modules = modules_array->GetSize(); |
652 | for (size_t i = 0; i < num_modules; i++) { |
653 | std::optional<llvm::StringRef> maybe_module = |
654 | modules_array->GetItemAtIndexAsString(idx: i); |
655 | if (!maybe_module) { |
656 | error = Status::FromErrorStringWithFormat( |
657 | format: "SFBM::CFSD: filter module item %zu not a string." , i); |
658 | return result_sp; |
659 | } |
660 | modules.EmplaceBack(args&: *maybe_module); |
661 | } |
662 | } |
663 | |
664 | StructuredData::Array *cus_array = nullptr; |
665 | success = |
666 | data_dict.GetValueForKeyAsArray(key: GetKey(enum_value: OptionNames::CUList), result&: cus_array); |
667 | if (!success) { |
668 | error = |
669 | Status::FromErrorString(str: "SFBM::CFSD: Could not find the CU list key." ); |
670 | return result_sp; |
671 | } |
672 | |
673 | size_t num_cus = cus_array->GetSize(); |
674 | FileSpecList cus; |
675 | for (size_t i = 0; i < num_cus; i++) { |
676 | std::optional<llvm::StringRef> maybe_cu = |
677 | cus_array->GetItemAtIndexAsString(idx: i); |
678 | if (!maybe_cu) { |
679 | error = Status::FromErrorStringWithFormat( |
680 | format: "SFBM::CFSD: filter CU item %zu not a string." , i); |
681 | return nullptr; |
682 | } |
683 | cus.EmplaceBack(args&: *maybe_cu); |
684 | } |
685 | |
686 | return std::make_shared<SearchFilterByModuleListAndCU>( |
687 | args: target_sp, args&: modules, args&: cus); |
688 | } |
689 | |
690 | StructuredData::ObjectSP |
691 | SearchFilterByModuleListAndCU::SerializeToStructuredData() { |
692 | auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
693 | SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp); |
694 | SerializeFileSpecList(options_dict_sp, name: OptionNames::CUList, file_list&: m_cu_spec_list); |
695 | return WrapOptionsDict(options_dict_sp); |
696 | } |
697 | |
698 | bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) { |
699 | SymbolContext sym_ctx; |
700 | address.CalculateSymbolContext(sc: &sym_ctx, resolve_scope: eSymbolContextEverything); |
701 | if (!sym_ctx.comp_unit) { |
702 | if (m_cu_spec_list.GetSize() != 0) |
703 | return false; // Has no comp_unit so can't pass the file check. |
704 | } |
705 | FileSpec cu_spec; |
706 | if (sym_ctx.comp_unit) |
707 | cu_spec = sym_ctx.comp_unit->GetPrimaryFile(); |
708 | if (m_cu_spec_list.FindFileIndex(idx: 0, file: cu_spec, full: false) == UINT32_MAX) |
709 | return false; // Fails the file check |
710 | return SearchFilterByModuleList::ModulePasses(module_sp: sym_ctx.module_sp); |
711 | } |
712 | |
713 | bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) { |
714 | return m_cu_spec_list.FindFileIndex(idx: 0, file: fileSpec, full: false) != UINT32_MAX; |
715 | } |
716 | |
717 | bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) { |
718 | bool in_cu_list = m_cu_spec_list.FindFileIndex(idx: 0, file: compUnit.GetPrimaryFile(), |
719 | full: false) != UINT32_MAX; |
720 | if (!in_cu_list) |
721 | return false; |
722 | |
723 | ModuleSP module_sp(compUnit.GetModule()); |
724 | if (!module_sp) |
725 | return true; |
726 | |
727 | return SearchFilterByModuleList::ModulePasses(module_sp); |
728 | } |
729 | |
730 | void SearchFilterByModuleListAndCU::Search(Searcher &searcher) { |
731 | if (!m_target_sp) |
732 | return; |
733 | |
734 | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
735 | SymbolContext empty_sc; |
736 | empty_sc.target_sp = m_target_sp; |
737 | searcher.SearchCallback(filter&: *this, context&: empty_sc, addr: nullptr); |
738 | } |
739 | |
740 | // If the module file spec is a full path, then we can just find the one |
741 | // filespec that passes. Otherwise, we need to go through all modules and |
742 | // find the ones that match the file name. |
743 | |
744 | ModuleList matching_modules; |
745 | |
746 | bool no_modules_in_filter = m_module_spec_list.GetSize() == 0; |
747 | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
748 | if (!no_modules_in_filter && |
749 | m_module_spec_list.FindFileIndex(idx: 0, file: module_sp->GetFileSpec(), full: false) == |
750 | UINT32_MAX) |
751 | continue; |
752 | |
753 | SymbolContext matchingContext(m_target_sp, module_sp); |
754 | Searcher::CallbackReturn shouldContinue; |
755 | |
756 | if (searcher.GetDepth() == lldb::eSearchDepthModule) { |
757 | shouldContinue = DoModuleIteration(context: matchingContext, searcher); |
758 | if (shouldContinue == Searcher::eCallbackReturnStop) |
759 | return; |
760 | continue; |
761 | } |
762 | |
763 | const size_t num_cu = module_sp->GetNumCompileUnits(); |
764 | for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++) { |
765 | CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(idx: cu_idx); |
766 | matchingContext.comp_unit = cu_sp.get(); |
767 | if (!matchingContext.comp_unit) |
768 | continue; |
769 | if (m_cu_spec_list.FindFileIndex( |
770 | idx: 0, file: matchingContext.comp_unit->GetPrimaryFile(), full: false) == |
771 | UINT32_MAX) |
772 | continue; |
773 | shouldContinue = DoCUIteration(module_sp, context: matchingContext, searcher); |
774 | if (shouldContinue == Searcher::eCallbackReturnStop) |
775 | return; |
776 | } |
777 | } |
778 | } |
779 | |
780 | void SearchFilterByModuleListAndCU::GetDescription(Stream *s) { |
781 | size_t num_modules = m_module_spec_list.GetSize(); |
782 | if (num_modules == 1) { |
783 | s->Printf(format: ", module = " ); |
784 | s->PutCString( |
785 | cstr: m_module_spec_list.GetFileSpecAtIndex(idx: 0).GetFilename().AsCString( |
786 | value_if_empty: "<Unknown>" )); |
787 | } else if (num_modules > 0) { |
788 | s->Printf(format: ", modules(%" PRIu64 ") = " , static_cast<uint64_t>(num_modules)); |
789 | for (size_t i = 0; i < num_modules; i++) { |
790 | s->PutCString( |
791 | cstr: m_module_spec_list.GetFileSpecAtIndex(idx: i).GetFilename().AsCString( |
792 | value_if_empty: "<Unknown>" )); |
793 | if (i != num_modules - 1) |
794 | s->PutCString(cstr: ", " ); |
795 | } |
796 | } |
797 | } |
798 | |
799 | uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() { |
800 | return eSymbolContextModule | eSymbolContextCompUnit; |
801 | } |
802 | |
803 | void SearchFilterByModuleListAndCU::Dump(Stream *s) const {} |
804 | |
805 | SearchFilterSP SearchFilterByModuleListAndCU::DoCreateCopy() { |
806 | return std::make_shared<SearchFilterByModuleListAndCU>(args&: *this); |
807 | } |
808 | |