Skip to content

Commit 7b8ca7b

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. This was previously reviewed in llvm#97273. Signed-off-by: Med Ismail Bennani <[email protected]> (cherry picked from commit bccff3b)
1 parent bf56de2 commit 7b8ca7b

File tree

15 files changed

+375
-10
lines changed

15 files changed

+375
-10
lines changed

lldb/include/lldb/Core/PluginManager.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_CORE_PLUGINMANAGER_H
1111

1212
#include "lldb/Core/Architecture.h"
13+
#include "lldb/Interpreter/Interfaces/ScriptedInterfaceUsages.h"
1314
#include "lldb/Symbol/TypeSystem.h"
1415
#include "lldb/Utility/CompletionRequest.h"
1516
#include "lldb/Utility/FileSpec.h"
@@ -488,6 +489,25 @@ class PluginManager {
488489

489490
static LanguageSet GetAllTypeSystemSupportedLanguagesForExpressions();
490491

492+
// Scripted Interface
493+
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
494+
ScriptedInterfaceCreateInstance create_callback,
495+
lldb::ScriptLanguage language,
496+
ScriptedInterfaceUsages usages);
497+
498+
static bool UnregisterPlugin(ScriptedInterfaceCreateInstance create_callback);
499+
500+
static uint32_t GetNumScriptedInterfaces();
501+
502+
static llvm::StringRef GetScriptedInterfaceNameAtIndex(uint32_t idx);
503+
504+
static llvm::StringRef GetScriptedInterfaceDescriptionAtIndex(uint32_t idx);
505+
506+
static lldb::ScriptLanguage GetScriptedInterfaceLanguageAtIndex(uint32_t idx);
507+
508+
static ScriptedInterfaceUsages
509+
GetScriptedInterfaceUsagesAtIndex(uint32_t idx);
510+
491511
// REPL
492512
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
493513
REPLCreateInstance create_callback,

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDINTERFACE_H
1010
#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDINTERFACE_H
1111

12+
#include "ScriptedInterfaceUsages.h"
13+
1214
#include "lldb/Core/StructuredDataImpl.h"
1315
#include "lldb/Utility/LLDBLog.h"
1416
#include "lldb/Utility/Log.h"
@@ -68,6 +70,11 @@ class ScriptedInterface {
6870
return true;
6971
}
7072

73+
static bool CreateInstance(lldb::ScriptLanguage language,
74+
ScriptedInterfaceUsages usages) {
75+
return false;
76+
}
77+
7178
protected:
7279
StructuredData::GenericSP m_object_instance_sp;
7380
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===-- ScriptedInterfaceUsages.h ---------------------------- -*- C++ -*-===//
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+
#ifndef LLDB_INTERPRETER_SCRIPTEDINTERFACEUSAGES_H
10+
#define LLDB_INTERPRETER_SCRIPTEDINTERFACEUSAGES_H
11+
12+
#include "lldb/lldb-types.h"
13+
14+
#include "lldb/Utility/Stream.h"
15+
#include "llvm/ADT/StringRef.h"
16+
17+
namespace lldb_private {
18+
class ScriptedInterfaceUsages {
19+
public:
20+
ScriptedInterfaceUsages() = default;
21+
ScriptedInterfaceUsages(const std::vector<llvm::StringRef> ci_usages,
22+
const std::vector<llvm::StringRef> sbapi_usages)
23+
: m_command_interpreter_usages(ci_usages), m_sbapi_usages(sbapi_usages) {}
24+
25+
const std::vector<llvm::StringRef> &GetCommandInterpreterUsages() const {
26+
return m_command_interpreter_usages;
27+
}
28+
29+
const std::vector<llvm::StringRef> &GetSBAPIUsages() const {
30+
return m_sbapi_usages;
31+
}
32+
33+
enum class UsageKind { CommandInterpreter, API };
34+
35+
void Dump(Stream &s, UsageKind kind) const;
36+
37+
private:
38+
std::vector<llvm::StringRef> m_command_interpreter_usages;
39+
std::vector<llvm::StringRef> m_sbapi_usages;
40+
};
41+
} // namespace lldb_private
42+
43+
#endif // LLDB_INTERPRETER_SCRIPTEDINTERFACEUSAGES_H

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Value;
2525
} // namespace llvm
2626

2727
namespace lldb_private {
28+
class ScriptedInterfaceUsages;
2829
typedef lldb::ABISP (*ABICreateInstance)(lldb::ProcessSP process_sp,
2930
const ArchSpec &arch);
3031
typedef std::unique_ptr<Architecture> (*ArchitectureCreateInstance)(
@@ -125,6 +126,8 @@ typedef lldb::REPLSP (*REPLCreateInstance)(Status &error,
125126
lldb::LanguageType language,
126127
Debugger *debugger, Target *target,
127128
const char *repl_options);
129+
typedef bool (*ScriptedInterfaceCreateInstance)(lldb::ScriptLanguage language,
130+
ScriptedInterfaceUsages usages);
128131
typedef int (*ComparisonFunction)(const void *, const void *);
129132
typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
130133
/// Trace

lldb/source/Commands/CommandObjectScripting.cpp

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
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"
1415
#include "lldb/Interpreter/CommandInterpreter.h"
1516
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
1617
#include "lldb/Interpreter/CommandReturnObject.h"
18+
#include "lldb/Interpreter/Interfaces/ScriptedInterfaceUsages.h"
1719
#include "lldb/Interpreter/OptionArgParser.h"
1820
#include "lldb/Interpreter/ScriptInterpreter.h"
1921
#include "lldb/Utility/Args.h"
@@ -127,9 +129,126 @@ class CommandObjectScriptingRun : public CommandObjectRaw {
127129
CommandOptions m_options;
128130
};
129131

130-
#pragma mark CommandObjectMultiwordScripting
132+
#define LLDB_OPTIONS_scripting_template_list
133+
#include "CommandOptions.inc"
134+
135+
class CommandObjectScriptingTemplateList : public CommandObjectParsed {
136+
public:
137+
CommandObjectScriptingTemplateList(CommandInterpreter &interpreter)
138+
: CommandObjectParsed(
139+
interpreter, "scripting template list",
140+
"List all the available scripting extension templates. ",
141+
"scripting template list [--language <scripting-language> --]") {}
142+
143+
~CommandObjectScriptingTemplateList() override = default;
144+
145+
Options *GetOptions() override { return &m_options; }
146+
147+
class CommandOptions : public Options {
148+
public:
149+
CommandOptions() = default;
150+
~CommandOptions() override = default;
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;
131155

132-
// CommandObjectMultiwordScripting
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.SetErrorStringWithFormatv(
163+
"unrecognized value for language '{0}'", option_arg);
164+
break;
165+
default:
166+
llvm_unreachable("Unimplemented option");
167+
}
168+
169+
return error;
170+
}
171+
172+
void OptionParsingStarting(ExecutionContext *execution_context) override {
173+
m_language = lldb::eScriptLanguageDefault;
174+
}
175+
176+
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
177+
return llvm::ArrayRef(g_scripting_template_list_options);
178+
}
179+
180+
lldb::ScriptLanguage m_language = lldb::eScriptLanguageDefault;
181+
};
182+
183+
protected:
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_templates = PluginManager::GetNumScriptedInterfaces();
199+
for (size_t i = 0; i < num_templates; 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_templates - 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 CommandObjectMultiwordScriptingTemplate : public CommandObjectMultiword {
239+
public:
240+
CommandObjectMultiwordScriptingTemplate(CommandInterpreter &interpreter)
241+
: CommandObjectMultiword(
242+
interpreter, "scripting template",
243+
"Commands for operating on the scripting templates.",
244+
"scripting template [<subcommand-options>]") {
245+
LoadSubCommand(
246+
"list",
247+
CommandObjectSP(new CommandObjectScriptingTemplateList(interpreter)));
248+
}
249+
250+
~CommandObjectMultiwordScriptingTemplate() override = default;
251+
};
133252

134253
CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
135254
CommandInterpreter &interpreter)
@@ -139,6 +258,9 @@ CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
139258
"scripting <subcommand> [<subcommand-options>]") {
140259
LoadSubCommand("run",
141260
CommandObjectSP(new CommandObjectScriptingRun(interpreter)));
261+
LoadSubCommand("template",
262+
CommandObjectSP(
263+
new CommandObjectMultiwordScriptingTemplate(interpreter)));
142264
}
143265

144266
CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;

lldb/source/Commands/Options.td

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

856+
let Command = "scripting template list" in {
857+
def scripting_template_list_language : Option<"language", "l">,
858+
EnumArg<"ScriptLang">, Desc<"Specify the scripting "
859+
" language. If none is specified the default scripting language is used.">;
860+
}
861+
856862
let Command = "source info" in {
857863
def source_info_count : Option<"count", "c">, Arg<"Count">,
858864
Desc<"The number of line entries to display.">;

lldb/source/Core/PluginManager.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,70 @@ LanguageSet PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions() {
15071507
return all;
15081508
}
15091509

1510+
#pragma mark ScriptedInterfaces
1511+
1512+
struct ScriptedInterfaceInstance
1513+
: public PluginInstance<ScriptedInterfaceCreateInstance> {
1514+
ScriptedInterfaceInstance(llvm::StringRef name, llvm::StringRef description,
1515+
ScriptedInterfaceCreateInstance create_callback,
1516+
lldb::ScriptLanguage language,
1517+
ScriptedInterfaceUsages usages)
1518+
: PluginInstance<ScriptedInterfaceCreateInstance>(name, description,
1519+
create_callback),
1520+
language(language), usages(usages) {}
1521+
1522+
lldb::ScriptLanguage language;
1523+
ScriptedInterfaceUsages usages;
1524+
};
1525+
1526+
typedef PluginInstances<ScriptedInterfaceInstance> ScriptedInterfaceInstances;
1527+
1528+
static ScriptedInterfaceInstances &GetScriptedInterfaceInstances() {
1529+
static ScriptedInterfaceInstances g_instances;
1530+
return g_instances;
1531+
}
1532+
1533+
bool PluginManager::RegisterPlugin(
1534+
llvm::StringRef name, llvm::StringRef description,
1535+
ScriptedInterfaceCreateInstance create_callback,
1536+
lldb::ScriptLanguage language, ScriptedInterfaceUsages usages) {
1537+
return GetScriptedInterfaceInstances().RegisterPlugin(
1538+
name, description, create_callback, language, usages);
1539+
}
1540+
1541+
bool PluginManager::UnregisterPlugin(
1542+
ScriptedInterfaceCreateInstance create_callback) {
1543+
return GetScriptedInterfaceInstances().UnregisterPlugin(create_callback);
1544+
}
1545+
1546+
uint32_t PluginManager::GetNumScriptedInterfaces() {
1547+
return GetScriptedInterfaceInstances().GetInstances().size();
1548+
}
1549+
1550+
llvm::StringRef PluginManager::GetScriptedInterfaceNameAtIndex(uint32_t index) {
1551+
return GetScriptedInterfaceInstances().GetNameAtIndex(index);
1552+
}
1553+
1554+
llvm::StringRef
1555+
PluginManager::GetScriptedInterfaceDescriptionAtIndex(uint32_t index) {
1556+
return GetScriptedInterfaceInstances().GetDescriptionAtIndex(index);
1557+
}
1558+
1559+
lldb::ScriptLanguage
1560+
PluginManager::GetScriptedInterfaceLanguageAtIndex(uint32_t idx) {
1561+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1562+
return idx < instances.size() ? instances[idx].language
1563+
: ScriptLanguage::eScriptLanguageNone;
1564+
}
1565+
1566+
ScriptedInterfaceUsages
1567+
PluginManager::GetScriptedInterfaceUsagesAtIndex(uint32_t idx) {
1568+
const auto &instances = GetScriptedInterfaceInstances().GetInstances();
1569+
if (idx >= instances.size())
1570+
return {};
1571+
return instances[idx].usages;
1572+
}
1573+
15101574
#pragma mark REPL
15111575

15121576
struct REPLInstance : public PluginInstance<REPLCreateInstance> {
@@ -1568,6 +1632,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
15681632
GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
15691633
GetTracePluginInstances().PerformDebuggerCallback(debugger);
15701634
GetTypeSystemInstances().PerformDebuggerCallback(debugger);
1635+
GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
15711636
}
15721637

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

lldb/source/Interpreter/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ lldb_tablegen(InterpreterPropertiesEnum.inc -gen-lldb-property-enum-defs
66
SOURCE InterpreterProperties.td
77
TARGET LLDBInterpreterPropertiesEnumGen)
88

9+
add_subdirectory(Interfaces)
10+
911
add_lldb_library(lldbInterpreter NO_PLUGIN_DEPENDENCIES
1012
CommandAlias.cpp
1113
CommandHistory.cpp
@@ -54,6 +56,7 @@ add_lldb_library(lldbInterpreter NO_PLUGIN_DEPENDENCIES
5456
ScriptInterpreter.cpp
5557

5658
LINK_LIBS
59+
lldbInterpreterInterfaces
5760
lldbCommands
5861
lldbCore
5962
lldbDataFormatters
@@ -66,6 +69,7 @@ add_lldb_library(lldbInterpreter NO_PLUGIN_DEPENDENCIES
6669
)
6770

6871
add_dependencies(lldbInterpreter
72+
lldbInterpreterInterfaces
6973
LLDBInterpreterPropertiesGen
7074
LLDBInterpreterPropertiesEnumGen)
7175

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_lldb_library(lldbInterpreterInterfaces NO_PLUGIN_DEPENDENCIES
2+
ScriptedInterfaceUsages.cpp
3+
4+
LINK_LIBS
5+
lldbUtility
6+
7+
LINK_COMPONENTS
8+
Support
9+
)
10+

0 commit comments

Comments
 (0)