1 //===-- CommandObjectScripting.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 "CommandObjectScripting.h"
10 #include "lldb/Core/Debugger.h"
11 #include "lldb/Core/PluginManager.h"
12 #include "lldb/DataFormatters/DataVisualization.h"
13 #include "lldb/Host/Config.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/Interfaces/ScriptedInterfaceUsages.h"
19 #include "lldb/Interpreter/OptionArgParser.h"
20 #include "lldb/Interpreter/ScriptInterpreter.h"
21 #include "lldb/Utility/Args.h"
22
23 using namespace lldb;
24 using namespace lldb_private;
25
26 #define LLDB_OPTIONS_scripting_run
27 #include "CommandOptions.inc"
28
29 class CommandObjectScriptingRun : public CommandObjectRaw {
30 public:
CommandObjectScriptingRun(CommandInterpreter & interpreter)31 CommandObjectScriptingRun(CommandInterpreter &interpreter)
32 : CommandObjectRaw(
33 interpreter, "scripting run",
34 "Invoke the script interpreter with provided code and display any "
35 "results. Start the interactive interpreter if no code is "
36 "supplied.",
37 "scripting run [--language <scripting-language> --] "
38 "[<script-code>]") {}
39
40 ~CommandObjectScriptingRun() override = default;
41
GetOptions()42 Options *GetOptions() override { return &m_options; }
43
44 class CommandOptions : public Options {
45 public:
46 CommandOptions() = default;
47 ~CommandOptions() override = default;
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)48 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
49 ExecutionContext *execution_context) override {
50 Status error;
51 const int short_option = m_getopt_table[option_idx].val;
52
53 switch (short_option) {
54 case 'l':
55 language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
56 option_arg, GetDefinitions()[option_idx].enum_values,
57 eScriptLanguageNone, error);
58 if (!error.Success())
59 error = Status::FromErrorStringWithFormat(
60 "unrecognized value for language '%s'", option_arg.str().c_str());
61 break;
62 default:
63 llvm_unreachable("Unimplemented option");
64 }
65
66 return error;
67 }
68
OptionParsingStarting(ExecutionContext * execution_context)69 void OptionParsingStarting(ExecutionContext *execution_context) override {
70 language = lldb::eScriptLanguageNone;
71 }
72
GetDefinitions()73 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
74 return llvm::ArrayRef(g_scripting_run_options);
75 }
76
77 lldb::ScriptLanguage language = lldb::eScriptLanguageNone;
78 };
79
80 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)81 void DoExecute(llvm::StringRef command,
82 CommandReturnObject &result) override {
83 // Try parsing the language option but when the command contains a raw part
84 // separated by the -- delimiter.
85 OptionsWithRaw raw_args(command);
86 if (raw_args.HasArgs()) {
87 if (!ParseOptions(raw_args.GetArgs(), result))
88 return;
89 command = raw_args.GetRawPart();
90 }
91
92 lldb::ScriptLanguage language =
93 (m_options.language == lldb::eScriptLanguageNone)
94 ? m_interpreter.GetDebugger().GetScriptLanguage()
95 : m_options.language;
96
97 if (language == lldb::eScriptLanguageNone) {
98 result.AppendError(
99 "the script-lang setting is set to none - scripting not available");
100 return;
101 }
102
103 ScriptInterpreter *script_interpreter =
104 GetDebugger().GetScriptInterpreter(true, language);
105
106 if (script_interpreter == nullptr) {
107 result.AppendError("no script interpreter");
108 return;
109 }
110
111 // Script might change Python code we use for formatting. Make sure we keep
112 // up to date with it.
113 DataVisualization::ForceUpdate();
114
115 if (command.empty()) {
116 script_interpreter->ExecuteInterpreterLoop();
117 result.SetStatus(eReturnStatusSuccessFinishNoResult);
118 return;
119 }
120
121 // We can do better when reporting the status of one-liner script execution.
122 if (script_interpreter->ExecuteOneLine(command, &result))
123 result.SetStatus(eReturnStatusSuccessFinishNoResult);
124 else
125 result.SetStatus(eReturnStatusFailed);
126 }
127
128 private:
129 CommandOptions m_options;
130 };
131
132 #define LLDB_OPTIONS_scripting_extension_list
133 #include "CommandOptions.inc"
134
135 class CommandObjectScriptingExtensionList : public CommandObjectParsed {
136 public:
CommandObjectScriptingExtensionList(CommandInterpreter & interpreter)137 CommandObjectScriptingExtensionList(CommandInterpreter &interpreter)
138 : CommandObjectParsed(
139 interpreter, "scripting extension list",
140 "List all the available scripting extension templates. ",
141 "scripting template list [--language <scripting-language> --]") {}
142
143 ~CommandObjectScriptingExtensionList() override = default;
144
GetOptions()145 Options *GetOptions() override { return &m_options; }
146
147 class CommandOptions : public Options {
148 public:
149 CommandOptions() = default;
150 ~CommandOptions() override = default;
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)151 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
152 ExecutionContext *execution_context) override {
153 Status error;
154 const int short_option = m_getopt_table[option_idx].val;
155
156 switch (short_option) {
157 case 'l':
158 m_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
159 option_arg, GetDefinitions()[option_idx].enum_values,
160 eScriptLanguageNone, error);
161 if (!error.Success())
162 error = Status::FromErrorStringWithFormatv(
163 "unrecognized value for language '{0}'", option_arg);
164 break;
165 default:
166 llvm_unreachable("Unimplemented option");
167 }
168
169 return error;
170 }
171
OptionParsingStarting(ExecutionContext * execution_context)172 void OptionParsingStarting(ExecutionContext *execution_context) override {
173 m_language = lldb::eScriptLanguageDefault;
174 }
175
GetDefinitions()176 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
177 return llvm::ArrayRef(g_scripting_extension_list_options);
178 }
179
180 lldb::ScriptLanguage m_language = lldb::eScriptLanguageDefault;
181 };
182
183 protected:
DoExecute(Args & command,CommandReturnObject & result)184 void DoExecute(Args &command, CommandReturnObject &result) override {
185 Stream &s = result.GetOutputStream();
186 s.Printf("Available scripted extension templates:");
187
188 auto print_field = [&s](llvm::StringRef key, llvm::StringRef value) {
189 if (!value.empty()) {
190 s.IndentMore();
191 s.Indent();
192 s << key << ": " << value << '\n';
193 s.IndentLess();
194 }
195 };
196
197 size_t num_listed_interface = 0;
198 size_t num_extensions = PluginManager::GetNumScriptedInterfaces();
199 for (size_t i = 0; i < num_extensions; i++) {
200 llvm::StringRef plugin_name =
201 PluginManager::GetScriptedInterfaceNameAtIndex(i);
202 if (plugin_name.empty())
203 break;
204
205 lldb::ScriptLanguage lang =
206 PluginManager::GetScriptedInterfaceLanguageAtIndex(i);
207 if (lang != m_options.m_language)
208 continue;
209
210 if (!num_listed_interface)
211 s.EOL();
212
213 num_listed_interface++;
214
215 llvm::StringRef desc =
216 PluginManager::GetScriptedInterfaceDescriptionAtIndex(i);
217 ScriptedInterfaceUsages usages =
218 PluginManager::GetScriptedInterfaceUsagesAtIndex(i);
219
220 print_field("Name", plugin_name);
221 print_field("Language", ScriptInterpreter::LanguageToString(lang));
222 print_field("Description", desc);
223 usages.Dump(s, ScriptedInterfaceUsages::UsageKind::API);
224 usages.Dump(s, ScriptedInterfaceUsages::UsageKind::CommandInterpreter);
225
226 if (i != num_extensions - 1)
227 s.EOL();
228 }
229
230 if (!num_listed_interface)
231 s << " None\n";
232 }
233
234 private:
235 CommandOptions m_options;
236 };
237
238 class CommandObjectMultiwordScriptingExtension : public CommandObjectMultiword {
239 public:
CommandObjectMultiwordScriptingExtension(CommandInterpreter & interpreter)240 CommandObjectMultiwordScriptingExtension(CommandInterpreter &interpreter)
241 : CommandObjectMultiword(
242 interpreter, "scripting extension",
243 "Commands for operating on the scripting extensions.",
244 "scripting extension [<subcommand-options>]") {
245 LoadSubCommand(
246 "list",
247 CommandObjectSP(new CommandObjectScriptingExtensionList(interpreter)));
248 }
249
250 ~CommandObjectMultiwordScriptingExtension() override = default;
251 };
252
CommandObjectMultiwordScripting(CommandInterpreter & interpreter)253 CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
254 CommandInterpreter &interpreter)
255 : CommandObjectMultiword(
256 interpreter, "scripting",
257 "Commands for operating on the scripting functionalities.",
258 "scripting <subcommand> [<subcommand-options>]") {
259 LoadSubCommand("run",
260 CommandObjectSP(new CommandObjectScriptingRun(interpreter)));
261 LoadSubCommand("extension",
262 CommandObjectSP(new CommandObjectMultiwordScriptingExtension(
263 interpreter)));
264 }
265
266 CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;
267