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
FilterTyToName(enum FilterTy type)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
NameToFilterTy(llvm::StringRef name)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
GetDescription(Stream * s)70 void Searcher::GetDescription(Stream *s) {}
71
SearchFilter(const TargetSP & target_sp,unsigned char filterType)72 SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType)
73 : m_target_sp(target_sp), SubclassID(filterType) {}
74
75 SearchFilter::~SearchFilter() = default;
76
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & filter_dict,Status & error)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 "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 GetSerializationSubclassKey(), subclass_name);
92 if (!success) {
93 error = Status::FromErrorString("Filter data missing subclass key");
94 return result_sp;
95 }
96
97 FilterTy filter_type = NameToFilterTy(subclass_name);
98 if (filter_type == UnknownFilter) {
99 error = Status::FromErrorStringWithFormatv("Unknown filter type: {0}.",
100 subclass_name);
101 return result_sp;
102 }
103
104 StructuredData::Dictionary *subclass_options = nullptr;
105 success = filter_dict.GetValueForKeyAsDictionary(
106 GetSerializationSubclassOptionsKey(), subclass_options);
107 if (!success || !subclass_options || !subclass_options->IsValid()) {
108 error =
109 Status::FromErrorString("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, *subclass_options, error);
117 break;
118 case ByModule:
119 result_sp = SearchFilterByModule::CreateFromStructuredData(
120 target_sp, *subclass_options, error);
121 break;
122 case ByModules:
123 result_sp = SearchFilterByModuleList::CreateFromStructuredData(
124 target_sp, *subclass_options, error);
125 break;
126 case ByModulesAndCU:
127 result_sp = SearchFilterByModuleListAndCU::CreateFromStructuredData(
128 target_sp, *subclass_options, error);
129 break;
130 case Exception:
131 error =
132 Status::FromErrorString("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
ModulePasses(const FileSpec & spec)141 bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; }
142
ModulePasses(const ModuleSP & module_sp)143 bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; }
144
AddressPasses(Address & address)145 bool SearchFilter::AddressPasses(Address &address) { return true; }
146
CompUnitPasses(FileSpec & fileSpec)147 bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; }
148
CompUnitPasses(CompileUnit & compUnit)149 bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; }
150
FunctionPasses(Function & function)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(addr);
157 }
158
159
GetFilterRequiredItems()160 uint32_t SearchFilter::GetFilterRequiredItems() {
161 return (lldb::SymbolContextItem)0;
162 }
163
GetDescription(Stream * s)164 void SearchFilter::GetDescription(Stream *s) {}
165
Dump(Stream * s) const166 void SearchFilter::Dump(Stream *s) const {}
167
CreateCopy(lldb::TargetSP & target_sp)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
WrapOptionsDict(StructuredData::DictionarySP options_dict_sp)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(GetSerializationSubclassKey(), GetFilterName());
183 type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
184
185 return type_dict_sp;
186 }
187
SerializeFileSpecList(StructuredData::DictionarySP & options_dict_sp,OptionNames name,FileSpecList & file_list)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(std::make_shared<StructuredData::String>(
200 file_list.GetFileSpecAtIndex(i).GetPath()));
201 }
202 options_dict_sp->AddItem(GetKey(name), module_array_sp);
203 }
204
205 // UTILITY Functions to help iterate down through the elements of the
206 // SymbolContext.
207
Search(Searcher & searcher)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(*this, empty_sc, nullptr);
217 return;
218 }
219
220 DoModuleIteration(empty_sc, searcher);
221 }
222
SearchInModuleList(Searcher & searcher,ModuleList & modules)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(*this, empty_sc, 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
DoModuleIteration(const lldb::ModuleSP & module_sp,Searcher & searcher)244 SearchFilter::DoModuleIteration(const lldb::ModuleSP &module_sp,
245 Searcher &searcher) {
246 SymbolContext matchingContext(m_target_sp, module_sp);
247 return DoModuleIteration(matchingContext, searcher);
248 }
249
250 Searcher::CallbackReturn
DoModuleIteration(const SymbolContext & context,Searcher & searcher)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(context.module_sp, context, searcher);
259
260 SymbolContext matchingContext(context.module_sp.get());
261 searcher.SearchCallback(*this, matchingContext, 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(*this, matchingContext, 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
DoCUIteration(const ModuleSP & module_sp,const SymbolContext & context,Searcher & searcher)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(*context.comp_unit)) {
298 SymbolContext matchingContext(m_target_sp, module_sp, context.comp_unit);
299 return searcher.SearchCallback(*this, matchingContext, 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(i));
307 if (!cu_sp)
308 continue;
309 if (!CompUnitPasses(*(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(*this, matchingContext, 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(*cu_sp))
331 continue;
332 // If we got any functions, use ForeachFunction to do the iteration.
333 cu_sp->ForeachFunction([&](const FunctionSP &func_sp) {
334 if (!FunctionPasses(*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(*this, matchingContext, nullptr);
341 } else {
342 shouldContinue = DoFunctionIteration(func_sp.get(), context, searcher);
343 }
344 return shouldContinue != Searcher::eCallbackReturnContinue;
345 });
346 }
347 return Searcher::eCallbackReturnContinue;
348 }
349
DoFunctionIteration(Function * function,const SymbolContext & context,Searcher & searcher)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".
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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>(target_sp);
365 }
366
367 StructuredData::ObjectSP
SerializeToStructuredData()368 SearchFilterForUnconstrainedSearches::SerializeToStructuredData() {
369 // The options dictionary is an empty dictionary:
370 auto result_sp = std::make_shared<StructuredData::Dictionary>();
371 return WrapOptionsDict(result_sp);
372 }
373
ModulePasses(const FileSpec & module_spec)374 bool SearchFilterForUnconstrainedSearches::ModulePasses(
375 const FileSpec &module_spec) {
376 return !m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec);
377 }
378
ModulePasses(const lldb::ModuleSP & module_sp)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
DoCreateCopy()388 SearchFilterSP SearchFilterForUnconstrainedSearches::DoCreateCopy() {
389 return std::make_shared<SearchFilterForUnconstrainedSearches>(*this);
390 }
391
392 // SearchFilterByModule:
393 // Selects a shared library matching a given file spec
394
SearchFilterByModule(const lldb::TargetSP & target_sp,const FileSpec & module)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
ModulePasses(const ModuleSP & module_sp)401 bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) {
402 return (module_sp &&
403 FileSpec::Match(m_module_spec, module_sp->GetFileSpec()));
404 }
405
ModulePasses(const FileSpec & spec)406 bool SearchFilterByModule::ModulePasses(const FileSpec &spec) {
407 return FileSpec::Match(m_module_spec, spec);
408 }
409
AddressPasses(Address & address)410 bool SearchFilterByModule::AddressPasses(Address &address) {
411 // FIXME: Not yet implemented
412 return true;
413 }
414
Search(Searcher & searcher)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(*this, empty_sc, 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(m_module_spec, module_sp->GetFileSpec())) {
434 SymbolContext matchingContext(m_target_sp, module_sp);
435 Searcher::CallbackReturn shouldContinue;
436
437 shouldContinue = DoModuleIteration(matchingContext, searcher);
438 if (shouldContinue == Searcher::eCallbackReturnStop)
439 return;
440 }
441 }
442 }
443
GetDescription(Stream * s)444 void SearchFilterByModule::GetDescription(Stream *s) {
445 s->PutCString(", module = ");
446 s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
447 }
448
GetFilterRequiredItems()449 uint32_t SearchFilterByModule::GetFilterRequiredItems() {
450 return eSymbolContextModule;
451 }
452
Dump(Stream * s) const453 void SearchFilterByModule::Dump(Stream *s) const {}
454
DoCreateCopy()455 SearchFilterSP SearchFilterByModule::DoCreateCopy() {
456 return std::make_shared<SearchFilterByModule>(*this);
457 }
458
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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(GetKey(OptionNames::ModList),
465 modules_array);
466 if (!success) {
467 error = Status::FromErrorString(
468 "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 "SFBM::CFSD: Only one modules allowed for SearchFilterByModule.");
476 return nullptr;
477 }
478
479 std::optional<llvm::StringRef> maybe_module =
480 modules_array->GetItemAtIndexAsString(0);
481 if (!maybe_module) {
482 error =
483 Status::FromErrorString("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>(target_sp, module_spec);
489 }
490
SerializeToStructuredData()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 std::make_shared<StructuredData::String>(m_module_spec.GetPath()));
496 options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp);
497 return WrapOptionsDict(options_dict_sp);
498 }
499
500 // SearchFilterByModuleList:
501 // Selects a shared library matching a given file spec
502
SearchFilterByModuleList(const lldb::TargetSP & target_sp,const FileSpecList & module_list)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
SearchFilterByModuleList(const lldb::TargetSP & target_sp,const FileSpecList & module_list,enum FilterTy filter_ty)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
ModulePasses(const ModuleSP & module_sp)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 0, module_sp->GetFileSpec(), false) != UINT32_MAX;
521 }
522
ModulePasses(const FileSpec & spec)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(0, spec, true) != UINT32_MAX;
528 }
529
AddressPasses(Address & address)530 bool SearchFilterByModuleList::AddressPasses(Address &address) {
531 // FIXME: Not yet implemented
532 return true;
533 }
534
Search(Searcher & searcher)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(*this, empty_sc, 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(0, module_sp->GetFileSpec(), false) ==
550 UINT32_MAX)
551 continue;
552 SymbolContext matchingContext(m_target_sp, module_sp);
553 Searcher::CallbackReturn shouldContinue;
554
555 shouldContinue = DoModuleIteration(matchingContext, searcher);
556 if (shouldContinue == Searcher::eCallbackReturnStop)
557 return;
558 }
559 }
560
GetDescription(Stream * s)561 void SearchFilterByModuleList::GetDescription(Stream *s) {
562 size_t num_modules = m_module_spec_list.GetSize();
563 if (num_modules == 1) {
564 s->Printf(", module = ");
565 s->PutCString(
566 m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
567 "<Unknown>"));
568 return;
569 }
570
571 s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules);
572 for (size_t i = 0; i < num_modules; i++) {
573 s->PutCString(
574 m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
575 "<Unknown>"));
576 if (i != num_modules - 1)
577 s->PutCString(", ");
578 }
579 }
580
GetFilterRequiredItems()581 uint32_t SearchFilterByModuleList::GetFilterRequiredItems() {
582 return eSymbolContextModule;
583 }
584
Dump(Stream * s) const585 void SearchFilterByModuleList::Dump(Stream *s) const {}
586
DoCreateCopy()587 lldb::SearchFilterSP SearchFilterByModuleList::DoCreateCopy() {
588 return std::make_shared<SearchFilterByModuleList>(*this);
589 }
590
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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(GetKey(OptionNames::ModList),
597 modules_array);
598
599 if (!success)
600 return std::make_shared<SearchFilterByModuleList>(target_sp,
601 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(i);
607 if (!maybe_module) {
608 error = Status::FromErrorStringWithFormat(
609 "SFBM::CFSD: filter module item %zu not a string.", i);
610 return nullptr;
611 }
612 modules.EmplaceBack(*maybe_module);
613 }
614 return std::make_shared<SearchFilterByModuleList>(target_sp, modules);
615 }
616
SerializeUnwrapped(StructuredData::DictionarySP & options_dict_sp)617 void SearchFilterByModuleList::SerializeUnwrapped(
618 StructuredData::DictionarySP &options_dict_sp) {
619 SerializeFileSpecList(options_dict_sp, OptionNames::ModList,
620 m_module_spec_list);
621 }
622
SerializeToStructuredData()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
SearchFilterByModuleListAndCU(const lldb::TargetSP & target_sp,const FileSpecList & module_list,const FileSpecList & cu_list)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
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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(GetKey(OptionNames::ModList),
648 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(i);
655 if (!maybe_module) {
656 error = Status::FromErrorStringWithFormat(
657 "SFBM::CFSD: filter module item %zu not a string.", i);
658 return result_sp;
659 }
660 modules.EmplaceBack(*maybe_module);
661 }
662 }
663
664 StructuredData::Array *cus_array = nullptr;
665 success =
666 data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array);
667 if (!success) {
668 error =
669 Status::FromErrorString("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(i);
678 if (!maybe_cu) {
679 error = Status::FromErrorStringWithFormat(
680 "SFBM::CFSD: filter CU item %zu not a string.", i);
681 return nullptr;
682 }
683 cus.EmplaceBack(*maybe_cu);
684 }
685
686 return std::make_shared<SearchFilterByModuleListAndCU>(
687 target_sp, modules, cus);
688 }
689
690 StructuredData::ObjectSP
SerializeToStructuredData()691 SearchFilterByModuleListAndCU::SerializeToStructuredData() {
692 auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
693 SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp);
694 SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list);
695 return WrapOptionsDict(options_dict_sp);
696 }
697
AddressPasses(Address & address)698 bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
699 SymbolContext sym_ctx;
700 address.CalculateSymbolContext(&sym_ctx, 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(0, cu_spec, false) == UINT32_MAX)
709 return false; // Fails the file check
710 return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp);
711 }
712
CompUnitPasses(FileSpec & fileSpec)713 bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {
714 return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX;
715 }
716
CompUnitPasses(CompileUnit & compUnit)717 bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) {
718 bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit.GetPrimaryFile(),
719 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
Search(Searcher & searcher)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(*this, empty_sc, 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(0, module_sp->GetFileSpec(), 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(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(cu_idx);
766 matchingContext.comp_unit = cu_sp.get();
767 if (!matchingContext.comp_unit)
768 continue;
769 if (m_cu_spec_list.FindFileIndex(
770 0, matchingContext.comp_unit->GetPrimaryFile(), false) ==
771 UINT32_MAX)
772 continue;
773 shouldContinue = DoCUIteration(module_sp, matchingContext, searcher);
774 if (shouldContinue == Searcher::eCallbackReturnStop)
775 return;
776 }
777 }
778 }
779
GetDescription(Stream * s)780 void SearchFilterByModuleListAndCU::GetDescription(Stream *s) {
781 size_t num_modules = m_module_spec_list.GetSize();
782 if (num_modules == 1) {
783 s->Printf(", module = ");
784 s->PutCString(
785 m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
786 "<Unknown>"));
787 } else if (num_modules > 0) {
788 s->Printf(", modules(%" PRIu64 ") = ", static_cast<uint64_t>(num_modules));
789 for (size_t i = 0; i < num_modules; i++) {
790 s->PutCString(
791 m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
792 "<Unknown>"));
793 if (i != num_modules - 1)
794 s->PutCString(", ");
795 }
796 }
797 }
798
GetFilterRequiredItems()799 uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() {
800 return eSymbolContextModule | eSymbolContextCompUnit;
801 }
802
Dump(Stream * s) const803 void SearchFilterByModuleListAndCU::Dump(Stream *s) const {}
804
DoCreateCopy()805 SearchFilterSP SearchFilterByModuleListAndCU::DoCreateCopy() {
806 return std::make_shared<SearchFilterByModuleListAndCU>(*this);
807 }
808