LLDB mainline
ModuleList.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Core/Debugger.h"
11#include "lldb/Core/Module.h"
24#include "lldb/Target/Target.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)
36#endif
37
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 {
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_modulelist
72#include "CoreProperties.inc"
73
74enum {
75#define LLDB_PROPERTIES_modulelist
76#include "CorePropertiesEnum.inc"
77};
78
79} // namespace
80
82 m_collection_sp = std::make_shared<OptionValueProperties>("symbols");
83 m_collection_sp->Initialize(g_modulelist_properties_def);
84 m_collection_sp->SetValueChangedCallback(ePropertySymLinkPaths,
85 [this] { UpdateSymlinkMappings(); });
86
87 llvm::SmallString<128> path;
88 if (clang::driver::Driver::getDefaultModuleCachePath(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");
97 }
98}
99
101 const uint32_t idx = ePropertyEnableExternalLookup;
103 idx, g_modulelist_properties[idx].default_uint_value != 0);
104}
105
107 return SetPropertyAtIndex(ePropertyEnableExternalLookup, new_value);
108}
109
111 // Backward compatibility alias.
112 if (GetPropertyAtIndexAs<bool>(ePropertyEnableBackgroundLookup, false))
114
115 const uint32_t idx = ePropertyAutoDownload;
117 idx, static_cast<lldb::SymbolDownload>(
118 g_modulelist_properties[idx].default_uint_value));
119}
120
122 const uint32_t idx = ePropertySharedCacheBinaryLoading;
124 idx, static_cast<lldb::SymbolSharedCacheUse>(
125 g_modulelist_properties[idx].default_uint_value));
126}
127
129 const uint32_t idx = ePropertyClangModulesCachePath;
130 return GetPropertyAtIndexAs<FileSpec>(idx, {});
131}
132
134 const uint32_t idx = ePropertyClangModulesCachePath;
135 return SetPropertyAtIndex(idx, path);
136}
137
139 const uint32_t idx = ePropertyLLDBIndexCachePath;
140 return GetPropertyAtIndexAs<FileSpec>(idx, {});
141}
142
144 const uint32_t idx = ePropertyLLDBIndexCachePath;
145 return SetPropertyAtIndex(idx, path);
146}
147
149 const uint32_t idx = ePropertyEnableLLDBIndexCache;
151 idx, g_modulelist_properties[idx].default_uint_value != 0);
152}
153
155 return SetPropertyAtIndex(ePropertyEnableLLDBIndexCache, new_value);
156}
157
159 const uint32_t idx = ePropertyLLDBIndexCacheMaxByteSize;
161 idx, g_modulelist_properties[idx].default_uint_value);
162}
163
165 const uint32_t idx = ePropertyLLDBIndexCacheMaxPercent;
167 idx, g_modulelist_properties[idx].default_uint_value);
168}
169
171 const uint32_t idx = ePropertyLLDBIndexCacheExpirationDays;
173 idx, g_modulelist_properties[idx].default_uint_value);
174}
175
177 FileSpecList list =
178 GetPropertyAtIndexAs<FileSpecList>(ePropertySymLinkPaths, {});
179 llvm::sys::ScopedWriter lock(m_symlink_paths_mutex);
180 const bool notify = false;
181 m_symlink_paths.Clear(notify);
182 for (auto symlink : list) {
183 FileSpec resolved;
184 Status status = FileSystem::Instance().Readlink(symlink, resolved);
185 if (status.Success())
186 m_symlink_paths.Append(symlink.GetPath(), resolved.GetPath(), notify);
187 }
188}
189
191 llvm::sys::ScopedReader lock(m_symlink_paths_mutex);
192 return m_symlink_paths;
193}
194
196 const uint32_t idx = ePropertyLoadSymbolOnDemand;
198 idx, g_modulelist_properties[idx].default_uint_value != 0);
199}
200
202
204 std::lock_guard<std::recursive_mutex> lhs_guard(m_modules_mutex);
205 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_modules_mutex);
206 m_modules = rhs.m_modules;
207}
208
211
213 if (this != &rhs) {
214 std::lock(m_modules_mutex, rhs.m_modules_mutex);
215 std::lock_guard<std::recursive_mutex> lhs_guard(m_modules_mutex,
216 std::adopt_lock);
217 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_modules_mutex,
218 std::adopt_lock);
219 m_modules = rhs.m_modules;
220 }
221 return *this;
222}
223
224ModuleList::~ModuleList() = default;
225
226void ModuleList::AppendImpl(const ModuleSP &module_sp, bool use_notifier) {
227 if (!module_sp)
228 return;
229 {
230 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
231 // We are required to keep the first element of the Module List as the
232 // executable module. So check here and if the first module is NOT an
233 // but the new one is, we insert this module at the beginning, rather than
234 // at the end.
235 // We don't need to do any of this if the list is empty:
236 if (m_modules.empty()) {
237 m_modules.push_back(module_sp);
238 } else {
239 // Since producing the ObjectFile may take some work, first check the
240 // 0th element, and only if that's NOT an executable look at the
241 // incoming ObjectFile. That way in the normal case we only look at the
242 // element 0 ObjectFile.
243 lldb_private::ObjectFile *elem_zero_obj = m_modules[0]->GetObjectFile();
244 const bool elem_zero_is_executable =
245 elem_zero_obj &&
246 elem_zero_obj->GetType() == ObjectFile::Type::eTypeExecutable;
247 lldb_private::ObjectFile *obj = module_sp->GetObjectFile();
248 if (!elem_zero_is_executable && obj &&
250 m_modules.insert(m_modules.begin(), module_sp);
251 } else {
252 m_modules.push_back(module_sp);
253 }
254 }
255 }
256 // Release the mutex before calling the notifier to avoid deadlock
257 // NotifyModuleAdded should be thread-safe
258 if (use_notifier && m_notifier)
259 m_notifier->NotifyModuleAdded(*this, module_sp);
260}
261
262void ModuleList::Append(const ModuleSP &module_sp, bool notify) {
263 AppendImpl(module_sp, notify);
264}
265
267 const ModuleSP &module_sp,
269 if (module_sp) {
270 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
271
272 // First remove any equivalent modules. Equivalent modules are modules
273 // whose path, platform path and architecture match.
274 ModuleSpec equivalent_module_spec(module_sp->GetFileSpec(),
275 module_sp->GetArchitecture());
276 equivalent_module_spec.GetPlatformFileSpec() =
277 module_sp->GetPlatformFileSpec();
278
279 size_t idx = 0;
280 while (idx < m_modules.size()) {
281 ModuleSP test_module_sp(m_modules[idx]);
282 if (test_module_sp->MatchesModuleSpec(equivalent_module_spec)) {
283 if (old_modules)
284 old_modules->push_back(test_module_sp);
285 RemoveImpl(m_modules.begin() + idx);
286 } else {
287 ++idx;
288 }
289 }
290 // Now add the new module to the list
291 Append(module_sp);
292 }
293}
294
295bool ModuleList::AppendIfNeeded(const ModuleSP &new_module, bool notify) {
296 if (new_module) {
297 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
298 for (const ModuleSP &module_sp : m_modules) {
299 if (module_sp.get() == new_module.get())
300 return false; // Already in the list
301 }
302 // Only push module_sp on the list if it wasn't already in there.
303 Append(new_module, notify);
304 return true;
305 }
306 return false;
307}
308
309void ModuleList::Append(const ModuleList &module_list) {
310 for (auto pos : module_list.m_modules)
311 Append(pos);
312}
313
314bool ModuleList::AppendIfNeeded(const ModuleList &module_list) {
315 bool any_in = false;
316 for (auto pos : module_list.m_modules) {
317 if (AppendIfNeeded(pos))
318 any_in = true;
319 }
320 return any_in;
321}
322
323bool ModuleList::RemoveImpl(const ModuleSP &module_sp, bool use_notifier) {
324 if (module_sp) {
325 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
326 collection::iterator pos, end = m_modules.end();
327 for (pos = m_modules.begin(); pos != end; ++pos) {
328 if (pos->get() == module_sp.get()) {
329 m_modules.erase(pos);
330 if (use_notifier && m_notifier)
331 m_notifier->NotifyModuleRemoved(*this, module_sp);
332 return true;
333 }
334 }
335 }
336 return false;
337}
338
339ModuleList::collection::iterator
340ModuleList::RemoveImpl(ModuleList::collection::iterator pos,
341 bool use_notifier) {
342 ModuleSP module_sp(*pos);
343 collection::iterator retval = m_modules.erase(pos);
344 if (use_notifier && m_notifier)
345 m_notifier->NotifyModuleRemoved(*this, module_sp);
346 return retval;
347}
348
349bool ModuleList::Remove(const ModuleSP &module_sp, bool notify) {
350 return RemoveImpl(module_sp, notify);
351}
352
354 const lldb::ModuleSP &new_module_sp) {
355 if (!RemoveImpl(old_module_sp, false))
356 return false;
357 AppendImpl(new_module_sp, false);
358 if (m_notifier)
359 m_notifier->NotifyModuleUpdated(*this, old_module_sp, new_module_sp);
360 return true;
361}
362
364 if (auto module_sp = module_wp.lock()) {
365 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
366 collection::iterator pos, end = m_modules.end();
367 for (pos = m_modules.begin(); pos != end; ++pos) {
368 if (pos->get() == module_sp.get()) {
369 // Since module_sp increases the refcount by 1, the use count should be
370 // the regular use count + 1.
371 constexpr long kUseCountOrphaned = kUseCountModuleListOrphaned + 1;
372 if (pos->use_count() == kUseCountOrphaned) {
373 pos = RemoveImpl(pos);
374 return true;
375 }
376 return false;
377 }
378 }
379 }
380 return false;
381}
382
383size_t ModuleList::RemoveOrphans(bool mandatory) {
384 std::unique_lock<std::recursive_mutex> lock(m_modules_mutex, std::defer_lock);
385
386 if (mandatory) {
387 lock.lock();
388 } else {
389 // Not mandatory, remove orphans if we can get the mutex
390 if (!lock.try_lock())
391 return 0;
392 }
393 size_t remove_count = 0;
394 // Modules might hold shared pointers to other modules, so removing one
395 // module might make other modules orphans. Keep removing modules until
396 // there are no further modules that can be removed.
397 bool made_progress = true;
398 while (made_progress) {
399 // Keep track if we make progress this iteration.
400 made_progress = false;
401 collection::iterator pos = m_modules.begin();
402 while (pos != m_modules.end()) {
403 if (pos->use_count() == kUseCountModuleListOrphaned) {
404 pos = RemoveImpl(pos);
405 ++remove_count;
406 // We did make progress.
407 made_progress = true;
408 } else {
409 ++pos;
410 }
411 }
412 }
413 return remove_count;
414}
415
416size_t ModuleList::Remove(ModuleList &module_list) {
417 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
418 size_t num_removed = 0;
419 collection::iterator pos, end = module_list.m_modules.end();
420 for (pos = module_list.m_modules.begin(); pos != end; ++pos) {
421 if (Remove(*pos, false /* notify */))
422 ++num_removed;
423 }
424 if (m_notifier)
425 m_notifier->NotifyModulesRemoved(module_list);
426 return num_removed;
427}
428
430
432
433void ModuleList::ClearImpl(bool use_notifier) {
434 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
435 if (use_notifier && m_notifier)
436 m_notifier->NotifyWillClearList(*this);
437 m_modules.clear();
438}
439
441 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
442 if (idx < m_modules.size())
443 return m_modules[idx].get();
444 return nullptr;
445}
446
448 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
449 return GetModuleAtIndexUnlocked(idx);
450}
451
453 ModuleSP module_sp;
454 if (idx < m_modules.size())
455 module_sp = m_modules[idx];
456 return module_sp;
457}
458
460 FunctionNameType name_type_mask,
461 const ModuleFunctionSearchOptions &options,
462 SymbolContextList &sc_list) const {
463 if (name_type_mask & eFunctionNameTypeAuto) {
464 std::vector<Module::LookupInfo> lookup_infos =
465 Module::LookupInfo::MakeLookupInfos(name, name_type_mask,
467 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
468 for (const auto &lookup_info : lookup_infos) {
469 const size_t old_size = sc_list.GetSize();
470 for (const ModuleSP &module_sp : m_modules) {
471 module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options,
472 sc_list);
473 }
474
475 const size_t new_size = sc_list.GetSize();
476 if (old_size < new_size)
477 lookup_info.Prune(sc_list, old_size);
478 }
479 } else {
480 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
481 for (const ModuleSP &module_sp : m_modules) {
482 module_sp->FindFunctions(name, CompilerDeclContext(), name_type_mask,
483 options, sc_list);
484 }
485 }
486}
487
489 lldb::FunctionNameType name_type_mask,
490 SymbolContextList &sc_list) {
491 if (name_type_mask & eFunctionNameTypeAuto) {
492 std::vector<Module::LookupInfo> lookup_infos =
493 Module::LookupInfo::MakeLookupInfos(name, name_type_mask,
495
496 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
497 for (const auto &lookup_info : lookup_infos) {
498 const size_t old_size = sc_list.GetSize();
499 for (const ModuleSP &module_sp : m_modules) {
500 module_sp->FindFunctionSymbols(lookup_info.GetLookupName(),
501 lookup_info.GetNameTypeMask(), sc_list);
502 }
503
504 const size_t new_size = sc_list.GetSize();
505
506 if (old_size < new_size)
507 lookup_info.Prune(sc_list, old_size);
508 }
509 } else {
510 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
511 for (const ModuleSP &module_sp : m_modules) {
512 module_sp->FindFunctionSymbols(name, name_type_mask, sc_list);
513 }
514 }
515}
516
518 const ModuleFunctionSearchOptions &options,
519 SymbolContextList &sc_list) {
520 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
521 for (const ModuleSP &module_sp : m_modules)
522 module_sp->FindFunctions(name, options, sc_list);
523}
524
526 SymbolContextList &sc_list) const {
527 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
528 for (const ModuleSP &module_sp : m_modules)
529 module_sp->FindCompileUnits(path, sc_list);
530}
531
532void ModuleList::FindGlobalVariables(ConstString name, size_t max_matches,
533 VariableList &variable_list) const {
534 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
535 for (const ModuleSP &module_sp : m_modules) {
536 module_sp->FindGlobalVariables(name, CompilerDeclContext(), max_matches,
537 variable_list);
538 }
539}
540
542 size_t max_matches,
543 VariableList &variable_list) const {
544 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
545 for (const ModuleSP &module_sp : m_modules)
546 module_sp->FindGlobalVariables(regex, max_matches, variable_list);
547}
548
550 SymbolType symbol_type,
551 SymbolContextList &sc_list) const {
552 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
553 for (const ModuleSP &module_sp : m_modules)
554 module_sp->FindSymbolsWithNameAndType(name, symbol_type, sc_list);
555}
556
558 const RegularExpression &regex, lldb::SymbolType symbol_type,
559 SymbolContextList &sc_list) const {
560 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
561 for (const ModuleSP &module_sp : m_modules)
562 module_sp->FindSymbolsMatchingRegExAndType(regex, symbol_type, sc_list);
563}
564
565void ModuleList::FindModules(const ModuleSpec &module_spec,
566 ModuleList &matching_module_list) const {
567 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
568 for (const ModuleSP &module_sp : m_modules) {
569 if (module_sp->MatchesModuleSpec(module_spec))
570 matching_module_list.Append(module_sp);
571 }
572}
573
574ModuleSP ModuleList::FindModule(const Module *module_ptr) const {
575 ModuleSP module_sp;
576
577 // Scope for "locker"
578 {
579 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
580 collection::const_iterator pos, end = m_modules.end();
581
582 for (pos = m_modules.begin(); pos != end; ++pos) {
583 if ((*pos).get() == module_ptr) {
584 module_sp = (*pos);
585 break;
586 }
587 }
588 }
589 return module_sp;
590}
591
593 ModuleSP module_sp;
594
595 if (uuid.IsValid()) {
596 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
597 collection::const_iterator pos, end = m_modules.end();
598
599 for (pos = m_modules.begin(); pos != end; ++pos) {
600 if ((*pos)->GetUUID() == uuid) {
601 module_sp = (*pos);
602 break;
603 }
604 }
605 }
606 return module_sp;
607}
608
610 ModuleSP module_sp;
611 ForEach([&](const ModuleSP &m) {
612 if (m->GetID() == uid) {
613 module_sp = m;
615 }
616
618 });
619
620 return module_sp;
621}
622
623void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,
624 TypeResults &results) const {
625 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
626 if (search_first) {
627 search_first->FindTypes(query, results);
628 if (results.Done(query))
629 return;
630 }
631 for (const auto &module_sp : m_modules) {
632 if (search_first != module_sp.get()) {
633 module_sp->FindTypes(query, results);
634 if (results.Done(query))
635 return;
636 }
637 }
638}
639
641 FileSpec &new_spec) const {
642 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
643 for (const ModuleSP &module_sp : m_modules) {
644 if (module_sp->FindSourceFile(orig_spec, new_spec))
645 return true;
646 }
647 return false;
648}
649
651 const FileSpec &file, uint32_t line,
652 Function *function,
653 std::vector<Address> &output_local,
654 std::vector<Address> &output_extern) {
655 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
656 for (const ModuleSP &module_sp : m_modules) {
657 module_sp->FindAddressesForLine(target_sp, file, line, function,
658 output_local, output_extern);
659 }
660}
661
663 ModuleSP module_sp;
664 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
665 collection::const_iterator pos, end = m_modules.end();
666 for (pos = m_modules.begin(); pos != end; ++pos) {
667 ModuleSP module_sp(*pos);
668 if (module_sp->MatchesModuleSpec(module_spec))
669 return module_sp;
670 }
671 return module_sp;
672}
673
674size_t ModuleList::GetSize() const {
675 size_t size = 0;
676 {
677 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
678 size = m_modules.size();
679 }
680 return size;
681}
682
683void ModuleList::Dump(Stream *s) const {
684 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
685 for (const ModuleSP &module_sp : m_modules)
686 module_sp->Dump(s);
687}
688
689void ModuleList::LogUUIDAndPaths(Log *log, const char *prefix_cstr) {
690 if (log != nullptr) {
691 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
692 collection::const_iterator pos, begin = m_modules.begin(),
693 end = m_modules.end();
694 for (pos = begin; pos != end; ++pos) {
695 Module *module = pos->get();
696 const FileSpec &module_file_spec = module->GetFileSpec();
697 LLDB_LOGF(log, "%s[%u] %s (%s) \"%s\"", prefix_cstr ? prefix_cstr : "",
698 (uint32_t)std::distance(begin, pos),
699 module->GetUUID().GetAsString().c_str(),
701 module_file_spec.GetPath().c_str());
702 }
703 }
704}
705
707 Address &so_addr) const {
708 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
709 for (const ModuleSP &module_sp : m_modules) {
710 if (module_sp->ResolveFileAddress(vm_addr, so_addr))
711 return true;
712 }
713
714 return false;
715}
716
717uint32_t
719 SymbolContextItem resolve_scope,
720 SymbolContext &sc) const {
721 // The address is already section offset so it has a module
722 uint32_t resolved_flags = 0;
723 ModuleSP module_sp(so_addr.GetModule());
724 if (module_sp) {
725 resolved_flags =
726 module_sp->ResolveSymbolContextForAddress(so_addr, resolve_scope, sc);
727 } else {
728 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
729 collection::const_iterator pos, end = m_modules.end();
730 for (pos = m_modules.begin(); pos != end; ++pos) {
731 resolved_flags =
732 (*pos)->ResolveSymbolContextForAddress(so_addr, resolve_scope, sc);
733 if (resolved_flags != 0)
734 break;
735 }
736 }
737
738 return resolved_flags;
739}
740
742 const char *file_path, uint32_t line, bool check_inlines,
743 SymbolContextItem resolve_scope, SymbolContextList &sc_list) const {
744 FileSpec file_spec(file_path);
745 return ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines,
746 resolve_scope, sc_list);
747}
748
750 const FileSpec &file_spec, uint32_t line, bool check_inlines,
751 SymbolContextItem resolve_scope, SymbolContextList &sc_list) const {
752 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
753 for (const ModuleSP &module_sp : m_modules) {
754 module_sp->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines,
755 resolve_scope, sc_list);
756 }
757
758 return sc_list.GetSize();
759}
760
761size_t ModuleList::GetIndexForModule(const Module *module) const {
762 if (module) {
763 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
764 collection::const_iterator pos;
765 collection::const_iterator begin = m_modules.begin();
766 collection::const_iterator end = m_modules.end();
767 for (pos = begin; pos != end; ++pos) {
768 if ((*pos).get() == module)
769 return std::distance(begin, pos);
770 }
771 }
773}
774
775namespace {
776/// A wrapper around ModuleList for shared modules. Provides fast lookups for
777/// file-based ModuleSpec queries.
778class SharedModuleList {
779public:
780 /// Finds all the modules matching the module_spec, and adds them to \p
781 /// matching_module_list.
782 void FindModules(const ModuleSpec &module_spec,
783 ModuleList &matching_module_list) const {
784 std::lock_guard<std::recursive_mutex> guard(GetMutex());
785 // Try map first for performance - if found, skip expensive full list
786 // search.
787 FindModulesInMap(module_spec, matching_module_list);
788 if (!matching_module_list.IsEmpty())
789 return;
790 m_list.FindModules(module_spec, matching_module_list);
791 // Assert that modules were found in the list but not the map, it's
792 // because the module_spec has no filename or the found module has a
793 // different filename. For example, when searching by UUID and finding a
794 // module with an alias.
795 assert((matching_module_list.IsEmpty() ||
796 module_spec.GetFileSpec().GetFilename().empty() ||
797 module_spec.GetFileSpec().GetFilename() !=
798 matching_module_list.GetModuleAtIndex(0)
799 ->GetFileSpec()
800 .GetFilename()) &&
801 "Search by name not found in SharedModuleList's map");
802 }
803
804 ModuleSP FindModule(const Module &module) {
805
806 std::lock_guard<std::recursive_mutex> guard(GetMutex());
807 if (ModuleSP result = FindModuleInMap(module))
808 return result;
809 return m_list.FindModule(&module);
810 }
811
812 // UUID searches bypass map since UUIDs aren't indexed by filename.
813 ModuleSP FindModule(const UUID &uuid) const {
814 return m_list.FindModule(uuid);
815 }
816
817 void Append(const ModuleSP &module_sp, bool use_notifier) {
818 if (!module_sp)
819 return;
820 std::lock_guard<std::recursive_mutex> guard(GetMutex());
821 m_list.Append(module_sp, use_notifier);
822 AddToMap(module_sp);
823 }
824
825 size_t RemoveOrphans(bool mandatory) {
826 std::unique_lock<std::recursive_mutex> lock(GetMutex(), std::defer_lock);
827 if (mandatory) {
828 lock.lock();
829 } else {
830 if (!lock.try_lock())
831 return 0;
832 }
833 size_t total_count = 0;
834 size_t run_count;
835 do {
836 // Remove indexed orphans first, then remove non-indexed orphans. This
837 // order is important because the shared count will be different if a
838 // module is indexed or not.
839 run_count = RemoveOrphansFromMapAndList();
840 run_count += m_list.RemoveOrphans(mandatory);
841 total_count += run_count;
842 // Because removing orphans might make new orphans, remove from both
843 // containers until a fixed-point is reached.
844 } while (run_count != 0);
845
846 return total_count;
847 }
848
849 bool Remove(const ModuleSP &module_sp, bool use_notifier = true) {
850 if (!module_sp)
851 return false;
852 std::lock_guard<std::recursive_mutex> guard(GetMutex());
853 RemoveFromMap(module_sp);
854 return m_list.Remove(module_sp, use_notifier);
855 }
856
857 void ReplaceEquivalent(const ModuleSP &module_sp,
858 llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
859 std::lock_guard<std::recursive_mutex> guard(GetMutex());
860 m_list.ReplaceEquivalent(module_sp, old_modules);
861 ReplaceEquivalentInMap(module_sp);
862 }
863
864 bool RemoveIfOrphaned(const ModuleWP module_wp) {
865 std::lock_guard<std::recursive_mutex> guard(GetMutex());
866 RemoveFromMap(module_wp, /*if_orphaned=*/true);
867 return m_list.RemoveIfOrphaned(module_wp);
868 }
869
870 std::recursive_mutex &GetMutex() const { return m_list.GetMutex(); }
871
872private:
873 ModuleSP FindModuleInMap(const Module &module) const {
874 if (module.GetFileSpec().GetFilename().empty())
875 return ModuleSP();
876 llvm::StringRef name = module.GetFileSpec().GetFilename();
877 auto it = m_name_to_modules.find(ConstString(name));
878 if (it == m_name_to_modules.end())
879 return ModuleSP();
880 const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;
881 for (const ModuleSP &module_sp : vector) {
882 if (module_sp.get() == &module)
883 return module_sp;
884 }
885 return ModuleSP();
886 }
887
888 void FindModulesInMap(const ModuleSpec &module_spec,
889 ModuleList &matching_module_list) const {
890 auto it = m_name_to_modules.find(
891 ConstString(module_spec.GetFileSpec().GetFilename()));
892 if (it == m_name_to_modules.end())
893 return;
894 const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;
895 for (const ModuleSP &module_sp : vector) {
896 if (module_sp->MatchesModuleSpec(module_spec))
897 matching_module_list.Append(module_sp);
898 }
899 }
900
901 void AddToMap(const ModuleSP &module_sp) {
902 llvm::StringRef name = module_sp->GetFileSpec().GetFilename();
903 if (name.empty())
904 return;
905 m_name_to_modules[ConstString(name)].push_back(module_sp);
906 }
907
908 void RemoveFromMap(const ModuleWP module_wp, bool if_orphaned = false) {
909 if (auto module_sp = module_wp.lock()) {
910 ConstString name = ConstString(module_sp->GetFileSpec().GetFilename());
911 if (!m_name_to_modules.contains(name))
912 return;
913 llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
914 for (auto *it = vec.begin(); it != vec.end(); ++it) {
915 if (it->get() == module_sp.get()) {
916 // Since module_sp increases the refcount by 1, the use count should
917 // be the regular use count + 1.
918 constexpr long kUseCountOrphaned =
919 kUseCountSharedModuleListOrphaned + 1;
920 if (!if_orphaned || it->use_count() == kUseCountOrphaned) {
921 vec.erase(it);
922 break;
923 }
924 }
925 }
926 }
927 }
928
929 void ReplaceEquivalentInMap(const ModuleSP &module_sp) {
930 RemoveEquivalentModulesFromMap(module_sp);
931 AddToMap(module_sp);
932 }
933
934 void RemoveEquivalentModulesFromMap(const ModuleSP &module_sp) {
935 llvm::StringRef name = module_sp->GetFileSpec().GetFilename();
936 if (name.empty())
937 return;
938
939 auto it = m_name_to_modules.find(ConstString(name));
940 if (it == m_name_to_modules.end())
941 return;
942
943 // First remove any equivalent modules. Equivalent modules are modules
944 // whose path, platform path and architecture match.
945 ModuleSpec equivalent_module_spec(module_sp->GetFileSpec(),
946 module_sp->GetArchitecture());
947 equivalent_module_spec.GetPlatformFileSpec() =
948 module_sp->GetPlatformFileSpec();
949
950 llvm::SmallVectorImpl<ModuleSP> &vec = it->second;
951 llvm::erase_if(vec, [&equivalent_module_spec](ModuleSP &element) {
952 return element->MatchesModuleSpec(equivalent_module_spec);
953 });
954 }
955
956 /// Remove orphans from the vector and return the removed modules.
957 ModuleList RemoveOrphansFromVector(llvm::SmallVectorImpl<ModuleSP> &vec) {
958 // remove_if moves the elements that match the condition to the end of the
959 // container, and returns an iterator to the first element that was moved.
960 auto *to_remove_start = llvm::remove_if(vec, [](const ModuleSP &module) {
961 return module.use_count() == kUseCountSharedModuleListOrphaned;
962 });
963
964 ModuleList to_remove;
965 for (ModuleSP *it = to_remove_start; it != vec.end(); ++it)
966 to_remove.Append(*it);
967
968 vec.erase(to_remove_start, vec.end());
969 return to_remove;
970 }
971
972 /// Remove orphans that exist in both the map and list. This does not remove
973 /// any orphans that exist exclusively on the list.
974 ///
975 /// The mutex must be locked by the caller.
976 int RemoveOrphansFromMapAndList() {
977 // Modules might hold shared pointers to other modules, so removing one
978 // module might orphan other modules. Keep removing modules until
979 // there are no further modules that can be removed.
980 int remove_count = 0;
981 int previous_remove_count;
982 do {
983 previous_remove_count = remove_count;
984 for (auto &[name, vec] : m_name_to_modules) {
985 if (vec.empty())
986 continue;
987 ModuleList to_remove = RemoveOrphansFromVector(vec);
988 remove_count += to_remove.GetSize();
989 m_list.Remove(to_remove);
990 }
991 // Break when fixed-point is reached.
992 } while (previous_remove_count != remove_count);
993
994 return remove_count;
995 }
996
997 ModuleList m_list;
998
999 /// A hash map from a module's filename to all the modules that share that
1000 /// filename, for fast module lookups by name.
1001 llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1>> m_name_to_modules;
1002
1003 /// The use count of a module held only by m_list and m_name_to_modules.
1004 static constexpr long kUseCountSharedModuleListOrphaned = 2;
1005};
1006
1007struct SharedModuleListInfo {
1008 SharedModuleList module_list;
1009 ModuleListProperties module_list_properties;
1010};
1011} // namespace
1012static SharedModuleListInfo &GetSharedModuleListInfo() {
1013 static SharedModuleListInfo *g_shared_module_list_info = nullptr;
1014 static llvm::once_flag g_once_flag;
1015 llvm::call_once(g_once_flag, []() {
1016 // NOTE: Intentionally leak the module list so a program doesn't have to
1017 // cleanup all modules and object files as it exits. This just wastes time
1018 // doing a bunch of cleanup that isn't required.
1019 if (g_shared_module_list_info == nullptr)
1020 g_shared_module_list_info = new SharedModuleListInfo();
1021 });
1022 return *g_shared_module_list_info;
1023}
1024
1025static SharedModuleList &GetSharedModuleList() {
1026 return GetSharedModuleListInfo().module_list;
1027}
1028
1032
1033bool ModuleList::ModuleIsInCache(const Module *module_ptr) {
1034 if (module_ptr) {
1035 SharedModuleList &shared_module_list = GetSharedModuleList();
1036 return shared_module_list.FindModule(*module_ptr).get() != nullptr;
1037 }
1038 return false;
1039}
1040
1042 ModuleList &matching_module_list) {
1043 GetSharedModuleList().FindModules(module_spec, matching_module_list);
1044}
1045
1047 return GetSharedModuleList().FindModule(uuid);
1048}
1049
1051 return GetSharedModuleList().RemoveOrphans(mandatory);
1052}
1053
1054Status
1055ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
1057 bool *did_create_ptr, bool invoke_locate_callback,
1058 bool invoke_symbol_locators) {
1059 SharedModuleList &shared_module_list = GetSharedModuleList();
1060 std::lock_guard<std::recursive_mutex> guard(shared_module_list.GetMutex());
1061 char path[PATH_MAX];
1062
1063 Status error;
1064
1065 module_sp.reset();
1066
1067 if (did_create_ptr)
1068 *did_create_ptr = false;
1069
1070 const UUID *uuid_ptr = module_spec.GetUUIDPtr();
1071 const FileSpec &module_file_spec = module_spec.GetFileSpec();
1072 const ArchSpec &arch = module_spec.GetArchitecture();
1073
1074 // Make sure no one else can try and get or create a module while this
1075 // function is actively working on it by doing an extra lock on the global
1076 // mutex list.
1077 {
1078 ModuleList matching_module_list;
1079 shared_module_list.FindModules(module_spec, matching_module_list);
1080 const size_t num_matching_modules = matching_module_list.GetSize();
1081
1082 if (num_matching_modules > 0) {
1083 for (size_t module_idx = 0; module_idx < num_matching_modules;
1084 ++module_idx) {
1085 module_sp = matching_module_list.GetModuleAtIndex(module_idx);
1086
1087 // Make sure the file for the module hasn't been modified
1088 if (module_sp->FileHasChanged()) {
1089 if (old_modules)
1090 old_modules->push_back(module_sp);
1091
1092 Log *log = GetLog(LLDBLog::Modules);
1093 LLDB_LOG(
1094 log,
1095 "{0:x} '{1}' module changed: removing from global module list",
1096 static_cast<void *>(module_sp.get()),
1097 module_sp->GetFileSpec().GetFilename());
1098
1099 shared_module_list.Remove(module_sp);
1100 module_sp.reset();
1101 } else {
1102 // The module matches and the module was not modified from when it
1103 // was last loaded.
1104 return error;
1105 }
1106 }
1107 }
1108 }
1109
1110 if (module_sp)
1111 return error;
1112
1113 // Try platform's locate module callback before second attempt.
1114 // The platform can come from either the Target (if available) or directly
1115 // from the ModuleSpec (useful when Target is not yet created, e.g., during
1116 // target creation for launch mode).
1117 if (invoke_locate_callback) {
1118 PlatformSP platform_sp;
1119 if (TargetSP target_sp = module_spec.GetTargetSP()) {
1120 if (target_sp->IsValid())
1121 platform_sp = target_sp->GetPlatform();
1122 }
1123 if (!platform_sp)
1124 platform_sp = module_spec.GetPlatformSP();
1125
1126 if (platform_sp) {
1127 FileSpec symbol_file_spec;
1128 platform_sp->CallLocateModuleCallbackIfSet(
1129 module_spec, module_sp, symbol_file_spec, did_create_ptr);
1130 if (module_sp) {
1131 // The callback found a module.
1132 return error;
1133 }
1134 }
1135 }
1136
1137 module_sp = std::make_shared<Module>(module_spec);
1138 // Make sure there are a module and an object file since we can specify a
1139 // valid file path with an architecture that might not be in that file. By
1140 // getting the object file we can guarantee that the architecture matches
1141 if (module_sp->GetObjectFile()) {
1142 // If we get in here we got the correct arch, now we just need to verify
1143 // the UUID if one was given
1144 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID()) {
1145 module_sp.reset();
1146 } else {
1147 if (module_sp->GetObjectFile() && module_sp->GetObjectFile()->GetType() ==
1149 module_sp.reset();
1150 } else {
1151 if (did_create_ptr) {
1152 *did_create_ptr = true;
1153 }
1154
1155 shared_module_list.ReplaceEquivalent(module_sp, old_modules);
1156 return error;
1157 }
1158 }
1159 } else {
1160 module_sp.reset();
1161 }
1162
1163 // Get module search paths from the target if available.
1164 lldb::TargetSP target_sp = module_spec.GetTargetSP();
1165 FileSpecList module_search_paths;
1166 if (target_sp)
1167 module_search_paths = target_sp->GetExecutableSearchPaths();
1168
1169 if (!module_search_paths.IsEmpty()) {
1170 const auto num_directories = module_search_paths.GetSize();
1171 for (size_t idx = 0; idx < num_directories; ++idx) {
1172 auto search_path_spec = module_search_paths.GetFileSpecAtIndex(idx);
1173 FileSystem::Instance().Resolve(search_path_spec);
1174 namespace fs = llvm::sys::fs;
1175 if (!FileSystem::Instance().IsDirectory(search_path_spec))
1176 continue;
1177 search_path_spec.AppendPathComponent(
1178 module_spec.GetFileSpec().GetFilename());
1179 if (!FileSystem::Instance().Exists(search_path_spec))
1180 continue;
1181
1182 auto resolved_module_spec(module_spec);
1183 resolved_module_spec.GetFileSpec() = search_path_spec;
1184 module_sp = std::make_shared<Module>(resolved_module_spec);
1185 if (module_sp->GetObjectFile()) {
1186 // If we get in here we got the correct arch, now we just need to
1187 // verify the UUID if one was given
1188 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID()) {
1189 module_sp.reset();
1190 } else {
1191 if (module_sp->GetObjectFile()->GetType() ==
1193 module_sp.reset();
1194 } else {
1195 if (did_create_ptr)
1196 *did_create_ptr = true;
1197
1198 shared_module_list.ReplaceEquivalent(module_sp, old_modules);
1199 return Status();
1200 }
1201 }
1202 } else {
1203 module_sp.reset();
1204 }
1205 }
1206 }
1207
1208 // Either the file didn't exist where at the path, or no path was given, so we
1209 // now either have to use more extreme measures to try and find the
1210 // appropriate module or end our search here.
1211 if (!invoke_symbol_locators) {
1212 std::string uuid_str;
1213 if (uuid_ptr && uuid_ptr->IsValid())
1214 uuid_str = uuid_ptr->GetAsString();
1215 if (!uuid_str.empty())
1217 "cannot locate module for UUID '{}'", uuid_str);
1218 return Status::FromErrorString("cannot locate module");
1219 }
1220
1221 // Fixup the incoming path in case the path points to a valid file, yet the
1222 // arch or UUID (if one was passed in) don't match.
1223 ModuleSpec located_binary_modulespec;
1224 StatisticsMap symbol_locator_map;
1225 located_binary_modulespec = PluginManager::LocateExecutableObjectFile(
1226 module_spec, symbol_locator_map);
1227 // Don't look for the file if it appears to be the same one we already
1228 // checked for above...
1229 if (located_binary_modulespec.GetFileSpec() != module_file_spec) {
1230 if (!FileSystem::Instance().Exists(
1231 located_binary_modulespec.GetFileSpec())) {
1232 located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path));
1233 if (path[0] == '\0')
1234 module_file_spec.GetPath(path, sizeof(path));
1235 // How can this check ever be true? This branch it is false, and we
1236 // haven't modified file_spec.
1237 if (FileSystem::Instance().Exists(
1238 located_binary_modulespec.GetFileSpec())) {
1239 std::string uuid_str;
1240 if (uuid_ptr && uuid_ptr->IsValid())
1241 uuid_str = uuid_ptr->GetAsString();
1242
1243 if (arch.IsValid()) {
1244 if (!uuid_str.empty())
1246 "'%s' does not contain the %s architecture and UUID %s", path,
1247 arch.GetArchitectureName(), uuid_str.c_str());
1248 else
1250 "'%s' does not contain the %s architecture.", path,
1251 arch.GetArchitectureName());
1252 }
1253 } else {
1254 error = Status::FromErrorStringWithFormat("'%s' does not exist", path);
1255 }
1256 if (error.Fail())
1257 module_sp.reset();
1258 return error;
1259 }
1260
1261 // Make sure no one else can try and get or create a module while this
1262 // function is actively working on it by doing an extra lock on the global
1263 // mutex list.
1264 ModuleSpec platform_module_spec(module_spec);
1265 platform_module_spec.GetFileSpec() =
1266 located_binary_modulespec.GetFileSpec();
1267 platform_module_spec.GetPlatformFileSpec() =
1268 located_binary_modulespec.GetFileSpec();
1269 platform_module_spec.GetSymbolFileSpec() =
1270 located_binary_modulespec.GetSymbolFileSpec();
1271 ModuleList matching_module_list;
1272 shared_module_list.FindModules(platform_module_spec, matching_module_list);
1273 if (!matching_module_list.IsEmpty()) {
1274 module_sp = matching_module_list.GetModuleAtIndex(0);
1275
1276 // If we didn't have a UUID in mind when looking for the object file,
1277 // then we should make sure the modification time hasn't changed!
1278 if (platform_module_spec.GetUUIDPtr() == nullptr) {
1279 auto file_spec_mod_time = FileSystem::Instance().GetModificationTime(
1280 located_binary_modulespec.GetFileSpec());
1281 if (file_spec_mod_time != llvm::sys::TimePoint<>()) {
1282 if (file_spec_mod_time != module_sp->GetModificationTime()) {
1283 if (old_modules)
1284 old_modules->push_back(module_sp);
1285 shared_module_list.Remove(module_sp);
1286 module_sp.reset();
1287 }
1288 }
1289 }
1290 }
1291
1292 if (!module_sp) {
1293 module_sp = std::make_shared<Module>(platform_module_spec);
1294 // Make sure there are a module and an object file since we can specify a
1295 // valid file path with an architecture that might not be in that file.
1296 // By getting the object file we can guarantee that the architecture
1297 // matches
1298 if (module_sp && module_sp->GetObjectFile()) {
1299 module_sp->GetSymbolLocatorStatistics().merge(symbol_locator_map);
1300 if (module_sp->GetObjectFile()->GetType() ==
1302 module_sp.reset();
1303 } else {
1304 if (did_create_ptr)
1305 *did_create_ptr = true;
1306
1307 shared_module_list.ReplaceEquivalent(module_sp, old_modules);
1308 }
1309 } else {
1310 located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path));
1311
1312 if (located_binary_modulespec.GetFileSpec()) {
1313 if (arch.IsValid())
1315 "unable to open %s architecture in '%s'",
1316 arch.GetArchitectureName(), path);
1317 else
1318 error =
1319 Status::FromErrorStringWithFormat("unable to open '%s'", path);
1320 } else {
1321 std::string uuid_str;
1322 if (uuid_ptr && uuid_ptr->IsValid())
1323 uuid_str = uuid_ptr->GetAsString();
1324
1325 if (!uuid_str.empty())
1327 "cannot locate a module for UUID '%s'", uuid_str.c_str());
1328 else
1329 error = Status::FromErrorString("cannot locate a module");
1330 }
1331 }
1332 }
1333 }
1334
1335 return error;
1336}
1337
1339 return GetSharedModuleList().Remove(module_sp);
1340}
1341
1343 return GetSharedModuleList().RemoveIfOrphaned(module_wp);
1344}
1345
1346static bool LoadScriptingModule(const FileSpec &scripting_fspec,
1347 ScriptInterpreter &script_interpreter,
1348 Target &target, Status &error) {
1349 assert(scripting_fspec);
1350
1351 StreamString scripting_stream;
1352 scripting_fspec.Dump(scripting_stream.AsRawOstream());
1353 LoadScriptOptions options;
1354 return script_interpreter.LoadScriptingModule(
1355 scripting_stream.GetData(), options, error,
1356 /*module_sp*/ nullptr, /*extra_path*/ {}, target.shared_from_this());
1357}
1358
1360 Target &target,
1361 Status &error) {
1362 Log *log = GetLog(LLDBLog::Modules);
1363
1364 Debugger &debugger = target.GetDebugger();
1365 const ScriptLanguage script_language = debugger.GetScriptLanguage();
1366 if (script_language == eScriptLanguageNone)
1367 return true;
1368
1369 ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
1370 if (!script_interpreter) {
1371 error = Status::FromErrorString("invalid ScriptInterpreter");
1372 return false;
1373 }
1374
1375 PlatformSP platform_sp = target.GetPlatform();
1376 if (!platform_sp) {
1377 error = Status::FromErrorString("invalid Platform");
1378 return false;
1379 }
1380
1381 StreamString feedback_stream;
1382 llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile> file_specs =
1383 platform_sp->LocateExecutableScriptingResources(&target, module,
1384 feedback_stream);
1385
1386 if (!feedback_stream.Empty())
1387 debugger.ReportWarning(feedback_stream.GetString().str(), debugger.GetID());
1388
1389 const bool trusted = platform_sp->IsSymbolFileTrusted(module);
1390
1391 for (const auto &[scripting_fspec, load_style] : file_specs) {
1392 if (load_style == eLoadScriptFromSymFileFalse)
1393 continue;
1394
1395 if (!FileSystem::Instance().Exists(scripting_fspec))
1396 continue;
1397
1398 switch (load_style) {
1400 llvm_unreachable("case already handled");
1402 break;
1404 if (trusted)
1405 break;
1406 LLVM_FALLTHROUGH;
1408 debugger.ReportWarning(
1409 llvm::formatv(
1410 // clang-format off
1411R"('{0}' contains {1} debug script. To run this script in this debug session:
1412
1413 command script import "{2}"
1414
1415To run all discovered debug scripts in this session:
1416
1417 settings set target.load-script-from-symbol-file true
1418)",
1419 // clang-format on
1421 trusted ? "a trusted" : "an untrusted",
1422 scripting_fspec.GetPath()),
1423 debugger.GetID());
1424
1425 continue;
1426 }
1427
1428 LLDB_LOG(log, "Auto-loading {0}", scripting_fspec.GetPath());
1429
1430 if (!LoadScriptingModule(scripting_fspec, *script_interpreter, target,
1431 error)) {
1432 LLDB_LOG(log, "Failed to load '{0}'. Remaining scripts won't be loaded.",
1433 scripting_fspec.GetPath());
1434 return false;
1435 }
1436 }
1437
1438 return true;
1439}
1440
1442 std::list<Status> &errors,
1443 bool continue_on_error) {
1444 if (!target)
1445 return false;
1446 m_modules_mutex.lock();
1447 // Don't hold the module list mutex while loading the scripting resources,
1448 // The initializer might do any amount of work, and having that happen while
1449 // the module list is held is asking for A/B locking problems.
1450 const ModuleList tmp_module_list(*this);
1451 m_modules_mutex.unlock();
1452
1453 for (auto module : tmp_module_list.ModulesNoLocking()) {
1454 if (module) {
1455 Status error;
1456 if (!LoadScriptingResourceInTargetForModule(*module, *target, error)) {
1457 if (error.Fail() && error.AsCString()) {
1459 "unable to load scripting data for "
1460 "module {0} - error reported was {1}",
1461 module->GetFileSpec().GetFileNameStrippingExtension(),
1462 error.AsCString());
1463 errors.push_back(std::move(error));
1464 if (!continue_on_error)
1465 return false;
1467 }
1468 }
1469 }
1470 return errors.empty();
1471}
1472
1474 std::function<IterationAction(const ModuleSP &module_sp)> const &callback)
1475 const {
1476 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
1477 for (const auto &module_sp : m_modules) {
1478 assert(module_sp != nullptr);
1479 if (callback(module_sp) == IterationAction::Stop)
1480 break;
1481 }
1482}
1483
1485 std::function<bool(lldb_private::Module &module_sp)> const &callback)
1486 const {
1487 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
1488 for (const auto &module_sp : m_modules) {
1489 assert(module_sp != nullptr);
1490 if (callback(*module_sp))
1491 return true;
1492 }
1493
1494 return false;
1495}
1496
1498 // scoped_lock locks both mutexes at once.
1499 std::scoped_lock<std::recursive_mutex, std::recursive_mutex> lock(
1501 m_modules.swap(other.m_modules);
1502}
1503
1504void ModuleList::PreloadSymbols(bool parallelize) const {
1505 std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
1506
1507 if (!parallelize) {
1508 for (const ModuleSP &module_sp : m_modules)
1509 module_sp->PreloadSymbols();
1510 return;
1511 }
1512
1513 llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
1514 for (const ModuleSP &module_sp : m_modules)
1515 task_group.async([module_sp] {
1516 if (module_sp)
1517 module_sp->PreloadSymbols();
1518 });
1519 task_group.wait();
1520}
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition LLDBAssert.h:16
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOGF(log,...)
Definition Log.h:389
static SharedModuleListInfo & GetSharedModuleListInfo()
static bool LoadScriptingModule(const FileSpec &scripting_fspec, ScriptInterpreter &script_interpreter, Target &target, Status &error)
static SharedModuleList & GetSharedModuleList()
A section + offset based address class.
Definition Address.h:62
lldb::ModuleSP GetModule() const
Get accessor for the module for this address.
Definition Address.cpp:275
An architecture specification class.
Definition ArchSpec.h:32
bool IsValid() const
Tests if this ArchSpec is valid.
Definition ArchSpec.h:453
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition ArchSpec.cpp:742
Represents a generic declaration context in a program.
A uniqued constant string class.
Definition ConstString.h:40
A class to manage flag bits.
Definition Debugger.h:100
static void ReportWarning(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report warning events.
static llvm::ThreadPoolInterface & GetThreadPool()
Shared thread pool. Use only with ThreadPoolTaskGroup.
lldb::ScriptLanguage GetScriptLanguage() const
Definition Debugger.cpp:458
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
A file collection class.
const FileSpec & GetFileSpecAtIndex(size_t idx) const
Get file at index.
size_t GetSize() const
Get the number of files in the file list.
A file utility class.
Definition FileSpec.h:56
llvm::StringRef GetFileNameStrippingExtension() const
Return the filename without the extension part.
Definition FileSpec.cpp:414
llvm::StringRef GetFilename() const
Filename string const get accessor.
Definition FileSpec.h:248
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
void Dump(llvm::raw_ostream &s) const
Dump this object to a Stream.
Definition FileSpec.cpp:341
llvm::sys::TimePoint GetModificationTime(const FileSpec &file_spec) const
Returns the modification time of the given file.
Status Readlink(const FileSpec &src, FileSpec &dst)
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
A class that describes a function.
Definition Function.h:377
bool SetClangModulesCachePath(const FileSpec &path)
lldb::SymbolDownload GetSymbolAutoDownload() const
bool SetLLDBIndexCachePath(const FileSpec &path)
bool SetEnableExternalLookup(bool new_value)
PathMappingList GetSymlinkMappings() const
lldb::SymbolSharedCacheUse GetSharedCacheBinaryLoading() const
FileSpec GetClangModulesCachePath() const
llvm::sys::RWMutex m_symlink_paths_mutex
Definition ModuleList.h:95
bool SetEnableLLDBIndexCache(bool new_value)
virtual void NotifyModuleRemoved(const ModuleList &module_list, const lldb::ModuleSP &module_sp)=0
A collection class for Module objects.
Definition ModuleList.h:125
bool ReplaceModule(const lldb::ModuleSP &old_module_sp, const lldb::ModuleSP &new_module_sp)
collection m_modules
The collection of modules.
Definition ModuleList.h:555
void ClearImpl(bool use_notifier=true)
uint32_t ResolveSymbolContextsForFileSpec(const FileSpec &file_spec, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) const
Resolve items in the symbol context for a given file and line. (const FileSpec&,...
static bool RemoveSharedModule(lldb::ModuleSP &module_sp)
static Status GetSharedModule(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr, bool invoke_locate_callback=true, bool invoke_symbol_locators=true)
void FindFunctions(ConstString name, lldb::FunctionNameType name_type_mask, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) const
bool FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const
bool AnyOf(std::function< bool(lldb_private::Module &module)> const &callback) const
Returns true if 'callback' returns true for one of the modules in this ModuleList.
ModuleIterableNoLocking ModulesNoLocking() const
Definition ModuleList.h:577
static constexpr long kUseCountModuleListOrphaned
An orphaned module that lives only in the ModuleList has a count of 1.
Definition ModuleList.h:561
static bool ModuleIsInCache(const Module *module_ptr)
void FindGlobalVariables(ConstString name, size_t max_matches, VariableList &variable_list) const
Find global and static variables by name.
void Swap(ModuleList &other)
Atomically swaps the contents of this module list with other.
size_t GetIndexForModule(const Module *module) const
bool RemoveImpl(const lldb::ModuleSP &module_sp, bool use_notifier=true)
lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const
Finds the first module whose file specification matches module_spec.
void Clear()
Clear the object's state.
ModuleList()
Default constructor.
void Dump(Stream *s) const
Dump the description of each module contained in this list.
void FindTypes(Module *search_first, const TypeQuery &query, lldb_private::TypeResults &results) const
Find types using a type-matching object that contains all search parameters.
uint32_t ResolveSymbolContextForFilePath(const char *file_path, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) const
Resolve items in the symbol context for a given file and line. (const char*,uint32_t,...
static bool LoadScriptingResourceInTargetForModule(Module &module, Target &target, Status &error)
lldb::ModuleSP GetModuleAtIndexUnlocked(size_t idx) const
Get the module shared pointer for the module at index idx without acquiring the ModuleList mutex.
static bool RemoveSharedModuleIfOrphaned(const lldb::ModuleWP module_ptr)
void FindCompileUnits(const FileSpec &path, SymbolContextList &sc_list) const
Find compile units by partial or full path.
void PreloadSymbols(bool parallelize) const
For each module in this ModuleList, preload its symbols.
const ModuleList & operator=(const ModuleList &rhs)
Assignment operator.
std::recursive_mutex m_modules_mutex
Definition ModuleList.h:556
bool AppendIfNeeded(const lldb::ModuleSP &new_module, bool notify=true)
Append a module to the module list, if it is not already there.
Module * GetModulePointerAtIndex(size_t idx) const
Get the module pointer for the module at index idx.
void FindSymbolsWithNameAndType(ConstString name, lldb::SymbolType symbol_type, SymbolContextList &sc_list) const
static lldb::ModuleSP FindSharedModule(const UUID &uuid)
lldb::ModuleSP FindModule(const Module *module_ptr) const
static ModuleListProperties & GetGlobalModuleListProperties()
void FindModules(const ModuleSpec &module_spec, ModuleList &matching_module_list) const
Finds modules whose file specification matches module_spec.
void FindAddressesForLine(const lldb::TargetSP target_sp, const FileSpec &file, uint32_t line, Function *function, std::vector< Address > &output_local, std::vector< Address > &output_extern)
Find addresses by file/line.
uint32_t ResolveSymbolContextForAddress(const Address &so_addr, lldb::SymbolContextItem resolve_scope, SymbolContext &sc) const
Resolve the symbol context for the given address. (const Address&,uint32_t,SymbolContext&)
bool Remove(const lldb::ModuleSP &module_sp, bool notify=true)
Remove a module from the module list.
size_t RemoveOrphans(bool mandatory)
lldb::ModuleSP GetModuleAtIndex(size_t idx) const
Get the module shared pointer for the module at index idx.
void Append(const lldb::ModuleSP &module_sp, bool notify=true)
Append a module to the module list.
static size_t RemoveOrphanSharedModules(bool mandatory)
void Destroy()
Clear the object's state.
void AppendImpl(const lldb::ModuleSP &module_sp, bool use_notifier=true)
void ReplaceEquivalent(const lldb::ModuleSP &module_sp, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules=nullptr)
Append a module to the module list and remove any equivalent modules.
void FindFunctionSymbols(ConstString name, lldb::FunctionNameType name_type_mask, SymbolContextList &sc_list)
static void FindSharedModules(const ModuleSpec &module_spec, ModuleList &matching_module_list)
bool LoadScriptingResourcesInTarget(Target *target, std::list< Status > &errors, bool continue_on_error=true)
void FindSymbolsMatchingRegExAndType(const RegularExpression &regex, lldb::SymbolType symbol_type, SymbolContextList &sc_list) const
bool ResolveFileAddress(lldb::addr_t vm_addr, Address &so_addr) const
size_t GetSize() const
Gets the size of the module list.
bool RemoveIfOrphaned(const lldb::ModuleWP module_ptr)
void LogUUIDAndPaths(Log *log, const char *prefix_cstr)
void ForEach(std::function< IterationAction(const lldb::ModuleSP &module_sp)> const &callback) const
Applies 'callback' to each module in this ModuleList.
FileSpec & GetPlatformFileSpec()
Definition ModuleSpec.h:69
FileSpec & GetFileSpec()
Definition ModuleSpec.h:57
lldb::PlatformSP GetPlatformSP() const
Definition ModuleSpec.h:152
ArchSpec & GetArchitecture()
Definition ModuleSpec.h:93
FileSpec & GetSymbolFileSpec()
Definition ModuleSpec.h:81
lldb::TargetSP GetTargetSP() const
Definition ModuleSpec.h:142
static std::vector< LookupInfo > MakeLookupInfos(ConstString name, lldb::FunctionNameType name_type_mask, lldb::LanguageType lang_type, ConstString lookup_name_override={})
Creates a vector of lookup infos for function name resolution.
Definition Module.cpp:683
A class that describes an executable image and its associated object and symbol files.
Definition Module.h:91
const lldb_private::UUID & GetUUID()
Get a reference to the UUID value contained in this object.
Definition Module.cpp:337
const ArchSpec & GetArchitecture() const
Get const accessor for the module architecture.
Definition Module.cpp:1017
const FileSpec & GetFileSpec() const
Get const accessor for the module file specification.
Definition Module.h:447
void FindTypes(const TypeQuery &query, TypeResults &results)
Find types using a type-matching object that contains all search parameters.
Definition Module.cpp:953
A plug-in interface definition class for object file parsers.
Definition ObjectFile.h:46
@ eTypeExecutable
A normal executable.
Definition ObjectFile.h:55
@ eTypeStubLibrary
A library that can be linked against but not used for execution.
Definition ObjectFile.h:65
static ModuleSpec LocateExecutableObjectFile(const ModuleSpec &module_spec, StatisticsMap &map)
lldb::OptionValuePropertiesSP m_collection_sp
T GetPropertyAtIndexAs(uint32_t idx, T default_value, const ExecutionContext *exe_ctx=nullptr) const
bool SetPropertyAtIndex(uint32_t idx, T t, const ExecutionContext *exe_ctx=nullptr) const
virtual bool LoadScriptingModule(const char *filename, const LoadScriptOptions &options, lldb_private::Status &error, StructuredData::ObjectSP *module_sp=nullptr, FileSpec extra_search_dir={}, lldb::TargetSP loaded_into_target_sp={})
A class to count time for plugins.
Definition Statistics.h:94
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
bool Success() const
Test for success condition.
Definition Status.cpp:303
const char * GetData() const
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition Stream.h:405
Defines a list of symbol context objects.
uint32_t GetSize() const
Get accessor for a symbol context list size.
Defines a symbol context baton that can be handed other debug core functions.
Provides public interface for all SymbolFiles.
Definition SymbolFile.h:51
Debugger & GetDebugger() const
Definition Target.h:1337
lldb::PlatformSP GetPlatform()
Definition Target.h:1980
A class that contains all state required for type lookups.
Definition Type.h:104
This class tracks the state and results of a TypeQuery.
Definition Type.h:344
bool Done(const TypeQuery &query) const
Check if the type matching has found all of the matches that it needs.
Definition Type.cpp:201
Represents UUID's of various sizes.
Definition UUID.h:27
std::string GetAsString(llvm::StringRef separator="-") const
Definition UUID.cpp:54
bool IsValid() const
Definition UUID.h:69
#define LLDB_INVALID_INDEX32
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
@ eLoadScriptFromSymFileTrue
Definition Target.h:62
@ eLoadScriptFromSymFileTrusted
Definition Target.h:65
@ eLoadScriptFromSymFileFalse
Definition Target.h:63
@ eLoadScriptFromSymFileWarn
Definition Target.h:64
IterationAction
Useful for callbacks whose return type indicates whether to continue iteration or short-circuit.
ScriptLanguage
Script interpreter types.
@ eScriptLanguageNone
std::weak_ptr< lldb_private::Module > ModuleWP
std::shared_ptr< lldb_private::Platform > PlatformSP
@ eLanguageTypeUnknown
Unknown or invalid language value.
SymbolType
Symbol types.
uint64_t user_id_t
Definition lldb-types.h:83
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP
@ eSymbolDownloadBackground
std::shared_ptr< lldb_private::Module > ModuleSP
Options used by Module::FindFunctions.
Definition Module.h:67
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition UserID.h:47
#define PATH_MAX