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 <inttypes.h>
31 #include <string.h>
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.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 
ModulePasses(const FileSpec & spec)137 bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; }
138 
ModulePasses(const ModuleSP & module_sp)139 bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; }
140 
AddressPasses(Address & address)141 bool SearchFilter::AddressPasses(Address &address) { return true; }
142 
CompUnitPasses(FileSpec & fileSpec)143 bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; }
144 
CompUnitPasses(CompileUnit & compUnit)145 bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; }
146 
FunctionPasses(Function & function)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 
GetFilterRequiredItems()156 uint32_t SearchFilter::GetFilterRequiredItems() {
157   return (lldb::SymbolContextItem)0;
158 }
159 
GetDescription(Stream * s)160 void SearchFilter::GetDescription(Stream *s) {}
161 
Dump(Stream * s) const162 void SearchFilter::Dump(Stream *s) const {}
163 
CreateCopy(lldb::TargetSP & target_sp)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
WrapOptionsDict(StructuredData::DictionarySP options_dict_sp)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 
SerializeFileSpecList(StructuredData::DictionarySP & options_dict_sp,OptionNames name,FileSpecList & file_list)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 
Search(Searcher & searcher)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 
SearchInModuleList(Searcher & searcher,ModuleList & modules)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   std::lock_guard<std::recursive_mutex> guard(modules.GetMutex());
232   const size_t numModules = modules.GetSize();
233 
234   for (size_t i = 0; i < numModules; i++) {
235     ModuleSP module_sp(modules.GetModuleAtIndexUnlocked(i));
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   const ModuleList &target_images = m_target_sp->GetImages();
266   std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex());
267 
268   size_t n_modules = target_images.GetSize();
269   for (size_t i = 0; i < n_modules; i++) {
270     // If this is the last level supplied, then call the callback directly,
271     // otherwise descend.
272     ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked(i));
273     if (!ModulePasses(module_sp))
274       continue;
275 
276     if (searcher.GetDepth() == lldb::eSearchDepthModule) {
277       SymbolContext matchingContext(m_target_sp, module_sp);
278 
279       Searcher::CallbackReturn shouldContinue =
280           searcher.SearchCallback(*this, matchingContext, nullptr);
281       if (shouldContinue == Searcher::eCallbackReturnStop ||
282           shouldContinue == Searcher::eCallbackReturnPop)
283         return shouldContinue;
284     } else {
285       Searcher::CallbackReturn shouldContinue =
286           DoCUIteration(module_sp, context, searcher);
287       if (shouldContinue == Searcher::eCallbackReturnStop)
288         return shouldContinue;
289       else if (shouldContinue == Searcher::eCallbackReturnPop)
290         continue;
291     }
292   }
293 
294   return Searcher::eCallbackReturnContinue;
295 }
296 
297 Searcher::CallbackReturn
DoCUIteration(const ModuleSP & module_sp,const SymbolContext & context,Searcher & searcher)298 SearchFilter::DoCUIteration(const ModuleSP &module_sp,
299                             const SymbolContext &context, Searcher &searcher) {
300   Searcher::CallbackReturn shouldContinue;
301   if (context.comp_unit != nullptr) {
302     if (CompUnitPasses(*context.comp_unit)) {
303       SymbolContext matchingContext(m_target_sp, module_sp, context.comp_unit);
304       return searcher.SearchCallback(*this, matchingContext, nullptr);
305     }
306     return Searcher::eCallbackReturnContinue;
307   }
308 
309   const size_t num_comp_units = module_sp->GetNumCompileUnits();
310   for (size_t i = 0; i < num_comp_units; i++) {
311     CompUnitSP cu_sp(module_sp->GetCompileUnitAtIndex(i));
312     if (!cu_sp)
313       continue;
314     if (!CompUnitPasses(*(cu_sp.get())))
315       continue;
316 
317     if (searcher.GetDepth() == lldb::eSearchDepthCompUnit) {
318       SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get());
319 
320       shouldContinue = searcher.SearchCallback(*this, matchingContext, nullptr);
321 
322       if (shouldContinue == Searcher::eCallbackReturnPop)
323         return Searcher::eCallbackReturnContinue;
324       else if (shouldContinue == Searcher::eCallbackReturnStop)
325         return shouldContinue;
326       continue;
327     }
328 
329     // First make sure this compile unit's functions are parsed
330     // since CompUnit::ForeachFunction only iterates over already
331     // parsed functions.
332     SymbolFile *sym_file = module_sp->GetSymbolFile();
333     if (!sym_file)
334       continue;
335     if (!sym_file->ParseFunctions(*cu_sp))
336       continue;
337     // If we got any functions, use ForeachFunction to do the iteration.
338     cu_sp->ForeachFunction([&](const FunctionSP &func_sp) {
339       if (!FunctionPasses(*func_sp.get()))
340         return false; // Didn't pass the filter, just keep going.
341       if (searcher.GetDepth() == lldb::eSearchDepthFunction) {
342         SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get(),
343                                       func_sp.get());
344         shouldContinue =
345             searcher.SearchCallback(*this, matchingContext, nullptr);
346       } else {
347         shouldContinue = DoFunctionIteration(func_sp.get(), context, searcher);
348       }
349       return shouldContinue != Searcher::eCallbackReturnContinue;
350     });
351   }
352   return Searcher::eCallbackReturnContinue;
353 }
354 
DoFunctionIteration(Function * function,const SymbolContext & context,Searcher & searcher)355 Searcher::CallbackReturn SearchFilter::DoFunctionIteration(
356     Function *function, const SymbolContext &context, Searcher &searcher) {
357   // FIXME: Implement...
358   return Searcher::eCallbackReturnContinue;
359 }
360 
361 //  SearchFilterForUnconstrainedSearches:
362 //  Selects a shared library matching a given file spec, consulting the targets
363 //  "black list".
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)364 SearchFilterSP SearchFilterForUnconstrainedSearches::CreateFromStructuredData(
365     const lldb::TargetSP& target_sp,
366     const StructuredData::Dictionary &data_dict,
367     Status &error) {
368   // No options for an unconstrained search.
369   return std::make_shared<SearchFilterForUnconstrainedSearches>(target_sp);
370 }
371 
372 StructuredData::ObjectSP
SerializeToStructuredData()373 SearchFilterForUnconstrainedSearches::SerializeToStructuredData() {
374   // The options dictionary is an empty dictionary:
375   auto result_sp = std::make_shared<StructuredData::Dictionary>();
376   return WrapOptionsDict(result_sp);
377 }
378 
ModulePasses(const FileSpec & module_spec)379 bool SearchFilterForUnconstrainedSearches::ModulePasses(
380     const FileSpec &module_spec) {
381   return !m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec);
382 }
383 
ModulePasses(const lldb::ModuleSP & module_sp)384 bool SearchFilterForUnconstrainedSearches::ModulePasses(
385     const lldb::ModuleSP &module_sp) {
386   if (!module_sp)
387     return true;
388   else if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_sp))
389     return false;
390   return true;
391 }
392 
DoCreateCopy()393 SearchFilterSP SearchFilterForUnconstrainedSearches::DoCreateCopy() {
394   return std::make_shared<SearchFilterForUnconstrainedSearches>(*this);
395 }
396 
397 //  SearchFilterByModule:
398 //  Selects a shared library matching a given file spec
399 
SearchFilterByModule(const lldb::TargetSP & target_sp,const FileSpec & module)400 SearchFilterByModule::SearchFilterByModule(const lldb::TargetSP &target_sp,
401                                            const FileSpec &module)
402     : SearchFilter(target_sp, FilterTy::ByModule), m_module_spec(module) {}
403 
404 SearchFilterByModule::~SearchFilterByModule() = default;
405 
ModulePasses(const ModuleSP & module_sp)406 bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) {
407   return (module_sp &&
408           FileSpec::Match(m_module_spec, module_sp->GetFileSpec()));
409 }
410 
ModulePasses(const FileSpec & spec)411 bool SearchFilterByModule::ModulePasses(const FileSpec &spec) {
412   return FileSpec::Match(m_module_spec, spec);
413 }
414 
AddressPasses(Address & address)415 bool SearchFilterByModule::AddressPasses(Address &address) {
416   // FIXME: Not yet implemented
417   return true;
418 }
419 
Search(Searcher & searcher)420 void SearchFilterByModule::Search(Searcher &searcher) {
421   if (!m_target_sp)
422     return;
423 
424   if (searcher.GetDepth() == lldb::eSearchDepthTarget) {
425     SymbolContext empty_sc;
426     empty_sc.target_sp = m_target_sp;
427     searcher.SearchCallback(*this, empty_sc, nullptr);
428   }
429 
430   // If the module file spec is a full path, then we can just find the one
431   // filespec that passes.  Otherwise, we need to go through all modules and
432   // find the ones that match the file name.
433 
434   const ModuleList &target_modules = m_target_sp->GetImages();
435   std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
436 
437   const size_t num_modules = target_modules.GetSize();
438   for (size_t i = 0; i < num_modules; i++) {
439     Module *module = target_modules.GetModulePointerAtIndexUnlocked(i);
440     if (FileSpec::Match(m_module_spec, module->GetFileSpec())) {
441       SymbolContext matchingContext(m_target_sp, module->shared_from_this());
442       Searcher::CallbackReturn shouldContinue;
443 
444       shouldContinue = DoModuleIteration(matchingContext, searcher);
445       if (shouldContinue == Searcher::eCallbackReturnStop)
446         return;
447     }
448   }
449 }
450 
GetDescription(Stream * s)451 void SearchFilterByModule::GetDescription(Stream *s) {
452   s->PutCString(", module = ");
453   s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
454 }
455 
GetFilterRequiredItems()456 uint32_t SearchFilterByModule::GetFilterRequiredItems() {
457   return eSymbolContextModule;
458 }
459 
Dump(Stream * s) const460 void SearchFilterByModule::Dump(Stream *s) const {}
461 
DoCreateCopy()462 SearchFilterSP SearchFilterByModule::DoCreateCopy() {
463   return std::make_shared<SearchFilterByModule>(*this);
464 }
465 
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)466 SearchFilterSP SearchFilterByModule::CreateFromStructuredData(
467     const lldb::TargetSP& target_sp,
468     const StructuredData::Dictionary &data_dict,
469     Status &error) {
470   StructuredData::Array *modules_array;
471   bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
472                                                  modules_array);
473   if (!success) {
474     error.SetErrorString("SFBM::CFSD: Could not find the module list key.");
475     return nullptr;
476   }
477 
478   size_t num_modules = modules_array->GetSize();
479   if (num_modules > 1) {
480     error.SetErrorString(
481         "SFBM::CFSD: Only one modules allowed for SearchFilterByModule.");
482     return nullptr;
483   }
484 
485   llvm::StringRef module;
486   success = modules_array->GetItemAtIndexAsString(0, module);
487   if (!success) {
488     error.SetErrorString("SFBM::CFSD: filter module item not a string.");
489     return nullptr;
490   }
491   FileSpec module_spec(module);
492 
493   return std::make_shared<SearchFilterByModule>(target_sp, module_spec);
494 }
495 
SerializeToStructuredData()496 StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() {
497   auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
498   auto module_array_sp = std::make_shared<StructuredData::Array>();
499   module_array_sp->AddItem(
500       std::make_shared<StructuredData::String>(m_module_spec.GetPath()));
501   options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp);
502   return WrapOptionsDict(options_dict_sp);
503 }
504 
505 //  SearchFilterByModuleList:
506 //  Selects a shared library matching a given file spec
507 
SearchFilterByModuleList(const lldb::TargetSP & target_sp,const FileSpecList & module_list)508 SearchFilterByModuleList::SearchFilterByModuleList(
509     const lldb::TargetSP &target_sp, const FileSpecList &module_list)
510     : SearchFilter(target_sp, FilterTy::ByModules),
511       m_module_spec_list(module_list) {}
512 
SearchFilterByModuleList(const lldb::TargetSP & target_sp,const FileSpecList & module_list,enum FilterTy filter_ty)513 SearchFilterByModuleList::SearchFilterByModuleList(
514     const lldb::TargetSP &target_sp, const FileSpecList &module_list,
515     enum FilterTy filter_ty)
516     : SearchFilter(target_sp, filter_ty), m_module_spec_list(module_list) {}
517 
518 SearchFilterByModuleList::~SearchFilterByModuleList() = default;
519 
ModulePasses(const ModuleSP & module_sp)520 bool SearchFilterByModuleList::ModulePasses(const ModuleSP &module_sp) {
521   if (m_module_spec_list.GetSize() == 0)
522     return true;
523 
524   return module_sp && m_module_spec_list.FindFileIndex(
525                           0, module_sp->GetFileSpec(), false) != UINT32_MAX;
526 }
527 
ModulePasses(const FileSpec & spec)528 bool SearchFilterByModuleList::ModulePasses(const FileSpec &spec) {
529   if (m_module_spec_list.GetSize() == 0)
530     return true;
531 
532   return m_module_spec_list.FindFileIndex(0, spec, true) != UINT32_MAX;
533 }
534 
AddressPasses(Address & address)535 bool SearchFilterByModuleList::AddressPasses(Address &address) {
536   // FIXME: Not yet implemented
537   return true;
538 }
539 
Search(Searcher & searcher)540 void SearchFilterByModuleList::Search(Searcher &searcher) {
541   if (!m_target_sp)
542     return;
543 
544   if (searcher.GetDepth() == lldb::eSearchDepthTarget) {
545     SymbolContext empty_sc;
546     empty_sc.target_sp = m_target_sp;
547     searcher.SearchCallback(*this, empty_sc, nullptr);
548   }
549 
550   // If the module file spec is a full path, then we can just find the one
551   // filespec that passes.  Otherwise, we need to go through all modules and
552   // find the ones that match the file name.
553 
554   const ModuleList &target_modules = m_target_sp->GetImages();
555   std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
556 
557   const size_t num_modules = target_modules.GetSize();
558   for (size_t i = 0; i < num_modules; i++) {
559     Module *module = target_modules.GetModulePointerAtIndexUnlocked(i);
560     if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) ==
561         UINT32_MAX)
562       continue;
563     SymbolContext matchingContext(m_target_sp, module->shared_from_this());
564     Searcher::CallbackReturn shouldContinue;
565 
566     shouldContinue = DoModuleIteration(matchingContext, searcher);
567     if (shouldContinue == Searcher::eCallbackReturnStop)
568       return;
569   }
570 }
571 
GetDescription(Stream * s)572 void SearchFilterByModuleList::GetDescription(Stream *s) {
573   size_t num_modules = m_module_spec_list.GetSize();
574   if (num_modules == 1) {
575     s->Printf(", module = ");
576     s->PutCString(
577         m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
578             "<Unknown>"));
579     return;
580   }
581 
582   s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules);
583   for (size_t i = 0; i < num_modules; i++) {
584     s->PutCString(
585         m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
586             "<Unknown>"));
587     if (i != num_modules - 1)
588       s->PutCString(", ");
589   }
590 }
591 
GetFilterRequiredItems()592 uint32_t SearchFilterByModuleList::GetFilterRequiredItems() {
593   return eSymbolContextModule;
594 }
595 
Dump(Stream * s) const596 void SearchFilterByModuleList::Dump(Stream *s) const {}
597 
DoCreateCopy()598 lldb::SearchFilterSP SearchFilterByModuleList::DoCreateCopy() {
599   return std::make_shared<SearchFilterByModuleList>(*this);
600 }
601 
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)602 SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData(
603     const lldb::TargetSP& target_sp,
604     const StructuredData::Dictionary &data_dict,
605     Status &error) {
606   StructuredData::Array *modules_array;
607   bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
608                                                  modules_array);
609 
610   if (!success)
611     return std::make_shared<SearchFilterByModuleList>(target_sp,
612                                                       FileSpecList{});
613   FileSpecList modules;
614   size_t num_modules = modules_array->GetSize();
615   for (size_t i = 0; i < num_modules; i++) {
616     llvm::StringRef module;
617     success = modules_array->GetItemAtIndexAsString(i, module);
618     if (!success) {
619       error.SetErrorStringWithFormat(
620           "SFBM::CFSD: filter module item %zu not a string.", i);
621       return nullptr;
622     }
623     modules.EmplaceBack(module);
624   }
625   return std::make_shared<SearchFilterByModuleList>(target_sp, modules);
626 }
627 
SerializeUnwrapped(StructuredData::DictionarySP & options_dict_sp)628 void SearchFilterByModuleList::SerializeUnwrapped(
629     StructuredData::DictionarySP &options_dict_sp) {
630   SerializeFileSpecList(options_dict_sp, OptionNames::ModList,
631                         m_module_spec_list);
632 }
633 
SerializeToStructuredData()634 StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() {
635   auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
636   SerializeUnwrapped(options_dict_sp);
637   return WrapOptionsDict(options_dict_sp);
638 }
639 
640 //  SearchFilterByModuleListAndCU:
641 //  Selects a shared library matching a given file spec
642 
SearchFilterByModuleListAndCU(const lldb::TargetSP & target_sp,const FileSpecList & module_list,const FileSpecList & cu_list)643 SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU(
644     const lldb::TargetSP &target_sp, const FileSpecList &module_list,
645     const FileSpecList &cu_list)
646     : SearchFilterByModuleList(target_sp, module_list,
647                                FilterTy::ByModulesAndCU),
648       m_cu_spec_list(cu_list) {}
649 
650 SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default;
651 
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)652 lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData(
653     const lldb::TargetSP& target_sp,
654     const StructuredData::Dictionary &data_dict,
655     Status &error) {
656   StructuredData::Array *modules_array = nullptr;
657   SearchFilterSP result_sp;
658   bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
659                                                  modules_array);
660   FileSpecList modules;
661   if (success) {
662     size_t num_modules = modules_array->GetSize();
663     for (size_t i = 0; i < num_modules; i++) {
664       llvm::StringRef module;
665       success = modules_array->GetItemAtIndexAsString(i, module);
666       if (!success) {
667         error.SetErrorStringWithFormat(
668             "SFBM::CFSD: filter module item %zu not a string.", i);
669         return result_sp;
670       }
671       modules.EmplaceBack(module);
672     }
673   }
674 
675   StructuredData::Array *cus_array = nullptr;
676   success =
677       data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array);
678   if (!success) {
679     error.SetErrorString("SFBM::CFSD: Could not find the CU list key.");
680     return result_sp;
681   }
682 
683   size_t num_cus = cus_array->GetSize();
684   FileSpecList cus;
685   for (size_t i = 0; i < num_cus; i++) {
686     llvm::StringRef cu;
687     success = cus_array->GetItemAtIndexAsString(i, cu);
688     if (!success) {
689       error.SetErrorStringWithFormat(
690           "SFBM::CFSD: filter CU item %zu not a string.", i);
691       return nullptr;
692     }
693     cus.EmplaceBack(cu);
694   }
695 
696   return std::make_shared<SearchFilterByModuleListAndCU>(
697       target_sp, modules, cus);
698 }
699 
700 StructuredData::ObjectSP
SerializeToStructuredData()701 SearchFilterByModuleListAndCU::SerializeToStructuredData() {
702   auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
703   SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp);
704   SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list);
705   return WrapOptionsDict(options_dict_sp);
706 }
707 
AddressPasses(Address & address)708 bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
709   SymbolContext sym_ctx;
710   address.CalculateSymbolContext(&sym_ctx, eSymbolContextEverything);
711   if (!sym_ctx.comp_unit) {
712     if (m_cu_spec_list.GetSize() != 0)
713       return false; // Has no comp_unit so can't pass the file check.
714   }
715   FileSpec cu_spec;
716   if (sym_ctx.comp_unit)
717     cu_spec = sym_ctx.comp_unit->GetPrimaryFile();
718   if (m_cu_spec_list.FindFileIndex(0, cu_spec, false) == UINT32_MAX)
719     return false; // Fails the file check
720   return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp);
721 }
722 
CompUnitPasses(FileSpec & fileSpec)723 bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {
724   return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX;
725 }
726 
CompUnitPasses(CompileUnit & compUnit)727 bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) {
728   bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit.GetPrimaryFile(),
729                                                  false) != UINT32_MAX;
730   if (!in_cu_list)
731     return false;
732 
733   ModuleSP module_sp(compUnit.GetModule());
734   if (!module_sp)
735     return true;
736 
737   return SearchFilterByModuleList::ModulePasses(module_sp);
738 }
739 
Search(Searcher & searcher)740 void SearchFilterByModuleListAndCU::Search(Searcher &searcher) {
741   if (!m_target_sp)
742     return;
743 
744   if (searcher.GetDepth() == lldb::eSearchDepthTarget) {
745     SymbolContext empty_sc;
746     empty_sc.target_sp = m_target_sp;
747     searcher.SearchCallback(*this, empty_sc, nullptr);
748   }
749 
750   // If the module file spec is a full path, then we can just find the one
751   // filespec that passes.  Otherwise, we need to go through all modules and
752   // find the ones that match the file name.
753 
754   ModuleList matching_modules;
755   const ModuleList &target_images = m_target_sp->GetImages();
756   std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex());
757 
758   const size_t num_modules = target_images.GetSize();
759   bool no_modules_in_filter = m_module_spec_list.GetSize() == 0;
760   for (size_t i = 0; i < num_modules; i++) {
761     lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i);
762     if (!no_modules_in_filter &&
763         m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) ==
764             UINT32_MAX)
765       continue;
766 
767     SymbolContext matchingContext(m_target_sp, module_sp);
768     Searcher::CallbackReturn shouldContinue;
769 
770     if (searcher.GetDepth() == lldb::eSearchDepthModule) {
771       shouldContinue = DoModuleIteration(matchingContext, searcher);
772       if (shouldContinue == Searcher::eCallbackReturnStop)
773         return;
774       continue;
775     }
776 
777     const size_t num_cu = module_sp->GetNumCompileUnits();
778     for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++) {
779       CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(cu_idx);
780       matchingContext.comp_unit = cu_sp.get();
781       if (!matchingContext.comp_unit)
782         continue;
783       if (m_cu_spec_list.FindFileIndex(
784               0, matchingContext.comp_unit->GetPrimaryFile(), false) ==
785           UINT32_MAX)
786         continue;
787       shouldContinue = DoCUIteration(module_sp, matchingContext, searcher);
788       if (shouldContinue == Searcher::eCallbackReturnStop)
789         return;
790     }
791   }
792 }
793 
GetDescription(Stream * s)794 void SearchFilterByModuleListAndCU::GetDescription(Stream *s) {
795   size_t num_modules = m_module_spec_list.GetSize();
796   if (num_modules == 1) {
797     s->Printf(", module = ");
798     s->PutCString(
799         m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
800             "<Unknown>"));
801   } else if (num_modules > 0) {
802     s->Printf(", modules(%" PRIu64 ") = ", static_cast<uint64_t>(num_modules));
803     for (size_t i = 0; i < num_modules; i++) {
804       s->PutCString(
805           m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
806               "<Unknown>"));
807       if (i != num_modules - 1)
808         s->PutCString(", ");
809     }
810   }
811 }
812 
GetFilterRequiredItems()813 uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() {
814   return eSymbolContextModule | eSymbolContextCompUnit;
815 }
816 
Dump(Stream * s) const817 void SearchFilterByModuleListAndCU::Dump(Stream *s) const {}
818 
DoCreateCopy()819 SearchFilterSP SearchFilterByModuleListAndCU::DoCreateCopy() {
820   return std::make_shared<SearchFilterByModuleListAndCU>(*this);
821 }
822