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