1404 lines · cpp
1//===-- ModuleList.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Core/ModuleList.h"10#include "lldb/Core/Debugger.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/ModuleSpec.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Host/FileSystem.h"15#include "lldb/Interpreter/OptionValueFileSpec.h"16#include "lldb/Interpreter/OptionValueFileSpecList.h"17#include "lldb/Interpreter/OptionValueProperties.h"18#include "lldb/Interpreter/Property.h"19#include "lldb/Symbol/ObjectFile.h"20#include "lldb/Symbol/SymbolContext.h"21#include "lldb/Symbol/TypeList.h"22#include "lldb/Symbol/VariableList.h"23#include "lldb/Target/Platform.h"24#include "lldb/Target/Target.h"25#include "lldb/Utility/ArchSpec.h"26#include "lldb/Utility/ConstString.h"27#include "lldb/Utility/FileSpecList.h"28#include "lldb/Utility/LLDBLog.h"29#include "lldb/Utility/Log.h"30#include "lldb/Utility/UUID.h"31#include "lldb/lldb-defines.h"32#include "llvm/Support/ThreadPool.h"33 34#if defined(_WIN32)35#include "lldb/Host/windows/PosixApi.h"36#endif37 38#include "clang/Driver/Driver.h"39#include "llvm/ADT/StringRef.h"40#include "llvm/Support/FileSystem.h"41#include "llvm/Support/Threading.h"42#include "llvm/Support/raw_ostream.h"43 44#include <chrono>45#include <memory>46#include <mutex>47#include <string>48#include <utility>49 50namespace lldb_private {51class Function;52}53namespace lldb_private {54class RegularExpression;55}56namespace lldb_private {57class Stream;58}59namespace lldb_private {60class SymbolFile;61}62namespace lldb_private {63class Target;64}65 66using namespace lldb;67using namespace lldb_private;68 69namespace {70 71#define LLDB_PROPERTIES_modulelist72#include "CoreProperties.inc"73 74enum {75#define LLDB_PROPERTIES_modulelist76#include "CorePropertiesEnum.inc"77};78 79} // namespace80 81ModuleListProperties::ModuleListProperties() {82 m_collection_sp = std::make_shared<OptionValueProperties>("symbols");83 m_collection_sp->Initialize(g_modulelist_properties);84 m_collection_sp->SetValueChangedCallback(ePropertySymLinkPaths,85 [this] { UpdateSymlinkMappings(); });86 87 llvm::SmallString<128> path;88 if (clang::driver::Driver::getDefaultModuleCachePath(path)) {89 lldbassert(SetClangModulesCachePath(FileSpec(path)));90 }91 92 path.clear();93 if (llvm::sys::path::cache_directory(path)) {94 llvm::sys::path::append(path, "lldb");95 llvm::sys::path::append(path, "IndexCache");96 lldbassert(SetLLDBIndexCachePath(FileSpec(path)));97 }98 99}100 101bool ModuleListProperties::GetEnableExternalLookup() const {102 const uint32_t idx = ePropertyEnableExternalLookup;103 return GetPropertyAtIndexAs<bool>(104 idx, g_modulelist_properties[idx].default_uint_value != 0);105}106 107bool ModuleListProperties::SetEnableExternalLookup(bool new_value) {108 return SetPropertyAtIndex(ePropertyEnableExternalLookup, new_value);109}110 111SymbolDownload ModuleListProperties::GetSymbolAutoDownload() const {112 // Backward compatibility alias.113 if (GetPropertyAtIndexAs<bool>(ePropertyEnableBackgroundLookup, false))114 return eSymbolDownloadBackground;115 116 const uint32_t idx = ePropertyAutoDownload;117 return GetPropertyAtIndexAs<lldb::SymbolDownload>(118 idx, static_cast<lldb::SymbolDownload>(119 g_modulelist_properties[idx].default_uint_value));120}121 122FileSpec ModuleListProperties::GetClangModulesCachePath() const {123 const uint32_t idx = ePropertyClangModulesCachePath;124 return GetPropertyAtIndexAs<FileSpec>(idx, {});125}126 127bool ModuleListProperties::SetClangModulesCachePath(const FileSpec &path) {128 const uint32_t idx = ePropertyClangModulesCachePath;129 return SetPropertyAtIndex(idx, path);130}131 132FileSpec ModuleListProperties::GetLLDBIndexCachePath() const {133 const uint32_t idx = ePropertyLLDBIndexCachePath;134 return GetPropertyAtIndexAs<FileSpec>(idx, {});135}136 137bool ModuleListProperties::SetLLDBIndexCachePath(const FileSpec &path) {138 const uint32_t idx = ePropertyLLDBIndexCachePath;139 return SetPropertyAtIndex(idx, path);140}141 142bool ModuleListProperties::GetEnableLLDBIndexCache() const {143 const uint32_t idx = ePropertyEnableLLDBIndexCache;144 return GetPropertyAtIndexAs<bool>(145 idx, g_modulelist_properties[idx].default_uint_value != 0);146}147 148bool ModuleListProperties::SetEnableLLDBIndexCache(bool new_value) {149 return SetPropertyAtIndex(ePropertyEnableLLDBIndexCache, new_value);150}151 152uint64_t ModuleListProperties::GetLLDBIndexCacheMaxByteSize() {153 const uint32_t idx = ePropertyLLDBIndexCacheMaxByteSize;154 return GetPropertyAtIndexAs<uint64_t>(155 idx, g_modulelist_properties[idx].default_uint_value);156}157 158uint64_t ModuleListProperties::GetLLDBIndexCacheMaxPercent() {159 const uint32_t idx = ePropertyLLDBIndexCacheMaxPercent;160 return GetPropertyAtIndexAs<uint64_t>(161 idx, g_modulelist_properties[idx].default_uint_value);162}163 164uint64_t ModuleListProperties::GetLLDBIndexCacheExpirationDays() {165 const uint32_t idx = ePropertyLLDBIndexCacheExpirationDays;166 return GetPropertyAtIndexAs<uint64_t>(167 idx, g_modulelist_properties[idx].default_uint_value);168}169 170void ModuleListProperties::UpdateSymlinkMappings() {171 FileSpecList list =172 GetPropertyAtIndexAs<FileSpecList>(ePropertySymLinkPaths, {});173 llvm::sys::ScopedWriter lock(m_symlink_paths_mutex);174 const bool notify = false;175 m_symlink_paths.Clear(notify);176 for (auto symlink : list) {177 FileSpec resolved;178 Status status = FileSystem::Instance().Readlink(symlink, resolved);179 if (status.Success())180 m_symlink_paths.Append(symlink.GetPath(), resolved.GetPath(), notify);181 }182}183 184PathMappingList ModuleListProperties::GetSymlinkMappings() const {185 llvm::sys::ScopedReader lock(m_symlink_paths_mutex);186 return m_symlink_paths;187}188 189bool ModuleListProperties::GetLoadSymbolOnDemand() {190 const uint32_t idx = ePropertyLoadSymbolOnDemand;191 return GetPropertyAtIndexAs<bool>(192 idx, g_modulelist_properties[idx].default_uint_value != 0);193}194 195ModuleList::ModuleList() : m_modules(), m_modules_mutex() {}196 197ModuleList::ModuleList(const ModuleList &rhs) : m_modules(), m_modules_mutex() {198 std::lock_guard<std::recursive_mutex> lhs_guard(m_modules_mutex);199 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_modules_mutex);200 m_modules = rhs.m_modules;201}202 203ModuleList::ModuleList(ModuleList::Notifier *notifier)204 : m_modules(), m_modules_mutex(), m_notifier(notifier) {}205 206const ModuleList &ModuleList::operator=(const ModuleList &rhs) {207 if (this != &rhs) {208 std::lock(m_modules_mutex, rhs.m_modules_mutex);209 std::lock_guard<std::recursive_mutex> lhs_guard(m_modules_mutex,210 std::adopt_lock);211 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_modules_mutex,212 std::adopt_lock);213 m_modules = rhs.m_modules;214 }215 return *this;216}217 218ModuleList::~ModuleList() = default;219 220void ModuleList::AppendImpl(const ModuleSP &module_sp, bool use_notifier) {221 if (!module_sp)222 return;223 {224 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);225 // We are required to keep the first element of the Module List as the226 // executable module. So check here and if the first module is NOT an227 // but the new one is, we insert this module at the beginning, rather than228 // at the end.229 // We don't need to do any of this if the list is empty:230 if (m_modules.empty()) {231 m_modules.push_back(module_sp);232 } else {233 // Since producing the ObjectFile may take some work, first check the234 // 0th element, and only if that's NOT an executable look at the235 // incoming ObjectFile. That way in the normal case we only look at the236 // element 0 ObjectFile.237 const bool elem_zero_is_executable =238 m_modules[0]->GetObjectFile()->GetType() ==239 ObjectFile::Type::eTypeExecutable;240 lldb_private::ObjectFile *obj = module_sp->GetObjectFile();241 if (!elem_zero_is_executable && obj &&242 obj->GetType() == ObjectFile::Type::eTypeExecutable) {243 m_modules.insert(m_modules.begin(), module_sp);244 } else {245 m_modules.push_back(module_sp);246 }247 }248 }249 // Release the mutex before calling the notifier to avoid deadlock250 // NotifyModuleAdded should be thread-safe251 if (use_notifier && m_notifier)252 m_notifier->NotifyModuleAdded(*this, module_sp);253}254 255void ModuleList::Append(const ModuleSP &module_sp, bool notify) {256 AppendImpl(module_sp, notify);257}258 259void ModuleList::ReplaceEquivalent(260 const ModuleSP &module_sp,261 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {262 if (module_sp) {263 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);264 265 // First remove any equivalent modules. Equivalent modules are modules266 // whose path, platform path and architecture match.267 ModuleSpec equivalent_module_spec(module_sp->GetFileSpec(),268 module_sp->GetArchitecture());269 equivalent_module_spec.GetPlatformFileSpec() =270 module_sp->GetPlatformFileSpec();271 272 size_t idx = 0;273 while (idx < m_modules.size()) {274 ModuleSP test_module_sp(m_modules[idx]);275 if (test_module_sp->MatchesModuleSpec(equivalent_module_spec)) {276 if (old_modules)277 old_modules->push_back(test_module_sp);278 RemoveImpl(m_modules.begin() + idx);279 } else {280 ++idx;281 }282 }283 // Now add the new module to the list284 Append(module_sp);285 }286}287 288bool ModuleList::AppendIfNeeded(const ModuleSP &new_module, bool notify) {289 if (new_module) {290 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);291 for (const ModuleSP &module_sp : m_modules) {292 if (module_sp.get() == new_module.get())293 return false; // Already in the list294 }295 // Only push module_sp on the list if it wasn't already in there.296 Append(new_module, notify);297 return true;298 }299 return false;300}301 302void ModuleList::Append(const ModuleList &module_list) {303 for (auto pos : module_list.m_modules)304 Append(pos);305}306 307bool ModuleList::AppendIfNeeded(const ModuleList &module_list) {308 bool any_in = false;309 for (auto pos : module_list.m_modules) {310 if (AppendIfNeeded(pos))311 any_in = true;312 }313 return any_in;314}315 316bool ModuleList::RemoveImpl(const ModuleSP &module_sp, bool use_notifier) {317 if (module_sp) {318 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);319 collection::iterator pos, end = m_modules.end();320 for (pos = m_modules.begin(); pos != end; ++pos) {321 if (pos->get() == module_sp.get()) {322 m_modules.erase(pos);323 if (use_notifier && m_notifier)324 m_notifier->NotifyModuleRemoved(*this, module_sp);325 return true;326 }327 }328 }329 return false;330}331 332ModuleList::collection::iterator333ModuleList::RemoveImpl(ModuleList::collection::iterator pos,334 bool use_notifier) {335 ModuleSP module_sp(*pos);336 collection::iterator retval = m_modules.erase(pos);337 if (use_notifier && m_notifier)338 m_notifier->NotifyModuleRemoved(*this, module_sp);339 return retval;340}341 342bool ModuleList::Remove(const ModuleSP &module_sp, bool notify) {343 return RemoveImpl(module_sp, notify);344}345 346bool ModuleList::ReplaceModule(const lldb::ModuleSP &old_module_sp,347 const lldb::ModuleSP &new_module_sp) {348 if (!RemoveImpl(old_module_sp, false))349 return false;350 AppendImpl(new_module_sp, false);351 if (m_notifier)352 m_notifier->NotifyModuleUpdated(*this, old_module_sp, new_module_sp);353 return true;354}355 356bool ModuleList::RemoveIfOrphaned(const ModuleWP module_wp) {357 if (auto module_sp = module_wp.lock()) {358 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);359 collection::iterator pos, end = m_modules.end();360 for (pos = m_modules.begin(); pos != end; ++pos) {361 if (pos->get() == module_sp.get()) {362 // Since module_sp increases the refcount by 1, the use count should be363 // the regular use count + 1.364 constexpr long kUseCountOrphaned = kUseCountModuleListOrphaned + 1;365 if (pos->use_count() == kUseCountOrphaned) {366 pos = RemoveImpl(pos);367 return true;368 }369 return false;370 }371 }372 }373 return false;374}375 376size_t ModuleList::RemoveOrphans(bool mandatory) {377 std::unique_lock<std::recursive_mutex> lock(m_modules_mutex, std::defer_lock);378 379 if (mandatory) {380 lock.lock();381 } else {382 // Not mandatory, remove orphans if we can get the mutex383 if (!lock.try_lock())384 return 0;385 }386 size_t remove_count = 0;387 // Modules might hold shared pointers to other modules, so removing one388 // module might make other modules orphans. Keep removing modules until389 // there are no further modules that can be removed.390 bool made_progress = true;391 while (made_progress) {392 // Keep track if we make progress this iteration.393 made_progress = false;394 collection::iterator pos = m_modules.begin();395 while (pos != m_modules.end()) {396 if (pos->use_count() == kUseCountModuleListOrphaned) {397 pos = RemoveImpl(pos);398 ++remove_count;399 // We did make progress.400 made_progress = true;401 } else {402 ++pos;403 }404 }405 }406 return remove_count;407}408 409size_t ModuleList::Remove(ModuleList &module_list) {410 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);411 size_t num_removed = 0;412 collection::iterator pos, end = module_list.m_modules.end();413 for (pos = module_list.m_modules.begin(); pos != end; ++pos) {414 if (Remove(*pos, false /* notify */))415 ++num_removed;416 }417 if (m_notifier)418 m_notifier->NotifyModulesRemoved(module_list);419 return num_removed;420}421 422void ModuleList::Clear() { ClearImpl(); }423 424void ModuleList::Destroy() { ClearImpl(); }425 426void ModuleList::ClearImpl(bool use_notifier) {427 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);428 if (use_notifier && m_notifier)429 m_notifier->NotifyWillClearList(*this);430 m_modules.clear();431}432 433Module *ModuleList::GetModulePointerAtIndex(size_t idx) const {434 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);435 if (idx < m_modules.size())436 return m_modules[idx].get();437 return nullptr;438}439 440ModuleSP ModuleList::GetModuleAtIndex(size_t idx) const {441 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);442 return GetModuleAtIndexUnlocked(idx);443}444 445ModuleSP ModuleList::GetModuleAtIndexUnlocked(size_t idx) const {446 ModuleSP module_sp;447 if (idx < m_modules.size())448 module_sp = m_modules[idx];449 return module_sp;450}451 452void ModuleList::FindFunctions(ConstString name,453 FunctionNameType name_type_mask,454 const ModuleFunctionSearchOptions &options,455 SymbolContextList &sc_list) const {456 const size_t old_size = sc_list.GetSize();457 458 if (name_type_mask & eFunctionNameTypeAuto) {459 Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);460 461 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);462 for (const ModuleSP &module_sp : m_modules) {463 module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options,464 sc_list);465 }466 467 const size_t new_size = sc_list.GetSize();468 469 if (old_size < new_size)470 lookup_info.Prune(sc_list, old_size);471 } else {472 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);473 for (const ModuleSP &module_sp : m_modules) {474 module_sp->FindFunctions(name, CompilerDeclContext(), name_type_mask,475 options, sc_list);476 }477 }478}479 480void ModuleList::FindFunctionSymbols(ConstString name,481 lldb::FunctionNameType name_type_mask,482 SymbolContextList &sc_list) {483 const size_t old_size = sc_list.GetSize();484 485 if (name_type_mask & eFunctionNameTypeAuto) {486 Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);487 488 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);489 for (const ModuleSP &module_sp : m_modules) {490 module_sp->FindFunctionSymbols(lookup_info.GetLookupName(),491 lookup_info.GetNameTypeMask(), sc_list);492 }493 494 const size_t new_size = sc_list.GetSize();495 496 if (old_size < new_size)497 lookup_info.Prune(sc_list, old_size);498 } else {499 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);500 for (const ModuleSP &module_sp : m_modules) {501 module_sp->FindFunctionSymbols(name, name_type_mask, sc_list);502 }503 }504}505 506void ModuleList::FindFunctions(const RegularExpression &name,507 const ModuleFunctionSearchOptions &options,508 SymbolContextList &sc_list) {509 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);510 for (const ModuleSP &module_sp : m_modules)511 module_sp->FindFunctions(name, options, sc_list);512}513 514void ModuleList::FindCompileUnits(const FileSpec &path,515 SymbolContextList &sc_list) const {516 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);517 for (const ModuleSP &module_sp : m_modules)518 module_sp->FindCompileUnits(path, sc_list);519}520 521void ModuleList::FindGlobalVariables(ConstString name, size_t max_matches,522 VariableList &variable_list) const {523 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);524 for (const ModuleSP &module_sp : m_modules) {525 module_sp->FindGlobalVariables(name, CompilerDeclContext(), max_matches,526 variable_list);527 }528}529 530void ModuleList::FindGlobalVariables(const RegularExpression ®ex,531 size_t max_matches,532 VariableList &variable_list) const {533 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);534 for (const ModuleSP &module_sp : m_modules)535 module_sp->FindGlobalVariables(regex, max_matches, variable_list);536}537 538void ModuleList::FindSymbolsWithNameAndType(ConstString name,539 SymbolType symbol_type,540 SymbolContextList &sc_list) const {541 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);542 for (const ModuleSP &module_sp : m_modules)543 module_sp->FindSymbolsWithNameAndType(name, symbol_type, sc_list);544}545 546void ModuleList::FindSymbolsMatchingRegExAndType(547 const RegularExpression ®ex, lldb::SymbolType symbol_type,548 SymbolContextList &sc_list) const {549 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);550 for (const ModuleSP &module_sp : m_modules)551 module_sp->FindSymbolsMatchingRegExAndType(regex, symbol_type, sc_list);552}553 554void ModuleList::FindModules(const ModuleSpec &module_spec,555 ModuleList &matching_module_list) const {556 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);557 for (const ModuleSP &module_sp : m_modules) {558 if (module_sp->MatchesModuleSpec(module_spec))559 matching_module_list.Append(module_sp);560 }561}562 563ModuleSP ModuleList::FindModule(const Module *module_ptr) const {564 ModuleSP module_sp;565 566 // Scope for "locker"567 {568 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);569 collection::const_iterator pos, end = m_modules.end();570 571 for (pos = m_modules.begin(); pos != end; ++pos) {572 if ((*pos).get() == module_ptr) {573 module_sp = (*pos);574 break;575 }576 }577 }578 return module_sp;579}580 581ModuleSP ModuleList::FindModule(const UUID &uuid) const {582 ModuleSP module_sp;583 584 if (uuid.IsValid()) {585 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);586 collection::const_iterator pos, end = m_modules.end();587 588 for (pos = m_modules.begin(); pos != end; ++pos) {589 if ((*pos)->GetUUID() == uuid) {590 module_sp = (*pos);591 break;592 }593 }594 }595 return module_sp;596}597 598ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const {599 ModuleSP module_sp;600 ForEach([&](const ModuleSP &m) {601 if (m->GetID() == uid) {602 module_sp = m;603 return IterationAction::Stop;604 }605 606 return IterationAction::Continue;607 });608 609 return module_sp;610}611 612void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,613 TypeResults &results) const {614 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);615 if (search_first) {616 search_first->FindTypes(query, results);617 if (results.Done(query))618 return;619 }620 for (const auto &module_sp : m_modules) {621 if (search_first != module_sp.get()) {622 module_sp->FindTypes(query, results);623 if (results.Done(query))624 return;625 }626 }627}628 629bool ModuleList::FindSourceFile(const FileSpec &orig_spec,630 FileSpec &new_spec) const {631 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);632 for (const ModuleSP &module_sp : m_modules) {633 if (module_sp->FindSourceFile(orig_spec, new_spec))634 return true;635 }636 return false;637}638 639void ModuleList::FindAddressesForLine(const lldb::TargetSP target_sp,640 const FileSpec &file, uint32_t line,641 Function *function,642 std::vector<Address> &output_local,643 std::vector<Address> &output_extern) {644 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);645 for (const ModuleSP &module_sp : m_modules) {646 module_sp->FindAddressesForLine(target_sp, file, line, function,647 output_local, output_extern);648 }649}650 651ModuleSP ModuleList::FindFirstModule(const ModuleSpec &module_spec) const {652 ModuleSP module_sp;653 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);654 collection::const_iterator pos, end = m_modules.end();655 for (pos = m_modules.begin(); pos != end; ++pos) {656 ModuleSP module_sp(*pos);657 if (module_sp->MatchesModuleSpec(module_spec))658 return module_sp;659 }660 return module_sp;661}662 663size_t ModuleList::GetSize() const {664 size_t size = 0;665 {666 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);667 size = m_modules.size();668 }669 return size;670}671 672void ModuleList::Dump(Stream *s) const {673 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);674 for (const ModuleSP &module_sp : m_modules)675 module_sp->Dump(s);676}677 678void ModuleList::LogUUIDAndPaths(Log *log, const char *prefix_cstr) {679 if (log != nullptr) {680 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);681 collection::const_iterator pos, begin = m_modules.begin(),682 end = m_modules.end();683 for (pos = begin; pos != end; ++pos) {684 Module *module = pos->get();685 const FileSpec &module_file_spec = module->GetFileSpec();686 LLDB_LOGF(log, "%s[%u] %s (%s) \"%s\"", prefix_cstr ? prefix_cstr : "",687 (uint32_t)std::distance(begin, pos),688 module->GetUUID().GetAsString().c_str(),689 module->GetArchitecture().GetArchitectureName(),690 module_file_spec.GetPath().c_str());691 }692 }693}694 695bool ModuleList::ResolveFileAddress(lldb::addr_t vm_addr,696 Address &so_addr) const {697 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);698 for (const ModuleSP &module_sp : m_modules) {699 if (module_sp->ResolveFileAddress(vm_addr, so_addr))700 return true;701 }702 703 return false;704}705 706uint32_t707ModuleList::ResolveSymbolContextForAddress(const Address &so_addr,708 SymbolContextItem resolve_scope,709 SymbolContext &sc) const {710 // The address is already section offset so it has a module711 uint32_t resolved_flags = 0;712 ModuleSP module_sp(so_addr.GetModule());713 if (module_sp) {714 resolved_flags =715 module_sp->ResolveSymbolContextForAddress(so_addr, resolve_scope, sc);716 } else {717 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);718 collection::const_iterator pos, end = m_modules.end();719 for (pos = m_modules.begin(); pos != end; ++pos) {720 resolved_flags =721 (*pos)->ResolveSymbolContextForAddress(so_addr, resolve_scope, sc);722 if (resolved_flags != 0)723 break;724 }725 }726 727 return resolved_flags;728}729 730uint32_t ModuleList::ResolveSymbolContextForFilePath(731 const char *file_path, uint32_t line, bool check_inlines,732 SymbolContextItem resolve_scope, SymbolContextList &sc_list) const {733 FileSpec file_spec(file_path);734 return ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines,735 resolve_scope, sc_list);736}737 738uint32_t ModuleList::ResolveSymbolContextsForFileSpec(739 const FileSpec &file_spec, uint32_t line, bool check_inlines,740 SymbolContextItem resolve_scope, SymbolContextList &sc_list) const {741 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);742 for (const ModuleSP &module_sp : m_modules) {743 module_sp->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines,744 resolve_scope, sc_list);745 }746 747 return sc_list.GetSize();748}749 750size_t ModuleList::GetIndexForModule(const Module *module) const {751 if (module) {752 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);753 collection::const_iterator pos;754 collection::const_iterator begin = m_modules.begin();755 collection::const_iterator end = m_modules.end();756 for (pos = begin; pos != end; ++pos) {757 if ((*pos).get() == module)758 return std::distance(begin, pos);759 }760 }761 return LLDB_INVALID_INDEX32;762}763 764namespace {765/// A wrapper around ModuleList for shared modules. Provides fast lookups for766/// file-based ModuleSpec queries.767class SharedModuleList {768public:769 /// Finds all the modules matching the module_spec, and adds them to \p770 /// matching_module_list.771 void FindModules(const ModuleSpec &module_spec,772 ModuleList &matching_module_list) const {773 std::lock_guard<std::recursive_mutex> guard(GetMutex());774 // Try map first for performance - if found, skip expensive full list775 // search.776 FindModulesInMap(module_spec, matching_module_list);777 if (!matching_module_list.IsEmpty())778 return;779 m_list.FindModules(module_spec, matching_module_list);780 // Assert that modules were found in the list but not the map, it's781 // because the module_spec has no filename or the found module has a782 // different filename. For example, when searching by UUID and finding a783 // module with an alias.784 assert((matching_module_list.IsEmpty() ||785 module_spec.GetFileSpec().GetFilename().IsEmpty() ||786 module_spec.GetFileSpec().GetFilename() !=787 matching_module_list.GetModuleAtIndex(0)788 ->GetFileSpec()789 .GetFilename()) &&790 "Search by name not found in SharedModuleList's map");791 }792 793 ModuleSP FindModule(const Module &module) {794 795 std::lock_guard<std::recursive_mutex> guard(GetMutex());796 if (ModuleSP result = FindModuleInMap(module))797 return result;798 return m_list.FindModule(&module);799 }800 801 // UUID searches bypass map since UUIDs aren't indexed by filename.802 ModuleSP FindModule(const UUID &uuid) const {803 return m_list.FindModule(uuid);804 }805 806 void Append(const ModuleSP &module_sp, bool use_notifier) {807 if (!module_sp)808 return;809 std::lock_guard<std::recursive_mutex> guard(GetMutex());810 m_list.Append(module_sp, use_notifier);811 AddToMap(module_sp);812 }813 814 size_t RemoveOrphans(bool mandatory) {815 std::unique_lock<std::recursive_mutex> lock(GetMutex(), std::defer_lock);816 if (mandatory) {817 lock.lock();818 } else {819 if (!lock.try_lock())820 return 0;821 }822 size_t total_count = 0;823 size_t run_count;824 do {825 // Remove indexed orphans first, then remove non-indexed orphans. This826 // order is important because the shared count will be different if a827 // module is indexed or not.828 run_count = RemoveOrphansFromMapAndList();829 run_count += m_list.RemoveOrphans(mandatory);830 total_count += run_count;831 // Because removing orphans might make new orphans, remove from both832 // containers until a fixed-point is reached.833 } while (run_count != 0);834 835 return total_count;836 }837 838 bool Remove(const ModuleSP &module_sp, bool use_notifier = true) {839 if (!module_sp)840 return false;841 std::lock_guard<std::recursive_mutex> guard(GetMutex());842 RemoveFromMap(module_sp);843 return m_list.Remove(module_sp, use_notifier);844 }845 846 void ReplaceEquivalent(const ModuleSP &module_sp,847 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {848 std::lock_guard<std::recursive_mutex> guard(GetMutex());849 m_list.ReplaceEquivalent(module_sp, old_modules);850 ReplaceEquivalentInMap(module_sp);851 }852 853 bool RemoveIfOrphaned(const ModuleWP module_wp) {854 std::lock_guard<std::recursive_mutex> guard(GetMutex());855 RemoveFromMap(module_wp, /*if_orphaned=*/true);856 return m_list.RemoveIfOrphaned(module_wp);857 }858 859 std::recursive_mutex &GetMutex() const { return m_list.GetMutex(); }860 861private:862 ModuleSP FindModuleInMap(const Module &module) const {863 if (!module.GetFileSpec().GetFilename())864 return ModuleSP();865 ConstString name = module.GetFileSpec().GetFilename();866 auto it = m_name_to_modules.find(name);867 if (it == m_name_to_modules.end())868 return ModuleSP();869 const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;870 for (const ModuleSP &module_sp : vector) {871 if (module_sp.get() == &module)872 return module_sp;873 }874 return ModuleSP();875 }876 877 void FindModulesInMap(const ModuleSpec &module_spec,878 ModuleList &matching_module_list) const {879 auto it = m_name_to_modules.find(module_spec.GetFileSpec().GetFilename());880 if (it == m_name_to_modules.end())881 return;882 const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;883 for (const ModuleSP &module_sp : vector) {884 if (module_sp->MatchesModuleSpec(module_spec))885 matching_module_list.Append(module_sp);886 }887 }888 889 void AddToMap(const ModuleSP &module_sp) {890 ConstString name = module_sp->GetFileSpec().GetFilename();891 if (name.IsEmpty())892 return;893 m_name_to_modules[name].push_back(module_sp);894 }895 896 void RemoveFromMap(const ModuleWP module_wp, bool if_orphaned = false) {897 if (auto module_sp = module_wp.lock()) {898 ConstString name = module_sp->GetFileSpec().GetFilename();899 if (!m_name_to_modules.contains(name))900 return;901 llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];902 for (auto *it = vec.begin(); it != vec.end(); ++it) {903 if (it->get() == module_sp.get()) {904 // Since module_sp increases the refcount by 1, the use count should905 // be the regular use count + 1.906 constexpr long kUseCountOrphaned =907 kUseCountSharedModuleListOrphaned + 1;908 if (!if_orphaned || it->use_count() == kUseCountOrphaned) {909 vec.erase(it);910 break;911 }912 }913 }914 }915 }916 917 void ReplaceEquivalentInMap(const ModuleSP &module_sp) {918 RemoveEquivalentModulesFromMap(module_sp);919 AddToMap(module_sp);920 }921 922 void RemoveEquivalentModulesFromMap(const ModuleSP &module_sp) {923 ConstString name = module_sp->GetFileSpec().GetFilename();924 if (name.IsEmpty())925 return;926 927 auto it = m_name_to_modules.find(name);928 if (it == m_name_to_modules.end())929 return;930 931 // First remove any equivalent modules. Equivalent modules are modules932 // whose path, platform path and architecture match.933 ModuleSpec equivalent_module_spec(module_sp->GetFileSpec(),934 module_sp->GetArchitecture());935 equivalent_module_spec.GetPlatformFileSpec() =936 module_sp->GetPlatformFileSpec();937 938 llvm::SmallVectorImpl<ModuleSP> &vec = it->second;939 llvm::erase_if(vec, [&equivalent_module_spec](ModuleSP &element) {940 return element->MatchesModuleSpec(equivalent_module_spec);941 });942 }943 944 /// Remove orphans from the vector and return the removed modules.945 ModuleList RemoveOrphansFromVector(llvm::SmallVectorImpl<ModuleSP> &vec) {946 // remove_if moves the elements that match the condition to the end of the947 // container, and returns an iterator to the first element that was moved.948 auto *to_remove_start = llvm::remove_if(vec, [](const ModuleSP &module) {949 return module.use_count() == kUseCountSharedModuleListOrphaned;950 });951 952 ModuleList to_remove;953 for (ModuleSP *it = to_remove_start; it != vec.end(); ++it)954 to_remove.Append(*it);955 956 vec.erase(to_remove_start, vec.end());957 return to_remove;958 }959 960 /// Remove orphans that exist in both the map and list. This does not remove961 /// any orphans that exist exclusively on the list.962 ///963 /// The mutex must be locked by the caller.964 int RemoveOrphansFromMapAndList() {965 // Modules might hold shared pointers to other modules, so removing one966 // module might orphan other modules. Keep removing modules until967 // there are no further modules that can be removed.968 int remove_count = 0;969 int previous_remove_count;970 do {971 previous_remove_count = remove_count;972 for (auto &[name, vec] : m_name_to_modules) {973 if (vec.empty())974 continue;975 ModuleList to_remove = RemoveOrphansFromVector(vec);976 remove_count += to_remove.GetSize();977 m_list.Remove(to_remove);978 }979 // Break when fixed-point is reached.980 } while (previous_remove_count != remove_count);981 982 return remove_count;983 }984 985 ModuleList m_list;986 987 /// A hash map from a module's filename to all the modules that share that988 /// filename, for fast module lookups by name.989 llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1>> m_name_to_modules;990 991 /// The use count of a module held only by m_list and m_name_to_modules.992 static constexpr long kUseCountSharedModuleListOrphaned = 2;993};994 995struct SharedModuleListInfo {996 SharedModuleList module_list;997 ModuleListProperties module_list_properties;998};999}1000static SharedModuleListInfo &GetSharedModuleListInfo()1001{1002 static SharedModuleListInfo *g_shared_module_list_info = nullptr;1003 static llvm::once_flag g_once_flag;1004 llvm::call_once(g_once_flag, []() {1005 // NOTE: Intentionally leak the module list so a program doesn't have to1006 // cleanup all modules and object files as it exits. This just wastes time1007 // doing a bunch of cleanup that isn't required.1008 if (g_shared_module_list_info == nullptr)1009 g_shared_module_list_info = new SharedModuleListInfo();1010 });1011 return *g_shared_module_list_info;1012}1013 1014static SharedModuleList &GetSharedModuleList() {1015 return GetSharedModuleListInfo().module_list;1016}1017 1018ModuleListProperties &ModuleList::GetGlobalModuleListProperties() {1019 return GetSharedModuleListInfo().module_list_properties;1020}1021 1022bool ModuleList::ModuleIsInCache(const Module *module_ptr) {1023 if (module_ptr) {1024 SharedModuleList &shared_module_list = GetSharedModuleList();1025 return shared_module_list.FindModule(*module_ptr).get() != nullptr;1026 }1027 return false;1028}1029 1030void ModuleList::FindSharedModules(const ModuleSpec &module_spec,1031 ModuleList &matching_module_list) {1032 GetSharedModuleList().FindModules(module_spec, matching_module_list);1033}1034 1035lldb::ModuleSP ModuleList::FindSharedModule(const UUID &uuid) {1036 return GetSharedModuleList().FindModule(uuid);1037}1038 1039size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) {1040 return GetSharedModuleList().RemoveOrphans(mandatory);1041}1042 1043Status1044ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,1045 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,1046 bool *did_create_ptr, bool always_create,1047 bool invoke_locate_callback) {1048 SharedModuleList &shared_module_list = GetSharedModuleList();1049 std::lock_guard<std::recursive_mutex> guard(shared_module_list.GetMutex());1050 char path[PATH_MAX];1051 1052 Status error;1053 1054 module_sp.reset();1055 1056 if (did_create_ptr)1057 *did_create_ptr = false;1058 1059 const UUID *uuid_ptr = module_spec.GetUUIDPtr();1060 const FileSpec &module_file_spec = module_spec.GetFileSpec();1061 const ArchSpec &arch = module_spec.GetArchitecture();1062 1063 // Make sure no one else can try and get or create a module while this1064 // function is actively working on it by doing an extra lock on the global1065 // mutex list.1066 if (!always_create) {1067 ModuleList matching_module_list;1068 shared_module_list.FindModules(module_spec, matching_module_list);1069 const size_t num_matching_modules = matching_module_list.GetSize();1070 1071 if (num_matching_modules > 0) {1072 for (size_t module_idx = 0; module_idx < num_matching_modules;1073 ++module_idx) {1074 module_sp = matching_module_list.GetModuleAtIndex(module_idx);1075 1076 // Make sure the file for the module hasn't been modified1077 if (module_sp->FileHasChanged()) {1078 if (old_modules)1079 old_modules->push_back(module_sp);1080 1081 Log *log = GetLog(LLDBLog::Modules);1082 if (log != nullptr)1083 LLDB_LOGF(1084 log, "%p '%s' module changed: removing from global module list",1085 static_cast<void *>(module_sp.get()),1086 module_sp->GetFileSpec().GetFilename().GetCString());1087 1088 shared_module_list.Remove(module_sp);1089 module_sp.reset();1090 } else {1091 // The module matches and the module was not modified from when it1092 // was last loaded.1093 return error;1094 }1095 }1096 }1097 }1098 1099 if (module_sp)1100 return error;1101 1102 // Try target's platform locate module callback before second attempt.1103 if (invoke_locate_callback) {1104 TargetSP target_sp = module_spec.GetTargetSP();1105 if (target_sp && target_sp->IsValid()) {1106 if (PlatformSP platform_sp = target_sp->GetPlatform()) {1107 FileSpec symbol_file_spec;1108 platform_sp->CallLocateModuleCallbackIfSet(1109 module_spec, module_sp, symbol_file_spec, did_create_ptr);1110 if (module_sp) {1111 // The callback found a module.1112 return error;1113 }1114 }1115 }1116 }1117 1118 module_sp = std::make_shared<Module>(module_spec);1119 // Make sure there are a module and an object file since we can specify a1120 // valid file path with an architecture that might not be in that file. By1121 // getting the object file we can guarantee that the architecture matches1122 if (module_sp->GetObjectFile()) {1123 // If we get in here we got the correct arch, now we just need to verify1124 // the UUID if one was given1125 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID()) {1126 module_sp.reset();1127 } else {1128 if (module_sp->GetObjectFile() &&1129 module_sp->GetObjectFile()->GetType() ==1130 ObjectFile::eTypeStubLibrary) {1131 module_sp.reset();1132 } else {1133 if (did_create_ptr) {1134 *did_create_ptr = true;1135 }1136 1137 shared_module_list.ReplaceEquivalent(module_sp, old_modules);1138 return error;1139 }1140 }1141 } else {1142 module_sp.reset();1143 }1144 1145 // Get module search paths from the target if available.1146 lldb::TargetSP target_sp = module_spec.GetTargetSP();1147 FileSpecList module_search_paths;1148 if (target_sp)1149 module_search_paths = target_sp->GetExecutableSearchPaths();1150 1151 if (!module_search_paths.IsEmpty()) {1152 const auto num_directories = module_search_paths.GetSize();1153 for (size_t idx = 0; idx < num_directories; ++idx) {1154 auto search_path_spec = module_search_paths.GetFileSpecAtIndex(idx);1155 FileSystem::Instance().Resolve(search_path_spec);1156 namespace fs = llvm::sys::fs;1157 if (!FileSystem::Instance().IsDirectory(search_path_spec))1158 continue;1159 search_path_spec.AppendPathComponent(1160 module_spec.GetFileSpec().GetFilename().GetStringRef());1161 if (!FileSystem::Instance().Exists(search_path_spec))1162 continue;1163 1164 auto resolved_module_spec(module_spec);1165 resolved_module_spec.GetFileSpec() = search_path_spec;1166 module_sp = std::make_shared<Module>(resolved_module_spec);1167 if (module_sp->GetObjectFile()) {1168 // If we get in here we got the correct arch, now we just need to1169 // verify the UUID if one was given1170 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID()) {1171 module_sp.reset();1172 } else {1173 if (module_sp->GetObjectFile()->GetType() ==1174 ObjectFile::eTypeStubLibrary) {1175 module_sp.reset();1176 } else {1177 if (did_create_ptr)1178 *did_create_ptr = true;1179 1180 shared_module_list.ReplaceEquivalent(module_sp, old_modules);1181 return Status();1182 }1183 }1184 } else {1185 module_sp.reset();1186 }1187 }1188 }1189 1190 // Either the file didn't exist where at the path, or no path was given, so1191 // we now have to use more extreme measures to try and find the appropriate1192 // module.1193 1194 // Fixup the incoming path in case the path points to a valid file, yet the1195 // arch or UUID (if one was passed in) don't match.1196 ModuleSpec located_binary_modulespec;1197 StatisticsMap symbol_locator_map;1198 located_binary_modulespec = PluginManager::LocateExecutableObjectFile(1199 module_spec, symbol_locator_map);1200 // Don't look for the file if it appears to be the same one we already1201 // checked for above...1202 if (located_binary_modulespec.GetFileSpec() != module_file_spec) {1203 if (!FileSystem::Instance().Exists(1204 located_binary_modulespec.GetFileSpec())) {1205 located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path));1206 if (path[0] == '\0')1207 module_file_spec.GetPath(path, sizeof(path));1208 // How can this check ever be true? This branch it is false, and we1209 // haven't modified file_spec.1210 if (FileSystem::Instance().Exists(1211 located_binary_modulespec.GetFileSpec())) {1212 std::string uuid_str;1213 if (uuid_ptr && uuid_ptr->IsValid())1214 uuid_str = uuid_ptr->GetAsString();1215 1216 if (arch.IsValid()) {1217 if (!uuid_str.empty())1218 error = Status::FromErrorStringWithFormat(1219 "'%s' does not contain the %s architecture and UUID %s", path,1220 arch.GetArchitectureName(), uuid_str.c_str());1221 else1222 error = Status::FromErrorStringWithFormat(1223 "'%s' does not contain the %s architecture.", path,1224 arch.GetArchitectureName());1225 }1226 } else {1227 error = Status::FromErrorStringWithFormat("'%s' does not exist", path);1228 }1229 if (error.Fail())1230 module_sp.reset();1231 return error;1232 }1233 1234 // Make sure no one else can try and get or create a module while this1235 // function is actively working on it by doing an extra lock on the global1236 // mutex list.1237 ModuleSpec platform_module_spec(module_spec);1238 platform_module_spec.GetFileSpec() =1239 located_binary_modulespec.GetFileSpec();1240 platform_module_spec.GetPlatformFileSpec() =1241 located_binary_modulespec.GetFileSpec();1242 platform_module_spec.GetSymbolFileSpec() =1243 located_binary_modulespec.GetSymbolFileSpec();1244 ModuleList matching_module_list;1245 shared_module_list.FindModules(platform_module_spec, matching_module_list);1246 if (!matching_module_list.IsEmpty()) {1247 module_sp = matching_module_list.GetModuleAtIndex(0);1248 1249 // If we didn't have a UUID in mind when looking for the object file,1250 // then we should make sure the modification time hasn't changed!1251 if (platform_module_spec.GetUUIDPtr() == nullptr) {1252 auto file_spec_mod_time = FileSystem::Instance().GetModificationTime(1253 located_binary_modulespec.GetFileSpec());1254 if (file_spec_mod_time != llvm::sys::TimePoint<>()) {1255 if (file_spec_mod_time != module_sp->GetModificationTime()) {1256 if (old_modules)1257 old_modules->push_back(module_sp);1258 shared_module_list.Remove(module_sp);1259 module_sp.reset();1260 }1261 }1262 }1263 }1264 1265 if (!module_sp) {1266 module_sp = std::make_shared<Module>(platform_module_spec);1267 // Make sure there are a module and an object file since we can specify a1268 // valid file path with an architecture that might not be in that file.1269 // By getting the object file we can guarantee that the architecture1270 // matches1271 if (module_sp && module_sp->GetObjectFile()) {1272 module_sp->GetSymbolLocatorStatistics().merge(symbol_locator_map);1273 if (module_sp->GetObjectFile()->GetType() ==1274 ObjectFile::eTypeStubLibrary) {1275 module_sp.reset();1276 } else {1277 if (did_create_ptr)1278 *did_create_ptr = true;1279 1280 shared_module_list.ReplaceEquivalent(module_sp, old_modules);1281 }1282 } else {1283 located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path));1284 1285 if (located_binary_modulespec.GetFileSpec()) {1286 if (arch.IsValid())1287 error = Status::FromErrorStringWithFormat(1288 "unable to open %s architecture in '%s'",1289 arch.GetArchitectureName(), path);1290 else1291 error =1292 Status::FromErrorStringWithFormat("unable to open '%s'", path);1293 } else {1294 std::string uuid_str;1295 if (uuid_ptr && uuid_ptr->IsValid())1296 uuid_str = uuid_ptr->GetAsString();1297 1298 if (!uuid_str.empty())1299 error = Status::FromErrorStringWithFormat(1300 "cannot locate a module for UUID '%s'", uuid_str.c_str());1301 else1302 error = Status::FromErrorString("cannot locate a module");1303 }1304 }1305 }1306 }1307 1308 return error;1309}1310 1311bool ModuleList::RemoveSharedModule(lldb::ModuleSP &module_sp) {1312 return GetSharedModuleList().Remove(module_sp);1313}1314 1315bool ModuleList::RemoveSharedModuleIfOrphaned(const ModuleWP module_wp) {1316 return GetSharedModuleList().RemoveIfOrphaned(module_wp);1317}1318 1319bool ModuleList::LoadScriptingResourcesInTarget(Target *target,1320 std::list<Status> &errors,1321 Stream &feedback_stream,1322 bool continue_on_error) {1323 if (!target)1324 return false;1325 m_modules_mutex.lock();1326 // Don't hold the module list mutex while loading the scripting resources,1327 // The initializer might do any amount of work, and having that happen while1328 // the module list is held is asking for A/B locking problems.1329 const ModuleList tmp_module_list(*this);1330 m_modules_mutex.unlock();1331 1332 for (auto module : tmp_module_list.ModulesNoLocking()) {1333 if (module) {1334 Status error;1335 if (!module->LoadScriptingResourceInTarget(target, error,1336 feedback_stream)) {1337 if (error.Fail() && error.AsCString()) {1338 error = Status::FromErrorStringWithFormat(1339 "unable to load scripting data for "1340 "module %s - error reported was %s",1341 module->GetFileSpec()1342 .GetFileNameStrippingExtension()1343 .GetCString(),1344 error.AsCString());1345 errors.push_back(std::move(error));1346 if (!continue_on_error)1347 return false;1348 }1349 }1350 }1351 }1352 return errors.empty();1353}1354 1355void ModuleList::ForEach(1356 std::function<IterationAction(const ModuleSP &module_sp)> const &callback)1357 const {1358 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);1359 for (const auto &module_sp : m_modules) {1360 assert(module_sp != nullptr);1361 if (callback(module_sp) == IterationAction::Stop)1362 break;1363 }1364}1365 1366bool ModuleList::AnyOf(1367 std::function<bool(lldb_private::Module &module_sp)> const &callback)1368 const {1369 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);1370 for (const auto &module_sp : m_modules) {1371 assert(module_sp != nullptr);1372 if (callback(*module_sp))1373 return true;1374 }1375 1376 return false;1377}1378 1379 1380void ModuleList::Swap(ModuleList &other) {1381 // scoped_lock locks both mutexes at once.1382 std::scoped_lock<std::recursive_mutex, std::recursive_mutex> lock(1383 m_modules_mutex, other.m_modules_mutex);1384 m_modules.swap(other.m_modules);1385}1386 1387void ModuleList::PreloadSymbols(bool parallelize) const {1388 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);1389 1390 if (!parallelize) {1391 for (const ModuleSP &module_sp : m_modules)1392 module_sp->PreloadSymbols();1393 return;1394 }1395 1396 llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());1397 for (const ModuleSP &module_sp : m_modules)1398 task_group.async([module_sp] {1399 if (module_sp)1400 module_sp->PreloadSymbols();1401 });1402 task_group.wait();1403}1404