| //===-- SearchFilter.cpp ----------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Core/SearchFilter.h" |
| |
| #include "lldb/Breakpoint/Breakpoint.h" // for Breakpoint |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/ModuleList.h" // for ModuleList |
| #include "lldb/Symbol/CompileUnit.h" |
| #include "lldb/Symbol/SymbolContext.h" // for SymbolContext |
| #include "lldb/Target/Target.h" |
| #include "lldb/Utility/ConstString.h" // for ConstString |
| #include "lldb/Utility/Status.h" // for Status |
| #include "lldb/Utility/Stream.h" // for Stream |
| #include "lldb/lldb-enumerations.h" // for SymbolContextItem::eSymbolCo... |
| |
| #include "llvm/ADT/StringRef.h" // for StringRef |
| #include "llvm/Support/ErrorHandling.h" // for llvm_unreachable |
| |
| #include <memory> // for shared_ptr |
| #include <mutex> // for recursive_mutex, lock_guard |
| #include <string> // for string |
| |
| #include <inttypes.h> // for PRIu64 |
| #include <string.h> // for size_t, strcmp |
| |
| namespace lldb_private { |
| class Address; |
| } |
| namespace lldb_private { |
| class Function; |
| } |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| const char *SearchFilter::g_ty_to_name[] = {"Unconstrained", "Exception", |
| "Module", "Modules", |
| "ModulesAndCU", "Unknown"}; |
| |
| const char |
| *SearchFilter::g_option_names[SearchFilter::OptionNames::LastOptionName] = { |
| "ModuleList", "CUList"}; |
| |
| const char *SearchFilter::FilterTyToName(enum FilterTy type) { |
| if (type > LastKnownFilterType) |
| return g_ty_to_name[UnknownFilter]; |
| |
| return g_ty_to_name[type]; |
| } |
| |
| SearchFilter::FilterTy SearchFilter::NameToFilterTy(llvm::StringRef name) { |
| for (size_t i = 0; i <= LastKnownFilterType; i++) { |
| if (name == g_ty_to_name[i]) |
| return (FilterTy)i; |
| } |
| return UnknownFilter; |
| } |
| |
| Searcher::Searcher() = default; |
| |
| Searcher::~Searcher() = default; |
| |
| void Searcher::GetDescription(Stream *s) {} |
| |
| SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType) |
| : m_target_sp(target_sp), SubclassID(filterType) {} |
| |
| SearchFilter::SearchFilter(const SearchFilter &rhs) = default; |
| |
| SearchFilter &SearchFilter::operator=(const SearchFilter &rhs) = default; |
| |
| SearchFilter::~SearchFilter() = default; |
| |
| SearchFilterSP SearchFilter::CreateFromStructuredData( |
| Target &target, const StructuredData::Dictionary &filter_dict, |
| Status &error) { |
| SearchFilterSP result_sp; |
| if (!filter_dict.IsValid()) { |
| error.SetErrorString("Can't deserialize from an invalid data object."); |
| return result_sp; |
| } |
| |
| llvm::StringRef subclass_name; |
| |
| bool success = filter_dict.GetValueForKeyAsString( |
| GetSerializationSubclassKey(), subclass_name); |
| if (!success) { |
| error.SetErrorStringWithFormat("Filter data missing subclass key"); |
| return result_sp; |
| } |
| |
| FilterTy filter_type = NameToFilterTy(subclass_name); |
| if (filter_type == UnknownFilter) { |
| error.SetErrorStringWithFormatv("Unknown filter type: {0}.", subclass_name); |
| return result_sp; |
| } |
| |
| StructuredData::Dictionary *subclass_options = nullptr; |
| success = filter_dict.GetValueForKeyAsDictionary( |
| GetSerializationSubclassOptionsKey(), subclass_options); |
| if (!success || !subclass_options || !subclass_options->IsValid()) { |
| error.SetErrorString("Filter data missing subclass options key."); |
| return result_sp; |
| } |
| |
| switch (filter_type) { |
| case Unconstrained: |
| result_sp = SearchFilterForUnconstrainedSearches::CreateFromStructuredData( |
| target, *subclass_options, error); |
| break; |
| case ByModule: |
| result_sp = SearchFilterByModule::CreateFromStructuredData( |
| target, *subclass_options, error); |
| break; |
| case ByModules: |
| result_sp = SearchFilterByModuleList::CreateFromStructuredData( |
| target, *subclass_options, error); |
| break; |
| case ByModulesAndCU: |
| result_sp = SearchFilterByModuleListAndCU::CreateFromStructuredData( |
| target, *subclass_options, error); |
| break; |
| case Exception: |
| error.SetErrorString("Can't serialize exception breakpoints yet."); |
| break; |
| default: |
| llvm_unreachable("Should never get an uresolvable filter type."); |
| } |
| |
| return result_sp; |
| } |
| |
| bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; } |
| |
| bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; } |
| |
| bool SearchFilter::AddressPasses(Address &address) { return true; } |
| |
| bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; } |
| |
| bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; } |
| |
| uint32_t SearchFilter::GetFilterRequiredItems() { |
| return (lldb::SymbolContextItem)0; |
| } |
| |
| void SearchFilter::GetDescription(Stream *s) {} |
| |
| void SearchFilter::Dump(Stream *s) const {} |
| |
| lldb::SearchFilterSP SearchFilter::CopyForBreakpoint(Breakpoint &breakpoint) { |
| SearchFilterSP ret_sp = DoCopyForBreakpoint(breakpoint); |
| TargetSP target_sp = breakpoint.GetTargetSP(); |
| ret_sp->SetTarget(target_sp); |
| return ret_sp; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Helper functions for serialization. |
| //---------------------------------------------------------------------- |
| |
| StructuredData::DictionarySP |
| SearchFilter::WrapOptionsDict(StructuredData::DictionarySP options_dict_sp) { |
| if (!options_dict_sp || !options_dict_sp->IsValid()) |
| return StructuredData::DictionarySP(); |
| |
| auto type_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
| type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetFilterName()); |
| type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp); |
| |
| return type_dict_sp; |
| } |
| |
| void SearchFilter::SerializeFileSpecList( |
| StructuredData::DictionarySP &options_dict_sp, OptionNames name, |
| FileSpecList &file_list) { |
| size_t num_modules = file_list.GetSize(); |
| |
| // Don't serialize empty lists. |
| if (num_modules == 0) |
| return; |
| |
| auto module_array_sp = std::make_shared<StructuredData::Array>(); |
| for (size_t i = 0; i < num_modules; i++) { |
| module_array_sp->AddItem(std::make_shared<StructuredData::String>( |
| file_list.GetFileSpecAtIndex(i).GetPath())); |
| } |
| options_dict_sp->AddItem(GetKey(name), module_array_sp); |
| } |
| |
| //---------------------------------------------------------------------- |
| // UTILITY Functions to help iterate down through the elements of the |
| // SymbolContext. |
| //---------------------------------------------------------------------- |
| |
| void SearchFilter::Search(Searcher &searcher) { |
| SymbolContext empty_sc; |
| |
| if (!m_target_sp) |
| return; |
| empty_sc.target_sp = m_target_sp; |
| |
| if (searcher.GetDepth() == Searcher::eDepthTarget) |
| searcher.SearchCallback(*this, empty_sc, nullptr, false); |
| else |
| DoModuleIteration(empty_sc, searcher); |
| } |
| |
| void SearchFilter::SearchInModuleList(Searcher &searcher, ModuleList &modules) { |
| SymbolContext empty_sc; |
| |
| if (!m_target_sp) |
| return; |
| empty_sc.target_sp = m_target_sp; |
| |
| if (searcher.GetDepth() == Searcher::eDepthTarget) |
| searcher.SearchCallback(*this, empty_sc, nullptr, false); |
| else { |
| std::lock_guard<std::recursive_mutex> guard(modules.GetMutex()); |
| const size_t numModules = modules.GetSize(); |
| |
| for (size_t i = 0; i < numModules; i++) { |
| ModuleSP module_sp(modules.GetModuleAtIndexUnlocked(i)); |
| if (ModulePasses(module_sp)) { |
| if (DoModuleIteration(module_sp, searcher) == |
| Searcher::eCallbackReturnStop) |
| return; |
| } |
| } |
| } |
| } |
| |
| Searcher::CallbackReturn |
| SearchFilter::DoModuleIteration(const lldb::ModuleSP &module_sp, |
| Searcher &searcher) { |
| SymbolContext matchingContext(m_target_sp, module_sp); |
| return DoModuleIteration(matchingContext, searcher); |
| } |
| |
| Searcher::CallbackReturn |
| SearchFilter::DoModuleIteration(const SymbolContext &context, |
| Searcher &searcher) { |
| if (searcher.GetDepth() >= Searcher::eDepthModule) { |
| if (context.module_sp) { |
| if (searcher.GetDepth() == Searcher::eDepthModule) { |
| SymbolContext matchingContext(context.module_sp.get()); |
| searcher.SearchCallback(*this, matchingContext, nullptr, false); |
| } else { |
| return DoCUIteration(context.module_sp, context, searcher); |
| } |
| } else { |
| const ModuleList &target_images = m_target_sp->GetImages(); |
| std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); |
| |
| size_t n_modules = target_images.GetSize(); |
| for (size_t i = 0; i < n_modules; i++) { |
| // If this is the last level supplied, then call the callback directly, |
| // otherwise descend. |
| ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked(i)); |
| if (!ModulePasses(module_sp)) |
| continue; |
| |
| if (searcher.GetDepth() == Searcher::eDepthModule) { |
| SymbolContext matchingContext(m_target_sp, module_sp); |
| |
| Searcher::CallbackReturn shouldContinue = |
| searcher.SearchCallback(*this, matchingContext, nullptr, false); |
| if (shouldContinue == Searcher::eCallbackReturnStop || |
| shouldContinue == Searcher::eCallbackReturnPop) |
| return shouldContinue; |
| } else { |
| Searcher::CallbackReturn shouldContinue = |
| DoCUIteration(module_sp, context, searcher); |
| if (shouldContinue == Searcher::eCallbackReturnStop) |
| return shouldContinue; |
| else if (shouldContinue == Searcher::eCallbackReturnPop) |
| continue; |
| } |
| } |
| } |
| } |
| return Searcher::eCallbackReturnContinue; |
| } |
| |
| Searcher::CallbackReturn |
| SearchFilter::DoCUIteration(const ModuleSP &module_sp, |
| const SymbolContext &context, Searcher &searcher) { |
| Searcher::CallbackReturn shouldContinue; |
| if (context.comp_unit == nullptr) { |
| const size_t num_comp_units = module_sp->GetNumCompileUnits(); |
| for (size_t i = 0; i < num_comp_units; i++) { |
| CompUnitSP cu_sp(module_sp->GetCompileUnitAtIndex(i)); |
| if (cu_sp) { |
| if (!CompUnitPasses(*(cu_sp.get()))) |
| continue; |
| |
| if (searcher.GetDepth() == Searcher::eDepthCompUnit) { |
| SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get()); |
| |
| shouldContinue = |
| searcher.SearchCallback(*this, matchingContext, nullptr, false); |
| |
| if (shouldContinue == Searcher::eCallbackReturnPop) |
| return Searcher::eCallbackReturnContinue; |
| else if (shouldContinue == Searcher::eCallbackReturnStop) |
| return shouldContinue; |
| } else { |
| // FIXME Descend to block. |
| } |
| } |
| } |
| } else { |
| if (CompUnitPasses(*context.comp_unit)) { |
| SymbolContext matchingContext(m_target_sp, module_sp, context.comp_unit); |
| return searcher.SearchCallback(*this, matchingContext, nullptr, false); |
| } |
| } |
| return Searcher::eCallbackReturnContinue; |
| } |
| |
| Searcher::CallbackReturn SearchFilter::DoFunctionIteration( |
| Function *function, const SymbolContext &context, Searcher &searcher) { |
| // FIXME: Implement... |
| return Searcher::eCallbackReturnContinue; |
| } |
| |
| //---------------------------------------------------------------------- |
| // SearchFilterForUnconstrainedSearches: |
| // Selects a shared library matching a given file spec, consulting the targets |
| // "black list". |
| //---------------------------------------------------------------------- |
| SearchFilterSP SearchFilterForUnconstrainedSearches::CreateFromStructuredData( |
| Target &target, const StructuredData::Dictionary &data_dict, |
| Status &error) { |
| // No options for an unconstrained search. |
| return std::make_shared<SearchFilterForUnconstrainedSearches>( |
| target.shared_from_this()); |
| } |
| |
| StructuredData::ObjectSP |
| SearchFilterForUnconstrainedSearches::SerializeToStructuredData() { |
| // The options dictionary is an empty dictionary: |
| auto result_sp = std::make_shared<StructuredData::Dictionary>(); |
| return WrapOptionsDict(result_sp); |
| } |
| |
| bool SearchFilterForUnconstrainedSearches::ModulePasses( |
| const FileSpec &module_spec) { |
| if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec)) |
| return false; |
| else |
| return true; |
| } |
| |
| bool SearchFilterForUnconstrainedSearches::ModulePasses( |
| const lldb::ModuleSP &module_sp) { |
| if (!module_sp) |
| return true; |
| else if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_sp)) |
| return false; |
| else |
| return true; |
| } |
| |
| lldb::SearchFilterSP SearchFilterForUnconstrainedSearches::DoCopyForBreakpoint( |
| Breakpoint &breakpoint) { |
| return std::make_shared<SearchFilterForUnconstrainedSearches>(*this); |
| } |
| |
| //---------------------------------------------------------------------- |
| // SearchFilterByModule: |
| // Selects a shared library matching a given file spec |
| //---------------------------------------------------------------------- |
| |
| SearchFilterByModule::SearchFilterByModule(const lldb::TargetSP &target_sp, |
| const FileSpec &module) |
| : SearchFilter(target_sp, FilterTy::ByModule), m_module_spec(module) {} |
| |
| SearchFilterByModule::SearchFilterByModule(const SearchFilterByModule &rhs) = |
| default; |
| |
| SearchFilterByModule &SearchFilterByModule:: |
| operator=(const SearchFilterByModule &rhs) { |
| m_target_sp = rhs.m_target_sp; |
| m_module_spec = rhs.m_module_spec; |
| return *this; |
| } |
| |
| SearchFilterByModule::~SearchFilterByModule() = default; |
| |
| bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) { |
| return (module_sp && |
| FileSpec::Equal(module_sp->GetFileSpec(), m_module_spec, false)); |
| } |
| |
| bool SearchFilterByModule::ModulePasses(const FileSpec &spec) { |
| // Do a full match only if "spec" has a directory |
| const bool full_match = (bool)spec.GetDirectory(); |
| return FileSpec::Equal(spec, m_module_spec, full_match); |
| } |
| |
| bool SearchFilterByModule::AddressPasses(Address &address) { |
| // FIXME: Not yet implemented |
| return true; |
| } |
| |
| bool SearchFilterByModule::CompUnitPasses(FileSpec &fileSpec) { return true; } |
| |
| bool SearchFilterByModule::CompUnitPasses(CompileUnit &compUnit) { |
| return true; |
| } |
| |
| void SearchFilterByModule::Search(Searcher &searcher) { |
| if (!m_target_sp) |
| return; |
| |
| if (searcher.GetDepth() == Searcher::eDepthTarget) { |
| SymbolContext empty_sc; |
| empty_sc.target_sp = m_target_sp; |
| searcher.SearchCallback(*this, empty_sc, nullptr, false); |
| } |
| |
| // If the module file spec is a full path, then we can just find the one |
| // filespec that passes. Otherwise, we need to go through all modules and |
| // find the ones that match the file name. |
| |
| const ModuleList &target_modules = m_target_sp->GetImages(); |
| std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); |
| |
| const size_t num_modules = target_modules.GetSize(); |
| for (size_t i = 0; i < num_modules; i++) { |
| Module *module = target_modules.GetModulePointerAtIndexUnlocked(i); |
| const bool full_match = (bool)m_module_spec.GetDirectory(); |
| if (FileSpec::Equal(m_module_spec, module->GetFileSpec(), full_match)) { |
| SymbolContext matchingContext(m_target_sp, module->shared_from_this()); |
| Searcher::CallbackReturn shouldContinue; |
| |
| shouldContinue = DoModuleIteration(matchingContext, searcher); |
| if (shouldContinue == Searcher::eCallbackReturnStop) |
| return; |
| } |
| } |
| } |
| |
| void SearchFilterByModule::GetDescription(Stream *s) { |
| s->PutCString(", module = "); |
| s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>")); |
| } |
| |
| uint32_t SearchFilterByModule::GetFilterRequiredItems() { |
| return eSymbolContextModule; |
| } |
| |
| void SearchFilterByModule::Dump(Stream *s) const {} |
| |
| lldb::SearchFilterSP |
| SearchFilterByModule::DoCopyForBreakpoint(Breakpoint &breakpoint) { |
| return std::make_shared<SearchFilterByModule>(*this); |
| } |
| |
| SearchFilterSP SearchFilterByModule::CreateFromStructuredData( |
| Target &target, const StructuredData::Dictionary &data_dict, |
| Status &error) { |
| StructuredData::Array *modules_array; |
| bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), |
| modules_array); |
| if (!success) { |
| error.SetErrorString("SFBM::CFSD: Could not find the module list key."); |
| return nullptr; |
| } |
| |
| size_t num_modules = modules_array->GetSize(); |
| if (num_modules > 1) { |
| error.SetErrorString( |
| "SFBM::CFSD: Only one modules allowed for SearchFilterByModule."); |
| return nullptr; |
| } |
| |
| llvm::StringRef module; |
| success = modules_array->GetItemAtIndexAsString(0, module); |
| if (!success) { |
| error.SetErrorString("SFBM::CFSD: filter module item not a string."); |
| return nullptr; |
| } |
| FileSpec module_spec(module, false); |
| |
| return std::make_shared<SearchFilterByModule>(target.shared_from_this(), |
| module_spec); |
| } |
| |
| StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() { |
| auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
| auto module_array_sp = std::make_shared<StructuredData::Array>(); |
| module_array_sp->AddItem( |
| std::make_shared<StructuredData::String>(m_module_spec.GetPath())); |
| options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp); |
| return WrapOptionsDict(options_dict_sp); |
| } |
| |
| //---------------------------------------------------------------------- |
| // SearchFilterByModuleList: |
| // Selects a shared library matching a given file spec |
| //---------------------------------------------------------------------- |
| |
| SearchFilterByModuleList::SearchFilterByModuleList( |
| const lldb::TargetSP &target_sp, const FileSpecList &module_list) |
| : SearchFilter(target_sp, FilterTy::ByModules), |
| m_module_spec_list(module_list) {} |
| |
| SearchFilterByModuleList::SearchFilterByModuleList( |
| const lldb::TargetSP &target_sp, const FileSpecList &module_list, |
| enum FilterTy filter_ty) |
| : SearchFilter(target_sp, filter_ty), m_module_spec_list(module_list) {} |
| |
| SearchFilterByModuleList::SearchFilterByModuleList( |
| const SearchFilterByModuleList &rhs) = default; |
| |
| SearchFilterByModuleList &SearchFilterByModuleList:: |
| operator=(const SearchFilterByModuleList &rhs) { |
| m_target_sp = rhs.m_target_sp; |
| m_module_spec_list = rhs.m_module_spec_list; |
| return *this; |
| } |
| |
| SearchFilterByModuleList::~SearchFilterByModuleList() = default; |
| |
| bool SearchFilterByModuleList::ModulePasses(const ModuleSP &module_sp) { |
| if (m_module_spec_list.GetSize() == 0) |
| return true; |
| |
| if (module_sp && |
| m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) != |
| UINT32_MAX) |
| return true; |
| else |
| return false; |
| } |
| |
| bool SearchFilterByModuleList::ModulePasses(const FileSpec &spec) { |
| if (m_module_spec_list.GetSize() == 0) |
| return true; |
| |
| if (m_module_spec_list.FindFileIndex(0, spec, true) != UINT32_MAX) |
| return true; |
| else |
| return false; |
| } |
| |
| bool SearchFilterByModuleList::AddressPasses(Address &address) { |
| // FIXME: Not yet implemented |
| return true; |
| } |
| |
| bool SearchFilterByModuleList::CompUnitPasses(FileSpec &fileSpec) { |
| return true; |
| } |
| |
| bool SearchFilterByModuleList::CompUnitPasses(CompileUnit &compUnit) { |
| return true; |
| } |
| |
| void SearchFilterByModuleList::Search(Searcher &searcher) { |
| if (!m_target_sp) |
| return; |
| |
| if (searcher.GetDepth() == Searcher::eDepthTarget) { |
| SymbolContext empty_sc; |
| empty_sc.target_sp = m_target_sp; |
| searcher.SearchCallback(*this, empty_sc, nullptr, false); |
| } |
| |
| // If the module file spec is a full path, then we can just find the one |
| // filespec that passes. Otherwise, we need to go through all modules and |
| // find the ones that match the file name. |
| |
| const ModuleList &target_modules = m_target_sp->GetImages(); |
| std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); |
| |
| const size_t num_modules = target_modules.GetSize(); |
| for (size_t i = 0; i < num_modules; i++) { |
| Module *module = target_modules.GetModulePointerAtIndexUnlocked(i); |
| if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) != |
| UINT32_MAX) { |
| SymbolContext matchingContext(m_target_sp, module->shared_from_this()); |
| Searcher::CallbackReturn shouldContinue; |
| |
| shouldContinue = DoModuleIteration(matchingContext, searcher); |
| if (shouldContinue == Searcher::eCallbackReturnStop) |
| return; |
| } |
| } |
| } |
| |
| void SearchFilterByModuleList::GetDescription(Stream *s) { |
| size_t num_modules = m_module_spec_list.GetSize(); |
| if (num_modules == 1) { |
| s->Printf(", module = "); |
| s->PutCString( |
| m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString( |
| "<Unknown>")); |
| } else { |
| s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules); |
| for (size_t i = 0; i < num_modules; i++) { |
| s->PutCString( |
| m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString( |
| "<Unknown>")); |
| if (i != num_modules - 1) |
| s->PutCString(", "); |
| } |
| } |
| } |
| |
| uint32_t SearchFilterByModuleList::GetFilterRequiredItems() { |
| return eSymbolContextModule; |
| } |
| |
| void SearchFilterByModuleList::Dump(Stream *s) const {} |
| |
| lldb::SearchFilterSP |
| SearchFilterByModuleList::DoCopyForBreakpoint(Breakpoint &breakpoint) { |
| return std::make_shared<SearchFilterByModuleList>(*this); |
| } |
| |
| SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData( |
| Target &target, const StructuredData::Dictionary &data_dict, |
| Status &error) { |
| StructuredData::Array *modules_array; |
| bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), |
| modules_array); |
| FileSpecList modules; |
| if (success) { |
| size_t num_modules = modules_array->GetSize(); |
| for (size_t i = 0; i < num_modules; i++) { |
| llvm::StringRef module; |
| success = modules_array->GetItemAtIndexAsString(i, module); |
| if (!success) { |
| error.SetErrorStringWithFormat( |
| "SFBM::CFSD: filter module item %zu not a string.", i); |
| return nullptr; |
| } |
| modules.Append(FileSpec(module, false)); |
| } |
| } |
| |
| return std::make_shared<SearchFilterByModuleList>(target.shared_from_this(), |
| modules); |
| } |
| |
| void SearchFilterByModuleList::SerializeUnwrapped( |
| StructuredData::DictionarySP &options_dict_sp) { |
| SerializeFileSpecList(options_dict_sp, OptionNames::ModList, |
| m_module_spec_list); |
| } |
| |
| StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() { |
| auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
| SerializeUnwrapped(options_dict_sp); |
| return WrapOptionsDict(options_dict_sp); |
| } |
| |
| //---------------------------------------------------------------------- |
| // SearchFilterByModuleListAndCU: |
| // Selects a shared library matching a given file spec |
| //---------------------------------------------------------------------- |
| |
| SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU( |
| const lldb::TargetSP &target_sp, const FileSpecList &module_list, |
| const FileSpecList &cu_list) |
| : SearchFilterByModuleList(target_sp, module_list, |
| FilterTy::ByModulesAndCU), |
| m_cu_spec_list(cu_list) {} |
| |
| SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU( |
| const SearchFilterByModuleListAndCU &rhs) = default; |
| |
| SearchFilterByModuleListAndCU &SearchFilterByModuleListAndCU:: |
| operator=(const SearchFilterByModuleListAndCU &rhs) { |
| if (&rhs != this) { |
| m_target_sp = rhs.m_target_sp; |
| m_module_spec_list = rhs.m_module_spec_list; |
| m_cu_spec_list = rhs.m_cu_spec_list; |
| } |
| return *this; |
| } |
| |
| SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default; |
| |
| lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( |
| Target &target, const StructuredData::Dictionary &data_dict, |
| Status &error) { |
| StructuredData::Array *modules_array = nullptr; |
| SearchFilterSP result_sp; |
| bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), |
| modules_array); |
| FileSpecList modules; |
| if (success) { |
| size_t num_modules = modules_array->GetSize(); |
| for (size_t i = 0; i < num_modules; i++) { |
| llvm::StringRef module; |
| success = modules_array->GetItemAtIndexAsString(i, module); |
| if (!success) { |
| error.SetErrorStringWithFormat( |
| "SFBM::CFSD: filter module item %zu not a string.", i); |
| return result_sp; |
| } |
| modules.Append(FileSpec(module, false)); |
| } |
| } |
| |
| StructuredData::Array *cus_array = nullptr; |
| success = |
| data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array); |
| if (!success) { |
| error.SetErrorString("SFBM::CFSD: Could not find the CU list key."); |
| return result_sp; |
| } |
| |
| size_t num_cus = cus_array->GetSize(); |
| FileSpecList cus; |
| for (size_t i = 0; i < num_cus; i++) { |
| llvm::StringRef cu; |
| success = cus_array->GetItemAtIndexAsString(i, cu); |
| if (!success) { |
| error.SetErrorStringWithFormat( |
| "SFBM::CFSD: filter cu item %zu not a string.", i); |
| return nullptr; |
| } |
| cus.Append(FileSpec(cu, false)); |
| } |
| |
| return std::make_shared<SearchFilterByModuleListAndCU>( |
| target.shared_from_this(), modules, cus); |
| } |
| |
| StructuredData::ObjectSP |
| SearchFilterByModuleListAndCU::SerializeToStructuredData() { |
| auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
| SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp); |
| SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list); |
| return WrapOptionsDict(options_dict_sp); |
| } |
| |
| bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) { |
| return true; |
| } |
| |
| bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) { |
| return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX; |
| } |
| |
| bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) { |
| bool in_cu_list = |
| m_cu_spec_list.FindFileIndex(0, compUnit, false) != UINT32_MAX; |
| if (in_cu_list) { |
| ModuleSP module_sp(compUnit.GetModule()); |
| if (module_sp) { |
| bool module_passes = SearchFilterByModuleList::ModulePasses(module_sp); |
| return module_passes; |
| } else |
| return true; |
| } else |
| return false; |
| } |
| |
| void SearchFilterByModuleListAndCU::Search(Searcher &searcher) { |
| if (!m_target_sp) |
| return; |
| |
| if (searcher.GetDepth() == Searcher::eDepthTarget) { |
| SymbolContext empty_sc; |
| empty_sc.target_sp = m_target_sp; |
| searcher.SearchCallback(*this, empty_sc, nullptr, false); |
| } |
| |
| // If the module file spec is a full path, then we can just find the one |
| // filespec that passes. Otherwise, we need to go through all modules and |
| // find the ones that match the file name. |
| |
| ModuleList matching_modules; |
| const ModuleList &target_images = m_target_sp->GetImages(); |
| std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); |
| |
| const size_t num_modules = target_images.GetSize(); |
| bool no_modules_in_filter = m_module_spec_list.GetSize() == 0; |
| for (size_t i = 0; i < num_modules; i++) { |
| lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i); |
| if (no_modules_in_filter || |
| m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) != |
| UINT32_MAX) { |
| SymbolContext matchingContext(m_target_sp, module_sp); |
| Searcher::CallbackReturn shouldContinue; |
| |
| if (searcher.GetDepth() == Searcher::eDepthModule) { |
| shouldContinue = DoModuleIteration(matchingContext, searcher); |
| if (shouldContinue == Searcher::eCallbackReturnStop) |
| return; |
| } else { |
| const size_t num_cu = module_sp->GetNumCompileUnits(); |
| for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++) { |
| CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(cu_idx); |
| matchingContext.comp_unit = cu_sp.get(); |
| if (matchingContext.comp_unit) { |
| if (m_cu_spec_list.FindFileIndex(0, *matchingContext.comp_unit, |
| false) != UINT32_MAX) { |
| shouldContinue = |
| DoCUIteration(module_sp, matchingContext, searcher); |
| if (shouldContinue == Searcher::eCallbackReturnStop) |
| return; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void SearchFilterByModuleListAndCU::GetDescription(Stream *s) { |
| size_t num_modules = m_module_spec_list.GetSize(); |
| if (num_modules == 1) { |
| s->Printf(", module = "); |
| s->PutCString( |
| m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString( |
| "<Unknown>")); |
| } else if (num_modules > 0) { |
| s->Printf(", modules(%" PRIu64 ") = ", static_cast<uint64_t>(num_modules)); |
| for (size_t i = 0; i < num_modules; i++) { |
| s->PutCString( |
| m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString( |
| "<Unknown>")); |
| if (i != num_modules - 1) |
| s->PutCString(", "); |
| } |
| } |
| } |
| |
| uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() { |
| return eSymbolContextModule | eSymbolContextCompUnit; |
| } |
| |
| void SearchFilterByModuleListAndCU::Dump(Stream *s) const {} |
| |
| lldb::SearchFilterSP |
| SearchFilterByModuleListAndCU::DoCopyForBreakpoint(Breakpoint &breakpoint) { |
| return std::make_shared<SearchFilterByModuleListAndCU>(*this); |
| } |