//===-- PluginManager.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_CORE_PLUGINMANAGER_H
#define LLDB_CORE_PLUGINMANAGER_H

#include "lldb/Core/Architecture.h"
#include "lldb/Interpreter/Interfaces/ScriptedInterfaceUsages.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Statistics.h"
#include "lldb/Utility/CompletionRequest.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-interfaces.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"

#include <cstddef>
#include <cstdint>
#include <functional>
#include <variant>
#include <vector>

// Match the PluginInitCallback and PluginTermCallback signature. The generated
// initializer always succeeds.
#define LLDB_PLUGIN_DEFINE_ADV(ClassName, PluginName)                          \
  extern "C" {                                                                 \
  bool lldb_initialize_##PluginName() {                                        \
    ClassName::Initialize();                                                   \
    return true;                                                               \
  }                                                                            \
  void lldb_terminate_##PluginName() { ClassName::Terminate(); }               \
  }

#define LLDB_PLUGIN_DEFINE(PluginName)                                         \
  LLDB_PLUGIN_DEFINE_ADV(PluginName, PluginName)

// FIXME: Generate me with CMake
#define LLDB_PLUGIN_DECLARE(PluginName)                                        \
  extern "C" {                                                                 \
  extern bool lldb_initialize_##PluginName();                                  \
  extern void lldb_terminate_##PluginName();                                   \
  }

#define LLDB_PLUGIN_INITIALIZE(PluginName) lldb_initialize_##PluginName()
#define LLDB_PLUGIN_TERMINATE(PluginName) lldb_terminate_##PluginName()

namespace lldb_private {
class CommandInterpreter;
class Debugger;
class StringList;

struct RegisteredPluginInfo {
  llvm::StringRef name = "";
  llvm::StringRef description = "";
  bool enabled = false;
};

// Define some data structures to describe known plugin "namespaces".
// The PluginManager is organized into a series of static functions
// that operate on different types of plugins. For example SystemRuntime
// and ObjectFile plugins.
//
// The namespace name is used a prefix when matching plugin names. For example,
// if we have an "macosx" plugin in the "system-runtime" namespace then we will
// match a plugin name pattern against the "system-runtime.macosx" name.
//
// The plugin namespace here is used so we can operate on all the plugins
// of a given type so it is easy to enable or disable them as a group.
using GetPluginInfo = std::function<llvm::SmallVector<RegisteredPluginInfo>()>;
using SetPluginEnabledGlobalDomain = std::function<bool(llvm::StringRef, bool)>;
using SetPluginEnabledAllDomains = std::function<llvm::Error(
    llvm::StringRef, bool, Debugger &, lldb::PluginDomainKind)>;
class PluginNamespace {
public:
  static constexpr uint8_t kAllDomains = lldb::ePluginDomainKindGlobal |
                                         lldb::ePluginDomainKindDebugger |
                                         lldb::ePluginDomainKindTarget;

  /// Plugin that only supports enable/disable in the global domain
  PluginNamespace(llvm::StringRef name, GetPluginInfo get_info,
                  SetPluginEnabledGlobalDomain set_enabled)
      : name(name), get_info(get_info),
        supported_domains(lldb::ePluginDomainKindGlobal),
        set_enabled_fn(set_enabled) {}

  /// Plugin that supports enable/disable in all domains.
  PluginNamespace(llvm::StringRef name, GetPluginInfo get_info,
                  SetPluginEnabledAllDomains set_enabled)
      : name(name), get_info(get_info), supported_domains(kAllDomains),
        set_enabled_fn(set_enabled) {}

  std::optional<SetPluginEnabledGlobalDomain> GetSetEnabledGlobalFn() const {
    if (SupportsOnlyDomain(lldb::ePluginDomainKindGlobal))
      return std::get<SetPluginEnabledGlobalDomain>(set_enabled_fn);
    return std::nullopt;
  }

  std::optional<SetPluginEnabledAllDomains> GetSetEnabledAllDomainsFn() const {
    if (supported_domains == kAllDomains)
      return std::get<SetPluginEnabledAllDomains>(set_enabled_fn);
    return std::nullopt;
  }

  bool SupportsDomain(lldb::PluginDomainKind domain) const {
    assert(llvm::has_single_bit(static_cast<uint8_t>(domain)));
    return supported_domains & domain;
  }

  bool SupportsOnlyDomain(lldb::PluginDomainKind domain) const {
    assert(llvm::has_single_bit(static_cast<uint8_t>(domain)));
    return supported_domains == domain;
  }

  llvm::StringRef name;
  GetPluginInfo get_info;

private:
  uint8_t supported_domains;
  std::variant<SetPluginEnabledGlobalDomain, SetPluginEnabledAllDomains>
      set_enabled_fn;
};

struct InstrumentationRuntimeCallbacks {
  InstrumentationRuntimeCreateInstance create_callback;
  InstrumentationRuntimeGetType get_type_callback;
};

struct LanguageRuntimeCallbacks {
  LanguageRuntimeCreateInstance create_callback;
  LanguageRuntimeGetCommandObject command_callback;
  LanguageRuntimeGetExceptionPrecondition precondition_callback;
};

struct ObjectFileCallbacks {
  ObjectFileCreateInstance create_callback;
  ObjectFileCreateMemoryInstance create_memory_callback;
  ObjectFileGetModuleSpecifications get_module_specifications;
  ObjectFileSaveCore save_core;
};

struct ObjectContainerCallbacks {
  ObjectContainerCreateInstance create_callback;
  ObjectContainerCreateMemoryInstance create_memory_callback;
  ObjectFileGetModuleSpecifications get_module_specifications;
};

struct StructuredDataPluginCallbacks {
  StructuredDataPluginCreateInstance create_callback;
  StructuredDataFilterLaunchInfo filter_callback;
};

struct REPLCallbacks {
  REPLCreateInstance create_callback;
  LanguageSet supported_languages;
};

struct TraceExporterCallbacks {
  llvm::StringRef name;
  TraceExporterCreateInstance create_callback;
  ThreadTraceExportCommandCreator create_thread_trace_export_command;
};

class PluginManager {
public:
  static void Initialize();

  static void Terminate();

  // Support for enabling and disabling plugins.

  // Return the plugins that can be enabled or disabled by the user.
  static llvm::ArrayRef<PluginNamespace> GetPluginNamespaces();

  // Generate a json object that describes the plugins that are available.
  // This is a json representation of the plugin info returned by
  // GetPluginNamespaces().
  //
  //    {
  //       <plugin-namespace>: [
  //           {
  //               "enabled": <bool>,
  //               "name": <plugin-name>,
  //           },
  //           ...
  //       ],
  //       ...
  //    }
  //
  // If pattern is given it will be used to filter the plugins that are
  // are returned. The pattern filters the plugin names using the
  // PluginManager::MatchPluginName() function.
  static llvm::json::Object GetJSON(llvm::StringRef pattern = "");

  // Return true if the pattern matches the plugin name.
  //
  // The pattern matches the name if it is exactly equal to the namespace name
  // or if it is equal to the qualified name, which is the namespace name
  // followed by a dot and the plugin name (e.g. "system-runtime.foo").
  //
  // An empty pattern matches all plugins.
  static bool MatchPluginName(llvm::StringRef pattern,
                              const PluginNamespace &plugin_ns,
                              const RegisteredPluginInfo &plugin);

  // ABI
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             ABICreateInstance create_callback);

  static bool UnregisterPlugin(ABICreateInstance create_callback);

  static llvm::SmallVector<ABICreateInstance> GetABICreateCallbacks();

  // Architecture
  static void RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             ArchitectureCreateInstance create_callback);

  static void UnregisterPlugin(ArchitectureCreateInstance create_callback);

  static std::unique_ptr<Architecture>
  CreateArchitectureInstance(const ArchSpec &arch);

  // BugReporter
  static void RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             BugReporterCreateInstance create_callback);

  static void UnregisterPlugin(BugReporterCreateInstance create_callback);

  static std::unique_ptr<BugReporter>
  CreateBugReporterInstance(llvm::StringRef name = {});

  // Disassembler
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             DisassemblerCreateInstance create_callback);

  static bool UnregisterPlugin(DisassemblerCreateInstance create_callback);

  static llvm::SmallVector<DisassemblerCreateInstance>
  GetDisassemblerCreateCallbacks();

  static DisassemblerCreateInstance
  GetDisassemblerCreateCallbackForPluginName(llvm::StringRef name);

  // DynamicLoader
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 DynamicLoaderCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(DynamicLoaderCreateInstance create_callback);

  static llvm::SmallVector<DynamicLoaderCreateInstance>
  GetDynamicLoaderCreateCallbacks();

  static DynamicLoaderCreateInstance
  GetDynamicLoaderCreateCallbackForPluginName(llvm::StringRef name);

  // JITLoader
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 JITLoaderCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(JITLoaderCreateInstance create_callback);

  static llvm::SmallVector<JITLoaderCreateInstance>
  GetJITLoaderCreateCallbacks();

  // EmulateInstruction
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             EmulateInstructionCreateInstance create_callback);

  static bool
  UnregisterPlugin(EmulateInstructionCreateInstance create_callback);

  static llvm::SmallVector<EmulateInstructionCreateInstance>
  GetEmulateInstructionCreateCallbacks();

  static EmulateInstructionCreateInstance
  GetEmulateInstructionCreateCallbackForPluginName(llvm::StringRef name);

  // OperatingSystem
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             OperatingSystemCreateInstance create_callback,
                             DebuggerInitializeCallback debugger_init_callback);

  static bool UnregisterPlugin(OperatingSystemCreateInstance create_callback);

  static llvm::SmallVector<OperatingSystemCreateInstance>
  GetOperatingSystemCreateCallbacks();

  static OperatingSystemCreateInstance
  GetOperatingSystemCreateCallbackForPluginName(llvm::StringRef name);

  // Language
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 LanguageCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(LanguageCreateInstance create_callback);

  static llvm::SmallVector<LanguageCreateInstance> GetLanguageCreateCallbacks();

  // LanguageRuntime
  static bool RegisterPlugin(
      llvm::StringRef name, llvm::StringRef description,
      LanguageRuntimeCreateInstance create_callback,
      LanguageRuntimeGetCommandObject command_callback = nullptr,
      LanguageRuntimeGetExceptionPrecondition precondition_callback = nullptr);

  static bool UnregisterPlugin(LanguageRuntimeCreateInstance create_callback);

  static llvm::SmallVector<LanguageRuntimeCallbacks>
  GetLanguageRuntimeCallbacks();

  // SystemRuntime
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             SystemRuntimeCreateInstance create_callback);

  static bool UnregisterPlugin(SystemRuntimeCreateInstance create_callback);

  static llvm::SmallVector<SystemRuntimeCreateInstance>
  GetSystemRuntimeCreateCallbacks();

  // ObjectFile
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 ObjectFileCreateInstance create_callback,
                 ObjectFileCreateMemoryInstance create_memory_callback,
                 ObjectFileGetModuleSpecifications get_module_specifications,
                 ObjectFileSaveCore save_core = nullptr,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(ObjectFileCreateInstance create_callback);

  static bool IsRegisteredObjectFilePluginName(llvm::StringRef name);

  static llvm::SmallVector<ObjectFileCallbacks> GetObjectFileCallbacks();

  static ObjectFileCreateMemoryInstance
  GetObjectFileCreateMemoryCallbackForPluginName(llvm::StringRef name);

  static Status SaveCore(lldb_private::SaveCoreOptions &core_options);

  static llvm::SmallVector<llvm::StringRef> GetSaveCorePluginNames();

  // ObjectContainer
  static bool RegisterPlugin(
      llvm::StringRef name, llvm::StringRef description,
      ObjectContainerCreateInstance create_callback,
      ObjectFileGetModuleSpecifications get_module_specifications,
      ObjectContainerCreateMemoryInstance create_memory_callback = nullptr);

  static bool UnregisterPlugin(ObjectContainerCreateInstance create_callback);

  static llvm::SmallVector<ObjectContainerCallbacks>
  GetObjectContainerCallbacks();

  // Platform
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 PlatformCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(PlatformCreateInstance create_callback);

  static llvm::SmallVector<PlatformCreateInstance> GetPlatformCreateCallbacks();

  static PlatformCreateInstance
  GetPlatformCreateCallbackForPluginName(llvm::StringRef name);

  static llvm::StringRef GetPlatformPluginNameAtIndex(uint32_t idx);

  static llvm::StringRef GetPlatformPluginDescriptionAtIndex(uint32_t idx);

  static void AutoCompletePlatformName(llvm::StringRef partial_name,
                                       CompletionRequest &request);
  // Process
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 ProcessCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(ProcessCreateInstance create_callback);

  static llvm::SmallVector<ProcessCreateInstance> GetProcessCreateCallbacks();

  static ProcessCreateInstance
  GetProcessCreateCallbackForPluginName(llvm::StringRef name);

  static llvm::StringRef GetProcessPluginNameAtIndex(uint32_t idx);

  static llvm::StringRef GetProcessPluginDescriptionAtIndex(uint32_t idx);

  static void AutoCompleteProcessName(llvm::StringRef partial_name,
                                      CompletionRequest &request);

  // Protocol
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             ProtocolServerCreateInstance create_callback);

  static bool UnregisterPlugin(ProtocolServerCreateInstance create_callback);

  static llvm::StringRef GetProtocolServerPluginNameAtIndex(uint32_t idx);

  static ProtocolServerCreateInstance
  GetProtocolCreateCallbackForPluginName(llvm::StringRef name);

  // Register Type Provider
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             RegisterTypeBuilderCreateInstance create_callback);

  static bool
  UnregisterPlugin(RegisterTypeBuilderCreateInstance create_callback);

  static lldb::RegisterTypeBuilderSP GetRegisterTypeBuilder(Target &target);

  // ScriptInterpreter
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 lldb::ScriptLanguage script_lang,
                 ScriptInterpreterCreateInstance create_callback,
                 ScriptInterpreterGetPath get_path_callback = nullptr);

  static bool UnregisterPlugin(ScriptInterpreterCreateInstance create_callback);

  static llvm::SmallVector<ScriptInterpreterCreateInstance>
  GetScriptInterpreterCreateCallbacks();

  static lldb::ScriptInterpreterSP
  GetScriptInterpreterForLanguage(lldb::ScriptLanguage script_lang,
                                  Debugger &debugger);

  static FileSpec
  GetScriptInterpreterLibraryPath(lldb::ScriptLanguage script_lang);

  // SyntheticFrameProvider
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 SyntheticFrameProviderCreateInstance create_native_callback,
                 ScriptedFrameProviderCreateInstance create_scripted_callback);

  static bool
  UnregisterPlugin(SyntheticFrameProviderCreateInstance create_callback);

  static bool
  UnregisterPlugin(ScriptedFrameProviderCreateInstance create_callback);

  static SyntheticFrameProviderCreateInstance
  GetSyntheticFrameProviderCreateCallbackForPluginName(llvm::StringRef name);

  static llvm::SmallVector<ScriptedFrameProviderCreateInstance>
  GetScriptedFrameProviderCreateCallbacks();

  // StructuredDataPlugin

  /// Register a StructuredDataPlugin class along with optional
  /// callbacks for debugger initialization and Process launch info
  /// filtering and manipulation.
  ///
  /// \param[in] name
  ///    The name of the plugin.
  ///
  /// \param[in] description
  ///    A description string for the plugin.
  ///
  /// \param[in] create_callback
  ///    The callback that will be invoked to create an instance of
  ///    the callback.  This may not be nullptr.
  ///
  /// \param[in] debugger_init_callback
  ///    An optional callback that will be made when a Debugger
  ///    instance is initialized.
  ///
  /// \param[in] filter_callback
  ///    An optional callback that will be invoked before LLDB
  ///    launches a process for debugging.  The callback must
  ///    do the following:
  ///    1. Only do something if the plugin's behavior is enabled.
  ///    2. Only make changes for processes that are relevant to the
  ///       plugin.  The callback gets a pointer to the Target, which
  ///       can be inspected as needed.  The ProcessLaunchInfo is
  ///       provided in read-write mode, and may be modified by the
  ///       plugin if, for instance, additional environment variables
  ///       are needed to support the feature when enabled.
  ///
  /// \return
  ///    Returns true upon success; otherwise, false.
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 StructuredDataPluginCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr,
                 StructuredDataFilterLaunchInfo filter_callback = nullptr);

  static bool
  UnregisterPlugin(StructuredDataPluginCreateInstance create_callback);

  static llvm::SmallVector<StructuredDataPluginCallbacks>
  GetStructuredDataPluginCallbacks();

  // SymbolFile
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 SymbolFileCreateInstance create_callback,
                 DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(SymbolFileCreateInstance create_callback);

  static llvm::SmallVector<SymbolFileCreateInstance>
  GetSymbolFileCreateCallbacks();

  // SymbolVendor
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             SymbolVendorCreateInstance create_callback);

  static bool UnregisterPlugin(SymbolVendorCreateInstance create_callback);

  static llvm::SmallVector<SymbolVendorCreateInstance>
  GetSymbolVendorCreateCallbacks();

  // SymbolLocator
  static bool RegisterPlugin(
      llvm::StringRef name, llvm::StringRef description,
      SymbolLocatorCreateInstance create_callback,
      SymbolLocatorLocateExecutableObjectFile locate_executable_object_file =
          nullptr,
      SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file =
          nullptr,
      SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file =
          nullptr,
      SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle = nullptr,
      DebuggerInitializeCallback debugger_init_callback = nullptr);

  static bool UnregisterPlugin(SymbolLocatorCreateInstance create_callback);

  static llvm::SmallVector<SymbolLocatorCreateInstance>
  GetSymbolLocatorCreateCallbacks();

  static ModuleSpec LocateExecutableObjectFile(const ModuleSpec &module_spec,
                                               StatisticsMap &map);

  static FileSpec
  LocateExecutableSymbolFile(const ModuleSpec &module_spec,
                             const FileSpecList &default_search_paths,
                             StatisticsMap &map);

  static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
                                          Status &error,
                                          bool force_lookup = true,
                                          bool copy_executable = true);

  static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
                                         const UUID *uuid,
                                         const ArchSpec *arch);

  // Trace
  static bool RegisterPlugin(
      llvm::StringRef name, llvm::StringRef description,
      TraceCreateInstanceFromBundle create_callback_from_bundle,
      TraceCreateInstanceForLiveProcess create_callback_for_live_process,
      llvm::StringRef schema,
      DebuggerInitializeCallback debugger_init_callback);

  static bool UnregisterPlugin(TraceCreateInstanceFromBundle create_callback);

  static TraceCreateInstanceFromBundle
  GetTraceCreateCallback(llvm::StringRef plugin_name);

  static TraceCreateInstanceForLiveProcess
  GetTraceCreateCallbackForLiveProcess(llvm::StringRef plugin_name);

  /// Get the JSON schema for a trace bundle description file corresponding to
  /// the given plugin.
  ///
  /// \param[in] plugin_name
  ///     The name of the plugin.
  ///
  /// \return
  ///     An empty \a StringRef if no plugin was found with that plugin name,
  ///     otherwise the actual schema is returned.
  static llvm::StringRef GetTraceSchema(llvm::StringRef plugin_name);

  /// Get the JSON schema for a trace bundle description file corresponding to
  /// the plugin given by its index.
  ///
  /// \param[in] index
  ///     The index of the plugin to get the schema of.
  ///
  /// \return
  ///     An empty \a StringRef if the index is greater than or equal to the
  ///     number plugins, otherwise the actual schema is returned.
  static llvm::StringRef GetTraceSchema(size_t index);

  // TraceExporter

  /// \param[in] create_thread_trace_export_command
  ///     This callback is used to create a CommandObject that will be listed
  ///     under "thread trace export". Can be \b null.
  static bool RegisterPlugin(
      llvm::StringRef name, llvm::StringRef description,
      TraceExporterCreateInstance create_callback,
      ThreadTraceExportCommandCreator create_thread_trace_export_command);

  static TraceExporterCreateInstance
  GetTraceExporterCreateCallback(llvm::StringRef plugin_name);

  static bool UnregisterPlugin(TraceExporterCreateInstance create_callback);

  static llvm::SmallVector<TraceExporterCallbacks> GetTraceExporterCallbacks();

  // UnwindAssembly
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             UnwindAssemblyCreateInstance create_callback);

  static bool UnregisterPlugin(UnwindAssemblyCreateInstance create_callback);

  static llvm::SmallVector<UnwindAssemblyCreateInstance>
  GetUnwindAssemblyCreateCallbacks();

  // MemoryHistory
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             MemoryHistoryCreateInstance create_callback);

  static bool UnregisterPlugin(MemoryHistoryCreateInstance create_callback);

  static llvm::SmallVector<MemoryHistoryCreateInstance>
  GetMemoryHistoryCreateCallbacks();

  // InstrumentationRuntime
  static bool
  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                 InstrumentationRuntimeCreateInstance create_callback,
                 InstrumentationRuntimeGetType get_type_callback);

  static bool
  UnregisterPlugin(InstrumentationRuntimeCreateInstance create_callback);

  static llvm::SmallVector<InstrumentationRuntimeCallbacks>
  GetInstrumentationRuntimeCallbacks(bool enabled_only = true);

  // TypeSystem
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             TypeSystemCreateInstance create_callback,
                             LanguageSet supported_languages_for_types,
                             LanguageSet supported_languages_for_expressions);

  static bool UnregisterPlugin(TypeSystemCreateInstance create_callback);

  static llvm::SmallVector<TypeSystemCreateInstance>
  GetTypeSystemCreateCallbacks();

  static LanguageSet GetAllTypeSystemSupportedLanguagesForTypes();

  static LanguageSet GetAllTypeSystemSupportedLanguagesForExpressions();

  // Scripted Interface
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             ScriptedInterfaceCreateInstance create_callback,
                             lldb::ScriptLanguage language,
                             ScriptedInterfaceUsages usages);

  static bool UnregisterPlugin(ScriptedInterfaceCreateInstance create_callback);

  static uint32_t GetNumScriptedInterfaces();

  static llvm::StringRef GetScriptedInterfaceNameAtIndex(uint32_t idx);

  static llvm::StringRef GetScriptedInterfaceDescriptionAtIndex(uint32_t idx);

  static lldb::ScriptLanguage GetScriptedInterfaceLanguageAtIndex(uint32_t idx);

  static ScriptedInterfaceUsages
  GetScriptedInterfaceUsagesAtIndex(uint32_t idx);

  // REPL
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             REPLCreateInstance create_callback,
                             LanguageSet supported_languages);

  static bool UnregisterPlugin(REPLCreateInstance create_callback);

  static llvm::SmallVector<REPLCallbacks> GetREPLCallbacks();

  static LanguageSet GetREPLAllTypeSystemSupportedLanguages();

  // Higlhighter
  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                             HighlighterCreateInstance create_callback);

  static bool UnregisterPlugin(HighlighterCreateInstance create_callback);

  static llvm::SmallVector<HighlighterCreateInstance>
  GetHighlighterCreateCallbacks();

  // Some plug-ins might register a DebuggerInitializeCallback callback when
  // registering the plug-in. After a new Debugger instance is created, this
  // DebuggerInitialize function will get called. This allows plug-ins to
  // install Properties and do any other initialization that requires a
  // debugger instance.
  static void DebuggerInitialize(Debugger &debugger);

  static lldb::OptionValuePropertiesSP
  GetSettingForDynamicLoaderPlugin(Debugger &debugger,
                                   llvm::StringRef setting_name);

  static bool CreateSettingForDynamicLoaderPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForPlatformPlugin(Debugger &debugger, llvm::StringRef setting_name);

  static bool CreateSettingForPlatformPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForProcessPlugin(Debugger &debugger, llvm::StringRef setting_name);

  static bool CreateSettingForProcessPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForSymbolLocatorPlugin(Debugger &debugger,
                                   llvm::StringRef setting_name);

  static bool CreateSettingForSymbolLocatorPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static bool CreateSettingForTracePlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForObjectFilePlugin(Debugger &debugger,
                                llvm::StringRef setting_name);

  static bool CreateSettingForObjectFilePlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForSymbolFilePlugin(Debugger &debugger,
                                llvm::StringRef setting_name);

  static bool CreateSettingForSymbolFilePlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForJITLoaderPlugin(Debugger &debugger,
                               llvm::StringRef setting_name);

  static bool CreateSettingForJITLoaderPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForOperatingSystemPlugin(Debugger &debugger,
                                     llvm::StringRef setting_name);

  static bool CreateSettingForOperatingSystemPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForStructuredDataPlugin(Debugger &debugger,
                                    llvm::StringRef setting_name);

  static bool CreateSettingForStructuredDataPlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  static lldb::OptionValuePropertiesSP
  GetSettingForCPlusPlusLanguagePlugin(Debugger &debugger,
                                       llvm::StringRef setting_name);

  static bool CreateSettingForCPlusPlusLanguagePlugin(
      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
      llvm::StringRef description, bool is_global_property);

  //
  // Plugin Info+Enable Declarations
  //
  static llvm::SmallVector<RegisteredPluginInfo> GetABIPluginInfo();
  static bool SetABIPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetArchitecturePluginInfo();
  static bool SetArchitecturePluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetBugReporterPluginInfo();
  static bool SetBugReporterPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetDisassemblerPluginInfo();
  static bool SetDisassemblerPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetDynamicLoaderPluginInfo();
  static bool SetDynamicLoaderPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo>
  GetEmulateInstructionPluginInfo();
  static bool SetEmulateInstructionPluginEnabled(llvm::StringRef name,
                                                 bool enable);

  static llvm::SmallVector<RegisteredPluginInfo>
  GetInstrumentationRuntimePluginInfo();
  static llvm::StringRef PluginDomainKindToStr(lldb::PluginDomainKind kind);
  static llvm::Error
  SetInstrumentationRuntimePluginEnabled(llvm::StringRef name, bool enable,
                                         Debugger &requesting_debugger,
                                         lldb::PluginDomainKind domain);

  static llvm::SmallVector<RegisteredPluginInfo> GetJITLoaderPluginInfo();
  static bool SetJITLoaderPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetLanguagePluginInfo();
  static bool SetLanguagePluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetLanguageRuntimePluginInfo();
  static bool SetLanguageRuntimePluginEnabled(llvm::StringRef name,
                                              bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetMemoryHistoryPluginInfo();
  static bool SetMemoryHistoryPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetObjectContainerPluginInfo();
  static bool SetObjectContainerPluginEnabled(llvm::StringRef name,
                                              bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetObjectFilePluginInfo();
  static bool SetObjectFilePluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetOperatingSystemPluginInfo();
  static bool SetOperatingSystemPluginEnabled(llvm::StringRef name,
                                              bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetPlatformPluginInfo();
  static bool SetPlatformPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetProcessPluginInfo();
  static bool SetProcessPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetREPLPluginInfo();
  static bool SetREPLPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo>
  GetRegisterTypeBuilderPluginInfo();
  static bool SetRegisterTypeBuilderPluginEnabled(llvm::StringRef name,
                                                  bool enable);

  static llvm::SmallVector<RegisteredPluginInfo>
  GetScriptInterpreterPluginInfo();
  static bool SetScriptInterpreterPluginEnabled(llvm::StringRef name,
                                                bool enable);

  static llvm::SmallVector<RegisteredPluginInfo>
  GetScriptedInterfacePluginInfo();
  static bool SetScriptedInterfacePluginEnabled(llvm::StringRef name,
                                                bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetStructuredDataPluginInfo();
  static bool SetStructuredDataPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetSymbolFilePluginInfo();
  static bool SetSymbolFilePluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetSymbolLocatorPluginInfo();
  static bool SetSymbolLocatorPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetSymbolVendorPluginInfo();
  static bool SetSymbolVendorPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetSystemRuntimePluginInfo();
  static bool SetSystemRuntimePluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetTracePluginInfo();
  static bool SetTracePluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetTraceExporterPluginInfo();
  static bool SetTraceExporterPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetTypeSystemPluginInfo();
  static bool SetTypeSystemPluginEnabled(llvm::StringRef name, bool enable);

  static llvm::SmallVector<RegisteredPluginInfo> GetUnwindAssemblyPluginInfo();
  static bool SetUnwindAssemblyPluginEnabled(llvm::StringRef name, bool enable);

  static void AutoCompletePluginName(llvm::StringRef partial_name,
                                     CompletionRequest &request);
};

} // namespace lldb_private

#endif // LLDB_CORE_PLUGINMANAGER_H
