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