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