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
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(arg_type: 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(in_string: "'plugin load' requires one argument");
35 return;
36 }
37
38 Status error;
39
40 FileSpec dylib_fspec(command[0].ref());
41 FileSystem::Instance().Resolve(file_spec&: dylib_fspec);
42
43 if (GetDebugger().LoadPlugin(spec: dylib_fspec, error))
44 result.SetStatus(eReturnStatusSuccessFinishResult);
45 else {
46 result.AppendError(in_string: 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 info
54// 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_ns: plugin_namespace,
69 plugin: plugin_info))
70 matching_plugins.push_back(x: 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 enable
84// and disable commands.
85int SetEnableOnMatchingPlugins(const llvm::StringRef &pattern,
86 CommandReturnObject &result, bool enabled) {
87 return ActOnMatchingPlugins(
88 pattern, action: [&](const PluginNamespace &plugin_namespace,
89 const std::vector<RegisteredPluginInfo> &plugins) {
90 result.AppendMessage(in_string: plugin_namespace.name);
91 for (const auto &plugin : plugins) {
92 if (!plugin_namespace.set_enabled(plugin.name, enabled)) {
93 result.AppendErrorWithFormat(format: "failed to enable plugin %s.%s",
94 plugin_namespace.name.data(),
95 plugin.name.data());
96 continue;
97 }
98
99 result.AppendMessageWithFormat(
100 format: " %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(Fmt: "{0:2}", Vals: json).str();
110 os.flush();
111 return str;
112}
113
114#define LLDB_OPTIONS_plugin_list
115#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} // namespace
152
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(arg_type: 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 description
166 [-] <plugin-name> Plugin #2 description
167
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 listed
175with just a namespace all plugins in that namespace are listed. When no arguments
176are given all plugins are listed.
177
178Examples:
179List all plugins
180
181 (lldb) plugin list
182
183List all plugins in the system-runtime namespace
184
185 (lldb) plugin list system-runtime
186
187List only the plugin 'foo' matching a fully qualified name exactly
188
189 (lldb) plugin list system-runtime.foo
190)");
191 }
192
193 ~CommandObjectPluginList() override = default;
194
195 Options *GetOptions() override { return &m_options; }
196
197protected:
198 void DoExecute(Args &command, CommandReturnObject &result) override {
199 size_t argc = command.GetArgumentCount();
200 result.SetStatus(eReturnStatusSuccessFinishResult);
201
202 // Create a temporary vector to hold the patterns to simplify the logic
203 // for the case when the user passes no patterns
204 std::vector<llvm::StringRef> patterns;
205 patterns.reserve(n: argc == 0 ? 1 : argc);
206 if (argc == 0)
207 patterns.push_back(x: "");
208 else
209 for (size_t i = 0; i < argc; ++i)
210 patterns.push_back(x: command[i].ref());
211
212 if (m_options.m_json_format)
213 OutputJsonFormat(patterns, result);
214 else
215 OutputTextFormat(patterns, result);
216 }
217
218private:
219 void OutputJsonFormat(const std::vector<llvm::StringRef> &patterns,
220 CommandReturnObject &result) {
221 llvm::json::Object obj;
222 bool found_empty = false;
223 for (const llvm::StringRef pattern : patterns) {
224 llvm::json::Object pat_obj = PluginManager::GetJSON(pattern);
225 if (pat_obj.empty()) {
226 found_empty = true;
227 result.AppendErrorWithFormat(
228 format: "Found no matching plugins for pattern '%s'", pattern.data());
229 break;
230 }
231 for (auto &entry : pat_obj) {
232 obj[entry.first] = std::move(entry.second);
233 }
234 }
235 if (!found_empty) {
236 result.AppendMessage(in_string: ConvertJSONToPrettyString(json: std::move(obj)));
237 }
238 }
239
240 void OutputTextFormat(const std::vector<llvm::StringRef> &patterns,
241 CommandReturnObject &result) {
242 for (const llvm::StringRef pattern : patterns) {
243 int num_matching = ActOnMatchingPlugins(
244 pattern, action: [&](const PluginNamespace &plugin_namespace,
245 const std::vector<RegisteredPluginInfo> &plugins) {
246 result.AppendMessage(in_string: plugin_namespace.name);
247 for (auto &plugin : plugins) {
248 result.AppendMessageWithFormat(
249 format: " %s %-30s %s\n", plugin.enabled ? "[+]" : "[-]",
250 plugin.name.data(), plugin.description.data());
251 }
252 });
253 if (num_matching == 0) {
254 result.AppendErrorWithFormat(
255 format: "Found no matching plugins for pattern '%s'", pattern.data());
256 break;
257 }
258 }
259 }
260
261 PluginListCommandOptions m_options;
262};
263
264static void DoPluginEnableDisable(Args &command, CommandReturnObject &result,
265 bool enable) {
266 const char *name = enable ? "enable" : "disable";
267 size_t argc = command.GetArgumentCount();
268 if (argc == 0) {
269 result.AppendErrorWithFormat(format: "'plugin %s' requires one or more arguments",
270 name);
271 return;
272 }
273 result.SetStatus(eReturnStatusSuccessFinishResult);
274
275 for (size_t i = 0; i < argc; ++i) {
276 llvm::StringRef pattern = command[i].ref();
277 int num_matching = SetEnableOnMatchingPlugins(pattern, result, enabled: enable);
278
279 if (num_matching == 0) {
280 result.AppendErrorWithFormat(
281 format: "Found no matching plugins to %s for pattern '%s'", name,
282 pattern.data());
283 break;
284 }
285 }
286}
287
288class CommandObjectPluginEnable : public CommandObjectParsed {
289public:
290 CommandObjectPluginEnable(CommandInterpreter &interpreter)
291 : CommandObjectParsed(interpreter, "plugin enable",
292 "Enable registered LLDB plugins.", nullptr) {
293 AddSimpleArgumentList(arg_type: eArgTypeManagedPlugin);
294 }
295
296 ~CommandObjectPluginEnable() override = default;
297
298protected:
299 void DoExecute(Args &command, CommandReturnObject &result) override {
300 DoPluginEnableDisable(command, result, /*enable=*/true);
301 }
302};
303
304class CommandObjectPluginDisable : public CommandObjectParsed {
305public:
306 CommandObjectPluginDisable(CommandInterpreter &interpreter)
307 : CommandObjectParsed(interpreter, "plugin disable",
308 "Disable registered LLDB plugins.", nullptr) {
309 AddSimpleArgumentList(arg_type: eArgTypeManagedPlugin);
310 }
311
312 ~CommandObjectPluginDisable() override = default;
313
314protected:
315 void DoExecute(Args &command, CommandReturnObject &result) override {
316 DoPluginEnableDisable(command, result, /*enable=*/false);
317 }
318};
319
320CommandObjectPlugin::CommandObjectPlugin(CommandInterpreter &interpreter)
321 : CommandObjectMultiword(interpreter, "plugin",
322 "Commands for managing LLDB plugins.",
323 "plugin <subcommand> [<subcommand-options>]") {
324 LoadSubCommand(cmd_name: "load",
325 command_obj: CommandObjectSP(new CommandObjectPluginLoad(interpreter)));
326 LoadSubCommand(cmd_name: "list",
327 command_obj: CommandObjectSP(new CommandObjectPluginList(interpreter)));
328 LoadSubCommand(cmd_name: "enable",
329 command_obj: CommandObjectSP(new CommandObjectPluginEnable(interpreter)));
330 LoadSubCommand(cmd_name: "disable",
331 command_obj: CommandObjectSP(new CommandObjectPluginDisable(interpreter)));
332}
333
334CommandObjectPlugin::~CommandObjectPlugin() = default;
335

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lldb/source/Commands/CommandObjectPlugin.cpp