================ @@ -46,12 +48,287 @@ class CommandObjectPluginLoad : public CommandObjectParsed { } }; +namespace { +// Helper function to perform an action on each matching plugin. +// The action callback is given the containing namespace along with plugin info +// for each matching plugin. +static int ActOnMatchingPlugins( + const llvm::StringRef pattern, + std::function<void(const PluginNamespace &plugin_namespace, + const std::vector<RegisteredPluginInfo> &plugin_info)> + action) { + int num_matching = 0; + + for (const PluginNamespace &plugin_namespace : + PluginManager::GetPluginNamespaces()) { + + std::vector<RegisteredPluginInfo> matching_plugins; + for (const RegisteredPluginInfo &plugin_info : + plugin_namespace.get_info()) { + if (PluginManager::MatchPluginName(pattern, plugin_namespace, + plugin_info)) + matching_plugins.push_back(plugin_info); + } + + if (!matching_plugins.empty()) { + num_matching += matching_plugins.size(); + action(plugin_namespace, matching_plugins); + } + } + + return num_matching; +} + +// Call the "SetEnable" function for each matching plugins. +// Used to share the majority of the code between the enable +// and disable commands. +int SetEnableOnMatchingPlugins(const llvm::StringRef &pattern, + CommandReturnObject &result, bool enabled) { + return ActOnMatchingPlugins( + pattern, [&](const PluginNamespace &plugin_namespace, + const std::vector<RegisteredPluginInfo> &plugins) { + result.AppendMessage(plugin_namespace.name); + for (const auto &plugin : plugins) { + if (!plugin_namespace.set_enabled(plugin.name, enabled)) { + result.AppendErrorWithFormat("failed to enable plugin %s.%s", + plugin_namespace.name.data(), + plugin.name.data()); + continue; + } + + result.AppendMessageWithFormat( + " %s %-30s %s\n", enabled ? "[+]" : "[-]", plugin.name.data(), + plugin.description.data()); + } + }); +} + +static std::string ConvertJSONToPrettyString(const llvm::json::Value &json) { + std::string str; + llvm::raw_string_ostream os(str); + os << llvm::formatv("{0:2}", json).str(); + os.flush(); + return str; +} + +#define LLDB_OPTIONS_plugin_list +#include "CommandOptions.inc" + +// These option definitions are used by the plugin list command. +class PluginListCommandOptions : public Options { +public: + PluginListCommandOptions() = default; + + ~PluginListCommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'j': + m_json_format = true; + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_json_format = false; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::ArrayRef(g_plugin_list_options); + } + + // Instance variables to hold the values for command options. + bool m_json_format = false; +}; +} // namespace + +class CommandObjectPluginList : public CommandObjectParsed { +public: + CommandObjectPluginList(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "plugin list", + "Report info about registered LLDB plugins.", + nullptr) { + AddSimpleArgumentList(eArgTypeManagedPlugin); + SetHelpLong(R"( +Display information about registered plugins. +The plugin information is formatted as shown below: + + <plugin-namespace> + [+] <plugin-name> Plugin #1 description + [-] <plugin-name> Plugin #2 description + +An enabled plugin is marked with [+] and a disabled plugin is marked with [-]. + +Plugins can be listed by namespace and name with: + + plugin list <plugin-namespace>[.<plugin-name>] + +Plugins can be listed by namespace alone or with a fully qualified name. When listed +with just a namespace all plugins in that namespace are listed. When no arguments +are given all plugins are listed. + +Examples: +List all plugins + + (lldb) plugin list + +List all plugins in the system-runtime namespace + + (lldb) plugin list system-runtime + +List only the plugin 'foo' matching a fully qualified name exactly + + (lldb) plugin list system-runtime.foo +)"); + } + + ~CommandObjectPluginList() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + void DoExecute(Args &command, CommandReturnObject &result) override { + size_t argc = command.GetArgumentCount(); + result.SetStatus(eReturnStatusSuccessFinishResult); + + // Create a temporary vector to hold the patterns to simplify the logic + // for the case when the user passes no patterns + std::vector<llvm::StringRef> patterns; + patterns.reserve(argc == 0 ? 1 : argc); + if (argc == 0) + patterns.push_back(""); + else + for (size_t i = 0; i < argc; ++i) + patterns.push_back(command[i].ref()); + + if (m_options.m_json_format) + OutputJsonFormat(patterns, result); + else + OutputTextFormat(patterns, result); + } + +private: + void OutputJsonFormat(const std::vector<llvm::StringRef> &patterns, + CommandReturnObject &result) { + llvm::json::Object obj; + bool found_empty = false; + for (const llvm::StringRef pattern : patterns) { + llvm::json::Object pat_obj = PluginManager::GetJSON(pattern); + if (pat_obj.empty()) { + found_empty = true; + result.AppendErrorWithFormat( + "Found no matching plugins for pattern '%s'", pattern.data()); + break; + } + for (auto &entry : pat_obj) { + obj[entry.first] = std::move(entry.second); + } + } + if (!found_empty) { + result.AppendMessage(ConvertJSONToPrettyString(std::move(obj))); + } + } + + void OutputTextFormat(const std::vector<llvm::StringRef> &patterns, + CommandReturnObject &result) { + for (const llvm::StringRef pattern : patterns) { + int num_matching = ActOnMatchingPlugins( + pattern, [&](const PluginNamespace &plugin_namespace, + const std::vector<RegisteredPluginInfo> &plugins) { + result.AppendMessage(plugin_namespace.name); + for (auto &plugin : plugins) { + result.AppendMessageWithFormat( + " %s %-30s %s\n", plugin.enabled ? "[+]" : "[-]", + plugin.name.data(), plugin.description.data()); + } + }); + if (num_matching == 0) { + result.AppendErrorWithFormat( + "Found no matching plugins for pattern '%s'", pattern.data()); + break; + } + } + } + + PluginListCommandOptions m_options; +}; + +static void DoPluginEnableDisable(Args &command, CommandReturnObject &result, + bool enable) { + const char *name = enable ? "enable" : "disable"; + size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendErrorWithFormat("'plugin %s' requires one or more arguments", + name); + return; + } + result.SetStatus(eReturnStatusSuccessFinishResult); + + for (size_t i = 0; i < argc; ++i) { + llvm::StringRef pattern = command[i].ref(); + int num_matching = SetEnableOnMatchingPlugins(pattern, result, enable); + + if (num_matching == 0) { + result.AppendErrorWithFormat( + "Found no matching plugins to %s for pattern '%s'", name, + pattern.data()); + break; + } + } +} + +class CommandObjectPluginEnable : public CommandObjectParsed { +public: + CommandObjectPluginEnable(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "plugin enable", + "Enable registered LLDB plugins.", nullptr) { + AddSimpleArgumentList(eArgTypeManagedPlugin); + } + + ~CommandObjectPluginEnable() override = default; + +protected: + void DoExecute(Args &command, CommandReturnObject &result) override { + DoPluginEnableDisable(command, result, true); ---------------- clayborg wrote:
``` DoPluginEnableDisable(command, result, /*enable=*/true); ``` https://github.com/llvm/llvm-project/pull/134418 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits