LLDB mainline
CommandObjectPlugin.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
16
17using namespace lldb;
18using namespace lldb_private;
19
21public:
23 : CommandObjectParsed(interpreter, "plugin load",
24 "Import a dylib that implements an LLDB plugin.",
25 nullptr) {
27 }
28
29 ~CommandObjectPluginLoad() override = default;
30
31protected:
32 void DoExecute(Args &command, CommandReturnObject &result) override {
33 size_t argc = command.GetArgumentCount();
34
35 if (argc != 1) {
36 result.AppendError("'plugin load' requires one argument");
37 return;
38 }
39
41
42 FileSpec dylib_fspec(command[0].ref());
43 FileSystem::Instance().Resolve(dylib_fspec);
44
45 if (GetDebugger().LoadPlugin(dylib_fspec, error))
47 else {
48 result.AppendError(error.AsCString());
49 }
50 }
51};
52
53namespace {
54// Helper function to perform an action on each matching plugin.
55// The action callback is given the containing namespace along with plugin info
56// for each matching plugin.
57static int ActOnMatchingPlugins(
58 const llvm::StringRef pattern,
59 std::function<void(const PluginNamespace &plugin_namespace,
60 const std::vector<RegisteredPluginInfo> &plugin_info)>
61 action) {
62 int num_matching = 0;
63
64 for (const PluginNamespace &plugin_namespace :
66
67 std::vector<RegisteredPluginInfo> matching_plugins;
68 for (const RegisteredPluginInfo &plugin_info :
69 plugin_namespace.get_info()) {
70 if (PluginManager::MatchPluginName(pattern, plugin_namespace,
71 plugin_info))
72 matching_plugins.push_back(plugin_info);
73 }
74
75 if (!matching_plugins.empty()) {
76 num_matching += matching_plugins.size();
77 action(plugin_namespace, matching_plugins);
78 }
79 }
80
81 return num_matching;
82}
83
84// Call the "SetEnable" function for each matching plugins.
85// Used to share the majority of the code between the enable
86// and disable commands.
87int SetEnableOnMatchingPlugins(const llvm::StringRef &pattern,
88 CommandReturnObject &result, bool enabled,
89 Debugger &requesting_debugger,
90 PluginDomainKind domain) {
91 return ActOnMatchingPlugins(
92 pattern, [&](const PluginNamespace &plugin_namespace,
93 const std::vector<RegisteredPluginInfo> &plugins) {
94 auto PrintEnablement = [enabled,
95 &result](const RegisteredPluginInfo plugin) {
96 result.AppendMessageWithFormatv(" {0} {1, -30} {2}",
97 enabled ? "[+]" : "[-]", plugin.name,
98 plugin.description);
99 };
100
101 result.AppendMessage(plugin_namespace.name);
102 for (const auto &plugin : plugins) {
103 if (plugin_namespace.SupportsOnlyDomain(
105 bool success = true;
106 if (domain != ePluginDomainKindGlobal) {
108 "failed to {} plugin {}.{}: {} domain is not supported",
109 enabled ? "enable" : "disable", plugin_namespace.name,
111 continue;
112 }
113 success = (*plugin_namespace.GetSetEnabledGlobalFn())(plugin.name,
114 enabled);
115
116 if (!success) {
117 result.AppendErrorWithFormatv("failed to {} plugin {}.{}",
118 enabled ? "enable" : "disable",
119 plugin_namespace.name, plugin.name);
120 continue;
121 }
122 PrintEnablement(plugin);
123 continue;
124 }
125
126 // Handle plugin namespace that supports more than just the global
127 // domain. Currently this is just the instrumentation-runtime
128 // namespace.
129 if (!plugin_namespace.SupportsDomain(domain)) {
131 "failed to {0} plugin {1}.{2}: the {1} namespace "
132 "does not support the {3} domain",
133 enabled ? "enable" : "disable", plugin_namespace.name,
135 continue;
136 }
137 assert(plugin_namespace.GetSetEnabledAllDomainsFn().has_value());
138 llvm::Error error = (*plugin_namespace.GetSetEnabledAllDomainsFn())(
139 plugin.name, enabled, requesting_debugger, domain);
140
141 if (error) {
142 result.AppendErrorWithFormatv("failed to {} plugin {}.{}: {}",
143 enabled ? "enable" : "disable",
144 plugin_namespace.name, plugin.name,
145 llvm::toString(std::move(error)));
146 continue;
147 }
148 PrintEnablement(plugin);
149 }
150 });
151}
152
153static std::string ConvertJSONToPrettyString(const llvm::json::Value &json) {
154 std::string str;
155 llvm::raw_string_ostream os(str);
156 os << llvm::formatv("{0:2}", json).str();
157 os.flush();
158 return str;
159}
160
161#define LLDB_OPTIONS_plugin_list
162#include "CommandOptions.inc"
163
164// These option definitions are used by the plugin list command.
165class PluginListCommandOptions : public Options {
166 static constexpr const PluginDomainKind kDefaultDomain =
168
169public:
170 PluginListCommandOptions() = default;
171
172 ~PluginListCommandOptions() override = default;
173
174 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
175 ExecutionContext *execution_context) override {
177 const int short_option = m_getopt_table[option_idx].val;
178
179 switch (short_option) {
180 case 'j':
181 m_json_format = true;
182 break;
183 case 'd':
184 m_domain = static_cast<PluginDomainKind>(OptionArgParser::ToOptionEnum(
185 option_arg, GetDefinitions()[option_idx].enum_values, kDefaultDomain,
186 error));
187 break;
188 default:
189 llvm_unreachable("Unimplemented option");
190 }
191
192 return error;
193 }
194
195 void OptionParsingStarting(ExecutionContext *execution_context) override {
196 m_json_format = false;
197 m_domain = kDefaultDomain;
198 }
199
200 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
201 return llvm::ArrayRef(g_plugin_list_options);
202 }
203
204 // Instance variables to hold the values for command options.
205 bool m_json_format = false;
206 PluginDomainKind m_domain = kDefaultDomain;
207};
208} // namespace
209
211public:
213 : CommandObjectParsed(interpreter, "plugin list",
214 "Report info about registered LLDB plugins.",
215 nullptr) {
217 SetHelpLong(R"(
218Display information about registered plugins.
219The plugin information is formatted as shown below:
221 <plugin-namespace>
222 [+] <plugin-name> Plugin #1 description
223 [-] <plugin-name> Plugin #2 description
224
225An enabled plugin is marked with [+] and a disabled plugin is marked with [-].
226
227Plugins can be listed by namespace and name with:
228
229 plugin list <plugin-namespace>[.<plugin-name>]
230
231Plugins can be listed by namespace alone or with a fully qualified name. When listed
232with just a namespace all plugins in that namespace are listed. When no arguments
233are given all plugins are listed.
234
235Examples:
236List all plugins
237
238 (lldb) plugin list
239
240List all plugins in the system-runtime namespace
241
242 (lldb) plugin list system-runtime
243
244List only the plugin 'foo' matching a fully qualified name exactly
245
246 (lldb) plugin list system-runtime.foo
247)");
248 }
249
250 ~CommandObjectPluginList() override = default;
251
252 Options *GetOptions() override { return &m_options; }
253
254 void
256 OptionElementVector &opt_element_vector) override {
259 nullptr);
260 }
261
262protected:
263 void DoExecute(Args &command, CommandReturnObject &result) override {
264 size_t argc = command.GetArgumentCount();
266
267 // Create a temporary vector to hold the patterns to simplify the logic
268 // for the case when the user passes no patterns
269 std::vector<llvm::StringRef> patterns;
270 patterns.reserve(argc == 0 ? 1 : argc);
271 if (argc == 0)
272 patterns.push_back("");
273 else
274 for (size_t i = 0; i < argc; ++i)
275 patterns.push_back(command[i].ref());
276
277 if (m_options.m_json_format)
278 OutputJsonFormat(patterns, result, GetDebugger(), m_options.m_domain);
279 else
280 OutputTextFormat(patterns, result, GetDebugger(), m_options.m_domain);
281 }
282
283private:
284 void OutputJsonFormat(const std::vector<llvm::StringRef> &patterns,
285 CommandReturnObject &result,
286 Debugger &requesting_debugger,
287 PluginDomainKind domain) {
290 "{} domain is not supported",
292 return;
293 }
294
295 llvm::json::Object obj;
296 bool found_empty = false;
297 for (const llvm::StringRef pattern : patterns) {
298 llvm::json::Object pat_obj = PluginManager::GetJSON(pattern);
299 if (pat_obj.empty()) {
300 found_empty = true;
302 "Found no matching plugins for pattern '%s'", pattern.data());
303 break;
304 }
305 for (auto &entry : pat_obj) {
306 obj[entry.first] = std::move(entry.second);
307 }
308 }
309 if (!found_empty) {
310 result.AppendMessage(ConvertJSONToPrettyString(std::move(obj)));
311 }
312 }
313
314 void OutputTextFormat(const std::vector<llvm::StringRef> &patterns,
315 CommandReturnObject &result,
316 Debugger &requesting_debugger,
317 PluginDomainKind domain) {
320 "{} domain is not supported",
322 return;
323 }
324
325 for (const llvm::StringRef pattern : patterns) {
326 int num_matching = ActOnMatchingPlugins(
327 pattern, [&](const PluginNamespace &plugin_namespace,
328 const std::vector<RegisteredPluginInfo> &plugins) {
329 result.AppendMessage(plugin_namespace.name);
330 for (auto &plugin : plugins) {
331 result.AppendMessageWithFormatv(" {0} {1, -30} {2}",
332 plugin.enabled ? "[+]" : "[-]",
333 plugin.name, plugin.description);
334 }
335 });
336 if (num_matching == 0) {
338 "Found no matching plugins for pattern '%s'", pattern.data());
339 break;
340 }
341 }
342 }
343
344 PluginListCommandOptions m_options;
345};
346
347static void DoPluginEnableDisable(Args &command, CommandReturnObject &result,
348 bool enable, Debugger &requesting_debugger,
349 PluginDomainKind domain) {
350 const char *name = enable ? "enable" : "disable";
351 size_t argc = command.GetArgumentCount();
352 if (argc == 0) {
353 result.AppendErrorWithFormat("'plugin %s' requires one or more arguments",
354 name);
355 return;
356 }
358
359 for (size_t i = 0; i < argc; ++i) {
360 llvm::StringRef pattern = command[i].ref();
361 int num_matching = SetEnableOnMatchingPlugins(pattern, result, enable,
362 requesting_debugger, domain);
363
364 if (num_matching == 0) {
366 "Found no matching plugins to %s for pattern '%s'", name,
367 pattern.data());
368 break;
369 }
370 }
371}
372
373#define LLDB_OPTIONS_plugin_enable
374#include "CommandOptions.inc"
375
376#define LLDB_OPTIONS_plugin_disable
377#include "CommandOptions.inc"
378
379// Options class for the --domain flag, shared by plugin enable and
380// plugin disable (and reusable by plugin status in the future).
382 static constexpr const PluginDomainKind kDefaultDomain =
384
385public:
386 PluginDomainOptions(llvm::ArrayRef<OptionDefinition> definitions)
387 : m_definitions(definitions) {}
388
389 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
390 ExecutionContext *execution_context) override {
392 const int short_option = m_getopt_table[option_idx].val;
393 switch (short_option) {
394 case 'd':
396 option_arg, GetDefinitions()[option_idx].enum_values, kDefaultDomain,
397 error));
398 break;
399 default:
400 llvm_unreachable("Unimplemented option");
401 }
402 return error;
403 }
404
405 void OptionParsingStarting(ExecutionContext *execution_context) override {
407 }
408
409 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
410 return m_definitions;
411 }
412
414
415private:
416 llvm::ArrayRef<OptionDefinition> m_definitions;
417};
418
420public:
422 : CommandObjectParsed(interpreter, "plugin enable",
423 "Enable registered LLDB plugins.", nullptr),
424 m_options(llvm::ArrayRef(g_plugin_enable_options)) {
426 }
427
428 void
435
436 ~CommandObjectPluginEnable() override = default;
437
438 Options *GetOptions() override { return &m_options; }
439
440protected:
441 void DoExecute(Args &command, CommandReturnObject &result) override {
442 DoPluginEnableDisable(command, result, /*enable=*/true, GetDebugger(),
443 m_options.m_domain);
444 }
445
447};
448
450public:
452 : CommandObjectParsed(interpreter, "plugin disable",
453 "Disable registered LLDB plugins.", nullptr),
454 m_options(llvm::ArrayRef(g_plugin_disable_options)) {
456 }
457
458 void
465
466 ~CommandObjectPluginDisable() override = default;
467
468 Options *GetOptions() override { return &m_options; }
469
470protected:
471 void DoExecute(Args &command, CommandReturnObject &result) override {
472 DoPluginEnableDisable(command, result, /*enable=*/false, GetDebugger(),
473 m_options.m_domain);
474 }
475
477};
478
480 : CommandObjectMultiword(interpreter, "plugin",
481 "Commands for managing LLDB plugins.",
482 "plugin <subcommand> [<subcommand-options>]") {
483 LoadSubCommand("load",
484 CommandObjectSP(new CommandObjectPluginLoad(interpreter)));
485 LoadSubCommand("list",
486 CommandObjectSP(new CommandObjectPluginList(interpreter)));
487 LoadSubCommand("enable",
489 LoadSubCommand("disable",
491}
492
static void DoPluginEnableDisable(Args &command, CommandReturnObject &result, bool enable, Debugger &requesting_debugger, PluginDomainKind domain)
static llvm::raw_ostream & error(Stream &strm)
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
~CommandObjectPluginDisable() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectPluginDisable(CommandInterpreter &interpreter)
CommandObjectPluginEnable(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectPluginEnable() override=default
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
~CommandObjectPluginList() override=default
PluginListCommandOptions m_options
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectPluginList(CommandInterpreter &interpreter)
void OutputJsonFormat(const std::vector< llvm::StringRef > &patterns, CommandReturnObject &result, Debugger &requesting_debugger, PluginDomainKind domain)
void OutputTextFormat(const std::vector< llvm::StringRef > &patterns, CommandReturnObject &result, Debugger &requesting_debugger, PluginDomainKind domain)
Options * GetOptions() override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectPluginLoad() override=default
CommandObjectPluginLoad(CommandInterpreter &interpreter)
llvm::ArrayRef< OptionDefinition > m_definitions
static constexpr const PluginDomainKind kDefaultDomain
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
PluginDomainOptions(llvm::ArrayRef< OptionDefinition > definitions)
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
void OptionParsingStarting(ExecutionContext *execution_context) override
A command line argument class.
Definition Args.h:33
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition Args.h:120
static bool InvokeCommonCompletionCallbacks(CommandInterpreter &interpreter, uint32_t completion_mask, lldb_private::CompletionRequest &request, SearchFilter *searcher)
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
CommandObjectMultiword(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
CommandObjectParsed(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
CommandObjectPlugin(CommandInterpreter &interpreter)
virtual void SetHelpLong(llvm::StringRef str)
void AddSimpleArgumentList(lldb::CommandArgumentType arg_type, ArgumentRepetitionType repetition_type=eArgRepeatPlain)
CommandInterpreter & GetCommandInterpreter()
void AppendMessage(llvm::StringRef in_string)
void AppendError(llvm::StringRef in_string)
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void void AppendMessageWithFormatv(const char *format, Args &&...args)
void AppendErrorWithFormatv(const char *format, Args &&...args)
"lldb/Utility/ArgCompletionRequest.h"
A class to manage flag bits.
Definition Debugger.h:100
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
A file utility class.
Definition FileSpec.h:57
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
A command line option parsing protocol class.
Definition Options.h:58
std::vector< Option > m_getopt_table
Definition Options.h:198
static bool MatchPluginName(llvm::StringRef pattern, const PluginNamespace &plugin_ns, const RegisteredPluginInfo &plugin)
static llvm::StringRef PluginDomainKindToStr(lldb::PluginDomainKind kind)
static llvm::json::Object GetJSON(llvm::StringRef pattern="")
static llvm::ArrayRef< PluginNamespace > GetPluginNamespaces()
std::optional< SetPluginEnabledGlobalDomain > GetSetEnabledGlobalFn() const
std::optional< SetPluginEnabledAllDomains > GetSetEnabledAllDomainsFn() const
bool SupportsOnlyDomain(lldb::PluginDomainKind domain) const
bool SupportsDomain(lldb::PluginDomainKind domain) const
An error handling class.
Definition Status.h:118
A class that represents a running process on the host machine.
std::vector< OptionArgElement > OptionElementVector
Definition Options.h:43
@ eManagedPluginCompletion
@ ePluginDomainKindGlobal
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
@ eReturnStatusSuccessFinishResult
@ eArgTypeManagedPlugin
static int64_t ToOptionEnum(llvm::StringRef s, const OptionEnumValues &enum_values, int32_t fail_value, Status &error)