Skip to content

Commit 55e53e4

Browse files
committed
[lldb/Commands] Add scripting template list command with auto discovery
This patch introduces a new `template` multiword sub-command to the `scripting` top-level command. As the name suggests, this sub-command operates on scripting templates, and currently has the ability to automatically discover the various scripting extensions that lldb supports. Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent 8e016c7 commit 55e53e4

13 files changed

+389
-3
lines changed

lldb/include/lldb/Core/PluginManager.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,31 @@ class PluginManager {
487487

488488
static LanguageSet GetAllTypeSystemSupportedLanguagesForExpressions();
489489

490+
// Scripted Interface
491+
static bool
492+
RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
493+
ScriptedInterfaceCreateInstance create_callback,
494+
lldb::ScriptLanguage language,
495+
std::vector<llvm::StringRef> command_interpreter_usages,
496+
std::vector<llvm::StringRef> api_usages);
497+
498+
static bool UnregisterPlugin(ScriptedInterfaceCreateInstance create_callback);
499+
500+
static ScriptedInterfaceCreateInstance
501+
GetScriptedInterfaceCreateCallbackAtIndex(uint32_t idx);
502+
503+
static llvm::StringRef GetScriptedInterfaceNameAtIndex(uint32_t idx);
504+
505+
static llvm::StringRef GetScriptedInterfaceDescriptionAtIndex(uint32_t idx);
506+
507+
static lldb::ScriptLanguage GetScriptedInterfaceLanguageAtIndex(uint32_t idx);
508+
509+
static std::vector<llvm::StringRef>
510+
GetScriptedInterfaceCommandInterpreterUsagesAtIndex(uint32_t idx);
511+
512+
static std::vector<llvm::StringRef>
513+
GetScriptedInterfaceAPIUsagesAtIndex(uint32_t idx);
514+
490515
// REPL
491516
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
492517
REPLCreateInstance create_callback,

lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ class ScriptedInterface {
6868
return true;
6969
}
7070

71+
static bool
72+
CreateInstance(lldb::ScriptLanguage language,
73+
std::vector<llvm::StringRef> command_interpreter_usages,
74+
std::vector<llvm::StringRef> api_usages) {
75+
return false;
76+
}
77+
7178
protected:
7279
StructuredData::GenericSP m_object_instance_sp;
7380
};

lldb/include/lldb/lldb-private-interfaces.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ typedef lldb::REPLSP (*REPLCreateInstance)(Status &error,
124124
lldb::LanguageType language,
125125
Debugger *debugger, Target *target,
126126
const char *repl_options);
127+
typedef bool (*ScriptedInterfaceCreateInstance)(
128+
lldb::ScriptLanguage language,
129+
std::vector<llvm::StringRef> command_interpreter_usages,
130+
std::vector<llvm::StringRef> api_usages);
127131
typedef int (*ComparisonFunction)(const void *, const void *);
128132
typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
129133
/// Trace

lldb/source/Commands/CommandObjectScripting.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "CommandObjectScripting.h"
1010
#include "lldb/Core/Debugger.h"
11+
#include "lldb/Core/PluginManager.h"
1112
#include "lldb/DataFormatters/DataVisualization.h"
1213
#include "lldb/Host/Config.h"
1314
#include "lldb/Host/OptionParser.h"
@@ -21,6 +22,8 @@
2122
using namespace lldb;
2223
using namespace lldb_private;
2324

25+
#pragma mark CommandObjectScriptingExecute
26+
2427
#define LLDB_OPTIONS_scripting_execute
2528
#include "CommandOptions.inc"
2629

@@ -114,6 +117,159 @@ void CommandObjectScriptingExecute::DoExecute(llvm::StringRef command,
114117
result.SetStatus(eReturnStatusFailed);
115118
}
116119

120+
#pragma mark CommandObjectScriptingTemplateList
121+
122+
#define LLDB_OPTIONS_scripting_template_list
123+
#include "CommandOptions.inc"
124+
125+
Status CommandObjectScriptingTemplateList::CommandOptions::SetOptionValue(
126+
uint32_t option_idx, llvm::StringRef option_arg,
127+
ExecutionContext *execution_context) {
128+
Status error;
129+
const int short_option = m_getopt_table[option_idx].val;
130+
131+
switch (short_option) {
132+
case 'l':
133+
language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
134+
option_arg, GetDefinitions()[option_idx].enum_values,
135+
eScriptLanguageNone, error);
136+
if (!error.Success())
137+
error.SetErrorStringWithFormat("unrecognized value for language '%s'",
138+
option_arg.str().c_str());
139+
break;
140+
default:
141+
llvm_unreachable("Unimplemented option");
142+
}
143+
144+
return error;
145+
}
146+
147+
void CommandObjectScriptingTemplateList::CommandOptions::OptionParsingStarting(
148+
ExecutionContext *execution_context) {
149+
language = lldb::eScriptLanguageNone;
150+
}
151+
152+
llvm::ArrayRef<OptionDefinition>
153+
CommandObjectScriptingTemplateList::CommandOptions::GetDefinitions() {
154+
return llvm::ArrayRef(g_scripting_execute_options);
155+
}
156+
157+
CommandObjectScriptingTemplateList::CommandObjectScriptingTemplateList(
158+
CommandInterpreter &interpreter)
159+
: CommandObjectParsed(
160+
interpreter, "scripting template list",
161+
"List all the available scripting affordances templates. ",
162+
"scripting template list [--language <scripting-language> --]") {}
163+
164+
CommandObjectScriptingTemplateList::~CommandObjectScriptingTemplateList() =
165+
default;
166+
167+
void CommandObjectScriptingTemplateList::DoExecute(
168+
Args &command, CommandReturnObject &result) {
169+
lldb::ScriptLanguage language =
170+
(m_options.language == lldb::eScriptLanguageNone)
171+
? m_interpreter.GetDebugger().GetScriptLanguage()
172+
: m_options.language;
173+
174+
if (language == lldb::eScriptLanguageNone) {
175+
result.AppendError(
176+
"the script-lang setting is set to none - scripting not available");
177+
return;
178+
}
179+
180+
ScriptInterpreter *script_interpreter =
181+
GetDebugger().GetScriptInterpreter(true, language);
182+
183+
if (script_interpreter == nullptr) {
184+
result.AppendError("no script interpreter");
185+
return;
186+
}
187+
188+
Stream &s = result.GetOutputStream();
189+
s.Printf("Available scripted affordances:\n");
190+
191+
auto print_field = [&s](llvm::StringRef key, llvm::StringRef value,
192+
bool check_validy = false) {
193+
if (!check_validy || !value.empty()) {
194+
s.IndentMore();
195+
s.Indent();
196+
s << key << ": " << value << '\n';
197+
s.IndentLess();
198+
}
199+
};
200+
auto print_usages = [&s](llvm::StringRef usage_kind,
201+
std::vector<llvm::StringRef> &usages) {
202+
s.IndentMore();
203+
s.Indent();
204+
s << usage_kind << " Usages:";
205+
if (usages.empty())
206+
s << " No usages.\n";
207+
else if (usages.size() == 1)
208+
s << " " << usages.front() << '\n';
209+
else {
210+
s << '\n';
211+
for (llvm::StringRef usage : usages) {
212+
s.IndentMore();
213+
s.Indent();
214+
s << usage << '\n';
215+
s.IndentLess();
216+
}
217+
}
218+
s.IndentLess();
219+
};
220+
221+
size_t i = 0;
222+
for (llvm::StringRef plugin_name =
223+
PluginManager::GetScriptedInterfaceNameAtIndex(i);
224+
!plugin_name.empty();) {
225+
226+
llvm::StringRef desc =
227+
PluginManager::GetScriptedInterfaceDescriptionAtIndex(i);
228+
lldb::ScriptLanguage lang =
229+
PluginManager::GetScriptedInterfaceLanguageAtIndex(i);
230+
std::vector<llvm::StringRef> ci_usages =
231+
PluginManager::GetScriptedInterfaceCommandInterpreterUsagesAtIndex(i);
232+
std::vector<llvm::StringRef> api_usages =
233+
PluginManager::GetScriptedInterfaceAPIUsagesAtIndex(i);
234+
235+
print_field("Name", plugin_name);
236+
switch (lang) {
237+
case eScriptLanguagePython:
238+
print_field("Language", "Python");
239+
break;
240+
case eScriptLanguageLua:
241+
print_field("Language", "Lua");
242+
break;
243+
default:
244+
break;
245+
}
246+
print_field("Description", desc);
247+
print_usages("Command Interpreter", ci_usages);
248+
print_usages("API", api_usages);
249+
250+
plugin_name = PluginManager::GetScriptedInterfaceNameAtIndex(++i);
251+
if (!plugin_name.empty())
252+
s.EOL();
253+
}
254+
}
255+
256+
#pragma mark CommandObjectMultiwordScriptingTemplate
257+
258+
// CommandObjectMultiwordScriptingTemplate
259+
260+
CommandObjectMultiwordScriptingTemplate::
261+
CommandObjectMultiwordScriptingTemplate(CommandInterpreter &interpreter)
262+
: CommandObjectMultiword(
263+
interpreter, "scripting template",
264+
"Commands for operating on the scripting templates.",
265+
"scripting template [<subcommand-options>]") {
266+
LoadSubCommand("list", CommandObjectSP(new CommandObjectScriptingTemplateList(
267+
interpreter)));
268+
}
269+
270+
CommandObjectMultiwordScriptingTemplate::
271+
~CommandObjectMultiwordScriptingTemplate() = default;
272+
117273
#pragma mark CommandObjectMultiwordScripting
118274

119275
// CommandObjectMultiwordScripting
@@ -126,6 +282,9 @@ CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
126282
"scripting <subcommand> [<subcommand-options>]") {
127283
LoadSubCommand("execute", CommandObjectSP(new CommandObjectScriptingExecute(
128284
interpreter)));
285+
LoadSubCommand("template",
286+
CommandObjectSP(
287+
new CommandObjectMultiwordScriptingTemplate(interpreter)));
129288
}
130289

131290
CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;

lldb/source/Commands/CommandObjectScripting.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,37 @@ class CommandObjectScriptingExecute : public CommandObjectRaw {
4444
CommandOptions m_options;
4545
};
4646

47+
class CommandObjectMultiwordScriptingTemplate : public CommandObjectMultiword {
48+
public:
49+
CommandObjectMultiwordScriptingTemplate(CommandInterpreter &interpreter);
50+
51+
~CommandObjectMultiwordScriptingTemplate() override;
52+
};
53+
54+
class CommandObjectScriptingTemplateList : public CommandObjectParsed {
55+
public:
56+
CommandObjectScriptingTemplateList(CommandInterpreter &interpreter);
57+
~CommandObjectScriptingTemplateList() override;
58+
Options *GetOptions() override { return &m_options; }
59+
60+
class CommandOptions : public Options {
61+
public:
62+
CommandOptions() = default;
63+
~CommandOptions() override = default;
64+
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
65+
ExecutionContext *execution_context) override;
66+
void OptionParsingStarting(ExecutionContext *execution_context) override;
67+
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
68+
lldb::ScriptLanguage language = lldb::eScriptLanguageNone;
69+
};
70+
71+
protected:
72+
void DoExecute(Args &command, CommandReturnObject &result) override;
73+
74+
private:
75+
CommandOptions m_options;
76+
};
77+
4778
} // namespace lldb_private
4879

4980
#endif // LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H

lldb/source/Commands/Options.td

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,13 @@ let Command = "container add" in {
836836
}
837837

838838
let Command = "scripting execute" in {
839-
def script_language : Option<"language", "l">,
839+
def scripting_execute_language : Option<"language", "l">,
840+
EnumArg<"ScriptLang">, Desc<"Specify the scripting "
841+
" language. If none is specific the default scripting language is used.">;
842+
}
843+
844+
let Command = "scripting template list" in {
845+
def scripting_template_list_language : Option<"language", "l">,
840846
EnumArg<"ScriptLang">, Desc<"Specify the scripting "
841847
" language. If none is specific the default scripting language is used.">;
842848
}

lldb/source/Core/PluginManager.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,88 @@ LanguageSet PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions() {
14791479
return all;
14801480
}
14811481

1482+
#pragma mark ScriptedInterfaces
1483+
1484+
struct ScriptedInterfaceInstance
1485+
: public PluginInstance<ScriptedInterfaceCreateInstance> {
1486+
ScriptedInterfaceInstance(
1487+
llvm::StringRef name, llvm::StringRef description,
1488+
ScriptedInterfaceCreateInstance create_callback,
1489+
lldb::ScriptLanguage language,
1490+
std::vector<llvm::StringRef> command_interpreter_usages,
1491+
std::vector<llvm::StringRef> api_usages)
1492+
: PluginInstance<ScriptedInterfaceCreateInstance>(name, description,
1493+
create_callback),
1494+
language(language),
1495+
command_interpreter_usages(command_interpreter_usages),
1496+
api_usages(api_usages) {}
1497+
1498+
lldb::ScriptLanguage language;
1499+
std::vector<llvm::StringRef> command_interpreter_usages;
1500+
std::vector<llvm::StringRef> api_usages;
1501+
};
1502+
1503+
typedef PluginInstances<ScriptedInterfaceInstance> ScriptedInterfaceInstances;
1504+
1505+
static ScriptedInterfaceInstances &GetScriptedInterfaceInstances() {
1506+
static ScriptedInterfaceInstances g_instances;
1507+
return g_instances;
1508+
}
1509+
1510+
bool PluginManager::RegisterPlugin(
1511+
llvm::StringRef name, llvm::StringRef description,
1512+
ScriptedInterfaceCreateInstance create_callback,
1513+
lldb::ScriptLanguage language,
1514+
std::vector<llvm::StringRef> command_interpreter_usages,
1515+
std::vector<llvm::StringRef> api_usages) {
1516+
return GetScriptedInterfaceInstances().RegisterPlugin(
1517+
name, description, create_callback, language, command_interpreter_usages,
1518+
api_usages);
1519+
}
1520+
1521+
bool PluginManager::UnregisterPlugin(
1522+
ScriptedInterfaceCreateInstance create_callback) {
1523+
return GetScriptedInterfaceInstances().UnregisterPlugin(create_callback);
1524+
}
1525+
1526+
ScriptedInterfaceCreateInstance
1527+
PluginManager::GetScriptedInterfaceCreateCallbackAtIndex(uint32_t idx) {
1528+
return GetScriptedInterfaceInstances().GetCallbackAtIndex(idx);
1529+
}
1530+
1531+
llvm::StringRef PluginManager::GetScriptedInterfaceNameAtIndex(uint32_t index) {
1532+
return GetScriptedInterfaceInstances().GetNameAtIndex(index);
1533+
}
1534+
1535+
llvm::StringRef
1536+
PluginManager::GetScriptedInterfaceDescriptionAtIndex(uint32_t index) {
1537+
return GetScriptedInterfaceInstances().GetDescriptionAtIndex(index);
1538+
}
1539+
1540+
lldb::ScriptLanguage
1541+
PluginManager::GetScriptedInterfaceLanguageAtIndex(uint32_t idx) {
1542+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1543+
return idx < instances.size() ? instances[idx].language
1544+
: ScriptLanguage::eScriptLanguageNone;
1545+
}
1546+
1547+
std::vector<llvm::StringRef>
1548+
PluginManager::GetScriptedInterfaceCommandInterpreterUsagesAtIndex(
1549+
uint32_t idx) {
1550+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1551+
if (idx >= instances.size())
1552+
return {};
1553+
return instances[idx].command_interpreter_usages;
1554+
}
1555+
1556+
std::vector<llvm::StringRef>
1557+
PluginManager::GetScriptedInterfaceAPIUsagesAtIndex(uint32_t idx) {
1558+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1559+
if (idx >= instances.size())
1560+
return {};
1561+
return instances[idx].api_usages;
1562+
}
1563+
14821564
#pragma mark REPL
14831565

14841566
struct REPLInstance : public PluginInstance<REPLCreateInstance> {
@@ -1539,6 +1621,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
15391621
GetOperatingSystemInstances().PerformDebuggerCallback(debugger);
15401622
GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
15411623
GetTracePluginInstances().PerformDebuggerCallback(debugger);
1624+
GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
15421625
}
15431626

15441627
// This is the preferred new way to register plugin specific settings. e.g.

0 commit comments

Comments
 (0)