359 lines · cpp
1//===-- CommandObjectPlugin.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CommandObjectPlugin.h"10#include "lldb/Core/PluginManager.h"11#include "lldb/Host/OptionParser.h"12#include "lldb/Interpreter/CommandInterpreter.h"13#include "lldb/Interpreter/CommandReturnObject.h"14 15using namespace lldb;16using namespace lldb_private;17 18class CommandObjectPluginLoad : public CommandObjectParsed {19public:20 CommandObjectPluginLoad(CommandInterpreter &interpreter)21 : CommandObjectParsed(interpreter, "plugin load",22 "Import a dylib that implements an LLDB plugin.",23 nullptr) {24 AddSimpleArgumentList(eArgTypeFilename);25 }26 27 ~CommandObjectPluginLoad() override = default;28 29protected:30 void DoExecute(Args &command, CommandReturnObject &result) override {31 size_t argc = command.GetArgumentCount();32 33 if (argc != 1) {34 result.AppendError("'plugin load' requires one argument");35 return;36 }37 38 Status error;39 40 FileSpec dylib_fspec(command[0].ref());41 FileSystem::Instance().Resolve(dylib_fspec);42 43 if (GetDebugger().LoadPlugin(dylib_fspec, error))44 result.SetStatus(eReturnStatusSuccessFinishResult);45 else {46 result.AppendError(error.AsCString());47 }48 }49};50 51namespace {52// Helper function to perform an action on each matching plugin.53// The action callback is given the containing namespace along with plugin info54// for each matching plugin.55static int ActOnMatchingPlugins(56 const llvm::StringRef pattern,57 std::function<void(const PluginNamespace &plugin_namespace,58 const std::vector<RegisteredPluginInfo> &plugin_info)>59 action) {60 int num_matching = 0;61 62 for (const PluginNamespace &plugin_namespace :63 PluginManager::GetPluginNamespaces()) {64 65 std::vector<RegisteredPluginInfo> matching_plugins;66 for (const RegisteredPluginInfo &plugin_info :67 plugin_namespace.get_info()) {68 if (PluginManager::MatchPluginName(pattern, plugin_namespace,69 plugin_info))70 matching_plugins.push_back(plugin_info);71 }72 73 if (!matching_plugins.empty()) {74 num_matching += matching_plugins.size();75 action(plugin_namespace, matching_plugins);76 }77 }78 79 return num_matching;80}81 82// Call the "SetEnable" function for each matching plugins.83// Used to share the majority of the code between the enable84// and disable commands.85int SetEnableOnMatchingPlugins(const llvm::StringRef &pattern,86 CommandReturnObject &result, bool enabled) {87 return ActOnMatchingPlugins(88 pattern, [&](const PluginNamespace &plugin_namespace,89 const std::vector<RegisteredPluginInfo> &plugins) {90 result.AppendMessage(plugin_namespace.name);91 for (const auto &plugin : plugins) {92 if (!plugin_namespace.set_enabled(plugin.name, enabled)) {93 result.AppendErrorWithFormat("failed to enable plugin %s.%s",94 plugin_namespace.name.data(),95 plugin.name.data());96 continue;97 }98 99 result.AppendMessageWithFormat(100 " %s %-30s %s\n", enabled ? "[+]" : "[-]", plugin.name.data(),101 plugin.description.data());102 }103 });104}105 106static std::string ConvertJSONToPrettyString(const llvm::json::Value &json) {107 std::string str;108 llvm::raw_string_ostream os(str);109 os << llvm::formatv("{0:2}", json).str();110 os.flush();111 return str;112}113 114#define LLDB_OPTIONS_plugin_list115#include "CommandOptions.inc"116 117// These option definitions are used by the plugin list command.118class PluginListCommandOptions : public Options {119public:120 PluginListCommandOptions() = default;121 122 ~PluginListCommandOptions() override = default;123 124 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,125 ExecutionContext *execution_context) override {126 Status error;127 const int short_option = m_getopt_table[option_idx].val;128 129 switch (short_option) {130 case 'j':131 m_json_format = true;132 break;133 default:134 llvm_unreachable("Unimplemented option");135 }136 137 return error;138 }139 140 void OptionParsingStarting(ExecutionContext *execution_context) override {141 m_json_format = false;142 }143 144 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {145 return llvm::ArrayRef(g_plugin_list_options);146 }147 148 // Instance variables to hold the values for command options.149 bool m_json_format = false;150};151} // namespace152 153class CommandObjectPluginList : public CommandObjectParsed {154public:155 CommandObjectPluginList(CommandInterpreter &interpreter)156 : CommandObjectParsed(interpreter, "plugin list",157 "Report info about registered LLDB plugins.",158 nullptr) {159 AddSimpleArgumentList(eArgTypeManagedPlugin);160 SetHelpLong(R"(161Display information about registered plugins.162The plugin information is formatted as shown below:163 164 <plugin-namespace>165 [+] <plugin-name> Plugin #1 description166 [-] <plugin-name> Plugin #2 description167 168An enabled plugin is marked with [+] and a disabled plugin is marked with [-].169 170Plugins can be listed by namespace and name with:171 172 plugin list <plugin-namespace>[.<plugin-name>]173 174Plugins can be listed by namespace alone or with a fully qualified name. When listed175with just a namespace all plugins in that namespace are listed. When no arguments176are given all plugins are listed.177 178Examples:179List all plugins180 181 (lldb) plugin list182 183List all plugins in the system-runtime namespace184 185 (lldb) plugin list system-runtime186 187List only the plugin 'foo' matching a fully qualified name exactly188 189 (lldb) plugin list system-runtime.foo190)");191 }192 193 ~CommandObjectPluginList() override = default;194 195 Options *GetOptions() override { return &m_options; }196 197 void198 HandleArgumentCompletion(CompletionRequest &request,199 OptionElementVector &opt_element_vector) override {200 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(201 GetCommandInterpreter(), lldb::eManagedPluginCompletion, request,202 nullptr);203 }204 205protected:206 void DoExecute(Args &command, CommandReturnObject &result) override {207 size_t argc = command.GetArgumentCount();208 result.SetStatus(eReturnStatusSuccessFinishResult);209 210 // Create a temporary vector to hold the patterns to simplify the logic211 // for the case when the user passes no patterns212 std::vector<llvm::StringRef> patterns;213 patterns.reserve(argc == 0 ? 1 : argc);214 if (argc == 0)215 patterns.push_back("");216 else217 for (size_t i = 0; i < argc; ++i)218 patterns.push_back(command[i].ref());219 220 if (m_options.m_json_format)221 OutputJsonFormat(patterns, result);222 else223 OutputTextFormat(patterns, result);224 }225 226private:227 void OutputJsonFormat(const std::vector<llvm::StringRef> &patterns,228 CommandReturnObject &result) {229 llvm::json::Object obj;230 bool found_empty = false;231 for (const llvm::StringRef pattern : patterns) {232 llvm::json::Object pat_obj = PluginManager::GetJSON(pattern);233 if (pat_obj.empty()) {234 found_empty = true;235 result.AppendErrorWithFormat(236 "Found no matching plugins for pattern '%s'", pattern.data());237 break;238 }239 for (auto &entry : pat_obj) {240 obj[entry.first] = std::move(entry.second);241 }242 }243 if (!found_empty) {244 result.AppendMessage(ConvertJSONToPrettyString(std::move(obj)));245 }246 }247 248 void OutputTextFormat(const std::vector<llvm::StringRef> &patterns,249 CommandReturnObject &result) {250 for (const llvm::StringRef pattern : patterns) {251 int num_matching = ActOnMatchingPlugins(252 pattern, [&](const PluginNamespace &plugin_namespace,253 const std::vector<RegisteredPluginInfo> &plugins) {254 result.AppendMessage(plugin_namespace.name);255 for (auto &plugin : plugins) {256 result.AppendMessageWithFormat(257 " %s %-30s %s\n", plugin.enabled ? "[+]" : "[-]",258 plugin.name.data(), plugin.description.data());259 }260 });261 if (num_matching == 0) {262 result.AppendErrorWithFormat(263 "Found no matching plugins for pattern '%s'", pattern.data());264 break;265 }266 }267 }268 269 PluginListCommandOptions m_options;270};271 272static void DoPluginEnableDisable(Args &command, CommandReturnObject &result,273 bool enable) {274 const char *name = enable ? "enable" : "disable";275 size_t argc = command.GetArgumentCount();276 if (argc == 0) {277 result.AppendErrorWithFormat("'plugin %s' requires one or more arguments",278 name);279 return;280 }281 result.SetStatus(eReturnStatusSuccessFinishResult);282 283 for (size_t i = 0; i < argc; ++i) {284 llvm::StringRef pattern = command[i].ref();285 int num_matching = SetEnableOnMatchingPlugins(pattern, result, enable);286 287 if (num_matching == 0) {288 result.AppendErrorWithFormat(289 "Found no matching plugins to %s for pattern '%s'", name,290 pattern.data());291 break;292 }293 }294}295 296class CommandObjectPluginEnable : public CommandObjectParsed {297public:298 CommandObjectPluginEnable(CommandInterpreter &interpreter)299 : CommandObjectParsed(interpreter, "plugin enable",300 "Enable registered LLDB plugins.", nullptr) {301 AddSimpleArgumentList(eArgTypeManagedPlugin);302 }303 304 void305 HandleArgumentCompletion(CompletionRequest &request,306 OptionElementVector &opt_element_vector) override {307 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(308 GetCommandInterpreter(), lldb::eManagedPluginCompletion, request,309 nullptr);310 }311 312 ~CommandObjectPluginEnable() override = default;313 314protected:315 void DoExecute(Args &command, CommandReturnObject &result) override {316 DoPluginEnableDisable(command, result, /*enable=*/true);317 }318};319 320class CommandObjectPluginDisable : public CommandObjectParsed {321public:322 CommandObjectPluginDisable(CommandInterpreter &interpreter)323 : CommandObjectParsed(interpreter, "plugin disable",324 "Disable registered LLDB plugins.", nullptr) {325 AddSimpleArgumentList(eArgTypeManagedPlugin);326 }327 328 void329 HandleArgumentCompletion(CompletionRequest &request,330 OptionElementVector &opt_element_vector) override {331 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(332 GetCommandInterpreter(), lldb::eManagedPluginCompletion, request,333 nullptr);334 }335 336 ~CommandObjectPluginDisable() override = default;337 338protected:339 void DoExecute(Args &command, CommandReturnObject &result) override {340 DoPluginEnableDisable(command, result, /*enable=*/false);341 }342};343 344CommandObjectPlugin::CommandObjectPlugin(CommandInterpreter &interpreter)345 : CommandObjectMultiword(interpreter, "plugin",346 "Commands for managing LLDB plugins.",347 "plugin <subcommand> [<subcommand-options>]") {348 LoadSubCommand("load",349 CommandObjectSP(new CommandObjectPluginLoad(interpreter)));350 LoadSubCommand("list",351 CommandObjectSP(new CommandObjectPluginList(interpreter)));352 LoadSubCommand("enable",353 CommandObjectSP(new CommandObjectPluginEnable(interpreter)));354 LoadSubCommand("disable",355 CommandObjectSP(new CommandObjectPluginDisable(interpreter)));356}357 358CommandObjectPlugin::~CommandObjectPlugin() = default;359