Skip to content

Commit c475dcf

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 4e56724 commit c475dcf

12 files changed

+352
-2
lines changed

lldb/include/lldb/Core/PluginManager.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,33 @@ 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 uint32_t GetNumScriptedInterfaces();
504+
505+
static llvm::StringRef GetScriptedInterfaceNameAtIndex(uint32_t idx);
506+
507+
static llvm::StringRef GetScriptedInterfaceDescriptionAtIndex(uint32_t idx);
508+
509+
static lldb::ScriptLanguage GetScriptedInterfaceLanguageAtIndex(uint32_t idx);
510+
511+
static std::vector<llvm::StringRef>
512+
GetScriptedInterfaceCommandInterpreterUsagesAtIndex(uint32_t idx);
513+
514+
static std::vector<llvm::StringRef>
515+
GetScriptedInterfaceAPIUsagesAtIndex(uint32_t idx);
516+
490517
// REPL
491518
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
492519
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: 148 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,148 @@ 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+
m_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+
m_language = lldb::eScriptLanguageDefault;
177+
}
178+
179+
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
180+
return llvm::ArrayRef(g_scripting_template_list_options);
181+
}
182+
183+
lldb::ScriptLanguage m_language = lldb::eScriptLanguageDefault;
184+
};
185+
186+
protected:
187+
void DoExecute(Args &command, CommandReturnObject &result) override {
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_validity = false) {
193+
if (!check_validity || !value.empty()) {
194+
s.IndentMore();
195+
s.Indent();
196+
s << key << ": " << value << '\n';
197+
s.IndentLess();
198+
}
199+
};
200+
201+
auto print_usages = [&s](llvm::StringRef usage_kind,
202+
std::vector<llvm::StringRef> &usages) {
203+
s.IndentMore();
204+
s.Indent();
205+
s << usage_kind << " Usages:";
206+
if (usages.empty())
207+
s << " No usages.\n";
208+
else if (usages.size() == 1)
209+
s << " " << usages.front() << '\n';
210+
else {
211+
s << '\n';
212+
for (llvm::StringRef usage : usages) {
213+
s.IndentMore();
214+
s.Indent();
215+
s << usage << '\n';
216+
s.IndentLess();
217+
}
218+
}
219+
s.IndentLess();
220+
};
221+
222+
size_t num_templates = PluginManager::GetNumScriptedInterfaces();
223+
for (size_t i = 0; i < num_templates; i++) {
224+
llvm::StringRef plugin_name =
225+
PluginManager::GetScriptedInterfaceNameAtIndex(i);
226+
if (plugin_name.empty())
227+
break;
228+
229+
lldb::ScriptLanguage lang =
230+
PluginManager::GetScriptedInterfaceLanguageAtIndex(i);
231+
if (lang != m_options.m_language)
232+
continue;
233+
234+
llvm::StringRef desc =
235+
PluginManager::GetScriptedInterfaceDescriptionAtIndex(i);
236+
std::vector<llvm::StringRef> ci_usages =
237+
PluginManager::GetScriptedInterfaceCommandInterpreterUsagesAtIndex(i);
238+
std::vector<llvm::StringRef> api_usages =
239+
PluginManager::GetScriptedInterfaceAPIUsagesAtIndex(i);
240+
241+
print_field("Name", plugin_name);
242+
print_field("Language", ScriptInterpreter::LanguageToString(lang));
243+
print_field("Description", desc);
244+
print_usages("Command Interpreter", ci_usages);
245+
print_usages("API", api_usages);
246+
247+
if (i != num_templates - 1)
248+
s.EOL();
249+
}
250+
}
251+
252+
private:
253+
CommandOptions m_options;
254+
};
255+
256+
#pragma mark CommandObjectMultiwordScriptingTemplate
257+
258+
// CommandObjectMultiwordScriptingTemplate
259+
260+
class CommandObjectMultiwordScriptingTemplate : public CommandObjectMultiword {
261+
public:
262+
CommandObjectMultiwordScriptingTemplate(CommandInterpreter &interpreter)
263+
: CommandObjectMultiword(
264+
interpreter, "scripting template",
265+
"Commands for operating on the scripting templates.",
266+
"scripting template [<subcommand-options>]") {
267+
LoadSubCommand(
268+
"list",
269+
CommandObjectSP(new CommandObjectScriptingTemplateList(interpreter)));
270+
}
271+
272+
~CommandObjectMultiwordScriptingTemplate() override = default;
273+
};
274+
130275
#pragma mark CommandObjectMultiwordScripting
131276

132277
// CommandObjectMultiwordScripting
@@ -139,6 +284,9 @@ CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
139284
"scripting <subcommand> [<subcommand-options>]") {
140285
LoadSubCommand("run",
141286
CommandObjectSP(new CommandObjectScriptingRun(interpreter)));
287+
LoadSubCommand("template",
288+
CommandObjectSP(
289+
new CommandObjectMultiwordScriptingTemplate(interpreter)));
142290
}
143291

144292
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 specified 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: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,92 @@ 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+
uint32_t PluginManager::GetNumScriptedInterfaces() {
1532+
return GetScriptedInterfaceInstances().GetInstances().size();
1533+
}
1534+
1535+
llvm::StringRef PluginManager::GetScriptedInterfaceNameAtIndex(uint32_t index) {
1536+
return GetScriptedInterfaceInstances().GetNameAtIndex(index);
1537+
}
1538+
1539+
llvm::StringRef
1540+
PluginManager::GetScriptedInterfaceDescriptionAtIndex(uint32_t index) {
1541+
return GetScriptedInterfaceInstances().GetDescriptionAtIndex(index);
1542+
}
1543+
1544+
lldb::ScriptLanguage
1545+
PluginManager::GetScriptedInterfaceLanguageAtIndex(uint32_t idx) {
1546+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1547+
return idx < instances.size() ? instances[idx].language
1548+
: ScriptLanguage::eScriptLanguageNone;
1549+
}
1550+
1551+
std::vector<llvm::StringRef>
1552+
PluginManager::GetScriptedInterfaceCommandInterpreterUsagesAtIndex(
1553+
uint32_t idx) {
1554+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1555+
if (idx >= instances.size())
1556+
return {};
1557+
return instances[idx].command_interpreter_usages;
1558+
}
1559+
1560+
std::vector<llvm::StringRef>
1561+
PluginManager::GetScriptedInterfaceAPIUsagesAtIndex(uint32_t idx) {
1562+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1563+
if (idx >= instances.size())
1564+
return {};
1565+
return instances[idx].api_usages;
1566+
}
1567+
14821568
#pragma mark REPL
14831569

14841570
struct REPLInstance : public PluginInstance<REPLCreateInstance> {
@@ -1539,6 +1625,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
15391625
GetOperatingSystemInstances().PerformDebuggerCallback(debugger);
15401626
GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
15411627
GetTracePluginInstances().PerformDebuggerCallback(debugger);
1628+
GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
15421629
}
15431630

15441631
// 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)