xref: /llvm-project/lldb/source/Commands/CommandObjectScripting.cpp (revision 4494c54326fe33d19c14df851188f867b14ded2a)
1410de0c8SMed Ismail Bennani //===-- CommandObjectScripting.cpp ----------------------------------------===//
2410de0c8SMed Ismail Bennani //
3410de0c8SMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4410de0c8SMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
5410de0c8SMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6410de0c8SMed Ismail Bennani //
7410de0c8SMed Ismail Bennani //===----------------------------------------------------------------------===//
8410de0c8SMed Ismail Bennani 
9410de0c8SMed Ismail Bennani #include "CommandObjectScripting.h"
10410de0c8SMed Ismail Bennani #include "lldb/Core/Debugger.h"
11bccff3baSMed Ismail Bennani #include "lldb/Core/PluginManager.h"
12410de0c8SMed Ismail Bennani #include "lldb/DataFormatters/DataVisualization.h"
13410de0c8SMed Ismail Bennani #include "lldb/Host/Config.h"
14410de0c8SMed Ismail Bennani #include "lldb/Host/OptionParser.h"
15410de0c8SMed Ismail Bennani #include "lldb/Interpreter/CommandInterpreter.h"
16410de0c8SMed Ismail Bennani #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17410de0c8SMed Ismail Bennani #include "lldb/Interpreter/CommandReturnObject.h"
18bccff3baSMed Ismail Bennani #include "lldb/Interpreter/Interfaces/ScriptedInterfaceUsages.h"
19410de0c8SMed Ismail Bennani #include "lldb/Interpreter/OptionArgParser.h"
20410de0c8SMed Ismail Bennani #include "lldb/Interpreter/ScriptInterpreter.h"
21410de0c8SMed Ismail Bennani #include "lldb/Utility/Args.h"
22410de0c8SMed Ismail Bennani 
23410de0c8SMed Ismail Bennani using namespace lldb;
24410de0c8SMed Ismail Bennani using namespace lldb_private;
25410de0c8SMed Ismail Bennani 
26410de0c8SMed Ismail Bennani #define LLDB_OPTIONS_scripting_run
27410de0c8SMed Ismail Bennani #include "CommandOptions.inc"
28410de0c8SMed Ismail Bennani 
29410de0c8SMed Ismail Bennani class CommandObjectScriptingRun : public CommandObjectRaw {
30410de0c8SMed Ismail Bennani public:
31410de0c8SMed Ismail Bennani   CommandObjectScriptingRun(CommandInterpreter &interpreter)
32410de0c8SMed Ismail Bennani       : CommandObjectRaw(
33410de0c8SMed Ismail Bennani             interpreter, "scripting run",
34410de0c8SMed Ismail Bennani             "Invoke the script interpreter with provided code and display any "
35410de0c8SMed Ismail Bennani             "results.  Start the interactive interpreter if no code is "
36410de0c8SMed Ismail Bennani             "supplied.",
37410de0c8SMed Ismail Bennani             "scripting run [--language <scripting-language> --] "
38410de0c8SMed Ismail Bennani             "[<script-code>]") {}
39410de0c8SMed Ismail Bennani 
40410de0c8SMed Ismail Bennani   ~CommandObjectScriptingRun() override = default;
41410de0c8SMed Ismail Bennani 
42410de0c8SMed Ismail Bennani   Options *GetOptions() override { return &m_options; }
43410de0c8SMed Ismail Bennani 
44410de0c8SMed Ismail Bennani   class CommandOptions : public Options {
45410de0c8SMed Ismail Bennani   public:
46410de0c8SMed Ismail Bennani     CommandOptions() = default;
47410de0c8SMed Ismail Bennani     ~CommandOptions() override = default;
48410de0c8SMed Ismail Bennani     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
49410de0c8SMed Ismail Bennani                           ExecutionContext *execution_context) override {
50410de0c8SMed Ismail Bennani       Status error;
51410de0c8SMed Ismail Bennani       const int short_option = m_getopt_table[option_idx].val;
52410de0c8SMed Ismail Bennani 
53410de0c8SMed Ismail Bennani       switch (short_option) {
54410de0c8SMed Ismail Bennani       case 'l':
55410de0c8SMed Ismail Bennani         language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
56410de0c8SMed Ismail Bennani             option_arg, GetDefinitions()[option_idx].enum_values,
57410de0c8SMed Ismail Bennani             eScriptLanguageNone, error);
58410de0c8SMed Ismail Bennani         if (!error.Success())
590642cd76SAdrian Prantl           error = Status::FromErrorStringWithFormat(
600642cd76SAdrian Prantl               "unrecognized value for language '%s'", option_arg.str().c_str());
61410de0c8SMed Ismail Bennani         break;
62410de0c8SMed Ismail Bennani       default:
63410de0c8SMed Ismail Bennani         llvm_unreachable("Unimplemented option");
64410de0c8SMed Ismail Bennani       }
65410de0c8SMed Ismail Bennani 
66410de0c8SMed Ismail Bennani       return error;
67410de0c8SMed Ismail Bennani     }
68410de0c8SMed Ismail Bennani 
69410de0c8SMed Ismail Bennani     void OptionParsingStarting(ExecutionContext *execution_context) override {
70410de0c8SMed Ismail Bennani       language = lldb::eScriptLanguageNone;
71410de0c8SMed Ismail Bennani     }
72410de0c8SMed Ismail Bennani 
73410de0c8SMed Ismail Bennani     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
74410de0c8SMed Ismail Bennani       return llvm::ArrayRef(g_scripting_run_options);
75410de0c8SMed Ismail Bennani     }
76410de0c8SMed Ismail Bennani 
77410de0c8SMed Ismail Bennani     lldb::ScriptLanguage language = lldb::eScriptLanguageNone;
78410de0c8SMed Ismail Bennani   };
79410de0c8SMed Ismail Bennani 
80410de0c8SMed Ismail Bennani protected:
81410de0c8SMed Ismail Bennani   void DoExecute(llvm::StringRef command,
82410de0c8SMed Ismail Bennani                  CommandReturnObject &result) override {
83410de0c8SMed Ismail Bennani     // Try parsing the language option but when the command contains a raw part
84410de0c8SMed Ismail Bennani     // separated by the -- delimiter.
85410de0c8SMed Ismail Bennani     OptionsWithRaw raw_args(command);
86410de0c8SMed Ismail Bennani     if (raw_args.HasArgs()) {
87410de0c8SMed Ismail Bennani       if (!ParseOptions(raw_args.GetArgs(), result))
88410de0c8SMed Ismail Bennani         return;
89410de0c8SMed Ismail Bennani       command = raw_args.GetRawPart();
90410de0c8SMed Ismail Bennani     }
91410de0c8SMed Ismail Bennani 
92410de0c8SMed Ismail Bennani     lldb::ScriptLanguage language =
93410de0c8SMed Ismail Bennani         (m_options.language == lldb::eScriptLanguageNone)
94410de0c8SMed Ismail Bennani             ? m_interpreter.GetDebugger().GetScriptLanguage()
95410de0c8SMed Ismail Bennani             : m_options.language;
96410de0c8SMed Ismail Bennani 
97410de0c8SMed Ismail Bennani     if (language == lldb::eScriptLanguageNone) {
98410de0c8SMed Ismail Bennani       result.AppendError(
99410de0c8SMed Ismail Bennani           "the script-lang setting is set to none - scripting not available");
100410de0c8SMed Ismail Bennani       return;
101410de0c8SMed Ismail Bennani     }
102410de0c8SMed Ismail Bennani 
103410de0c8SMed Ismail Bennani     ScriptInterpreter *script_interpreter =
104410de0c8SMed Ismail Bennani         GetDebugger().GetScriptInterpreter(true, language);
105410de0c8SMed Ismail Bennani 
106410de0c8SMed Ismail Bennani     if (script_interpreter == nullptr) {
107410de0c8SMed Ismail Bennani       result.AppendError("no script interpreter");
108410de0c8SMed Ismail Bennani       return;
109410de0c8SMed Ismail Bennani     }
110410de0c8SMed Ismail Bennani 
111410de0c8SMed Ismail Bennani     // Script might change Python code we use for formatting. Make sure we keep
112410de0c8SMed Ismail Bennani     // up to date with it.
113410de0c8SMed Ismail Bennani     DataVisualization::ForceUpdate();
114410de0c8SMed Ismail Bennani 
115410de0c8SMed Ismail Bennani     if (command.empty()) {
116410de0c8SMed Ismail Bennani       script_interpreter->ExecuteInterpreterLoop();
117410de0c8SMed Ismail Bennani       result.SetStatus(eReturnStatusSuccessFinishNoResult);
118410de0c8SMed Ismail Bennani       return;
119410de0c8SMed Ismail Bennani     }
120410de0c8SMed Ismail Bennani 
121410de0c8SMed Ismail Bennani     // We can do better when reporting the status of one-liner script execution.
122410de0c8SMed Ismail Bennani     if (script_interpreter->ExecuteOneLine(command, &result))
123410de0c8SMed Ismail Bennani       result.SetStatus(eReturnStatusSuccessFinishNoResult);
124410de0c8SMed Ismail Bennani     else
125410de0c8SMed Ismail Bennani       result.SetStatus(eReturnStatusFailed);
126410de0c8SMed Ismail Bennani   }
127410de0c8SMed Ismail Bennani 
128410de0c8SMed Ismail Bennani private:
129410de0c8SMed Ismail Bennani   CommandOptions m_options;
130410de0c8SMed Ismail Bennani };
131410de0c8SMed Ismail Bennani 
1325689ccceSMed Ismail Bennani #define LLDB_OPTIONS_scripting_extension_list
133bccff3baSMed Ismail Bennani #include "CommandOptions.inc"
134410de0c8SMed Ismail Bennani 
1355689ccceSMed Ismail Bennani class CommandObjectScriptingExtensionList : public CommandObjectParsed {
136bccff3baSMed Ismail Bennani public:
1375689ccceSMed Ismail Bennani   CommandObjectScriptingExtensionList(CommandInterpreter &interpreter)
138bccff3baSMed Ismail Bennani       : CommandObjectParsed(
1395689ccceSMed Ismail Bennani             interpreter, "scripting extension list",
140bccff3baSMed Ismail Bennani             "List all the available scripting extension templates. ",
141bccff3baSMed Ismail Bennani             "scripting template list [--language <scripting-language> --]") {}
142bccff3baSMed Ismail Bennani 
1435689ccceSMed Ismail Bennani   ~CommandObjectScriptingExtensionList() override = default;
144bccff3baSMed Ismail Bennani 
145bccff3baSMed Ismail Bennani   Options *GetOptions() override { return &m_options; }
146bccff3baSMed Ismail Bennani 
147bccff3baSMed Ismail Bennani   class CommandOptions : public Options {
148bccff3baSMed Ismail Bennani   public:
149bccff3baSMed Ismail Bennani     CommandOptions() = default;
150bccff3baSMed Ismail Bennani     ~CommandOptions() override = default;
151bccff3baSMed Ismail Bennani     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
152bccff3baSMed Ismail Bennani                           ExecutionContext *execution_context) override {
153bccff3baSMed Ismail Bennani       Status error;
154bccff3baSMed Ismail Bennani       const int short_option = m_getopt_table[option_idx].val;
155bccff3baSMed Ismail Bennani 
156bccff3baSMed Ismail Bennani       switch (short_option) {
157bccff3baSMed Ismail Bennani       case 'l':
158bccff3baSMed Ismail Bennani         m_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
159bccff3baSMed Ismail Bennani             option_arg, GetDefinitions()[option_idx].enum_values,
160bccff3baSMed Ismail Bennani             eScriptLanguageNone, error);
161bccff3baSMed Ismail Bennani         if (!error.Success())
1620642cd76SAdrian Prantl           error = Status::FromErrorStringWithFormatv(
163bccff3baSMed Ismail Bennani               "unrecognized value for language '{0}'", option_arg);
164bccff3baSMed Ismail Bennani         break;
165bccff3baSMed Ismail Bennani       default:
166bccff3baSMed Ismail Bennani         llvm_unreachable("Unimplemented option");
167bccff3baSMed Ismail Bennani       }
168bccff3baSMed Ismail Bennani 
169bccff3baSMed Ismail Bennani       return error;
170bccff3baSMed Ismail Bennani     }
171bccff3baSMed Ismail Bennani 
172bccff3baSMed Ismail Bennani     void OptionParsingStarting(ExecutionContext *execution_context) override {
173bccff3baSMed Ismail Bennani       m_language = lldb::eScriptLanguageDefault;
174bccff3baSMed Ismail Bennani     }
175bccff3baSMed Ismail Bennani 
176bccff3baSMed Ismail Bennani     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1775689ccceSMed Ismail Bennani       return llvm::ArrayRef(g_scripting_extension_list_options);
178bccff3baSMed Ismail Bennani     }
179bccff3baSMed Ismail Bennani 
180bccff3baSMed Ismail Bennani     lldb::ScriptLanguage m_language = lldb::eScriptLanguageDefault;
181bccff3baSMed Ismail Bennani   };
182bccff3baSMed Ismail Bennani 
183bccff3baSMed Ismail Bennani protected:
184bccff3baSMed Ismail Bennani   void DoExecute(Args &command, CommandReturnObject &result) override {
185bccff3baSMed Ismail Bennani     Stream &s = result.GetOutputStream();
186bccff3baSMed Ismail Bennani     s.Printf("Available scripted extension templates:");
187bccff3baSMed Ismail Bennani 
188bccff3baSMed Ismail Bennani     auto print_field = [&s](llvm::StringRef key, llvm::StringRef value) {
189bccff3baSMed Ismail Bennani       if (!value.empty()) {
190bccff3baSMed Ismail Bennani         s.IndentMore();
191bccff3baSMed Ismail Bennani         s.Indent();
192bccff3baSMed Ismail Bennani         s << key << ": " << value << '\n';
193bccff3baSMed Ismail Bennani         s.IndentLess();
194bccff3baSMed Ismail Bennani       }
195bccff3baSMed Ismail Bennani     };
196bccff3baSMed Ismail Bennani 
197bccff3baSMed Ismail Bennani     size_t num_listed_interface = 0;
1985689ccceSMed Ismail Bennani     size_t num_extensions = PluginManager::GetNumScriptedInterfaces();
1995689ccceSMed Ismail Bennani     for (size_t i = 0; i < num_extensions; i++) {
200bccff3baSMed Ismail Bennani       llvm::StringRef plugin_name =
201bccff3baSMed Ismail Bennani           PluginManager::GetScriptedInterfaceNameAtIndex(i);
202bccff3baSMed Ismail Bennani       if (plugin_name.empty())
203bccff3baSMed Ismail Bennani         break;
204bccff3baSMed Ismail Bennani 
205bccff3baSMed Ismail Bennani       lldb::ScriptLanguage lang =
206bccff3baSMed Ismail Bennani           PluginManager::GetScriptedInterfaceLanguageAtIndex(i);
207bccff3baSMed Ismail Bennani       if (lang != m_options.m_language)
208bccff3baSMed Ismail Bennani         continue;
209bccff3baSMed Ismail Bennani 
210bccff3baSMed Ismail Bennani       if (!num_listed_interface)
211bccff3baSMed Ismail Bennani         s.EOL();
212bccff3baSMed Ismail Bennani 
213bccff3baSMed Ismail Bennani       num_listed_interface++;
214bccff3baSMed Ismail Bennani 
215bccff3baSMed Ismail Bennani       llvm::StringRef desc =
216bccff3baSMed Ismail Bennani           PluginManager::GetScriptedInterfaceDescriptionAtIndex(i);
217bccff3baSMed Ismail Bennani       ScriptedInterfaceUsages usages =
218bccff3baSMed Ismail Bennani           PluginManager::GetScriptedInterfaceUsagesAtIndex(i);
219bccff3baSMed Ismail Bennani 
220bccff3baSMed Ismail Bennani       print_field("Name", plugin_name);
221bccff3baSMed Ismail Bennani       print_field("Language", ScriptInterpreter::LanguageToString(lang));
222bccff3baSMed Ismail Bennani       print_field("Description", desc);
223bccff3baSMed Ismail Bennani       usages.Dump(s, ScriptedInterfaceUsages::UsageKind::API);
224bccff3baSMed Ismail Bennani       usages.Dump(s, ScriptedInterfaceUsages::UsageKind::CommandInterpreter);
225bccff3baSMed Ismail Bennani 
2265689ccceSMed Ismail Bennani       if (i != num_extensions - 1)
227bccff3baSMed Ismail Bennani         s.EOL();
228bccff3baSMed Ismail Bennani     }
229bccff3baSMed Ismail Bennani 
230bccff3baSMed Ismail Bennani     if (!num_listed_interface)
231bccff3baSMed Ismail Bennani       s << " None\n";
232bccff3baSMed Ismail Bennani   }
233bccff3baSMed Ismail Bennani 
234bccff3baSMed Ismail Bennani private:
235bccff3baSMed Ismail Bennani   CommandOptions m_options;
236bccff3baSMed Ismail Bennani };
237bccff3baSMed Ismail Bennani 
2385689ccceSMed Ismail Bennani class CommandObjectMultiwordScriptingExtension : public CommandObjectMultiword {
239bccff3baSMed Ismail Bennani public:
2405689ccceSMed Ismail Bennani   CommandObjectMultiwordScriptingExtension(CommandInterpreter &interpreter)
241bccff3baSMed Ismail Bennani       : CommandObjectMultiword(
2425689ccceSMed Ismail Bennani             interpreter, "scripting extension",
2435689ccceSMed Ismail Bennani             "Commands for operating on the scripting extensions.",
2445689ccceSMed Ismail Bennani             "scripting extension [<subcommand-options>]") {
245bccff3baSMed Ismail Bennani     LoadSubCommand(
246bccff3baSMed Ismail Bennani         "list",
2475689ccceSMed Ismail Bennani         CommandObjectSP(new CommandObjectScriptingExtensionList(interpreter)));
248bccff3baSMed Ismail Bennani   }
249bccff3baSMed Ismail Bennani 
2505689ccceSMed Ismail Bennani   ~CommandObjectMultiwordScriptingExtension() override = default;
251bccff3baSMed Ismail Bennani };
252410de0c8SMed Ismail Bennani 
253410de0c8SMed Ismail Bennani CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
254410de0c8SMed Ismail Bennani     CommandInterpreter &interpreter)
255410de0c8SMed Ismail Bennani     : CommandObjectMultiword(
256410de0c8SMed Ismail Bennani           interpreter, "scripting",
257*4494c543SRyan Mansfield           "Commands for operating on the scripting functionalities.",
258410de0c8SMed Ismail Bennani           "scripting <subcommand> [<subcommand-options>]") {
259410de0c8SMed Ismail Bennani   LoadSubCommand("run",
260410de0c8SMed Ismail Bennani                  CommandObjectSP(new CommandObjectScriptingRun(interpreter)));
2615689ccceSMed Ismail Bennani   LoadSubCommand("extension",
2625689ccceSMed Ismail Bennani                  CommandObjectSP(new CommandObjectMultiwordScriptingExtension(
2635689ccceSMed Ismail Bennani                      interpreter)));
264410de0c8SMed Ismail Bennani }
265410de0c8SMed Ismail Bennani 
266410de0c8SMed Ismail Bennani CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;
267