Skip to content

Commit 828d8e8

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 6f60d2b commit 828d8e8

12 files changed

+369
-2
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: 171 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 CommandObjectScriptingRun
26+
2427
#define LLDB_OPTIONS_scripting_run
2528
#include "CommandOptions.inc"
2629

@@ -127,6 +130,171 @@ class CommandObjectScriptingRun : public CommandObjectRaw {
127130
CommandOptions m_options;
128131
};
129132

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

132300
// CommandObjectMultiwordScripting
@@ -139,6 +307,9 @@ CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
139307
"scripting <subcommand> [<subcommand-options>]") {
140308
LoadSubCommand("run",
141309
CommandObjectSP(new CommandObjectScriptingRun(interpreter)));
310+
LoadSubCommand("template",
311+
CommandObjectSP(
312+
new CommandObjectMultiwordScriptingTemplate(interpreter)));
142313
}
143314

144315
CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;

lldb/source/Commands/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,12 @@ let Command = "scripting run" in {
841841
" language. If none is specific the default scripting language is used.">;
842842
}
843843

844+
let Command = "scripting template list" in {
845+
def scripting_template_list_language : Option<"language", "l">,
846+
EnumArg<"ScriptLang">, Desc<"Specify the scripting "
847+
" language. If none is specific the default scripting language is used.">;
848+
}
849+
844850
let Command = "source info" in {
845851
def source_info_count : Option<"count", "c">, Arg<"Count">,
846852
Desc<"The number of line entries to display.">;

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.

lldb/source/Plugins/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ add_subdirectory(UnwindAssembly)
2929

3030
set(LLDB_STRIPPED_PLUGINS)
3131
get_property(LLDB_ALL_PLUGINS GLOBAL PROPERTY LLDB_PLUGINS)
32+
get_property(LLDB_EXTRA_PLUGINS GLOBAL PROPERTY LLDB_EXTRA_SCRIPT_PLUGINS)
33+
list(APPEND LLDB_ALL_PLUGINS ${LLDB_EXTRA_PLUGINS})
34+
3235

3336
set(LLDB_ENUM_PLUGINS "")
3437

lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ if (LLDB_ENABLE_LIBEDIT)
1919
list(APPEND LLDB_LIBEDIT_LIBS LibEdit::LibEdit)
2020
endif()
2121

22+
set_property(GLOBAL PROPERTY LLDB_EXTRA_SCRIPT_PLUGINS
23+
lldbPluginScriptedProcessPythonInterface
24+
lldbPluginScriptedThreadPlanPythonInterface
25+
)
26+
2227
add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces
2328
OperatingSystemPythonInterface.cpp
2429
ScriptedPythonInterface.cpp

0 commit comments

Comments
 (0)