[Lldb-commits] [lldb] [lldb/Commands] Add `scripting template list` command with auto discovery (PR #97273)

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Mon Jul 1 12:03:11 PDT 2024


https://github.com/medismailben updated https://github.com/llvm/llvm-project/pull/97273

>From 8e016c7aa66c4d5f7a90b5dc05b05c1838919177 Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Mon, 1 Jul 2024 12:00:04 -0700
Subject: [PATCH 1/2] [lldb/Commands] Alias `script` command to `scripting
 execute`

This patch introduces a new top-level `scripting` command with an
`execute` sub-command, that basically replaces the `script` raw command.

To avoid breaking the `script` command usages, this patch also adds an
`script` alias to the `scripting execute` sub-command.

The reason behind this change is to have a top-level command that will
cover scripting related subcommands.

Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
 lldb/source/Commands/CMakeLists.txt           |  2 +-
 ...tScript.cpp => CommandObjectScripting.cpp} | 44 +++++++++++++------
 ...bjectScript.h => CommandObjectScripting.h} | 17 ++++---
 lldb/source/Commands/Options.td               |  2 +-
 .../source/Interpreter/CommandInterpreter.cpp | 13 +++++-
 .../abbreviation/TestAbbreviations.py         |  4 +-
 6 files changed, 59 insertions(+), 23 deletions(-)
 rename lldb/source/Commands/{CommandObjectScript.cpp => CommandObjectScripting.cpp} (68%)
 rename lldb/source/Commands/{CommandObjectScript.h => CommandObjectScripting.h} (71%)

diff --git a/lldb/source/Commands/CMakeLists.txt b/lldb/source/Commands/CMakeLists.txt
index 6a36c5376d5c5..76397227d535d 100644
--- a/lldb/source/Commands/CMakeLists.txt
+++ b/lldb/source/Commands/CMakeLists.txt
@@ -26,7 +26,7 @@ add_lldb_library(lldbCommands NO_PLUGIN_DEPENDENCIES
   CommandObjectQuit.cpp
   CommandObjectRegexCommand.cpp
   CommandObjectRegister.cpp
-  CommandObjectScript.cpp
+  CommandObjectScripting.cpp
   CommandObjectSession.cpp
   CommandObjectSettings.cpp
   CommandObjectSource.cpp
diff --git a/lldb/source/Commands/CommandObjectScript.cpp b/lldb/source/Commands/CommandObjectScripting.cpp
similarity index 68%
rename from lldb/source/Commands/CommandObjectScript.cpp
rename to lldb/source/Commands/CommandObjectScripting.cpp
index 25f25b8e65947..72f653690e532 100644
--- a/lldb/source/Commands/CommandObjectScript.cpp
+++ b/lldb/source/Commands/CommandObjectScripting.cpp
@@ -1,4 +1,4 @@
-//===-- CommandObjectScript.cpp -------------------------------------------===//
+//===-- CommandObjectScripting.cpp ----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CommandObjectScript.h"
+#include "CommandObjectScripting.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/DataFormatters/DataVisualization.h"
 #include "lldb/Host/Config.h"
@@ -21,10 +21,10 @@
 using namespace lldb;
 using namespace lldb_private;
 
-#define LLDB_OPTIONS_script
+#define LLDB_OPTIONS_scripting_execute
 #include "CommandOptions.inc"
 
-Status CommandObjectScript::CommandOptions::SetOptionValue(
+Status CommandObjectScriptingExecute::CommandOptions::SetOptionValue(
     uint32_t option_idx, llvm::StringRef option_arg,
     ExecutionContext *execution_context) {
   Status error;
@@ -46,27 +46,29 @@ Status CommandObjectScript::CommandOptions::SetOptionValue(
   return error;
 }
 
-void CommandObjectScript::CommandOptions::OptionParsingStarting(
+void CommandObjectScriptingExecute::CommandOptions::OptionParsingStarting(
     ExecutionContext *execution_context) {
   language = lldb::eScriptLanguageNone;
 }
 
 llvm::ArrayRef<OptionDefinition>
-CommandObjectScript::CommandOptions::GetDefinitions() {
-  return llvm::ArrayRef(g_script_options);
+CommandObjectScriptingExecute::CommandOptions::GetDefinitions() {
+  return llvm::ArrayRef(g_scripting_execute_options);
 }
 
-CommandObjectScript::CommandObjectScript(CommandInterpreter &interpreter)
+CommandObjectScriptingExecute::CommandObjectScriptingExecute(
+    CommandInterpreter &interpreter)
     : CommandObjectRaw(
-          interpreter, "script",
+          interpreter, "scripting execute",
           "Invoke the script interpreter with provided code and display any "
           "results.  Start the interactive interpreter if no code is supplied.",
-          "script [--language <scripting-language> --] [<script-code>]") {}
+          "scripting execute [--language <scripting-language> --] "
+          "[<script-code>]") {}
 
-CommandObjectScript::~CommandObjectScript() = default;
+CommandObjectScriptingExecute::~CommandObjectScriptingExecute() = default;
 
-void CommandObjectScript::DoExecute(llvm::StringRef command,
-                                    CommandReturnObject &result) {
+void CommandObjectScriptingExecute::DoExecute(llvm::StringRef command,
+                                              CommandReturnObject &result) {
   // Try parsing the language option but when the command contains a raw part
   // separated by the -- delimiter.
   OptionsWithRaw raw_args(command);
@@ -111,3 +113,19 @@ void CommandObjectScript::DoExecute(llvm::StringRef command,
   else
     result.SetStatus(eReturnStatusFailed);
 }
+
+#pragma mark CommandObjectMultiwordScripting
+
+// CommandObjectMultiwordScripting
+
+CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
+    CommandInterpreter &interpreter)
+    : CommandObjectMultiword(
+          interpreter, "scripting",
+          "Commands for operating on the scripting functionnalities.",
+          "scripting <subcommand> [<subcommand-options>]") {
+  LoadSubCommand("execute", CommandObjectSP(new CommandObjectScriptingExecute(
+                                interpreter)));
+}
+
+CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;
diff --git a/lldb/source/Commands/CommandObjectScript.h b/lldb/source/Commands/CommandObjectScripting.h
similarity index 71%
rename from lldb/source/Commands/CommandObjectScript.h
rename to lldb/source/Commands/CommandObjectScripting.h
index 3a8c4a890404a..b4a8a32cb644a 100644
--- a/lldb/source/Commands/CommandObjectScript.h
+++ b/lldb/source/Commands/CommandObjectScripting.h
@@ -1,4 +1,4 @@
-//===-- CommandObjectScript.h -----------------------------------*- C++ -*-===//
+//===-- CommandObjectScripting.h --------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -9,14 +9,21 @@
 #ifndef LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H
 #define LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H
 
-#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
 
 namespace lldb_private {
 
-class CommandObjectScript : public CommandObjectRaw {
+class CommandObjectMultiwordScripting : public CommandObjectMultiword {
 public:
-  CommandObjectScript(CommandInterpreter &interpreter);
-  ~CommandObjectScript() override;
+  CommandObjectMultiwordScripting(CommandInterpreter &interpreter);
+
+  ~CommandObjectMultiwordScripting() override;
+};
+
+class CommandObjectScriptingExecute : public CommandObjectRaw {
+public:
+  CommandObjectScriptingExecute(CommandInterpreter &interpreter);
+  ~CommandObjectScriptingExecute() override;
   Options *GetOptions() override { return &m_options; }
 
   class CommandOptions : public Options {
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index fa8af7cb3d762..752121ee6edb2 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -835,7 +835,7 @@ let Command = "container add" in {
   Desc<"Overwrite an existing command at this node.">;
 }
 
-let Command = "script" in {
+let Command = "scripting execute" in {
   def script_language : Option<"language", "l">,
     EnumArg<"ScriptLang">, Desc<"Specify the scripting "
     " language. If none is specific the default scripting language is used.">;
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 40c915b2c94fc..6b701591d0326 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -33,7 +33,7 @@
 #include "Commands/CommandObjectQuit.h"
 #include "Commands/CommandObjectRegexCommand.h"
 #include "Commands/CommandObjectRegister.h"
-#include "Commands/CommandObjectScript.h"
+#include "Commands/CommandObjectScripting.h"
 #include "Commands/CommandObjectSession.h"
 #include "Commands/CommandObjectSettings.h"
 #include "Commands/CommandObjectSource.h"
@@ -518,6 +518,15 @@ void CommandInterpreter::Initialize() {
     AddAlias("re", cmd_obj_sp);
   }
 
+  cmd_obj_sp = GetCommandSPExact("scripting execute");
+  if (cmd_obj_sp) {
+    AddAlias("sc", cmd_obj_sp);
+    AddAlias("scr", cmd_obj_sp);
+    AddAlias("scri", cmd_obj_sp);
+    AddAlias("scrip", cmd_obj_sp);
+    AddAlias("script", cmd_obj_sp);
+  }
+
   cmd_obj_sp = GetCommandSPExact("session history");
   if (cmd_obj_sp) {
     AddAlias("history", cmd_obj_sp);
@@ -569,7 +578,7 @@ void CommandInterpreter::LoadCommandDictionary() {
   REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
   REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
   REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
-  REGISTER_COMMAND_OBJECT("script", CommandObjectScript);
+  REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting);
   REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
   REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
   REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource);
diff --git a/lldb/test/API/functionalities/abbreviation/TestAbbreviations.py b/lldb/test/API/functionalities/abbreviation/TestAbbreviations.py
index 10431e41dc81a..cd9b6c69a8ee3 100644
--- a/lldb/test/API/functionalities/abbreviation/TestAbbreviations.py
+++ b/lldb/test/API/functionalities/abbreviation/TestAbbreviations.py
@@ -80,7 +80,9 @@ def test_command_abbreviations_and_aliases(self):
         # Check a command that wants the raw input.
         command_interpreter.ResolveCommand(r"""sc print("\n\n\tHello!\n")""", result)
         self.assertTrue(result.Succeeded())
-        self.assertEqual(r"""script print("\n\n\tHello!\n")""", result.GetOutput())
+        self.assertEqual(
+            r"""scripting execute print("\n\n\tHello!\n")""", result.GetOutput()
+        )
 
         # Prompt changing stuff should be tested, but this doesn't seem like the
         # right test to do it in.  It has nothing to do with aliases or abbreviations.

>From 55e53e4a33db36d9f207d230112aed907a2dd9cf Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Mon, 1 Jul 2024 02:54:33 -0700
Subject: [PATCH 2/2] [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 <ismail at bennani.ma>
---
 lldb/include/lldb/Core/PluginManager.h        |  25 +++
 .../Interfaces/ScriptedInterface.h            |   7 +
 lldb/include/lldb/lldb-private-interfaces.h   |   4 +
 .../Commands/CommandObjectScripting.cpp       | 159 ++++++++++++++++++
 lldb/source/Commands/CommandObjectScripting.h |  31 ++++
 lldb/source/Commands/Options.td               |   8 +-
 lldb/source/Core/PluginManager.cpp            |  83 +++++++++
 lldb/source/Plugins/CMakeLists.txt            |   3 +
 .../Python/Interfaces/CMakeLists.txt          |   5 +
 .../ScriptedProcessPythonInterface.cpp        |  23 +++
 .../ScriptedProcessPythonInterface.h          |  13 +-
 .../ScriptedThreadPlanPythonInterface.cpp     |  18 ++
 .../ScriptedThreadPlanPythonInterface.h       |  13 +-
 13 files changed, 389 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index f2296e2920238..df20109e791a5 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -487,6 +487,31 @@ class PluginManager {
 
   static LanguageSet GetAllTypeSystemSupportedLanguagesForExpressions();
 
+  // Scripted Interface
+  static bool
+  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
+                 ScriptedInterfaceCreateInstance create_callback,
+                 lldb::ScriptLanguage language,
+                 std::vector<llvm::StringRef> command_interpreter_usages,
+                 std::vector<llvm::StringRef> api_usages);
+
+  static bool UnregisterPlugin(ScriptedInterfaceCreateInstance create_callback);
+
+  static ScriptedInterfaceCreateInstance
+  GetScriptedInterfaceCreateCallbackAtIndex(uint32_t idx);
+
+  static llvm::StringRef GetScriptedInterfaceNameAtIndex(uint32_t idx);
+
+  static llvm::StringRef GetScriptedInterfaceDescriptionAtIndex(uint32_t idx);
+
+  static lldb::ScriptLanguage GetScriptedInterfaceLanguageAtIndex(uint32_t idx);
+
+  static std::vector<llvm::StringRef>
+  GetScriptedInterfaceCommandInterpreterUsagesAtIndex(uint32_t idx);
+
+  static std::vector<llvm::StringRef>
+  GetScriptedInterfaceAPIUsagesAtIndex(uint32_t idx);
+
   // REPL
   static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                              REPLCreateInstance create_callback,
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h
index 69504dbcda5dc..23658b90bb90a 100644
--- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h
@@ -68,6 +68,13 @@ class ScriptedInterface {
     return true;
   }
 
+  static bool
+  CreateInstance(lldb::ScriptLanguage language,
+                 std::vector<llvm::StringRef> command_interpreter_usages,
+                 std::vector<llvm::StringRef> api_usages) {
+    return false;
+  }
+
 protected:
   StructuredData::GenericSP m_object_instance_sp;
 };
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index cdd9b51d9329c..2404e28158690 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -124,6 +124,10 @@ typedef lldb::REPLSP (*REPLCreateInstance)(Status &error,
                                            lldb::LanguageType language,
                                            Debugger *debugger, Target *target,
                                            const char *repl_options);
+typedef bool (*ScriptedInterfaceCreateInstance)(
+    lldb::ScriptLanguage language,
+    std::vector<llvm::StringRef> command_interpreter_usages,
+    std::vector<llvm::StringRef> api_usages);
 typedef int (*ComparisonFunction)(const void *, const void *);
 typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
 /// Trace
diff --git a/lldb/source/Commands/CommandObjectScripting.cpp b/lldb/source/Commands/CommandObjectScripting.cpp
index 72f653690e532..f03c93ed1ef9d 100644
--- a/lldb/source/Commands/CommandObjectScripting.cpp
+++ b/lldb/source/Commands/CommandObjectScripting.cpp
@@ -8,6 +8,7 @@
 
 #include "CommandObjectScripting.h"
 #include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
 #include "lldb/DataFormatters/DataVisualization.h"
 #include "lldb/Host/Config.h"
 #include "lldb/Host/OptionParser.h"
@@ -21,6 +22,8 @@
 using namespace lldb;
 using namespace lldb_private;
 
+#pragma mark CommandObjectScriptingExecute
+
 #define LLDB_OPTIONS_scripting_execute
 #include "CommandOptions.inc"
 
@@ -114,6 +117,159 @@ void CommandObjectScriptingExecute::DoExecute(llvm::StringRef command,
     result.SetStatus(eReturnStatusFailed);
 }
 
+#pragma mark CommandObjectScriptingTemplateList
+
+#define LLDB_OPTIONS_scripting_template_list
+#include "CommandOptions.inc"
+
+Status CommandObjectScriptingTemplateList::CommandOptions::SetOptionValue(
+    uint32_t option_idx, llvm::StringRef option_arg,
+    ExecutionContext *execution_context) {
+  Status error;
+  const int short_option = m_getopt_table[option_idx].val;
+
+  switch (short_option) {
+  case 'l':
+    language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
+        option_arg, GetDefinitions()[option_idx].enum_values,
+        eScriptLanguageNone, error);
+    if (!error.Success())
+      error.SetErrorStringWithFormat("unrecognized value for language '%s'",
+                                     option_arg.str().c_str());
+    break;
+  default:
+    llvm_unreachable("Unimplemented option");
+  }
+
+  return error;
+}
+
+void CommandObjectScriptingTemplateList::CommandOptions::OptionParsingStarting(
+    ExecutionContext *execution_context) {
+  language = lldb::eScriptLanguageNone;
+}
+
+llvm::ArrayRef<OptionDefinition>
+CommandObjectScriptingTemplateList::CommandOptions::GetDefinitions() {
+  return llvm::ArrayRef(g_scripting_execute_options);
+}
+
+CommandObjectScriptingTemplateList::CommandObjectScriptingTemplateList(
+    CommandInterpreter &interpreter)
+    : CommandObjectParsed(
+          interpreter, "scripting template list",
+          "List all the available scripting affordances templates. ",
+          "scripting template list [--language <scripting-language> --]") {}
+
+CommandObjectScriptingTemplateList::~CommandObjectScriptingTemplateList() =
+    default;
+
+void CommandObjectScriptingTemplateList::DoExecute(
+    Args &command, CommandReturnObject &result) {
+  lldb::ScriptLanguage language =
+      (m_options.language == lldb::eScriptLanguageNone)
+          ? m_interpreter.GetDebugger().GetScriptLanguage()
+          : m_options.language;
+
+  if (language == lldb::eScriptLanguageNone) {
+    result.AppendError(
+        "the script-lang setting is set to none - scripting not available");
+    return;
+  }
+
+  ScriptInterpreter *script_interpreter =
+      GetDebugger().GetScriptInterpreter(true, language);
+
+  if (script_interpreter == nullptr) {
+    result.AppendError("no script interpreter");
+    return;
+  }
+
+  Stream &s = result.GetOutputStream();
+  s.Printf("Available scripted affordances:\n");
+
+  auto print_field = [&s](llvm::StringRef key, llvm::StringRef value,
+                          bool check_validy = false) {
+    if (!check_validy || !value.empty()) {
+      s.IndentMore();
+      s.Indent();
+      s << key << ": " << value << '\n';
+      s.IndentLess();
+    }
+  };
+  auto print_usages = [&s](llvm::StringRef usage_kind,
+                           std::vector<llvm::StringRef> &usages) {
+    s.IndentMore();
+    s.Indent();
+    s << usage_kind << " Usages:";
+    if (usages.empty())
+      s << " No usages.\n";
+    else if (usages.size() == 1)
+      s << " " << usages.front() << '\n';
+    else {
+      s << '\n';
+      for (llvm::StringRef usage : usages) {
+        s.IndentMore();
+        s.Indent();
+        s << usage << '\n';
+        s.IndentLess();
+      }
+    }
+    s.IndentLess();
+  };
+
+  size_t i = 0;
+  for (llvm::StringRef plugin_name =
+           PluginManager::GetScriptedInterfaceNameAtIndex(i);
+       !plugin_name.empty();) {
+
+    llvm::StringRef desc =
+        PluginManager::GetScriptedInterfaceDescriptionAtIndex(i);
+    lldb::ScriptLanguage lang =
+        PluginManager::GetScriptedInterfaceLanguageAtIndex(i);
+    std::vector<llvm::StringRef> ci_usages =
+        PluginManager::GetScriptedInterfaceCommandInterpreterUsagesAtIndex(i);
+    std::vector<llvm::StringRef> api_usages =
+        PluginManager::GetScriptedInterfaceAPIUsagesAtIndex(i);
+
+    print_field("Name", plugin_name);
+    switch (lang) {
+    case eScriptLanguagePython:
+      print_field("Language", "Python");
+      break;
+    case eScriptLanguageLua:
+      print_field("Language", "Lua");
+      break;
+    default:
+      break;
+    }
+    print_field("Description", desc);
+    print_usages("Command Interpreter", ci_usages);
+    print_usages("API", api_usages);
+
+    plugin_name = PluginManager::GetScriptedInterfaceNameAtIndex(++i);
+    if (!plugin_name.empty())
+      s.EOL();
+  }
+}
+
+#pragma mark CommandObjectMultiwordScriptingTemplate
+
+// CommandObjectMultiwordScriptingTemplate
+
+CommandObjectMultiwordScriptingTemplate::
+    CommandObjectMultiwordScriptingTemplate(CommandInterpreter &interpreter)
+    : CommandObjectMultiword(
+          interpreter, "scripting template",
+          "Commands for operating on the scripting templates.",
+          "scripting template [<subcommand-options>]") {
+  LoadSubCommand("list", CommandObjectSP(new CommandObjectScriptingTemplateList(
+                             interpreter)));
+}
+
+CommandObjectMultiwordScriptingTemplate::
+    ~CommandObjectMultiwordScriptingTemplate() = default;
+
 #pragma mark CommandObjectMultiwordScripting
 
 // CommandObjectMultiwordScripting
@@ -126,6 +282,9 @@ CommandObjectMultiwordScripting::CommandObjectMultiwordScripting(
           "scripting <subcommand> [<subcommand-options>]") {
   LoadSubCommand("execute", CommandObjectSP(new CommandObjectScriptingExecute(
                                 interpreter)));
+  LoadSubCommand("template",
+                 CommandObjectSP(
+                     new CommandObjectMultiwordScriptingTemplate(interpreter)));
 }
 
 CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default;
diff --git a/lldb/source/Commands/CommandObjectScripting.h b/lldb/source/Commands/CommandObjectScripting.h
index b4a8a32cb644a..a9af6ee62e298 100644
--- a/lldb/source/Commands/CommandObjectScripting.h
+++ b/lldb/source/Commands/CommandObjectScripting.h
@@ -44,6 +44,37 @@ class CommandObjectScriptingExecute : public CommandObjectRaw {
   CommandOptions m_options;
 };
 
+class CommandObjectMultiwordScriptingTemplate : public CommandObjectMultiword {
+public:
+  CommandObjectMultiwordScriptingTemplate(CommandInterpreter &interpreter);
+
+  ~CommandObjectMultiwordScriptingTemplate() override;
+};
+
+class CommandObjectScriptingTemplateList : public CommandObjectParsed {
+public:
+  CommandObjectScriptingTemplateList(CommandInterpreter &interpreter);
+  ~CommandObjectScriptingTemplateList() override;
+  Options *GetOptions() override { return &m_options; }
+
+  class CommandOptions : public Options {
+  public:
+    CommandOptions() = default;
+    ~CommandOptions() override = default;
+    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+                          ExecutionContext *execution_context) override;
+    void OptionParsingStarting(ExecutionContext *execution_context) override;
+    llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
+    lldb::ScriptLanguage language = lldb::eScriptLanguageNone;
+  };
+
+protected:
+  void DoExecute(Args &command, CommandReturnObject &result) override;
+
+private:
+  CommandOptions m_options;
+};
+
 } // namespace lldb_private
 
 #endif // LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 752121ee6edb2..8eb17295e6df8 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -836,7 +836,13 @@ let Command = "container add" in {
 }
 
 let Command = "scripting execute" in {
-  def script_language : Option<"language", "l">,
+  def scripting_execute_language : Option<"language", "l">,
+    EnumArg<"ScriptLang">, Desc<"Specify the scripting "
+    " language. If none is specific the default scripting language is used.">;
+}
+
+let Command = "scripting template list" in {
+  def scripting_template_list_language : Option<"language", "l">,
     EnumArg<"ScriptLang">, Desc<"Specify the scripting "
     " language. If none is specific the default scripting language is used.">;
 }
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index b428370d7f333..2387d2ab6426b 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -1479,6 +1479,88 @@ LanguageSet PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions() {
   return all;
 }
 
+#pragma mark ScriptedInterfaces
+
+struct ScriptedInterfaceInstance
+    : public PluginInstance<ScriptedInterfaceCreateInstance> {
+  ScriptedInterfaceInstance(
+      llvm::StringRef name, llvm::StringRef description,
+      ScriptedInterfaceCreateInstance create_callback,
+      lldb::ScriptLanguage language,
+      std::vector<llvm::StringRef> command_interpreter_usages,
+      std::vector<llvm::StringRef> api_usages)
+      : PluginInstance<ScriptedInterfaceCreateInstance>(name, description,
+                                                        create_callback),
+        language(language),
+        command_interpreter_usages(command_interpreter_usages),
+        api_usages(api_usages) {}
+
+  lldb::ScriptLanguage language;
+  std::vector<llvm::StringRef> command_interpreter_usages;
+  std::vector<llvm::StringRef> api_usages;
+};
+
+typedef PluginInstances<ScriptedInterfaceInstance> ScriptedInterfaceInstances;
+
+static ScriptedInterfaceInstances &GetScriptedInterfaceInstances() {
+  static ScriptedInterfaceInstances g_instances;
+  return g_instances;
+}
+
+bool PluginManager::RegisterPlugin(
+    llvm::StringRef name, llvm::StringRef description,
+    ScriptedInterfaceCreateInstance create_callback,
+    lldb::ScriptLanguage language,
+    std::vector<llvm::StringRef> command_interpreter_usages,
+    std::vector<llvm::StringRef> api_usages) {
+  return GetScriptedInterfaceInstances().RegisterPlugin(
+      name, description, create_callback, language, command_interpreter_usages,
+      api_usages);
+}
+
+bool PluginManager::UnregisterPlugin(
+    ScriptedInterfaceCreateInstance create_callback) {
+  return GetScriptedInterfaceInstances().UnregisterPlugin(create_callback);
+}
+
+ScriptedInterfaceCreateInstance
+PluginManager::GetScriptedInterfaceCreateCallbackAtIndex(uint32_t idx) {
+  return GetScriptedInterfaceInstances().GetCallbackAtIndex(idx);
+}
+
+llvm::StringRef PluginManager::GetScriptedInterfaceNameAtIndex(uint32_t index) {
+  return GetScriptedInterfaceInstances().GetNameAtIndex(index);
+}
+
+llvm::StringRef
+PluginManager::GetScriptedInterfaceDescriptionAtIndex(uint32_t index) {
+  return GetScriptedInterfaceInstances().GetDescriptionAtIndex(index);
+}
+
+lldb::ScriptLanguage
+PluginManager::GetScriptedInterfaceLanguageAtIndex(uint32_t idx) {
+  const auto &instances = GetScriptedInterfaceInstances().GetInstances();
+  return idx < instances.size() ? instances[idx].language
+                                : ScriptLanguage::eScriptLanguageNone;
+}
+
+std::vector<llvm::StringRef>
+PluginManager::GetScriptedInterfaceCommandInterpreterUsagesAtIndex(
+    uint32_t idx) {
+  const auto &instances = GetScriptedInterfaceInstances().GetInstances();
+  if (idx >= instances.size())
+    return {};
+  return instances[idx].command_interpreter_usages;
+}
+
+std::vector<llvm::StringRef>
+PluginManager::GetScriptedInterfaceAPIUsagesAtIndex(uint32_t idx) {
+  const auto &instances = GetScriptedInterfaceInstances().GetInstances();
+  if (idx >= instances.size())
+    return {};
+  return instances[idx].api_usages;
+}
+
 #pragma mark REPL
 
 struct REPLInstance : public PluginInstance<REPLCreateInstance> {
@@ -1539,6 +1621,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
   GetOperatingSystemInstances().PerformDebuggerCallback(debugger);
   GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
   GetTracePluginInstances().PerformDebuggerCallback(debugger);
+  GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
 }
 
 // This is the preferred new way to register plugin specific settings.  e.g.
diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt
index 854f589f45ae0..34dd8c1eb22f6 100644
--- a/lldb/source/Plugins/CMakeLists.txt
+++ b/lldb/source/Plugins/CMakeLists.txt
@@ -29,6 +29,9 @@ add_subdirectory(UnwindAssembly)
 
 set(LLDB_STRIPPED_PLUGINS)
 get_property(LLDB_ALL_PLUGINS GLOBAL PROPERTY LLDB_PLUGINS)
+get_property(LLDB_EXTRA_PLUGINS GLOBAL PROPERTY LLDB_EXTRA_SCRIPT_PLUGINS)
+list(APPEND LLDB_ALL_PLUGINS ${LLDB_EXTRA_PLUGINS})
+
 
 set(LLDB_ENUM_PLUGINS "")
 
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
index c60e4bb503a37..c0ee9c8d0654d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
@@ -19,6 +19,11 @@ if (LLDB_ENABLE_LIBEDIT)
   list(APPEND LLDB_LIBEDIT_LIBS LibEdit::LibEdit)
 endif()
 
+set_property(GLOBAL PROPERTY LLDB_EXTRA_SCRIPT_PLUGINS
+  lldbPluginScriptedProcessPythonInterface
+  lldbPluginScriptedThreadPlanPythonInterface
+)
+
 add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces
   OperatingSystemPythonInterface.cpp
   ScriptedPythonInterface.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp
index 313c597ce48f3..1464467fb3797 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp
@@ -11,6 +11,7 @@
 // LLDB Python header must be included first
 #include "../lldb-python.h"
 #endif
+#include "lldb/Core/PluginManager.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Status.h"
@@ -29,6 +30,8 @@ using namespace lldb_private;
 using namespace lldb_private::python;
 using Locker = ScriptInterpreterPythonImpl::Locker;
 
+LLDB_PLUGIN_DEFINE(ScriptedProcessPythonInterface)
+
 ScriptedProcessPythonInterface::ScriptedProcessPythonInterface(
     ScriptInterpreterPythonImpl &interpreter)
     : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {}
@@ -208,4 +211,24 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetMetadata() {
   return dict;
 }
 
+void ScriptedProcessPythonInterface::Initialize() {
+  const std::vector<llvm::StringRef> ci_usages = {
+      "process attach -C <script-name> [-k key -v value ...]",
+      "process launch -C <script-name> [-k key -v value ...]"};
+  const std::vector<llvm::StringRef> api_usages = {
+      "SBAttachInfo.SetScriptedProcessClassName",
+      "SBAttachInfo.SetScriptedProcessDictionary",
+      "SBTarget.Attach",
+      "SBLaunchInfo.SetScriptedProcessClassName",
+      "SBLaunchInfo.SetScriptedProcessDictionary",
+      "SBTarget.Launch"};
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(), llvm::StringRef("Mock process state"),
+      CreateInstance, eScriptLanguagePython, ci_usages, api_usages);
+}
+
+void ScriptedProcessPythonInterface::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
 #endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h
index c75caa9340f25..8bfc3f2c0757c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.h
@@ -19,7 +19,8 @@
 
 namespace lldb_private {
 class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
-                                       public ScriptedPythonInterface {
+                                       public ScriptedPythonInterface,
+                                       public PluginInterface {
 public:
   ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter);
 
@@ -67,6 +68,16 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
 
   StructuredData::DictionarySP GetMetadata() override;
 
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() {
+    return "ScriptedProcessPythonInterface";
+  }
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
 private:
   lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
 };
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp
index f23858c01277c..05b7fbaa37af3 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp
@@ -18,11 +18,14 @@
 #include "../SWIGPythonBridge.h"
 #include "../ScriptInterpreterPythonImpl.h"
 #include "ScriptedThreadPlanPythonInterface.h"
+#include "lldb/Core/PluginManager.h"
 
 using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::python;
 
+LLDB_PLUGIN_DEFINE(ScriptedThreadPlanPythonInterface)
+
 ScriptedThreadPlanPythonInterface::ScriptedThreadPlanPythonInterface(
     ScriptInterpreterPythonImpl &interpreter)
     : ScriptedThreadPlanInterface(), ScriptedPythonInterface(interpreter) {}
@@ -102,4 +105,19 @@ ScriptedThreadPlanPythonInterface::GetStopDescription(lldb::StreamSP &stream) {
   return llvm::Error::success();
 }
 
+void ScriptedThreadPlanPythonInterface::Initialize() {
+  const std::vector<llvm::StringRef> ci_usages = {
+      "thread step-scripted -C <script-name> [-k key -v value ...]"};
+  const std::vector<llvm::StringRef> api_usages = {
+      "SBThread.StepUsingScriptedThreadPlan"};
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(),
+      llvm::StringRef("Alter thread stepping logic and stop reason"),
+      CreateInstance, eScriptLanguagePython, ci_usages, api_usages);
+}
+
+void ScriptedThreadPlanPythonInterface::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
 #endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h
index 6ec89b9f59253..4dc4607fb9c9d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h
@@ -19,7 +19,8 @@
 
 namespace lldb_private {
 class ScriptedThreadPlanPythonInterface : public ScriptedThreadPlanInterface,
-                                          public ScriptedPythonInterface {
+                                          public ScriptedPythonInterface,
+                                          public PluginInterface {
 public:
   ScriptedThreadPlanPythonInterface(ScriptInterpreterPythonImpl &interpreter);
 
@@ -41,6 +42,16 @@ class ScriptedThreadPlanPythonInterface : public ScriptedThreadPlanInterface,
   lldb::StateType GetRunState() override;
 
   llvm::Error GetStopDescription(lldb::StreamSP &stream) override;
+
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() {
+    return "ScriptedThreadPlanPythonInterface";
+  }
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
 };
 } // namespace lldb_private
 



More information about the lldb-commits mailing list