forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			1213 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1213 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- ModuleList.cpp ------------------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "lldb/Core/ModuleList.h"
 | |
| 
 | |
| // C Includes
 | |
| // C++ Includes
 | |
| #include <cstdint>
 | |
| #include <mutex>
 | |
| 
 | |
| // Other libraries and framework includes
 | |
| // Project includes
 | |
| #include "lldb/Core/Log.h"
 | |
| #include "lldb/Core/Module.h"
 | |
| #include "lldb/Core/ModuleSpec.h"
 | |
| #include "lldb/Host/Host.h"
 | |
| #include "lldb/Host/Symbols.h"
 | |
| #include "lldb/Symbol/ObjectFile.h"
 | |
| #include "lldb/Symbol/SymbolFile.h"
 | |
| #include "lldb/Symbol/VariableList.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| ModuleList::ModuleList() :
 | |
|     m_modules(),
 | |
|     m_modules_mutex (Mutex::eMutexTypeRecursive),
 | |
|     m_notifier(nullptr)
 | |
| {
 | |
| }
 | |
| 
 | |
| ModuleList::ModuleList(const ModuleList& rhs) :
 | |
|     m_modules(),
 | |
|     m_modules_mutex (Mutex::eMutexTypeRecursive),
 | |
|     m_notifier(nullptr)
 | |
| {
 | |
|     Mutex::Locker lhs_locker(m_modules_mutex);
 | |
|     Mutex::Locker rhs_locker(rhs.m_modules_mutex);
 | |
|     m_modules = rhs.m_modules;
 | |
| }
 | |
| 
 | |
| ModuleList::ModuleList (ModuleList::Notifier* notifier) :
 | |
|     m_modules(),
 | |
|     m_modules_mutex (Mutex::eMutexTypeRecursive),
 | |
|     m_notifier(notifier)
 | |
| {
 | |
| }
 | |
| 
 | |
| const ModuleList&
 | |
| ModuleList::operator= (const ModuleList& rhs)
 | |
| {
 | |
|     if (this != &rhs)
 | |
|     {
 | |
|         // That's probably me nit-picking, but in theoretical situation:
 | |
|         //
 | |
|         // * that two threads A B and
 | |
|         // * two ModuleList's x y do opposite assignments ie.:
 | |
|         //
 | |
|         //  in thread A: | in thread B:
 | |
|         //    x = y;     |   y = x;
 | |
|         //
 | |
|         // This establishes correct(same) lock taking order and thus
 | |
|         // avoids priority inversion.
 | |
|         if (uintptr_t(this) > uintptr_t(&rhs))
 | |
|         {
 | |
|             Mutex::Locker lhs_locker(m_modules_mutex);
 | |
|             Mutex::Locker rhs_locker(rhs.m_modules_mutex);
 | |
|             m_modules = rhs.m_modules;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             Mutex::Locker rhs_locker(rhs.m_modules_mutex);
 | |
|             Mutex::Locker lhs_locker(m_modules_mutex);
 | |
|             m_modules = rhs.m_modules;
 | |
|         }
 | |
|     }
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| ModuleList::~ModuleList() = default;
 | |
| 
 | |
| void
 | |
| ModuleList::AppendImpl (const ModuleSP &module_sp, bool use_notifier)
 | |
| {
 | |
|     if (module_sp)
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         m_modules.push_back(module_sp);
 | |
|         if (use_notifier && m_notifier)
 | |
|             m_notifier->ModuleAdded(*this, module_sp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::Append (const ModuleSP &module_sp)
 | |
| {
 | |
|     AppendImpl (module_sp);
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::ReplaceEquivalent (const ModuleSP &module_sp)
 | |
| {
 | |
|     if (module_sp)
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
| 
 | |
|         // First remove any equivalent modules. Equivalent modules are modules
 | |
|         // whose path, platform path and architecture match.
 | |
|         ModuleSpec equivalent_module_spec (module_sp->GetFileSpec(), module_sp->GetArchitecture());
 | |
|         equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
 | |
| 
 | |
|         size_t idx = 0;
 | |
|         while (idx < m_modules.size())
 | |
|         {
 | |
|             ModuleSP module_sp (m_modules[idx]);
 | |
|             if (module_sp->MatchesModuleSpec (equivalent_module_spec))
 | |
|                 RemoveImpl(m_modules.begin() + idx);
 | |
|             else
 | |
|                 ++idx;
 | |
|         }
 | |
|         // Now add the new module to the list
 | |
|         Append(module_sp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::AppendIfNeeded (const ModuleSP &module_sp)
 | |
| {
 | |
|     if (module_sp)
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             if (pos->get() == module_sp.get())
 | |
|                 return false; // Already in the list
 | |
|         }
 | |
|         // Only push module_sp on the list if it wasn't already in there.
 | |
|         Append(module_sp);
 | |
|         return true;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::Append (const ModuleList& module_list)
 | |
| {
 | |
|     for (auto pos : module_list.m_modules)
 | |
|         Append(pos);
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::AppendIfNeeded (const ModuleList& module_list)
 | |
| {
 | |
|     bool any_in = false;
 | |
|     for (auto pos : module_list.m_modules)
 | |
|     {
 | |
|         if (AppendIfNeeded(pos))
 | |
|             any_in = true;
 | |
|     }
 | |
|     return any_in;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::RemoveImpl (const ModuleSP &module_sp, bool use_notifier)
 | |
| {
 | |
|     if (module_sp)
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             if (pos->get() == module_sp.get())
 | |
|             {
 | |
|                 m_modules.erase (pos);
 | |
|                 if (use_notifier && m_notifier)
 | |
|                     m_notifier->ModuleRemoved(*this, module_sp);
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| ModuleList::collection::iterator
 | |
| ModuleList::RemoveImpl (ModuleList::collection::iterator pos, bool use_notifier)
 | |
| {
 | |
|     ModuleSP module_sp(*pos);
 | |
|     collection::iterator retval = m_modules.erase(pos);
 | |
|     if (use_notifier && m_notifier)
 | |
|         m_notifier->ModuleRemoved(*this, module_sp);
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::Remove (const ModuleSP &module_sp)
 | |
| {
 | |
|     return RemoveImpl (module_sp);
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::ReplaceModule (const lldb::ModuleSP &old_module_sp, const lldb::ModuleSP &new_module_sp)
 | |
| {
 | |
|     if (!RemoveImpl(old_module_sp, false))
 | |
|         return false;
 | |
|     AppendImpl (new_module_sp, false);
 | |
|     if (m_notifier)
 | |
|         m_notifier->ModuleUpdated(*this, old_module_sp,new_module_sp);
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::RemoveIfOrphaned (const Module *module_ptr)
 | |
| {
 | |
|     if (module_ptr)
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             if (pos->get() == module_ptr)
 | |
|             {
 | |
|                 if (pos->unique())
 | |
|                 {
 | |
|                     pos = RemoveImpl(pos);
 | |
|                     return true;
 | |
|                 }
 | |
|                 else
 | |
|                     return false;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::RemoveOrphans (bool mandatory)
 | |
| {
 | |
|     Mutex::Locker locker;
 | |
|     
 | |
|     if (mandatory)
 | |
|     {
 | |
|         locker.Lock (m_modules_mutex);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         // Not mandatory, remove orphans if we can get the mutex
 | |
|         if (!locker.TryLock(m_modules_mutex))
 | |
|             return 0;
 | |
|     }
 | |
|     collection::iterator pos = m_modules.begin();
 | |
|     size_t remove_count = 0;
 | |
|     while (pos != m_modules.end())
 | |
|     {
 | |
|         if (pos->unique())
 | |
|         {
 | |
|             pos = RemoveImpl(pos);
 | |
|             ++remove_count;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ++pos;
 | |
|         }
 | |
|     }
 | |
|     return remove_count;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::Remove (ModuleList &module_list)
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     size_t num_removed = 0;
 | |
|     collection::iterator pos, end = module_list.m_modules.end();
 | |
|     for (pos = module_list.m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         if (Remove (*pos))
 | |
|             ++num_removed;
 | |
|     }
 | |
|     return num_removed;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| ModuleList::Clear()
 | |
| {
 | |
|     ClearImpl();
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::Destroy()
 | |
| {
 | |
|     ClearImpl();
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::ClearImpl (bool use_notifier)
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     if (use_notifier && m_notifier)
 | |
|         m_notifier->WillClearList(*this);
 | |
|     m_modules.clear();
 | |
| }
 | |
| 
 | |
| Module*
 | |
| ModuleList::GetModulePointerAtIndex (size_t idx) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     return GetModulePointerAtIndexUnlocked(idx);
 | |
| }
 | |
| 
 | |
| Module*
 | |
| ModuleList::GetModulePointerAtIndexUnlocked (size_t idx) const
 | |
| {
 | |
|     if (idx < m_modules.size())
 | |
|         return m_modules[idx].get();
 | |
|     return nullptr;
 | |
| }
 | |
| 
 | |
| ModuleSP
 | |
| ModuleList::GetModuleAtIndex(size_t idx) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     return GetModuleAtIndexUnlocked(idx);
 | |
| }
 | |
| 
 | |
| ModuleSP
 | |
| ModuleList::GetModuleAtIndexUnlocked(size_t idx) const
 | |
| {
 | |
|     ModuleSP module_sp;
 | |
|     if (idx < m_modules.size())
 | |
|         module_sp = m_modules[idx];
 | |
|     return module_sp;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindFunctions (const ConstString &name, 
 | |
|                            uint32_t name_type_mask, 
 | |
|                            bool include_symbols,
 | |
|                            bool include_inlines,
 | |
|                            bool append, 
 | |
|                            SymbolContextList &sc_list) const
 | |
| {
 | |
|     if (!append)
 | |
|         sc_list.Clear();
 | |
|     
 | |
|     const size_t old_size = sc_list.GetSize();
 | |
|     
 | |
|     if (name_type_mask & eFunctionNameTypeAuto)
 | |
|     {
 | |
|         ConstString lookup_name;
 | |
|         uint32_t lookup_name_type_mask = 0;
 | |
|         bool match_name_after_lookup = false;
 | |
|         Module::PrepareForFunctionNameLookup (name, name_type_mask,
 | |
|                                               eLanguageTypeUnknown, // TODO: add support
 | |
|                                               lookup_name,
 | |
|                                               lookup_name_type_mask,
 | |
|                                               match_name_after_lookup);
 | |
|     
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             (*pos)->FindFunctions(lookup_name,
 | |
|                                   nullptr,
 | |
|                                   lookup_name_type_mask,
 | |
|                                   include_symbols,
 | |
|                                   include_inlines,
 | |
|                                   true,
 | |
|                                   sc_list);
 | |
|         }
 | |
|         
 | |
|         if (match_name_after_lookup)
 | |
|         {
 | |
|             SymbolContext sc;
 | |
|             size_t i = old_size;
 | |
|             while (i < sc_list.GetSize())
 | |
|             {
 | |
|                 if (sc_list.GetContextAtIndex(i, sc))
 | |
|                 {
 | |
|                     const char *func_name = sc.GetFunctionName().GetCString();
 | |
|                     if (func_name != nullptr && strstr(func_name, name.GetCString()) == nullptr)
 | |
|                     {
 | |
|                         // Remove the current context
 | |
|                         sc_list.RemoveContextAtIndex(i);
 | |
|                         // Don't increment i and continue in the loop
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
|                 ++i;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             (*pos)->FindFunctions(name, nullptr, name_type_mask, include_symbols, include_inlines, true, sc_list);
 | |
|         }
 | |
|     }
 | |
|     return sc_list.GetSize() - old_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindFunctionSymbols (const ConstString &name,
 | |
|                                  uint32_t name_type_mask,
 | |
|                                  SymbolContextList& sc_list)
 | |
| {
 | |
|     const size_t old_size = sc_list.GetSize();
 | |
| 
 | |
|     if (name_type_mask & eFunctionNameTypeAuto)
 | |
|     {
 | |
|         ConstString lookup_name;
 | |
|         uint32_t lookup_name_type_mask = 0;
 | |
|         bool match_name_after_lookup = false;
 | |
|         Module::PrepareForFunctionNameLookup (name, name_type_mask,
 | |
|                                               eLanguageTypeUnknown, // TODO: add support
 | |
|                                               lookup_name,
 | |
|                                               lookup_name_type_mask,
 | |
|                                               match_name_after_lookup);
 | |
|     
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             (*pos)->FindFunctionSymbols (lookup_name,
 | |
|                                    lookup_name_type_mask,
 | |
|                                    sc_list);
 | |
|         }
 | |
|         
 | |
|         if (match_name_after_lookup)
 | |
|         {
 | |
|             SymbolContext sc;
 | |
|             size_t i = old_size;
 | |
|             while (i < sc_list.GetSize())
 | |
|             {
 | |
|                 if (sc_list.GetContextAtIndex(i, sc))
 | |
|                 {
 | |
|                     const char *func_name = sc.GetFunctionName().GetCString();
 | |
|                     if (func_name != nullptr && strstr(func_name, name.GetCString()) == nullptr)
 | |
|                     {
 | |
|                         // Remove the current context
 | |
|                         sc_list.RemoveContextAtIndex(i);
 | |
|                         // Don't increment i and continue in the loop
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
|                 ++i;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             (*pos)->FindFunctionSymbols (name, name_type_mask, sc_list);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return sc_list.GetSize() - old_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindFunctions(const RegularExpression &name,
 | |
|                           bool include_symbols,
 | |
|                           bool include_inlines,
 | |
|                           bool append,
 | |
|                           SymbolContextList& sc_list)
 | |
| {
 | |
|     const size_t old_size = sc_list.GetSize();
 | |
| 
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->FindFunctions (name, include_symbols, include_inlines, append, sc_list);
 | |
|     }
 | |
| 
 | |
|     return sc_list.GetSize() - old_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindCompileUnits (const FileSpec &path, 
 | |
|                               bool append, 
 | |
|                               SymbolContextList &sc_list) const
 | |
| {
 | |
|     if (!append)
 | |
|         sc_list.Clear();
 | |
|     
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->FindCompileUnits (path, true, sc_list);
 | |
|     }
 | |
|     
 | |
|     return sc_list.GetSize();
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindGlobalVariables (const ConstString &name, 
 | |
|                                  bool append, 
 | |
|                                  size_t max_matches,
 | |
|                                  VariableList& variable_list) const
 | |
| {
 | |
|     size_t initial_size = variable_list.GetSize();
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->FindGlobalVariables(name, nullptr, append, max_matches, variable_list);
 | |
|     }
 | |
|     return variable_list.GetSize() - initial_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindGlobalVariables (const RegularExpression& regex, 
 | |
|                                  bool append, 
 | |
|                                  size_t max_matches,
 | |
|                                  VariableList& variable_list) const
 | |
| {
 | |
|     size_t initial_size = variable_list.GetSize();
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->FindGlobalVariables (regex, append, max_matches, variable_list);
 | |
|     }
 | |
|     return variable_list.GetSize() - initial_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindSymbolsWithNameAndType (const ConstString &name, 
 | |
|                                         SymbolType symbol_type, 
 | |
|                                         SymbolContextList &sc_list,
 | |
|                                         bool append) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     if (!append)
 | |
|         sc_list.Clear();
 | |
|     size_t initial_size = sc_list.GetSize();
 | |
|     
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         (*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
 | |
|     return sc_list.GetSize() - initial_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindSymbolsMatchingRegExAndType (const RegularExpression ®ex, 
 | |
|                                              lldb::SymbolType symbol_type, 
 | |
|                                              SymbolContextList &sc_list,
 | |
|                                              bool append) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     if (!append)
 | |
|         sc_list.Clear();
 | |
|     size_t initial_size = sc_list.GetSize();
 | |
|     
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         (*pos)->FindSymbolsMatchingRegExAndType (regex, symbol_type, sc_list);
 | |
|     return sc_list.GetSize() - initial_size;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindModules (const ModuleSpec &module_spec, ModuleList& matching_module_list) const
 | |
| {
 | |
|     size_t existing_matches = matching_module_list.GetSize();
 | |
| 
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         ModuleSP module_sp(*pos);
 | |
|         if (module_sp->MatchesModuleSpec (module_spec))
 | |
|             matching_module_list.Append(module_sp);
 | |
|     }
 | |
|     return matching_module_list.GetSize() - existing_matches;
 | |
| }
 | |
| 
 | |
| ModuleSP
 | |
| ModuleList::FindModule (const Module *module_ptr) const
 | |
| {
 | |
|     ModuleSP module_sp;
 | |
| 
 | |
|     // Scope for "locker"
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
| 
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             if ((*pos).get() == module_ptr)
 | |
|             {
 | |
|                 module_sp = (*pos);
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return module_sp;
 | |
| }
 | |
| 
 | |
| ModuleSP
 | |
| ModuleList::FindModule (const UUID &uuid) const
 | |
| {
 | |
|     ModuleSP module_sp;
 | |
|     
 | |
|     if (uuid.IsValid())
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
|         
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             if ((*pos)->GetUUID() == uuid)
 | |
|             {
 | |
|                 module_sp = (*pos);
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return module_sp;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool name_is_fully_qualified, size_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeList& types) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
| 
 | |
|     size_t total_matches = 0;
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     if (sc.module_sp)
 | |
|     {
 | |
|         // The symbol context "sc" contains a module so we want to search that
 | |
|         // one first if it is in our list...
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             if (sc.module_sp.get() == (*pos).get())
 | |
|             {
 | |
|                 total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, searched_symbol_files, types);
 | |
| 
 | |
|                 if (total_matches >= max_matches)
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     if (total_matches < max_matches)
 | |
|     {
 | |
|         SymbolContext world_sc;
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             // Search the module if the module is not equal to the one in the symbol
 | |
|             // context "sc". If "sc" contains a empty module shared pointer, then
 | |
|             // the comparison will always be true (valid_module_ptr != nullptr).
 | |
|             if (sc.module_sp.get() != (*pos).get())
 | |
|                 total_matches += (*pos)->FindTypes (world_sc, name, name_is_fully_qualified, max_matches, searched_symbol_files, types);
 | |
|             
 | |
|             if (total_matches >= max_matches)
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     return total_matches;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         if ((*pos)->FindSourceFile (orig_spec, new_spec))
 | |
|             return true;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::FindAddressesForLine (const lldb::TargetSP target_sp,
 | |
|                                   const FileSpec &file, uint32_t line,
 | |
|                                   Function *function,
 | |
|                                   std::vector<Address> &output_local, std::vector<Address> &output_extern)
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->FindAddressesForLine(target_sp, file, line, function, output_local, output_extern);
 | |
|     }
 | |
| }
 | |
| 
 | |
| ModuleSP
 | |
| ModuleList::FindFirstModule (const ModuleSpec &module_spec) const
 | |
| {
 | |
|     ModuleSP module_sp;
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         ModuleSP module_sp(*pos);
 | |
|         if (module_sp->MatchesModuleSpec (module_spec))
 | |
|             return module_sp;
 | |
|     }
 | |
|     return module_sp;
 | |
| 
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::GetSize() const
 | |
| {
 | |
|     size_t size = 0;
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         size = m_modules.size();
 | |
|     }
 | |
|     return size;
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::Dump(Stream *s) const
 | |
| {
 | |
| //  s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
 | |
| //  s.Indent();
 | |
| //  s << "ModuleList\n";
 | |
| 
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->Dump(s);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::LogUUIDAndPaths (Log *log, const char *prefix_cstr)
 | |
| {
 | |
|     if (log != nullptr)
 | |
|     {   
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, begin = m_modules.begin(), end = m_modules.end();
 | |
|         for (pos = begin; pos != end; ++pos)
 | |
|         {
 | |
|             Module *module = pos->get();
 | |
|             const FileSpec &module_file_spec = module->GetFileSpec();
 | |
|             log->Printf ("%s[%u] %s (%s) \"%s\"",
 | |
|                          prefix_cstr ? prefix_cstr : "",
 | |
|                          (uint32_t)std::distance (begin, pos),
 | |
|                          module->GetUUID().GetAsString().c_str(),
 | |
|                          module->GetArchitecture().GetArchitectureName(),
 | |
|                          module_file_spec.GetPath().c_str());
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         if ((*pos)->ResolveFileAddress (vm_addr, so_addr))
 | |
|             return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| uint32_t
 | |
| ModuleList::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) const
 | |
| {
 | |
|     // The address is already section offset so it has a module
 | |
|     uint32_t resolved_flags = 0;
 | |
|     ModuleSP module_sp (so_addr.GetModule());
 | |
|     if (module_sp)
 | |
|     {
 | |
|         resolved_flags = module_sp->ResolveSymbolContextForAddress (so_addr,
 | |
|                                                                     resolve_scope,
 | |
|                                                                     sc);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos, end = m_modules.end();
 | |
|         for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|         {
 | |
|             resolved_flags = (*pos)->ResolveSymbolContextForAddress (so_addr,
 | |
|                                                                      resolve_scope,
 | |
|                                                                      sc);
 | |
|             if (resolved_flags != 0)
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return resolved_flags;
 | |
| }
 | |
| 
 | |
| uint32_t
 | |
| ModuleList::ResolveSymbolContextForFilePath(const char *file_path,
 | |
|                                             uint32_t line,
 | |
|                                             bool check_inlines,
 | |
|                                             uint32_t resolve_scope,
 | |
|                                             SymbolContextList& sc_list) const
 | |
| {
 | |
|     FileSpec file_spec(file_path, false);
 | |
|     return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
 | |
| }
 | |
| 
 | |
| uint32_t
 | |
| ModuleList::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     collection::const_iterator pos, end = m_modules.end();
 | |
|     for (pos = m_modules.begin(); pos != end; ++pos)
 | |
|     {
 | |
|         (*pos)->ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
 | |
|     }
 | |
| 
 | |
|     return sc_list.GetSize();
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::GetIndexForModule (const Module *module) const
 | |
| {
 | |
|     if (module)
 | |
|     {
 | |
|         Mutex::Locker locker(m_modules_mutex);
 | |
|         collection::const_iterator pos;
 | |
|         collection::const_iterator begin = m_modules.begin();
 | |
|         collection::const_iterator end = m_modules.end();
 | |
|         for (pos = begin; pos != end; ++pos)
 | |
|         {
 | |
|             if ((*pos).get() == module)
 | |
|                 return std::distance (begin, pos);
 | |
|         }
 | |
|     }
 | |
|     return LLDB_INVALID_INDEX32;
 | |
| }
 | |
| 
 | |
| static ModuleList &
 | |
| GetSharedModuleList ()
 | |
| {
 | |
|     static ModuleList *g_shared_module_list = nullptr;
 | |
|     static std::once_flag g_once_flag;
 | |
|     std::call_once(g_once_flag, [](){
 | |
|         // NOTE: Intentionally leak the module list so a program doesn't have to
 | |
|         // cleanup all modules and object files as it exits. This just wastes time
 | |
|         // doing a bunch of cleanup that isn't required.
 | |
|         if (g_shared_module_list == nullptr)
 | |
|             g_shared_module_list = new ModuleList(); // <--- Intentional leak!!!
 | |
|     });
 | |
|     return *g_shared_module_list;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::ModuleIsInCache (const Module *module_ptr)
 | |
| {
 | |
|     if (module_ptr)
 | |
|     {
 | |
|         ModuleList &shared_module_list = GetSharedModuleList ();
 | |
|         return shared_module_list.FindModule(module_ptr).get() != nullptr;
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::FindSharedModules (const ModuleSpec &module_spec, ModuleList &matching_module_list)
 | |
| {
 | |
|     return GetSharedModuleList ().FindModules (module_spec, matching_module_list);
 | |
| }
 | |
| 
 | |
| size_t
 | |
| ModuleList::RemoveOrphanSharedModules (bool mandatory)
 | |
| {
 | |
|     return GetSharedModuleList ().RemoveOrphans(mandatory);
 | |
| }
 | |
| 
 | |
| Error
 | |
| ModuleList::GetSharedModule(const ModuleSpec &module_spec,
 | |
|                             ModuleSP &module_sp,
 | |
|                             const FileSpecList *module_search_paths_ptr,
 | |
|                             ModuleSP *old_module_sp_ptr,
 | |
|                             bool *did_create_ptr,
 | |
|                             bool always_create)
 | |
| {
 | |
|     ModuleList &shared_module_list = GetSharedModuleList ();
 | |
|     Mutex::Locker locker(shared_module_list.m_modules_mutex);
 | |
|     char path[PATH_MAX];
 | |
| 
 | |
|     Error error;
 | |
| 
 | |
|     module_sp.reset();
 | |
| 
 | |
|     if (did_create_ptr)
 | |
|         *did_create_ptr = false;
 | |
|     if (old_module_sp_ptr)
 | |
|         old_module_sp_ptr->reset();
 | |
| 
 | |
|     const UUID *uuid_ptr = module_spec.GetUUIDPtr();
 | |
|     const FileSpec &module_file_spec = module_spec.GetFileSpec();
 | |
|     const ArchSpec &arch = module_spec.GetArchitecture();
 | |
| 
 | |
|     // Make sure no one else can try and get or create a module while this
 | |
|     // function is actively working on it by doing an extra lock on the
 | |
|     // global mutex list.
 | |
|     if (!always_create)
 | |
|     {
 | |
|         ModuleList matching_module_list;
 | |
|         const size_t num_matching_modules = shared_module_list.FindModules (module_spec, matching_module_list);
 | |
|         if (num_matching_modules > 0)
 | |
|         {
 | |
|             for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx)
 | |
|             {
 | |
|                 module_sp = matching_module_list.GetModuleAtIndex(module_idx);
 | |
| 
 | |
|                 // Make sure the file for the module hasn't been modified
 | |
|                 if (module_sp->FileHasChanged())
 | |
|                 {
 | |
|                     if (old_module_sp_ptr && !*old_module_sp_ptr)
 | |
|                         *old_module_sp_ptr = module_sp;
 | |
| 
 | |
|                     Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES));
 | |
|                     if (log != nullptr)
 | |
|                         log->Printf("module changed: %p, removing from global module list",
 | |
|                                     static_cast<void*>(module_sp.get()));
 | |
| 
 | |
|                     shared_module_list.Remove (module_sp);
 | |
|                     module_sp.reset();
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // The module matches and the module was not modified from
 | |
|                     // when it was last loaded.
 | |
|                     return error;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (module_sp)
 | |
|         return error;
 | |
| 
 | |
|     module_sp.reset (new Module (module_spec));
 | |
|     // Make sure there are a module and an object file since we can specify
 | |
|     // a valid file path with an architecture that might not be in that file.
 | |
|     // By getting the object file we can guarantee that the architecture matches
 | |
|     if (module_sp->GetObjectFile())
 | |
|     {
 | |
|         // If we get in here we got the correct arch, now we just need
 | |
|         // to verify the UUID if one was given
 | |
|         if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
 | |
|         {
 | |
|             module_sp.reset();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if (module_sp->GetObjectFile() && module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeStubLibrary)
 | |
|             {
 | |
|                 module_sp.reset();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (did_create_ptr)
 | |
|                 {
 | |
|                     *did_create_ptr = true;
 | |
|                 }
 | |
| 
 | |
|                 shared_module_list.ReplaceEquivalent(module_sp);
 | |
|                 return error;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         module_sp.reset();
 | |
|     }
 | |
| 
 | |
|     if (module_search_paths_ptr)
 | |
|     {
 | |
|         const auto num_directories = module_search_paths_ptr->GetSize();
 | |
|         for (size_t idx = 0; idx < num_directories; ++idx)
 | |
|         {
 | |
|             auto search_path_spec = module_search_paths_ptr->GetFileSpecAtIndex(idx);
 | |
|             if (!search_path_spec.ResolvePath())
 | |
|                 continue;
 | |
|             if (!search_path_spec.Exists() || !search_path_spec.IsDirectory())
 | |
|                 continue;
 | |
|             search_path_spec.AppendPathComponent(module_spec.GetFileSpec().GetFilename().AsCString());
 | |
|             if (!search_path_spec.Exists())
 | |
|                 continue;
 | |
| 
 | |
|             auto resolved_module_spec(module_spec);
 | |
|             resolved_module_spec.GetFileSpec() = search_path_spec;
 | |
|             module_sp.reset (new Module (resolved_module_spec));
 | |
|             if (module_sp->GetObjectFile())
 | |
|             {
 | |
|                 // If we get in here we got the correct arch, now we just need
 | |
|                 // to verify the UUID if one was given
 | |
|                 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
 | |
|                 {
 | |
|                     module_sp.reset();
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeStubLibrary)
 | |
|                     {
 | |
|                         module_sp.reset();
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         if (did_create_ptr)
 | |
|                             *did_create_ptr = true;
 | |
|     
 | |
|                         shared_module_list.ReplaceEquivalent(module_sp);
 | |
|                         return Error();
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 module_sp.reset();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Either the file didn't exist where at the path, or no path was given, so
 | |
|     // we now have to use more extreme measures to try and find the appropriate
 | |
|     // module.
 | |
| 
 | |
|     // Fixup the incoming path in case the path points to a valid file, yet
 | |
|     // the arch or UUID (if one was passed in) don't match.
 | |
|     ModuleSpec located_binary_modulespec = Symbols::LocateExecutableObjectFile (module_spec);
 | |
| 
 | |
|     // Don't look for the file if it appears to be the same one we already
 | |
|     // checked for above...
 | |
|     if (located_binary_modulespec.GetFileSpec() != module_file_spec)
 | |
|     {
 | |
|         if (!located_binary_modulespec.GetFileSpec().Exists())
 | |
|         {
 | |
|             located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path));
 | |
|             if (path[0] == '\0')
 | |
|                 module_file_spec.GetPath(path, sizeof(path));
 | |
|             // How can this check ever be true? This branch it is false, and we haven't modified file_spec.
 | |
|             if (located_binary_modulespec.GetFileSpec().Exists())
 | |
|             {
 | |
|                 std::string uuid_str;
 | |
|                 if (uuid_ptr && uuid_ptr->IsValid())
 | |
|                     uuid_str = uuid_ptr->GetAsString();
 | |
| 
 | |
|                 if (arch.IsValid())
 | |
|                 {
 | |
|                     if (!uuid_str.empty())
 | |
|                         error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s", path, arch.GetArchitectureName(), uuid_str.c_str());
 | |
|                     else
 | |
|                         error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.", path, arch.GetArchitectureName());
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 error.SetErrorStringWithFormat("'%s' does not exist", path);
 | |
|             }
 | |
|             if (error.Fail())
 | |
|                 module_sp.reset();
 | |
|             return error;
 | |
|         }
 | |
| 
 | |
|         // Make sure no one else can try and get or create a module while this
 | |
|         // function is actively working on it by doing an extra lock on the
 | |
|         // global mutex list.
 | |
|         ModuleSpec platform_module_spec(module_spec);
 | |
|         platform_module_spec.GetFileSpec() = located_binary_modulespec.GetFileSpec();
 | |
|         platform_module_spec.GetPlatformFileSpec() = located_binary_modulespec.GetFileSpec();
 | |
|         platform_module_spec.GetSymbolFileSpec() = located_binary_modulespec.GetSymbolFileSpec();
 | |
|         ModuleList matching_module_list;
 | |
|         if (shared_module_list.FindModules (platform_module_spec, matching_module_list) > 0)
 | |
|         {
 | |
|             module_sp = matching_module_list.GetModuleAtIndex(0);
 | |
| 
 | |
|             // If we didn't have a UUID in mind when looking for the object file,
 | |
|             // then we should make sure the modification time hasn't changed!
 | |
|             if (platform_module_spec.GetUUIDPtr() == nullptr)
 | |
|             {
 | |
|                 TimeValue file_spec_mod_time(located_binary_modulespec.GetFileSpec().GetModificationTime());
 | |
|                 if (file_spec_mod_time.IsValid())
 | |
|                 {
 | |
|                     if (file_spec_mod_time != module_sp->GetModificationTime())
 | |
|                     {
 | |
|                         if (old_module_sp_ptr)
 | |
|                             *old_module_sp_ptr = module_sp;
 | |
|                         shared_module_list.Remove (module_sp);
 | |
|                         module_sp.reset();
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (!module_sp)
 | |
|         {
 | |
|             module_sp.reset (new Module (platform_module_spec));
 | |
|             // Make sure there are a module and an object file since we can specify
 | |
|             // a valid file path with an architecture that might not be in that file.
 | |
|             // By getting the object file we can guarantee that the architecture matches
 | |
|             if (module_sp && module_sp->GetObjectFile())
 | |
|             {
 | |
|                 if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeStubLibrary)
 | |
|                 {
 | |
|                     module_sp.reset();
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (did_create_ptr)
 | |
|                         *did_create_ptr = true;
 | |
| 
 | |
|                     shared_module_list.ReplaceEquivalent(module_sp);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path));
 | |
| 
 | |
|                 if (located_binary_modulespec.GetFileSpec())
 | |
|                 {
 | |
|                     if (arch.IsValid())
 | |
|                         error.SetErrorStringWithFormat("unable to open %s architecture in '%s'", arch.GetArchitectureName(), path);
 | |
|                     else
 | |
|                         error.SetErrorStringWithFormat("unable to open '%s'", path);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     std::string uuid_str;
 | |
|                     if (uuid_ptr && uuid_ptr->IsValid())
 | |
|                         uuid_str = uuid_ptr->GetAsString();
 | |
| 
 | |
|                     if (!uuid_str.empty())
 | |
|                         error.SetErrorStringWithFormat("cannot locate a module for UUID '%s'", uuid_str.c_str());
 | |
|                     else
 | |
|                         error.SetErrorStringWithFormat("cannot locate a module");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return error;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::RemoveSharedModule (lldb::ModuleSP &module_sp)
 | |
| {
 | |
|     return GetSharedModuleList ().Remove (module_sp);
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::RemoveSharedModuleIfOrphaned (const Module *module_ptr)
 | |
| {
 | |
|     return GetSharedModuleList ().RemoveIfOrphaned (module_ptr);
 | |
| }
 | |
| 
 | |
| bool
 | |
| ModuleList::LoadScriptingResourcesInTarget (Target *target,
 | |
|                                             std::list<Error>& errors,
 | |
|                                             Stream *feedback_stream,
 | |
|                                             bool continue_on_error)
 | |
| {
 | |
|     if (!target)
 | |
|         return false;
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     for (auto module : m_modules)
 | |
|     {
 | |
|         Error error;
 | |
|         if (module)
 | |
|         {
 | |
|             if (!module->LoadScriptingResourceInTarget(target, error, feedback_stream))
 | |
|             {
 | |
|                 if (error.Fail() && error.AsCString())
 | |
|                 {
 | |
|                     error.SetErrorStringWithFormat("unable to load scripting data for module %s - error reported was %s",
 | |
|                                                    module->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
 | |
|                                                    error.AsCString());
 | |
|                     errors.push_back(error);
 | |
| 
 | |
|                     if (!continue_on_error)
 | |
|                         return false;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return errors.empty();
 | |
| }
 | |
| 
 | |
| void
 | |
| ModuleList::ForEach (std::function <bool (const ModuleSP &module_sp)> const &callback) const
 | |
| {
 | |
|     Mutex::Locker locker(m_modules_mutex);
 | |
|     for (const auto &module : m_modules)
 | |
|     {
 | |
|         // If the callback returns false, then stop iterating and break out
 | |
|         if (!callback (module))
 | |
|             break;
 | |
|     }
 | |
| }
 |