SearchFilter.cpp revision 360784
1//===-- SearchFilter.cpp ----------------------------------------*- C++ -*-===//
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
33namespace lldb_private {
34class Address;
35}
36namespace lldb_private {
37class Function;
38}
39
40using namespace lldb;
41using namespace lldb_private;
42
43const char *SearchFilter::g_ty_to_name[] = {"Unconstrained", "Exception",
44                                            "Module",        "Modules",
45                                            "ModulesAndCU",  "Unknown"};
46
47const char
48    *SearchFilter::g_option_names[SearchFilter::OptionNames::LastOptionName] = {
49        "ModuleList", "CUList"};
50
51const 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
58SearchFilter::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
66Searcher::Searcher() = default;
67
68Searcher::~Searcher() = default;
69
70void Searcher::GetDescription(Stream *s) {}
71
72SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType)
73    : m_target_sp(target_sp), SubclassID(filterType) {}
74
75SearchFilter::~SearchFilter() = default;
76
77SearchFilterSP SearchFilter::CreateFromStructuredData(
78    Target &target, const StructuredData::Dictionary &filter_dict,
79    Status &error) {
80  SearchFilterSP result_sp;
81  if (!filter_dict.IsValid()) {
82    error.SetErrorString("Can't deserialize from an invalid data object.");
83    return result_sp;
84  }
85
86  llvm::StringRef subclass_name;
87
88  bool success = filter_dict.GetValueForKeyAsString(
89      GetSerializationSubclassKey(), subclass_name);
90  if (!success) {
91    error.SetErrorStringWithFormat("Filter data missing subclass key");
92    return result_sp;
93  }
94
95  FilterTy filter_type = NameToFilterTy(subclass_name);
96  if (filter_type == UnknownFilter) {
97    error.SetErrorStringWithFormatv("Unknown filter type: {0}.", subclass_name);
98    return result_sp;
99  }
100
101  StructuredData::Dictionary *subclass_options = nullptr;
102  success = filter_dict.GetValueForKeyAsDictionary(
103      GetSerializationSubclassOptionsKey(), subclass_options);
104  if (!success || !subclass_options || !subclass_options->IsValid()) {
105    error.SetErrorString("Filter data missing subclass options key.");
106    return result_sp;
107  }
108
109  switch (filter_type) {
110  case Unconstrained:
111    result_sp = SearchFilterForUnconstrainedSearches::CreateFromStructuredData(
112        target, *subclass_options, error);
113    break;
114  case ByModule:
115    result_sp = SearchFilterByModule::CreateFromStructuredData(
116        target, *subclass_options, error);
117    break;
118  case ByModules:
119    result_sp = SearchFilterByModuleList::CreateFromStructuredData(
120        target, *subclass_options, error);
121    break;
122  case ByModulesAndCU:
123    result_sp = SearchFilterByModuleListAndCU::CreateFromStructuredData(
124        target, *subclass_options, error);
125    break;
126  case Exception:
127    error.SetErrorString("Can't serialize exception breakpoints yet.");
128    break;
129  default:
130    llvm_unreachable("Should never get an uresolvable filter type.");
131  }
132
133  return result_sp;
134}
135
136bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; }
137
138bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; }
139
140bool SearchFilter::AddressPasses(Address &address) { return true; }
141
142bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; }
143
144bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; }
145
146bool SearchFilter::FunctionPasses(Function &function) {
147  // This is a slightly cheesy job, but since we don't have finer grained
148  // filters yet, just checking that the start address passes is probably
149  // good enough for the base class behavior.
150  Address addr = function.GetAddressRange().GetBaseAddress();
151  return AddressPasses(addr);
152}
153
154
155uint32_t SearchFilter::GetFilterRequiredItems() {
156  return (lldb::SymbolContextItem)0;
157}
158
159void SearchFilter::GetDescription(Stream *s) {}
160
161void SearchFilter::Dump(Stream *s) const {}
162
163lldb::SearchFilterSP SearchFilter::CopyForBreakpoint(Breakpoint &breakpoint) {
164  SearchFilterSP ret_sp = DoCopyForBreakpoint(breakpoint);
165  TargetSP target_sp = breakpoint.GetTargetSP();
166  ret_sp->SetTarget(target_sp);
167  return ret_sp;
168}
169
170// Helper functions for serialization.
171
172StructuredData::DictionarySP
173SearchFilter::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
184void 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
204void 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
219void 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
243Searcher::CallbackReturn
244SearchFilter::DoModuleIteration(const lldb::ModuleSP &module_sp,
245                                Searcher &searcher) {
246  SymbolContext matchingContext(m_target_sp, module_sp);
247  return DoModuleIteration(matchingContext, searcher);
248}
249
250Searcher::CallbackReturn
251SearchFilter::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
297Searcher::CallbackReturn
298SearchFilter::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
355Searcher::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".
364SearchFilterSP SearchFilterForUnconstrainedSearches::CreateFromStructuredData(
365    Target &target, const StructuredData::Dictionary &data_dict,
366    Status &error) {
367  // No options for an unconstrained search.
368  return std::make_shared<SearchFilterForUnconstrainedSearches>(
369      target.shared_from_this());
370}
371
372StructuredData::ObjectSP
373SearchFilterForUnconstrainedSearches::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
379bool SearchFilterForUnconstrainedSearches::ModulePasses(
380    const FileSpec &module_spec) {
381  return !m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec);
382}
383
384bool 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
393lldb::SearchFilterSP SearchFilterForUnconstrainedSearches::DoCopyForBreakpoint(
394    Breakpoint &breakpoint) {
395  return std::make_shared<SearchFilterForUnconstrainedSearches>(*this);
396}
397
398//  SearchFilterByModule:
399//  Selects a shared library matching a given file spec
400
401SearchFilterByModule::SearchFilterByModule(const lldb::TargetSP &target_sp,
402                                           const FileSpec &module)
403    : SearchFilter(target_sp, FilterTy::ByModule), m_module_spec(module) {}
404
405SearchFilterByModule::~SearchFilterByModule() = default;
406
407bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) {
408  return (module_sp &&
409          FileSpec::Match(m_module_spec, module_sp->GetFileSpec()));
410}
411
412bool SearchFilterByModule::ModulePasses(const FileSpec &spec) {
413  return FileSpec::Match(m_module_spec, spec);
414}
415
416bool SearchFilterByModule::AddressPasses(Address &address) {
417  // FIXME: Not yet implemented
418  return true;
419}
420
421bool SearchFilterByModule::CompUnitPasses(FileSpec &fileSpec) { return true; }
422
423bool SearchFilterByModule::CompUnitPasses(CompileUnit &compUnit) {
424  return true;
425}
426
427void SearchFilterByModule::Search(Searcher &searcher) {
428  if (!m_target_sp)
429    return;
430
431  if (searcher.GetDepth() == lldb::eSearchDepthTarget) {
432    SymbolContext empty_sc;
433    empty_sc.target_sp = m_target_sp;
434    searcher.SearchCallback(*this, empty_sc, nullptr);
435  }
436
437  // If the module file spec is a full path, then we can just find the one
438  // filespec that passes.  Otherwise, we need to go through all modules and
439  // find the ones that match the file name.
440
441  const ModuleList &target_modules = m_target_sp->GetImages();
442  std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
443
444  const size_t num_modules = target_modules.GetSize();
445  for (size_t i = 0; i < num_modules; i++) {
446    Module *module = target_modules.GetModulePointerAtIndexUnlocked(i);
447    if (FileSpec::Match(m_module_spec, module->GetFileSpec())) {
448      SymbolContext matchingContext(m_target_sp, module->shared_from_this());
449      Searcher::CallbackReturn shouldContinue;
450
451      shouldContinue = DoModuleIteration(matchingContext, searcher);
452      if (shouldContinue == Searcher::eCallbackReturnStop)
453        return;
454    }
455  }
456}
457
458void SearchFilterByModule::GetDescription(Stream *s) {
459  s->PutCString(", module = ");
460  s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
461}
462
463uint32_t SearchFilterByModule::GetFilterRequiredItems() {
464  return eSymbolContextModule;
465}
466
467void SearchFilterByModule::Dump(Stream *s) const {}
468
469lldb::SearchFilterSP
470SearchFilterByModule::DoCopyForBreakpoint(Breakpoint &breakpoint) {
471  return std::make_shared<SearchFilterByModule>(*this);
472}
473
474SearchFilterSP SearchFilterByModule::CreateFromStructuredData(
475    Target &target, const StructuredData::Dictionary &data_dict,
476    Status &error) {
477  StructuredData::Array *modules_array;
478  bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
479                                                 modules_array);
480  if (!success) {
481    error.SetErrorString("SFBM::CFSD: Could not find the module list key.");
482    return nullptr;
483  }
484
485  size_t num_modules = modules_array->GetSize();
486  if (num_modules > 1) {
487    error.SetErrorString(
488        "SFBM::CFSD: Only one modules allowed for SearchFilterByModule.");
489    return nullptr;
490  }
491
492  llvm::StringRef module;
493  success = modules_array->GetItemAtIndexAsString(0, module);
494  if (!success) {
495    error.SetErrorString("SFBM::CFSD: filter module item not a string.");
496    return nullptr;
497  }
498  FileSpec module_spec(module);
499
500  return std::make_shared<SearchFilterByModule>(target.shared_from_this(),
501                                                module_spec);
502}
503
504StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() {
505  auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
506  auto module_array_sp = std::make_shared<StructuredData::Array>();
507  module_array_sp->AddItem(
508      std::make_shared<StructuredData::String>(m_module_spec.GetPath()));
509  options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp);
510  return WrapOptionsDict(options_dict_sp);
511}
512
513//  SearchFilterByModuleList:
514//  Selects a shared library matching a given file spec
515
516SearchFilterByModuleList::SearchFilterByModuleList(
517    const lldb::TargetSP &target_sp, const FileSpecList &module_list)
518    : SearchFilter(target_sp, FilterTy::ByModules),
519      m_module_spec_list(module_list) {}
520
521SearchFilterByModuleList::SearchFilterByModuleList(
522    const lldb::TargetSP &target_sp, const FileSpecList &module_list,
523    enum FilterTy filter_ty)
524    : SearchFilter(target_sp, filter_ty), m_module_spec_list(module_list) {}
525
526SearchFilterByModuleList::~SearchFilterByModuleList() = default;
527
528bool SearchFilterByModuleList::ModulePasses(const ModuleSP &module_sp) {
529  if (m_module_spec_list.GetSize() == 0)
530    return true;
531
532  return module_sp && m_module_spec_list.FindFileIndex(
533                          0, module_sp->GetFileSpec(), false) != UINT32_MAX;
534}
535
536bool SearchFilterByModuleList::ModulePasses(const FileSpec &spec) {
537  if (m_module_spec_list.GetSize() == 0)
538    return true;
539
540  return m_module_spec_list.FindFileIndex(0, spec, true) != UINT32_MAX;
541}
542
543bool SearchFilterByModuleList::AddressPasses(Address &address) {
544  // FIXME: Not yet implemented
545  return true;
546}
547
548bool SearchFilterByModuleList::CompUnitPasses(FileSpec &fileSpec) {
549  return true;
550}
551
552bool SearchFilterByModuleList::CompUnitPasses(CompileUnit &compUnit) {
553  return true;
554}
555
556void SearchFilterByModuleList::Search(Searcher &searcher) {
557  if (!m_target_sp)
558    return;
559
560  if (searcher.GetDepth() == lldb::eSearchDepthTarget) {
561    SymbolContext empty_sc;
562    empty_sc.target_sp = m_target_sp;
563    searcher.SearchCallback(*this, empty_sc, nullptr);
564  }
565
566  // If the module file spec is a full path, then we can just find the one
567  // filespec that passes.  Otherwise, we need to go through all modules and
568  // find the ones that match the file name.
569
570  const ModuleList &target_modules = m_target_sp->GetImages();
571  std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
572
573  const size_t num_modules = target_modules.GetSize();
574  for (size_t i = 0; i < num_modules; i++) {
575    Module *module = target_modules.GetModulePointerAtIndexUnlocked(i);
576    if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) ==
577        UINT32_MAX)
578      continue;
579    SymbolContext matchingContext(m_target_sp, module->shared_from_this());
580    Searcher::CallbackReturn shouldContinue;
581
582    shouldContinue = DoModuleIteration(matchingContext, searcher);
583    if (shouldContinue == Searcher::eCallbackReturnStop)
584      return;
585  }
586}
587
588void SearchFilterByModuleList::GetDescription(Stream *s) {
589  size_t num_modules = m_module_spec_list.GetSize();
590  if (num_modules == 1) {
591    s->Printf(", module = ");
592    s->PutCString(
593        m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
594            "<Unknown>"));
595    return;
596  }
597
598  s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules);
599  for (size_t i = 0; i < num_modules; i++) {
600    s->PutCString(
601        m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
602            "<Unknown>"));
603    if (i != num_modules - 1)
604      s->PutCString(", ");
605  }
606}
607
608uint32_t SearchFilterByModuleList::GetFilterRequiredItems() {
609  return eSymbolContextModule;
610}
611
612void SearchFilterByModuleList::Dump(Stream *s) const {}
613
614lldb::SearchFilterSP
615SearchFilterByModuleList::DoCopyForBreakpoint(Breakpoint &breakpoint) {
616  return std::make_shared<SearchFilterByModuleList>(*this);
617}
618
619SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData(
620    Target &target, const StructuredData::Dictionary &data_dict,
621    Status &error) {
622  StructuredData::Array *modules_array;
623  bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
624                                                 modules_array);
625
626  if (!success)
627    return std::make_shared<SearchFilterByModuleList>(target.shared_from_this(),
628                                                      FileSpecList{});
629  FileSpecList modules;
630  size_t num_modules = modules_array->GetSize();
631  for (size_t i = 0; i < num_modules; i++) {
632    llvm::StringRef module;
633    success = modules_array->GetItemAtIndexAsString(i, module);
634    if (!success) {
635      error.SetErrorStringWithFormat(
636          "SFBM::CFSD: filter module item %zu not a string.", i);
637      return nullptr;
638    }
639    modules.EmplaceBack(module);
640  }
641  return std::make_shared<SearchFilterByModuleList>(target.shared_from_this(),
642                                                    modules);
643}
644
645void SearchFilterByModuleList::SerializeUnwrapped(
646    StructuredData::DictionarySP &options_dict_sp) {
647  SerializeFileSpecList(options_dict_sp, OptionNames::ModList,
648                        m_module_spec_list);
649}
650
651StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() {
652  auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
653  SerializeUnwrapped(options_dict_sp);
654  return WrapOptionsDict(options_dict_sp);
655}
656
657//  SearchFilterByModuleListAndCU:
658//  Selects a shared library matching a given file spec
659
660SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU(
661    const lldb::TargetSP &target_sp, const FileSpecList &module_list,
662    const FileSpecList &cu_list)
663    : SearchFilterByModuleList(target_sp, module_list,
664                               FilterTy::ByModulesAndCU),
665      m_cu_spec_list(cu_list) {}
666
667SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default;
668
669lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData(
670    Target &target, const StructuredData::Dictionary &data_dict,
671    Status &error) {
672  StructuredData::Array *modules_array = nullptr;
673  SearchFilterSP result_sp;
674  bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
675                                                 modules_array);
676  FileSpecList modules;
677  if (success) {
678    size_t num_modules = modules_array->GetSize();
679    for (size_t i = 0; i < num_modules; i++) {
680      llvm::StringRef module;
681      success = modules_array->GetItemAtIndexAsString(i, module);
682      if (!success) {
683        error.SetErrorStringWithFormat(
684            "SFBM::CFSD: filter module item %zu not a string.", i);
685        return result_sp;
686      }
687      modules.EmplaceBack(module);
688    }
689  }
690
691  StructuredData::Array *cus_array = nullptr;
692  success =
693      data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array);
694  if (!success) {
695    error.SetErrorString("SFBM::CFSD: Could not find the CU list key.");
696    return result_sp;
697  }
698
699  size_t num_cus = cus_array->GetSize();
700  FileSpecList cus;
701  for (size_t i = 0; i < num_cus; i++) {
702    llvm::StringRef cu;
703    success = cus_array->GetItemAtIndexAsString(i, cu);
704    if (!success) {
705      error.SetErrorStringWithFormat(
706          "SFBM::CFSD: filter CU item %zu not a string.", i);
707      return nullptr;
708    }
709    cus.EmplaceBack(cu);
710  }
711
712  return std::make_shared<SearchFilterByModuleListAndCU>(
713      target.shared_from_this(), modules, cus);
714}
715
716StructuredData::ObjectSP
717SearchFilterByModuleListAndCU::SerializeToStructuredData() {
718  auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
719  SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp);
720  SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list);
721  return WrapOptionsDict(options_dict_sp);
722}
723
724bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
725  SymbolContext sym_ctx;
726  address.CalculateSymbolContext(&sym_ctx, eSymbolContextEverything);
727  if (!sym_ctx.comp_unit) {
728    if (m_cu_spec_list.GetSize() != 0)
729      return false; // Has no comp_unit so can't pass the file check.
730  }
731  FileSpec cu_spec;
732  if (sym_ctx.comp_unit)
733    cu_spec = sym_ctx.comp_unit->GetPrimaryFile();
734  if (m_cu_spec_list.FindFileIndex(0, cu_spec, false) == UINT32_MAX)
735    return false; // Fails the file check
736  return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp);
737}
738
739bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {
740  return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX;
741}
742
743bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) {
744  bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit.GetPrimaryFile(),
745                                                 false) != UINT32_MAX;
746  if (!in_cu_list)
747    return false;
748
749  ModuleSP module_sp(compUnit.GetModule());
750  if (!module_sp)
751    return true;
752
753  return SearchFilterByModuleList::ModulePasses(module_sp);
754}
755
756void SearchFilterByModuleListAndCU::Search(Searcher &searcher) {
757  if (!m_target_sp)
758    return;
759
760  if (searcher.GetDepth() == lldb::eSearchDepthTarget) {
761    SymbolContext empty_sc;
762    empty_sc.target_sp = m_target_sp;
763    searcher.SearchCallback(*this, empty_sc, nullptr);
764  }
765
766  // If the module file spec is a full path, then we can just find the one
767  // filespec that passes.  Otherwise, we need to go through all modules and
768  // find the ones that match the file name.
769
770  ModuleList matching_modules;
771  const ModuleList &target_images = m_target_sp->GetImages();
772  std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex());
773
774  const size_t num_modules = target_images.GetSize();
775  bool no_modules_in_filter = m_module_spec_list.GetSize() == 0;
776  for (size_t i = 0; i < num_modules; i++) {
777    lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i);
778    if (!no_modules_in_filter &&
779        m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) ==
780            UINT32_MAX)
781      continue;
782
783    SymbolContext matchingContext(m_target_sp, module_sp);
784    Searcher::CallbackReturn shouldContinue;
785
786    if (searcher.GetDepth() == lldb::eSearchDepthModule) {
787      shouldContinue = DoModuleIteration(matchingContext, searcher);
788      if (shouldContinue == Searcher::eCallbackReturnStop)
789        return;
790      continue;
791    }
792
793    const size_t num_cu = module_sp->GetNumCompileUnits();
794    for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++) {
795      CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(cu_idx);
796      matchingContext.comp_unit = cu_sp.get();
797      if (!matchingContext.comp_unit)
798        continue;
799      if (m_cu_spec_list.FindFileIndex(
800              0, matchingContext.comp_unit->GetPrimaryFile(), false) ==
801          UINT32_MAX)
802        continue;
803      shouldContinue = DoCUIteration(module_sp, matchingContext, searcher);
804      if (shouldContinue == Searcher::eCallbackReturnStop)
805        return;
806    }
807  }
808}
809
810void SearchFilterByModuleListAndCU::GetDescription(Stream *s) {
811  size_t num_modules = m_module_spec_list.GetSize();
812  if (num_modules == 1) {
813    s->Printf(", module = ");
814    s->PutCString(
815        m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
816            "<Unknown>"));
817  } else if (num_modules > 0) {
818    s->Printf(", modules(%" PRIu64 ") = ", static_cast<uint64_t>(num_modules));
819    for (size_t i = 0; i < num_modules; i++) {
820      s->PutCString(
821          m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
822              "<Unknown>"));
823      if (i != num_modules - 1)
824        s->PutCString(", ");
825    }
826  }
827}
828
829uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() {
830  return eSymbolContextModule | eSymbolContextCompUnit;
831}
832
833void SearchFilterByModuleListAndCU::Dump(Stream *s) const {}
834
835lldb::SearchFilterSP
836SearchFilterByModuleListAndCU::DoCopyForBreakpoint(Breakpoint &breakpoint) {
837  return std::make_shared<SearchFilterByModuleListAndCU>(*this);
838}
839