//===-- PluginManager.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/lldb-python.h" #include "lldb/Core/PluginManager.h" #include <limits.h> #include <string> #include <vector> #include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/Mutex.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; enum PluginAction { ePluginRegisterInstance, ePluginUnregisterInstance, ePluginGetInstanceAtIndex }; typedef bool (*PluginInitCallback) (void); typedef void (*PluginTermCallback) (void); struct PluginInfo { void *plugin_handle; PluginInitCallback plugin_init_callback; PluginTermCallback plugin_term_callback; }; typedef std::map<FileSpec, PluginInfo> PluginTerminateMap; static Mutex & GetPluginMapMutex () { static Mutex g_plugin_map_mutex (Mutex::eMutexTypeRecursive); return g_plugin_map_mutex; } static PluginTerminateMap & GetPluginMap () { static PluginTerminateMap g_plugin_map; return g_plugin_map; } static bool PluginIsLoaded (const FileSpec &plugin_file_spec) { Mutex::Locker locker (GetPluginMapMutex ()); PluginTerminateMap &plugin_map = GetPluginMap (); return plugin_map.find (plugin_file_spec) != plugin_map.end(); } static void SetPluginInfo (const FileSpec &plugin_file_spec, const PluginInfo &plugin_info) { Mutex::Locker locker (GetPluginMapMutex ()); PluginTerminateMap &plugin_map = GetPluginMap (); assert (plugin_map.find (plugin_file_spec) == plugin_map.end()); plugin_map[plugin_file_spec] = plugin_info; } static FileSpec::EnumerateDirectoryResult LoadPluginCallback ( void *baton, FileSpec::FileType file_type, const FileSpec &file_spec ) { // PluginManager *plugin_manager = (PluginManager *)baton; Error error; // If we have a regular file, a symbolic link or unknown file type, try // and process the file. We must handle unknown as sometimes the directory // enumeration might be enumerating a file system that doesn't have correct // file type information. if (file_type == FileSpec::eFileTypeRegular || file_type == FileSpec::eFileTypeSymbolicLink || file_type == FileSpec::eFileTypeUnknown ) { FileSpec plugin_file_spec (file_spec); plugin_file_spec.ResolvePath(); if (PluginIsLoaded (plugin_file_spec)) return FileSpec::eEnumerateDirectoryResultNext; else { PluginInfo plugin_info = { NULL, NULL, NULL }; uint32_t flags = Host::eDynamicLibraryOpenOptionLazy | Host::eDynamicLibraryOpenOptionLocal | Host::eDynamicLibraryOpenOptionLimitGetSymbol; plugin_info.plugin_handle = Host::DynamicLibraryOpen (plugin_file_spec, flags, error); if (plugin_info.plugin_handle) { bool success = false; plugin_info.plugin_init_callback = (PluginInitCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginInitialize", error); if (plugin_info.plugin_init_callback) { // Call the plug-in "bool LLDBPluginInitialize(void)" function success = plugin_info.plugin_init_callback(); } if (success) { // It is ok for the "LLDBPluginTerminate" symbol to be NULL plugin_info.plugin_term_callback = (PluginTermCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginTerminate", error); } else { // The initialize function returned FALSE which means the // plug-in might not be compatible, or might be too new or // too old, or might not want to run on this machine. Host::DynamicLibraryClose (plugin_info.plugin_handle); plugin_info.plugin_handle = NULL; plugin_info.plugin_init_callback = NULL; } // Regardless of success or failure, cache the plug-in load // in our plug-in info so we don't try to load it again and // again. SetPluginInfo (plugin_file_spec, plugin_info); return FileSpec::eEnumerateDirectoryResultNext; } } } if (file_type == FileSpec::eFileTypeUnknown || file_type == FileSpec::eFileTypeDirectory || file_type == FileSpec::eFileTypeSymbolicLink ) { // Try and recurse into anything that a directory or symbolic link. // We must also do this for unknown as sometimes the directory enumeration // might be enurating a file system that doesn't have correct file type // information. return FileSpec::eEnumerateDirectoryResultEnter; } return FileSpec::eEnumerateDirectoryResultNext; } void PluginManager::Initialize () { #if 1 FileSpec dir_spec; const bool find_directories = true; const bool find_files = true; const bool find_other = true; char dir_path[PATH_MAX]; if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec)) { if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { FileSpec::EnumerateDirectory (dir_path, find_directories, find_files, find_other, LoadPluginCallback, NULL); } } if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec)) { if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { FileSpec::EnumerateDirectory (dir_path, find_directories, find_files, find_other, LoadPluginCallback, NULL); } } #endif } void PluginManager::Terminate () { Mutex::Locker locker (GetPluginMapMutex ()); PluginTerminateMap &plugin_map = GetPluginMap (); PluginTerminateMap::const_iterator pos, end = plugin_map.end(); for (pos = plugin_map.begin(); pos != end; ++pos) { // Call the plug-in "void LLDBPluginTerminate (void)" function if there // is one (if the symbol was not NULL). if (pos->second.plugin_handle) { if (pos->second.plugin_term_callback) pos->second.plugin_term_callback(); Host::DynamicLibraryClose (pos->second.plugin_handle); } } plugin_map.clear(); } #pragma mark ABI struct ABIInstance { ABIInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; ABICreateInstance create_callback; }; typedef std::vector<ABIInstance> ABIInstances; static Mutex & GetABIInstancesMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static ABIInstances & GetABIInstances () { static ABIInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, ABICreateInstance create_callback ) { if (create_callback) { ABIInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetABIInstancesMutex ()); GetABIInstances ().push_back (instance); return true; } return false; } bool PluginManager::UnregisterPlugin (ABICreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetABIInstancesMutex ()); ABIInstances &instances = GetABIInstances (); ABIInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } ABICreateInstance PluginManager::GetABICreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetABIInstancesMutex ()); ABIInstances &instances = GetABIInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } ABICreateInstance PluginManager::GetABICreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetABIInstancesMutex ()); ABIInstances &instances = GetABIInstances (); ABIInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark Disassembler struct DisassemblerInstance { DisassemblerInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; DisassemblerCreateInstance create_callback; }; typedef std::vector<DisassemblerInstance> DisassemblerInstances; static Mutex & GetDisassemblerMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static DisassemblerInstances & GetDisassemblerInstances () { static DisassemblerInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, DisassemblerCreateInstance create_callback ) { if (create_callback) { DisassemblerInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetDisassemblerMutex ()); GetDisassemblerInstances ().push_back (instance); return true; } return false; } bool PluginManager::UnregisterPlugin (DisassemblerCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetDisassemblerMutex ()); DisassemblerInstances &instances = GetDisassemblerInstances (); DisassemblerInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } DisassemblerCreateInstance PluginManager::GetDisassemblerCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetDisassemblerMutex ()); DisassemblerInstances &instances = GetDisassemblerInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } DisassemblerCreateInstance PluginManager::GetDisassemblerCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetDisassemblerMutex ()); DisassemblerInstances &instances = GetDisassemblerInstances (); DisassemblerInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark DynamicLoader struct DynamicLoaderInstance { DynamicLoaderInstance() : name(), description(), create_callback(NULL), debugger_init_callback (NULL) { } ConstString name; std::string description; DynamicLoaderCreateInstance create_callback; DebuggerInitializeCallback debugger_init_callback; }; typedef std::vector<DynamicLoaderInstance> DynamicLoaderInstances; static Mutex & GetDynamicLoaderMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static DynamicLoaderInstances & GetDynamicLoaderInstances () { static DynamicLoaderInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, DynamicLoaderCreateInstance create_callback, DebuggerInitializeCallback debugger_init_callback ) { if (create_callback) { DynamicLoaderInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; instance.debugger_init_callback = debugger_init_callback; Mutex::Locker locker (GetDynamicLoaderMutex ()); GetDynamicLoaderInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (DynamicLoaderCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetDynamicLoaderMutex ()); DynamicLoaderInstances &instances = GetDynamicLoaderInstances (); DynamicLoaderInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } DynamicLoaderCreateInstance PluginManager::GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetDynamicLoaderMutex ()); DynamicLoaderInstances &instances = GetDynamicLoaderInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } DynamicLoaderCreateInstance PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetDynamicLoaderMutex ()); DynamicLoaderInstances &instances = GetDynamicLoaderInstances (); DynamicLoaderInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark EmulateInstruction struct EmulateInstructionInstance { EmulateInstructionInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; EmulateInstructionCreateInstance create_callback; }; typedef std::vector<EmulateInstructionInstance> EmulateInstructionInstances; static Mutex & GetEmulateInstructionMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static EmulateInstructionInstances & GetEmulateInstructionInstances () { static EmulateInstructionInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, EmulateInstructionCreateInstance create_callback ) { if (create_callback) { EmulateInstructionInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetEmulateInstructionMutex ()); GetEmulateInstructionInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (EmulateInstructionCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetEmulateInstructionMutex ()); EmulateInstructionInstances &instances = GetEmulateInstructionInstances (); EmulateInstructionInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } EmulateInstructionCreateInstance PluginManager::GetEmulateInstructionCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetEmulateInstructionMutex ()); EmulateInstructionInstances &instances = GetEmulateInstructionInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } EmulateInstructionCreateInstance PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetEmulateInstructionMutex ()); EmulateInstructionInstances &instances = GetEmulateInstructionInstances (); EmulateInstructionInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark OperatingSystem struct OperatingSystemInstance { OperatingSystemInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; OperatingSystemCreateInstance create_callback; }; typedef std::vector<OperatingSystemInstance> OperatingSystemInstances; static Mutex & GetOperatingSystemMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static OperatingSystemInstances & GetOperatingSystemInstances () { static OperatingSystemInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin (const ConstString &name, const char *description, OperatingSystemCreateInstance create_callback) { if (create_callback) { OperatingSystemInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetOperatingSystemMutex ()); GetOperatingSystemInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (OperatingSystemCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetOperatingSystemMutex ()); OperatingSystemInstances &instances = GetOperatingSystemInstances (); OperatingSystemInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } OperatingSystemCreateInstance PluginManager::GetOperatingSystemCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetOperatingSystemMutex ()); OperatingSystemInstances &instances = GetOperatingSystemInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } OperatingSystemCreateInstance PluginManager::GetOperatingSystemCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetOperatingSystemMutex ()); OperatingSystemInstances &instances = GetOperatingSystemInstances (); OperatingSystemInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark LanguageRuntime struct LanguageRuntimeInstance { LanguageRuntimeInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; LanguageRuntimeCreateInstance create_callback; }; typedef std::vector<LanguageRuntimeInstance> LanguageRuntimeInstances; static Mutex & GetLanguageRuntimeMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static LanguageRuntimeInstances & GetLanguageRuntimeInstances () { static LanguageRuntimeInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, LanguageRuntimeCreateInstance create_callback ) { if (create_callback) { LanguageRuntimeInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetLanguageRuntimeMutex ()); GetLanguageRuntimeInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (LanguageRuntimeCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetLanguageRuntimeMutex ()); LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances (); LanguageRuntimeInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } LanguageRuntimeCreateInstance PluginManager::GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetLanguageRuntimeMutex ()); LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } LanguageRuntimeCreateInstance PluginManager::GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetLanguageRuntimeMutex ()); LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances (); LanguageRuntimeInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark ObjectFile struct ObjectFileInstance { ObjectFileInstance() : name(), description(), create_callback(NULL), create_memory_callback (NULL), get_module_specifications (NULL) { } ConstString name; std::string description; ObjectFileCreateInstance create_callback; ObjectFileCreateMemoryInstance create_memory_callback; ObjectFileGetModuleSpecifications get_module_specifications; }; typedef std::vector<ObjectFileInstance> ObjectFileInstances; static Mutex & GetObjectFileMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static ObjectFileInstances & GetObjectFileInstances () { static ObjectFileInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin (const ConstString &name, const char *description, ObjectFileCreateInstance create_callback, ObjectFileCreateMemoryInstance create_memory_callback, ObjectFileGetModuleSpecifications get_module_specifications) { if (create_callback) { ObjectFileInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; instance.create_memory_callback = create_memory_callback; instance.get_module_specifications = get_module_specifications; Mutex::Locker locker (GetObjectFileMutex ()); GetObjectFileInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (ObjectFileCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetObjectFileMutex ()); ObjectFileInstances &instances = GetObjectFileInstances (); ObjectFileInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } ObjectFileCreateInstance PluginManager::GetObjectFileCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetObjectFileMutex ()); ObjectFileInstances &instances = GetObjectFileInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } ObjectFileCreateMemoryInstance PluginManager::GetObjectFileCreateMemoryCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetObjectFileMutex ()); ObjectFileInstances &instances = GetObjectFileInstances (); if (idx < instances.size()) return instances[idx].create_memory_callback; return NULL; } ObjectFileGetModuleSpecifications PluginManager::GetObjectFileGetModuleSpecificationsCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetObjectFileMutex ()); ObjectFileInstances &instances = GetObjectFileInstances (); if (idx < instances.size()) return instances[idx].get_module_specifications; return NULL; } ObjectFileCreateInstance PluginManager::GetObjectFileCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetObjectFileMutex ()); ObjectFileInstances &instances = GetObjectFileInstances (); ObjectFileInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } ObjectFileCreateMemoryInstance PluginManager::GetObjectFileCreateMemoryCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetObjectFileMutex ()); ObjectFileInstances &instances = GetObjectFileInstances (); ObjectFileInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_memory_callback; } } return NULL; } #pragma mark ObjectContainer struct ObjectContainerInstance { ObjectContainerInstance() : name(), description(), create_callback (NULL), get_module_specifications (NULL) { } ConstString name; std::string description; ObjectContainerCreateInstance create_callback; ObjectFileGetModuleSpecifications get_module_specifications; }; typedef std::vector<ObjectContainerInstance> ObjectContainerInstances; static Mutex & GetObjectContainerMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static ObjectContainerInstances & GetObjectContainerInstances () { static ObjectContainerInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin (const ConstString &name, const char *description, ObjectContainerCreateInstance create_callback, ObjectFileGetModuleSpecifications get_module_specifications) { if (create_callback) { ObjectContainerInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; instance.get_module_specifications = get_module_specifications; Mutex::Locker locker (GetObjectContainerMutex ()); GetObjectContainerInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (ObjectContainerCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetObjectContainerMutex ()); ObjectContainerInstances &instances = GetObjectContainerInstances (); ObjectContainerInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } ObjectContainerCreateInstance PluginManager::GetObjectContainerCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetObjectContainerMutex ()); ObjectContainerInstances &instances = GetObjectContainerInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } ObjectContainerCreateInstance PluginManager::GetObjectContainerCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetObjectContainerMutex ()); ObjectContainerInstances &instances = GetObjectContainerInstances (); ObjectContainerInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } ObjectFileGetModuleSpecifications PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetObjectContainerMutex ()); ObjectContainerInstances &instances = GetObjectContainerInstances (); if (idx < instances.size()) return instances[idx].get_module_specifications; return NULL; } #pragma mark LogChannel struct LogInstance { LogInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; LogChannelCreateInstance create_callback; }; typedef std::vector<LogInstance> LogInstances; static Mutex & GetLogMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static LogInstances & GetLogInstances () { static LogInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, LogChannelCreateInstance create_callback ) { if (create_callback) { LogInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetLogMutex ()); GetLogInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (LogChannelCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetLogMutex ()); LogInstances &instances = GetLogInstances (); LogInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } const char * PluginManager::GetLogChannelCreateNameAtIndex (uint32_t idx) { Mutex::Locker locker (GetLogMutex ()); LogInstances &instances = GetLogInstances (); if (idx < instances.size()) return instances[idx].name.GetCString(); return NULL; } LogChannelCreateInstance PluginManager::GetLogChannelCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetLogMutex ()); LogInstances &instances = GetLogInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } LogChannelCreateInstance PluginManager::GetLogChannelCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetLogMutex ()); LogInstances &instances = GetLogInstances (); LogInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark Platform struct PlatformInstance { PlatformInstance() : name(), description(), create_callback(NULL), debugger_init_callback (NULL) { } ConstString name; std::string description; PlatformCreateInstance create_callback; DebuggerInitializeCallback debugger_init_callback; }; typedef std::vector<PlatformInstance> PlatformInstances; static Mutex & GetPlatformInstancesMutex () { static Mutex g_platform_instances_mutex (Mutex::eMutexTypeRecursive); return g_platform_instances_mutex; } static PlatformInstances & GetPlatformInstances () { static PlatformInstances g_platform_instances; return g_platform_instances; } bool PluginManager::RegisterPlugin (const ConstString &name, const char *description, PlatformCreateInstance create_callback, DebuggerInitializeCallback debugger_init_callback) { if (create_callback) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; instance.debugger_init_callback = debugger_init_callback; GetPlatformInstances ().push_back (instance); return true; } return false; } const char * PluginManager::GetPlatformPluginNameAtIndex (uint32_t idx) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); if (idx < instances.size()) return instances[idx].name.GetCString(); return NULL; } const char * PluginManager::GetPlatformPluginDescriptionAtIndex (uint32_t idx) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); if (idx < instances.size()) return instances[idx].description.c_str(); return NULL; } bool PluginManager::UnregisterPlugin (PlatformCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); PlatformInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } PlatformCreateInstance PluginManager::GetPlatformCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } PlatformCreateInstance PluginManager::GetPlatformCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); PlatformInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } size_t PluginManager::AutoCompletePlatformName (const char *name, StringList &matches) { if (name) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); llvm::StringRef name_sref(name); PlatformInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { llvm::StringRef plugin_name (pos->name.GetCString()); if (plugin_name.startswith(name_sref)) matches.AppendString (plugin_name.data()); } } return matches.GetSize(); } #pragma mark Process struct ProcessInstance { ProcessInstance() : name(), description(), create_callback(NULL), debugger_init_callback(NULL) { } ConstString name; std::string description; ProcessCreateInstance create_callback; DebuggerInitializeCallback debugger_init_callback; }; typedef std::vector<ProcessInstance> ProcessInstances; static Mutex & GetProcessMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static ProcessInstances & GetProcessInstances () { static ProcessInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin (const ConstString &name, const char *description, ProcessCreateInstance create_callback, DebuggerInitializeCallback debugger_init_callback) { if (create_callback) { ProcessInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; instance.debugger_init_callback = debugger_init_callback; Mutex::Locker locker (GetProcessMutex ()); GetProcessInstances ().push_back (instance); } return false; } const char * PluginManager::GetProcessPluginNameAtIndex (uint32_t idx) { Mutex::Locker locker (GetProcessMutex ()); ProcessInstances &instances = GetProcessInstances (); if (idx < instances.size()) return instances[idx].name.GetCString(); return NULL; } const char * PluginManager::GetProcessPluginDescriptionAtIndex (uint32_t idx) { Mutex::Locker locker (GetProcessMutex ()); ProcessInstances &instances = GetProcessInstances (); if (idx < instances.size()) return instances[idx].description.c_str(); return NULL; } bool PluginManager::UnregisterPlugin (ProcessCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetProcessMutex ()); ProcessInstances &instances = GetProcessInstances (); ProcessInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } ProcessCreateInstance PluginManager::GetProcessCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetProcessMutex ()); ProcessInstances &instances = GetProcessInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } ProcessCreateInstance PluginManager::GetProcessCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetProcessMutex ()); ProcessInstances &instances = GetProcessInstances (); ProcessInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark SymbolFile struct SymbolFileInstance { SymbolFileInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; SymbolFileCreateInstance create_callback; }; typedef std::vector<SymbolFileInstance> SymbolFileInstances; static Mutex & GetSymbolFileMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static SymbolFileInstances & GetSymbolFileInstances () { static SymbolFileInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, SymbolFileCreateInstance create_callback ) { if (create_callback) { SymbolFileInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetSymbolFileMutex ()); GetSymbolFileInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (SymbolFileCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetSymbolFileMutex ()); SymbolFileInstances &instances = GetSymbolFileInstances (); SymbolFileInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } SymbolFileCreateInstance PluginManager::GetSymbolFileCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetSymbolFileMutex ()); SymbolFileInstances &instances = GetSymbolFileInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } SymbolFileCreateInstance PluginManager::GetSymbolFileCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetSymbolFileMutex ()); SymbolFileInstances &instances = GetSymbolFileInstances (); SymbolFileInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark SymbolVendor struct SymbolVendorInstance { SymbolVendorInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; SymbolVendorCreateInstance create_callback; }; typedef std::vector<SymbolVendorInstance> SymbolVendorInstances; static Mutex & GetSymbolVendorMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static SymbolVendorInstances & GetSymbolVendorInstances () { static SymbolVendorInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, SymbolVendorCreateInstance create_callback ) { if (create_callback) { SymbolVendorInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetSymbolVendorMutex ()); GetSymbolVendorInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (SymbolVendorCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetSymbolVendorMutex ()); SymbolVendorInstances &instances = GetSymbolVendorInstances (); SymbolVendorInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } SymbolVendorCreateInstance PluginManager::GetSymbolVendorCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetSymbolVendorMutex ()); SymbolVendorInstances &instances = GetSymbolVendorInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } SymbolVendorCreateInstance PluginManager::GetSymbolVendorCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetSymbolVendorMutex ()); SymbolVendorInstances &instances = GetSymbolVendorInstances (); SymbolVendorInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } #pragma mark UnwindAssembly struct UnwindAssemblyInstance { UnwindAssemblyInstance() : name(), description(), create_callback(NULL) { } ConstString name; std::string description; UnwindAssemblyCreateInstance create_callback; }; typedef std::vector<UnwindAssemblyInstance> UnwindAssemblyInstances; static Mutex & GetUnwindAssemblyMutex () { static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); return g_instances_mutex; } static UnwindAssemblyInstances & GetUnwindAssemblyInstances () { static UnwindAssemblyInstances g_instances; return g_instances; } bool PluginManager::RegisterPlugin ( const ConstString &name, const char *description, UnwindAssemblyCreateInstance create_callback ) { if (create_callback) { UnwindAssemblyInstance instance; assert ((bool)name); instance.name = name; if (description && description[0]) instance.description = description; instance.create_callback = create_callback; Mutex::Locker locker (GetUnwindAssemblyMutex ()); GetUnwindAssemblyInstances ().push_back (instance); } return false; } bool PluginManager::UnregisterPlugin (UnwindAssemblyCreateInstance create_callback) { if (create_callback) { Mutex::Locker locker (GetUnwindAssemblyMutex ()); UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances (); UnwindAssemblyInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->create_callback == create_callback) { instances.erase(pos); return true; } } } return false; } UnwindAssemblyCreateInstance PluginManager::GetUnwindAssemblyCreateCallbackAtIndex (uint32_t idx) { Mutex::Locker locker (GetUnwindAssemblyMutex ()); UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances (); if (idx < instances.size()) return instances[idx].create_callback; return NULL; } UnwindAssemblyCreateInstance PluginManager::GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &name) { if (name) { Mutex::Locker locker (GetUnwindAssemblyMutex ()); UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances (); UnwindAssemblyInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (name == pos->name) return pos->create_callback; } } return NULL; } void PluginManager::DebuggerInitialize (Debugger &debugger) { // Initialize the DynamicLoader plugins { Mutex::Locker locker (GetDynamicLoaderMutex ()); DynamicLoaderInstances &instances = GetDynamicLoaderInstances (); DynamicLoaderInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->debugger_init_callback) pos->debugger_init_callback (debugger); } } // Initialize the Platform plugins { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); PlatformInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->debugger_init_callback) pos->debugger_init_callback (debugger); } } // Initialize the Process plugins { Mutex::Locker locker (GetProcessMutex()); ProcessInstances &instances = GetProcessInstances(); ProcessInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { if (pos->debugger_init_callback) pos->debugger_init_callback (debugger); } } } // This is the preferred new way to register plugin specific settings. e.g. // This will put a plugin's settings under e.g. "plugin.<plugin_type_name>.<plugin_type_desc>.SETTINGNAME". static lldb::OptionValuePropertiesSP GetDebuggerPropertyForPlugins (Debugger &debugger, const ConstString &plugin_type_name, const ConstString &plugin_type_desc, bool can_create) { lldb::OptionValuePropertiesSP parent_properties_sp (debugger.GetValueProperties()); if (parent_properties_sp) { static ConstString g_property_name("plugin"); OptionValuePropertiesSP plugin_properties_sp = parent_properties_sp->GetSubProperty (NULL, g_property_name); if (!plugin_properties_sp && can_create) { plugin_properties_sp.reset (new OptionValueProperties (g_property_name)); parent_properties_sp->AppendProperty (g_property_name, ConstString("Settings specify to plugins."), true, plugin_properties_sp); } if (plugin_properties_sp) { lldb::OptionValuePropertiesSP plugin_type_properties_sp = plugin_properties_sp->GetSubProperty (NULL, plugin_type_name); if (!plugin_type_properties_sp && can_create) { plugin_type_properties_sp.reset (new OptionValueProperties (plugin_type_name)); plugin_properties_sp->AppendProperty (plugin_type_name, plugin_type_desc, true, plugin_type_properties_sp); } return plugin_type_properties_sp; } } return lldb::OptionValuePropertiesSP(); } // This is deprecated way to register plugin specific settings. e.g. // "<plugin_type_name>.plugin.<plugin_type_desc>.SETTINGNAME" // and Platform generic settings would be under "platform.SETTINGNAME". static lldb::OptionValuePropertiesSP GetDebuggerPropertyForPluginsOldStyle (Debugger &debugger, const ConstString &plugin_type_name, const ConstString &plugin_type_desc, bool can_create) { static ConstString g_property_name("plugin"); lldb::OptionValuePropertiesSP parent_properties_sp (debugger.GetValueProperties()); if (parent_properties_sp) { OptionValuePropertiesSP plugin_properties_sp = parent_properties_sp->GetSubProperty (NULL, plugin_type_name); if (!plugin_properties_sp && can_create) { plugin_properties_sp.reset (new OptionValueProperties (plugin_type_name)); parent_properties_sp->AppendProperty (plugin_type_name, plugin_type_desc, true, plugin_properties_sp); } if (plugin_properties_sp) { lldb::OptionValuePropertiesSP plugin_type_properties_sp = plugin_properties_sp->GetSubProperty (NULL, g_property_name); if (!plugin_type_properties_sp && can_create) { plugin_type_properties_sp.reset (new OptionValueProperties (g_property_name)); plugin_properties_sp->AppendProperty (g_property_name, ConstString("Settings specific to plugins"), true, plugin_type_properties_sp); } return plugin_type_properties_sp; } } return lldb::OptionValuePropertiesSP(); } lldb::OptionValuePropertiesSP PluginManager::GetSettingForDynamicLoaderPlugin (Debugger &debugger, const ConstString &setting_name) { lldb::OptionValuePropertiesSP properties_sp; lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger, ConstString("dynamic-loader"), ConstString(), // not creating to so we don't need the description false)); if (plugin_type_properties_sp) properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name); return properties_sp; } bool PluginManager::CreateSettingForDynamicLoaderPlugin (Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, const ConstString &description, bool is_global_property) { if (properties_sp) { lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger, ConstString("dynamic-loader"), ConstString("Settings for dynamic loader plug-ins"), true)); if (plugin_type_properties_sp) { plugin_type_properties_sp->AppendProperty (properties_sp->GetName(), description, is_global_property, properties_sp); return true; } } return false; } lldb::OptionValuePropertiesSP PluginManager::GetSettingForPlatformPlugin (Debugger &debugger, const ConstString &setting_name) { lldb::OptionValuePropertiesSP properties_sp; lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPluginsOldStyle (debugger, ConstString("platform"), ConstString(), // not creating to so we don't need the description false)); if (plugin_type_properties_sp) properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name); return properties_sp; } bool PluginManager::CreateSettingForPlatformPlugin (Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, const ConstString &description, bool is_global_property) { if (properties_sp) { lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPluginsOldStyle (debugger, ConstString("platform"), ConstString("Settings for platform plug-ins"), true)); if (plugin_type_properties_sp) { plugin_type_properties_sp->AppendProperty (properties_sp->GetName(), description, is_global_property, properties_sp); return true; } } return false; } lldb::OptionValuePropertiesSP PluginManager::GetSettingForProcessPlugin (Debugger &debugger, const ConstString &setting_name) { lldb::OptionValuePropertiesSP properties_sp; lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger, ConstString("process"), ConstString(), // not creating to so we don't need the description false)); if (plugin_type_properties_sp) properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name); return properties_sp; } bool PluginManager::CreateSettingForProcessPlugin (Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, const ConstString &description, bool is_global_property) { if (properties_sp) { lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger, ConstString("process"), ConstString("Settings for process plug-ins"), true)); if (plugin_type_properties_sp) { plugin_type_properties_sp->AppendProperty (properties_sp->GetName(), description, is_global_property, properties_sp); return true; } } return false; }