1 //===-- SearchFilter.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "lldb/Core/SearchFilter.h"
10
11 #include "lldb/Breakpoint/Breakpoint.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/ModuleList.h"
14 #include "lldb/Symbol/CompileUnit.h"
15 #include "lldb/Symbol/SymbolContext.h"
16 #include "lldb/Symbol/SymbolFile.h"
17 #include "lldb/Target/Target.h"
18 #include "lldb/Utility/ConstString.h"
19 #include "lldb/Utility/Status.h"
20 #include "lldb/Utility/Stream.h"
21 #include "lldb/lldb-enumerations.h"
22
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/ErrorHandling.h"
25
26 #include <memory>
27 #include <mutex>
28 #include <string>
29
30 #include <cinttypes>
31 #include <cstring>
32
33 namespace lldb_private {
34 class Address;
35 }
36 namespace lldb_private {
37 class Function;
38 }
39
40 using namespace lldb;
41 using namespace lldb_private;
42
43 const char *SearchFilter::g_ty_to_name[] = {"Unconstrained", "Exception",
44 "Module", "Modules",
45 "ModulesAndCU", "Unknown"};
46
47 const char
48 *SearchFilter::g_option_names[SearchFilter::OptionNames::LastOptionName] = {
49 "ModuleList", "CUList"};
50
FilterTyToName(enum FilterTy type)51 const char *SearchFilter::FilterTyToName(enum FilterTy type) {
52 if (type > LastKnownFilterType)
53 return g_ty_to_name[UnknownFilter];
54
55 return g_ty_to_name[type];
56 }
57
NameToFilterTy(llvm::StringRef name)58 SearchFilter::FilterTy SearchFilter::NameToFilterTy(llvm::StringRef name) {
59 for (size_t i = 0; i <= LastKnownFilterType; i++) {
60 if (name == g_ty_to_name[i])
61 return (FilterTy)i;
62 }
63 return UnknownFilter;
64 }
65
66 Searcher::Searcher() = default;
67
68 Searcher::~Searcher() = default;
69
GetDescription(Stream * s)70 void Searcher::GetDescription(Stream *s) {}
71
SearchFilter(const TargetSP & target_sp,unsigned char filterType)72 SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType)
73 : m_target_sp(target_sp), SubclassID(filterType) {}
74
75 SearchFilter::~SearchFilter() = default;
76
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & filter_dict,Status & error)77 SearchFilterSP SearchFilter::CreateFromStructuredData(
78 const lldb::TargetSP& target_sp,
79 const StructuredData::Dictionary &filter_dict,
80 Status &error) {
81 SearchFilterSP result_sp;
82 if (!filter_dict.IsValid()) {
83 error.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 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
DoModuleIteration(const lldb::ModuleSP & module_sp,Searcher & searcher)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
DoModuleIteration(const SymbolContext & context,Searcher & searcher)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
DoCUIteration(const ModuleSP & module_sp,const SymbolContext & context,Searcher & searcher)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
DoFunctionIteration(Function * function,const SymbolContext & context,Searcher & searcher)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".
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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
SerializeToStructuredData()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
ModulePasses(const FileSpec & module_spec)370 bool SearchFilterForUnconstrainedSearches::ModulePasses(
371 const FileSpec &module_spec) {
372 return !m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec);
373 }
374
ModulePasses(const lldb::ModuleSP & module_sp)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
DoCreateCopy()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
SearchFilterByModule(const lldb::TargetSP & target_sp,const FileSpec & module)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
ModulePasses(const ModuleSP & module_sp)397 bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) {
398 return (module_sp &&
399 FileSpec::Match(m_module_spec, module_sp->GetFileSpec()));
400 }
401
ModulePasses(const FileSpec & spec)402 bool SearchFilterByModule::ModulePasses(const FileSpec &spec) {
403 return FileSpec::Match(m_module_spec, spec);
404 }
405
AddressPasses(Address & address)406 bool SearchFilterByModule::AddressPasses(Address &address) {
407 // FIXME: Not yet implemented
408 return true;
409 }
410
Search(Searcher & searcher)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
GetDescription(Stream * s)440 void SearchFilterByModule::GetDescription(Stream *s) {
441 s->PutCString(", module = ");
442 s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
443 }
444
GetFilterRequiredItems()445 uint32_t SearchFilterByModule::GetFilterRequiredItems() {
446 return eSymbolContextModule;
447 }
448
Dump(Stream * s) const449 void SearchFilterByModule::Dump(Stream *s) const {}
450
DoCreateCopy()451 SearchFilterSP SearchFilterByModule::DoCreateCopy() {
452 return std::make_shared<SearchFilterByModule>(*this);
453 }
454
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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
SerializeToStructuredData()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
SearchFilterByModuleList(const lldb::TargetSP & target_sp,const FileSpecList & module_list)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
SearchFilterByModuleList(const lldb::TargetSP & target_sp,const FileSpecList & module_list,enum FilterTy filter_ty)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
ModulePasses(const ModuleSP & module_sp)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
ModulePasses(const FileSpec & spec)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
AddressPasses(Address & address)524 bool SearchFilterByModuleList::AddressPasses(Address &address) {
525 // FIXME: Not yet implemented
526 return true;
527 }
528
Search(Searcher & searcher)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
GetDescription(Stream * s)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
GetFilterRequiredItems()575 uint32_t SearchFilterByModuleList::GetFilterRequiredItems() {
576 return eSymbolContextModule;
577 }
578
Dump(Stream * s) const579 void SearchFilterByModuleList::Dump(Stream *s) const {}
580
DoCreateCopy()581 lldb::SearchFilterSP SearchFilterByModuleList::DoCreateCopy() {
582 return std::make_shared<SearchFilterByModuleList>(*this);
583 }
584
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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
SerializeUnwrapped(StructuredData::DictionarySP & options_dict_sp)611 void SearchFilterByModuleList::SerializeUnwrapped(
612 StructuredData::DictionarySP &options_dict_sp) {
613 SerializeFileSpecList(options_dict_sp, OptionNames::ModList,
614 m_module_spec_list);
615 }
616
SerializeToStructuredData()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
SearchFilterByModuleListAndCU(const lldb::TargetSP & target_sp,const FileSpecList & module_list,const FileSpecList & cu_list)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
CreateFromStructuredData(const lldb::TargetSP & target_sp,const StructuredData::Dictionary & data_dict,Status & error)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
SerializeToStructuredData()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
AddressPasses(Address & address)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
CompUnitPasses(FileSpec & fileSpec)706 bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {
707 return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX;
708 }
709
CompUnitPasses(CompileUnit & compUnit)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
Search(Searcher & searcher)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
GetDescription(Stream * s)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
GetFilterRequiredItems()792 uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() {
793 return eSymbolContextModule | eSymbolContextCompUnit;
794 }
795
Dump(Stream * s) const796 void SearchFilterByModuleListAndCU::Dump(Stream *s) const {}
797
DoCreateCopy()798 SearchFilterSP SearchFilterByModuleListAndCU::DoCreateCopy() {
799 return std::make_shared<SearchFilterByModuleListAndCU>(*this);
800 }
801