[Lldb-commits] [lldb] [lldb/script] Migrate ParsedCommand and raw class commands onto Scrip… (PR #210430)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Fri Jul 17 13:51:37 PDT 2026
https://github.com/medismailben created https://github.com/llvm/llvm-project/pull/210430
Give both `command script add -c` (raw class) and `-P` (ParsedCommand) a single, shared `ScriptedCommandInterface`/`ScriptedCommandPythonInterface`, since they are instantiated through the same `CreateScriptCommandObject`-style call path and already shared several ad-hoc methods verbatim (help text, repeat-command, flags, option/argument definitions). Add a lighter `ScriptedCommand` ABC template (`scripted_command.py`) for raw mode, keeping the existing `ParsedCommand`/`LLDBOptionValueParser` classes as-is.
The interface plugs into the existing `ScriptedPythonInterface` machinery: `CreatePluginObject` delegates to the base template so class resolution, argument-count relaxation, and abstract-method validation all go through the shared code path. `RunRawCommand`, `RunParsedCommand`, `GetRepeatCommand`, `HandleArgumentCompletion`, and `HandleOptionArgumentCompletion` resolve `__call__` and method by name on the implementor and dispatch inline using `SWIGBridge::ToSWIGWrapper` helpers, since their locker configuration (`InitSession`/`TearDownSession` and interactive-mode-conditional `NoSTDIN`) does not fit the base's generic `Dispatch<T>()`. This lets us delete the standalone SWIG bridge functions this plugin was the sole caller of.
Add a `Transform(lldb::DebuggerSP)` overload in `ScriptedPythonInterface` so that a `DebuggerSP` argument to `CreatePluginObject` gets wrapped in `SBDebugger` via `SWIGBridge::ToSWIGWrapper` on its way to the Python `__init__`. `ScriptedCommandPythonInterface` caches the `DebuggerSP` passed into `CreatePluginObject`, since `ScriptInterpreterPythonImpl` has no accessor for the debugger that owns it.
`CommandObjectScriptingObjectRaw` and `CommandObjectScriptingObjectParsed` now hold a `ScriptedCommandInterfaceSP` instead of a raw `StructuredData::GenericSP`, and `command script add`'s `DoExecute` constructs the interface once via
`CreateScriptedCommandInterface()->CreatePluginObject(...)` regardless of `-P` vs `-c`, handing it to whichever `CommandObject` subclass is chosen.
`command script add -f` (function-based raw commands) is unchanged: it already has a class-based alternative in `-c`, so there is no user-facing gap to migrate.
>From 6bdce549a6a71f761398a343538b77f9d4073b21 Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Fri, 17 Jul 2026 11:05:57 -0700
Subject: [PATCH] [lldb/script] Migrate ParsedCommand and raw class commands
onto ScriptedPythonInterface
Give both `command script add -c` (raw class) and `-P` (ParsedCommand) a
single, shared `ScriptedCommandInterface`/`ScriptedCommandPythonInterface`,
since they are instantiated through the same `CreateScriptCommandObject`-style
call path and already shared several ad-hoc methods verbatim (help text,
repeat-command, flags, option/argument definitions). Add a lighter
`ScriptedCommand` ABC template (`scripted_command.py`) for raw mode, keeping
the existing `ParsedCommand`/`LLDBOptionValueParser` classes as-is.
The interface plugs into the existing `ScriptedPythonInterface` machinery:
`CreatePluginObject` delegates to the base template so class resolution,
argument-count relaxation, and abstract-method validation all go through the
shared code path. `RunRawCommand`, `RunParsedCommand`, `GetRepeatCommand`,
`HandleArgumentCompletion`, and `HandleOptionArgumentCompletion` resolve
`__call__` and method by name on the implementor and dispatch inline using
`SWIGBridge::ToSWIGWrapper` helpers, since their locker configuration
(`InitSession`/`TearDownSession` and interactive-mode-conditional `NoSTDIN`)
does not fit the base's generic `Dispatch<T>()`. This lets us delete the
standalone SWIG bridge functions this plugin was the sole caller of.
Add a `Transform(lldb::DebuggerSP)` overload in `ScriptedPythonInterface` so
that a `DebuggerSP` argument to `CreatePluginObject` gets wrapped in
`SBDebugger` via `SWIGBridge::ToSWIGWrapper` on its way to the Python
`__init__`. `ScriptedCommandPythonInterface` caches the `DebuggerSP` passed
into `CreatePluginObject`, since `ScriptInterpreterPythonImpl` has no
accessor for the debugger that owns it.
`CommandObjectScriptingObjectRaw` and `CommandObjectScriptingObjectParsed`
now hold a `ScriptedCommandInterfaceSP` instead of a raw
`StructuredData::GenericSP`, and `command script add`'s `DoExecute`
constructs the interface once via
`CreateScriptedCommandInterface()->CreatePluginObject(...)` regardless of
`-P` vs `-c`, handing it to whichever `CommandObject` subclass is chosen.
`command script add -f` (function-based raw commands) is unchanged: it
already has a class-based alternative in `-c`, so there is no user-facing
gap to migrate.
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
lldb/bindings/python/CMakeLists.txt | 1 +
lldb/bindings/python/python-wrapper.swig | 158 ------
lldb/docs/CMakeLists.txt | 1 +
.../python/templates/scripted_command.py | 86 +++
.../Interfaces/ScriptedCommandInterface.h | 83 +++
.../lldb/Interpreter/ScriptInterpreter.h | 82 +--
lldb/include/lldb/lldb-enumerations.h | 4 +-
lldb/include/lldb/lldb-forward.h | 3 +
.../source/Commands/CommandObjectCommands.cpp | 198 +++----
lldb/source/Interpreter/ScriptInterpreter.cpp | 6 +
.../ScriptInterpreter/Python/CMakeLists.txt | 1 +
.../ScriptInterpreterPythonInterfaces.cpp | 2 +
.../ScriptInterpreterPythonInterfaces.h | 1 +
.../ScriptedCommandPythonInterface.cpp | 233 ++++++++
.../ScriptedCommandPythonInterface.h | 81 +++
.../Interfaces/ScriptedPythonInterface.cpp | 54 ++
.../Interfaces/ScriptedPythonInterface.h | 19 +
.../Python/SWIGPythonBridge.h | 29 -
.../Python/ScriptInterpreterPython.cpp | 503 +-----------------
.../Python/ScriptInterpreterPythonImpl.h | 52 +-
.../Python/PythonTestSuite.cpp | 41 --
21 files changed, 673 insertions(+), 965 deletions(-)
create mode 100644 lldb/examples/python/templates/scripted_command.py
create mode 100644 lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h
create mode 100644 lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.cpp
create mode 100644 lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.h
diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index d29b143c1408c..6ffdf9ccafabc 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -120,6 +120,7 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_breakpoint.py"
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_hook.py"
"${LLDB_SOURCE_DIR}/examples/python/templates/scripted_stackframe_recognizer.py"
+ "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_command.py"
)
if(APPLE)
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index 2392737402e20..971298d8e4c78 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -213,25 +213,6 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateSyntheticProv
return PythonObject();
}
-PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject(
- const char *python_class_name, const char *session_dictionary_name,
- lldb::DebuggerSP debugger_sp) {
- if (python_class_name == NULL || python_class_name[0] == '\0' ||
- !session_dictionary_name)
- return PythonObject();
-
- PyErr_Cleaner py_err_cleaner(true);
- auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(
- session_dictionary_name);
- auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
- python_class_name, dict);
-
- if (!pfunc.IsAllocated())
- return PythonObject();
-
- return pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger_sp)), dict);
-}
-
// wrapper that calls an optional instance member of an object taking no
// arguments
static PyObject *LLDBSwigPython_CallOptionalMember(
@@ -639,145 +620,6 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommand(
return true;
}
-bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommandObject(
- PyObject *implementor, lldb::DebuggerSP debugger, const char *args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp) {
-
- PyErr_Cleaner py_err_cleaner(true);
-
- PythonObject self(PyRefType::Borrowed, implementor);
- auto pfunc = self.ResolveName<PythonCallable>("__call__");
-
- if (!pfunc.IsAllocated())
- return false;
-
- auto cmd_retobj_arg = SWIGBridge::ToSWIGWrapper(cmd_retobj);
-
- pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), PythonString(args),
- SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp), cmd_retobj_arg.obj());
-
- return true;
-}
-
-std::optional<std::string>
-lldb_private::python::SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor,
- std::string &command) {
- PyErr_Cleaner py_err_cleaner(true);
-
- PythonObject self(PyRefType::Borrowed, implementor);
- auto pfunc = self.ResolveName<PythonCallable>("get_repeat_command");
- // If not implemented, repeat the exact command.
- if (!pfunc.IsAllocated())
- return std::nullopt;
-
- PythonString command_str(command);
- PythonObject result = pfunc(command_str);
-
- // A return of None is the equivalent of nullopt - means repeat
- // the command as is:
- if (result.IsNone())
- return std::nullopt;
-
- return result.Str().GetString().str();
-}
-
-StructuredData::DictionarySP
-lldb_private::python::SWIGBridge::LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(PyObject *implementor,
- std::vector<llvm::StringRef> &args_vec, size_t args_pos, size_t pos_in_arg) {
-
- PyErr_Cleaner py_err_cleaner(true);
-
- PythonObject self(PyRefType::Borrowed, implementor);
- auto pfunc = self.ResolveName<PythonCallable>("handle_argument_completion");
- // If this isn't implemented, return an empty dict to signal falling back to default completion:
- if (!pfunc.IsAllocated())
- return {};
-
- PythonList args_list(PyInitialValue::Empty);
- for (auto elem : args_vec)
- args_list.AppendItem(PythonString(elem));
-
- PythonObject result = pfunc(args_list, PythonInteger(args_pos), PythonInteger(pos_in_arg));
- // Returning None means do the ordinary completion
- if (result.IsNone())
- return {};
-
- // Convert the return dictionary to a DictionarySP.
- StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
- if (!result_obj_sp)
- return {};
-
- StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(result_obj_sp));
- if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
- return {};
- return dict_sp;
-}
-
-StructuredData::DictionarySP
-lldb_private::python::SWIGBridge::LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(PyObject *implementor,
- llvm::StringRef &long_option, size_t pos_in_arg) {
-
- PyErr_Cleaner py_err_cleaner(true);
-
- PythonObject self(PyRefType::Borrowed, implementor);
- auto pfunc = self.ResolveName<PythonCallable>("handle_option_argument_completion");
- // If this isn't implemented, return an empty dict to signal falling back to default completion:
- if (!pfunc.IsAllocated())
- return {};
-
- PythonObject result = pfunc(PythonString(long_option), PythonInteger(pos_in_arg));
- // Returning None means do the ordinary completion
- if (result.IsNone())
- return {};
-
- // Returning a boolean:
- // True means the completion was handled, but there were no completions
- // False means that the completion was not handled, again, do the ordinary completion:
- if (result.GetObjectType() == PyObjectType::Boolean) {
- if (!result.IsTrue())
- return {};
- // Make up a completion dictionary with the right element:
- StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary());
- dict_sp->AddBooleanItem("no-completion", true);
- return dict_sp;
- }
-
-
- // Convert the return dictionary to a DictionarySP.
- StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
- if (!result_obj_sp)
- return {};
-
- StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(result_obj_sp));
- if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
- return {};
- return dict_sp;
-}
-
-#include "lldb/Interpreter/CommandReturnObject.h"
-
-bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject(
- PyObject *implementor, lldb::DebuggerSP debugger, lldb_private::StructuredDataImpl &args_impl,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp) {
-
- PyErr_Cleaner py_err_cleaner(true);
-
- PythonObject self(PyRefType::Borrowed, implementor);
- auto pfunc = self.ResolveName<PythonCallable>("__call__");
-
- if (!pfunc.IsAllocated()) {
- cmd_retobj.AppendError("Could not find '__call__' method in implementation class");
- return false;
- }
-
- pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), SWIGBridge::ToSWIGWrapper(args_impl),
- SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp), SWIGBridge::ToSWIGWrapper(cmd_retobj).obj());
-
- return true;
-}
-
PythonObject lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin(
const char *python_class_name, const char *session_dictionary_name,
const lldb::ProcessSP &process_sp) {
diff --git a/lldb/docs/CMakeLists.txt b/lldb/docs/CMakeLists.txt
index dd091836dc1aa..53647990f7842 100644
--- a/lldb/docs/CMakeLists.txt
+++ b/lldb/docs/CMakeLists.txt
@@ -33,6 +33,7 @@ if (LLDB_ENABLE_PYTHON AND SPHINX_FOUND)
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_breakpoint.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_hook.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_stackframe_recognizer.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
+ COMMAND "${CMAKE_COMMAND}" -E copy "${LLDB_SOURCE_DIR}/examples/python/templates/scripted_command.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/plugins/"
COMMENT "Copying lldb.py to pretend its a Python package.")
add_dependencies(lldb-python-doc-package swig_wrapper_python)
diff --git a/lldb/examples/python/templates/scripted_command.py b/lldb/examples/python/templates/scripted_command.py
new file mode 100644
index 0000000000000..d9b18ea4376aa
--- /dev/null
+++ b/lldb/examples/python/templates/scripted_command.py
@@ -0,0 +1,86 @@
+from abc import ABCMeta, abstractmethod
+from typing import Optional
+
+import lldb
+
+
+class ScriptedCommand(metaclass=ABCMeta):
+ """
+ The base class for a scripted (raw) command.
+
+ A raw command receives the unparsed argument string exactly as the user
+ typed it, and is responsible for any parsing it needs. For a command
+ with a table-driven option/argument parser, see `ParsedCommand` instead.
+ Register it with `command script add -c <ClassName> ...`.
+
+ Most of the base class methods are `@abstractmethod` that need to be
+ overwritten by the inheriting class.
+ """
+
+ def __init__(self, debugger: lldb.SBDebugger):
+ """Construct a scripted command.
+
+ Args:
+ debugger (lldb.SBDebugger): The debugger this command is being
+ added to.
+ """
+ pass
+
+ @abstractmethod
+ def __call__(
+ self,
+ debugger: lldb.SBDebugger,
+ args: str,
+ exe_ctx: lldb.SBExecutionContext,
+ result: lldb.SBCommandReturnObject,
+ ) -> None:
+ """Execute the command.
+
+ Args:
+ debugger (lldb.SBDebugger): The debugger the command runs
+ against.
+ args (str): The raw, unparsed argument string.
+ exe_ctx (lldb.SBExecutionContext): The execution context.
+ result (lldb.SBCommandReturnObject): Write command output/errors
+ here.
+ """
+ pass
+
+ def get_short_help(self) -> Optional[str]:
+ """A one-line description shown by `help`.
+
+ Returns:
+ str: The short help string.
+ """
+ pass
+
+ def get_long_help(self) -> Optional[str]:
+ """The full help text shown by `help <command>`.
+
+ Returns:
+ str: The long help string.
+ """
+ pass
+
+ def get_flags(self) -> int:
+ """Command flags (a bitmask of `lldb.eCommandRequires*`/
+ `lldb.eCommandProcessMustBe*` etc.) controlling when this command is
+ available.
+
+ Returns:
+ int: The flags bitmask. Defaults to 0 (no restrictions).
+ """
+ return 0
+
+ def get_repeat_command(self, command: str) -> Optional[str]:
+ """Customize what runs when the user presses Enter to repeat this
+ command.
+
+ Args:
+ command (str): The command line that was run.
+
+ Returns:
+ str: The command line to run on repeat. Defaults to `None`,
+ meaning repeat the original command unmodified.
+ """
+ pass
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h
new file mode 100644
index 0000000000000..a302c8d766eb9
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDCOMMANDINTERFACE_H
+#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDCOMMANDINTERFACE_H
+
+#include "ScriptedInterface.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+/// Interface for a scripted command, covering both the raw (`command script
+/// add -c`, `__call__(debugger, args, exe_ctx, result)`) and parsed
+/// (`command script add -P`, option/argument table driven) calling
+/// conventions. Both are instantiated through the same Python class lookup,
+/// and differ only in which of RunRawCommand/RunParsedCommand gets called.
+class ScriptedCommandInterface : virtual public ScriptedInterface {
+public:
+ virtual llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name,
+ lldb::DebuggerSP debugger_sp) = 0;
+
+ virtual bool RunRawCommand(llvm::StringRef args,
+ ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) {
+ return false;
+ }
+
+ virtual bool RunParsedCommand(Args &args,
+ ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) {
+ return false;
+ }
+
+ virtual std::optional<std::string> GetRepeatCommand(Args &args) {
+ return std::nullopt;
+ }
+
+ virtual StructuredData::DictionarySP
+ HandleArgumentCompletion(std::vector<llvm::StringRef> &args, size_t args_pos,
+ size_t char_in_arg) {
+ return {};
+ }
+
+ virtual StructuredData::DictionarySP
+ HandleOptionArgumentCompletion(llvm::StringRef &long_option,
+ size_t char_in_arg) {
+ return {};
+ }
+
+ virtual bool GetShortHelp(std::string &dest) {
+ dest.clear();
+ return false;
+ }
+
+ virtual bool GetLongHelp(std::string &dest) {
+ dest.clear();
+ return false;
+ }
+
+ virtual uint32_t GetFlags() { return 0; }
+
+ virtual StructuredData::ObjectSP GetOptionsDefinition() { return {}; }
+
+ virtual StructuredData::ObjectSP GetArgumentsDefinition() { return {}; }
+
+ virtual void OptionParsingStarted() {}
+
+ virtual bool SetOptionValue(ExecutionContext *exe_ctx,
+ llvm::StringRef long_option,
+ llvm::StringRef value) {
+ return false;
+ }
+};
+} // namespace lldb_private
+
+#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDCOMMANDINTERFACE_H
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 122e779bf0279..ebb0e8b310388 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -243,11 +243,6 @@ class ScriptInterpreter : public PluginInterface {
return StructuredData::ObjectSP();
}
- virtual StructuredData::GenericSP
- CreateScriptCommandObject(const char *class_name) {
- return StructuredData::GenericSP();
- }
-
virtual StructuredData::ObjectSP
LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
return StructuredData::ObjectSP();
@@ -374,42 +369,6 @@ class ScriptInterpreter : public PluginInterface {
return false;
}
- virtual bool RunScriptBasedCommand(
- StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,
- ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Status &error,
- const lldb_private::ExecutionContext &exe_ctx) {
- return false;
- }
-
- virtual bool RunScriptBasedParsedCommand(
- StructuredData::GenericSP impl_obj_sp, Args& args,
- ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Status &error,
- const lldb_private::ExecutionContext &exe_ctx) {
- return false;
- }
-
- virtual std::optional<std::string>
- GetRepeatCommandForScriptedCommand(StructuredData::GenericSP impl_obj_sp,
- Args &args) {
- return std::nullopt;
- }
-
- virtual StructuredData::DictionarySP
- HandleArgumentCompletionForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, std::vector<llvm::StringRef> &args,
- size_t args_pos, size_t char_in_arg) {
- return {};
- }
-
- virtual StructuredData::DictionarySP
- HandleOptionArgumentCompletionForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, llvm::StringRef &long_name,
- size_t char_in_arg) {
- return {};
- }
-
virtual bool RunScriptFormatKeyword(const char *impl_function,
Process *process, std::string &output,
Status &error) {
@@ -448,43 +407,6 @@ class ScriptInterpreter : public PluginInterface {
return false;
}
- virtual bool
- GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
- std::string &dest) {
- dest.clear();
- return false;
- }
-
- virtual StructuredData::ObjectSP
- GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
- return {};
- }
-
- virtual StructuredData::ObjectSP
- GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
- return {};
- }
-
- virtual bool SetOptionValueForCommandObject(
- StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx,
- llvm::StringRef long_option, llvm::StringRef value) {
- return false;
- }
-
- virtual void
- OptionParsingStartedForCommandObject(StructuredData::GenericSP cmd_obj_sp) {}
-
- virtual uint32_t
- GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
- return 0;
- }
-
- virtual bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
- std::string &dest) {
- dest.clear();
- return false;
- }
-
virtual bool CheckObjectExists(const char *name) { return false; }
virtual bool
@@ -561,6 +483,10 @@ class ScriptInterpreter : public PluginInterface {
return {};
}
+ virtual lldb::ScriptedCommandInterfaceSP CreateScriptedCommandInterface() {
+ return {};
+ }
+
virtual StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) {
return {};
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 93c252b55de99..f73d0085f2320 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -268,7 +268,9 @@ enum ScriptedExtension {
eScriptedExtensionScriptedThread,
eScriptedExtensionScriptedFrame,
eScriptedExtensionScriptedStackFrameRecognizer,
- kLastScriptedExtension = eScriptedExtensionScriptedStackFrameRecognizer
+ eScriptedExtensionScriptedCommand,
+ eScriptedExtensionParsedCommand,
+ kLastScriptedExtension = eScriptedExtensionParsedCommand
};
/// Register numbering types.
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 157aa5743f016..2572aa0dc344b 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -193,6 +193,7 @@ class ScriptedFrameInterface;
class ScriptedFrameProviderInterface;
class ScriptedMetadata;
class ScriptedBreakpointInterface;
+class ScriptedCommandInterface;
class ScriptedHookInterface;
class ScriptedPlatformInterface;
class ScriptedProcessInterface;
@@ -438,6 +439,8 @@ typedef std::shared_ptr<lldb_private::ScriptedBreakpointInterface>
ScriptedBreakpointInterfaceSP;
typedef std::shared_ptr<lldb_private::ScriptedStackFrameRecognizerInterface>
ScriptedStackFrameRecognizerInterfaceSP;
+typedef std::shared_ptr<lldb_private::ScriptedCommandInterface>
+ ScriptedCommandInterfaceSP;
typedef std::shared_ptr<lldb_private::Section> SectionSP;
typedef std::unique_ptr<lldb_private::SectionList> SectionListUP;
typedef std::weak_ptr<lldb_private::Section> SectionWP;
diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp
index 8f006768ecc9a..d59de4d980803 100644
--- a/lldb/source/Commands/CommandObjectCommands.cpp
+++ b/lldb/source/Commands/CommandObjectCommands.cpp
@@ -16,6 +16,7 @@
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Interfaces/ScriptedCommandInterface.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionValueBoolean.h"
#include "lldb/Interpreter/OptionValueString.h"
@@ -1119,19 +1120,19 @@ class CommandObjectPythonFunction : public CommandObjectRaw {
/// substitution).
class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
public:
- CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter,
- std::string name,
- StructuredData::GenericSP cmd_obj_sp,
- ScriptedCommandSynchronicity synch,
- CompletionType completion_type)
- : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp),
- m_synchro(synch), m_fetched_help_short(false),
- m_fetched_help_long(false), m_completion_type(completion_type) {
+ CommandObjectScriptingObjectRaw(
+ CommandInterpreter &interpreter, std::string name,
+ lldb::ScriptedCommandInterfaceSP cmd_interface_sp,
+ ScriptedCommandSynchronicity synch, CompletionType completion_type)
+ : CommandObjectRaw(interpreter, name),
+ m_cmd_interface_sp(cmd_interface_sp), m_synchro(synch),
+ m_fetched_help_short(false), m_fetched_help_long(false),
+ m_completion_type(completion_type) {
StreamString stream;
stream.Printf("For more information run 'help %s'", name.c_str());
SetHelp(stream.GetString());
- if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter())
- GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
+ if (m_cmd_interface_sp)
+ GetFlags().Set(m_cmd_interface_sp->GetFlags());
}
~CommandObjectScriptingObjectRaw() override = default;
@@ -1151,22 +1152,19 @@ class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
std::optional<std::string> GetRepeatCommand(Args &args,
uint32_t index) override {
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter)
+ if (!m_cmd_interface_sp)
return std::nullopt;
- return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
+ return m_cmd_interface_sp->GetRepeatCommand(args);
}
llvm::StringRef GetHelp() override {
if (m_fetched_help_short)
return CommandObjectRaw::GetHelp();
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter)
+ if (!m_cmd_interface_sp)
return CommandObjectRaw::GetHelp();
std::string docstring;
- m_fetched_help_short =
- scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
+ m_fetched_help_short = m_cmd_interface_sp->GetShortHelp(docstring);
if (!docstring.empty())
SetHelp(docstring);
@@ -1177,13 +1175,11 @@ class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
if (m_fetched_help_long)
return CommandObjectRaw::GetHelpLong();
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter)
+ if (!m_cmd_interface_sp)
return CommandObjectRaw::GetHelpLong();
std::string docstring;
- m_fetched_help_long =
- scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
+ m_fetched_help_long = m_cmd_interface_sp->GetLongHelp(docstring);
if (!docstring.empty())
SetHelpLong(docstring);
return CommandObjectRaw::GetHelpLong();
@@ -1192,15 +1188,13 @@ class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
protected:
void DoExecute(llvm::StringRef raw_command_line,
CommandReturnObject &result) override {
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
-
Status error;
result.SetStatus(eReturnStatusInvalid);
- if (!scripter ||
- !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line,
- m_synchro, result, error, m_exe_ctx)) {
+ if (!m_cmd_interface_sp ||
+ !m_cmd_interface_sp->RunRawCommand(raw_command_line, m_synchro, result,
+ error, m_exe_ctx)) {
result.AppendError(error.AsCString());
} else {
// Don't change the status if the command already set it...
@@ -1214,7 +1208,7 @@ class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
}
private:
- StructuredData::GenericSP m_cmd_obj_sp;
+ lldb::ScriptedCommandInterfaceSP m_cmd_interface_sp;
ScriptedCommandSynchronicity m_synchro;
bool m_fetched_help_short : 1;
bool m_fetched_help_long : 1;
@@ -1238,23 +1232,16 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
private:
class CommandOptions : public Options {
public:
- CommandOptions(CommandInterpreter &interpreter,
- StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter),
- m_cmd_obj_sp(cmd_obj_sp) {}
+ CommandOptions(CommandInterpreter &interpreter,
+ lldb::ScriptedCommandInterfaceSP cmd_interface_sp)
+ : m_interpreter(interpreter), m_cmd_interface_sp(cmd_interface_sp) {}
~CommandOptions() override = default;
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) override {
Status error;
- ScriptInterpreter *scripter =
- m_interpreter.GetDebugger().GetScriptInterpreter();
- if (!scripter) {
- return Status::FromErrorString(
- "No script interpreter for SetOptionValue.");
- return error;
- }
- if (!m_cmd_obj_sp) {
+ if (!m_cmd_interface_sp) {
return Status::FromErrorString(
"SetOptionValue called with empty cmd_obj.");
return error;
@@ -1268,10 +1255,10 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
// Pass the long option, since you aren't actually required to have a
// short_option, and for those options the index or short option character
// aren't meaningful on the python side.
- const char * long_option =
- m_options_definition_up.get()[option_idx].long_option;
- bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp,
- execution_context, long_option, option_arg);
+ const char *long_option =
+ m_options_definition_up.get()[option_idx].long_option;
+ bool success = m_cmd_interface_sp->SetOptionValue(
+ execution_context, long_option, option_arg);
if (!success)
return Status::FromErrorStringWithFormatv(
"Error setting option: {0} to {1}", long_option, option_arg);
@@ -1279,12 +1266,10 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
}
void OptionParsingStarting(ExecutionContext *execution_context) override {
- ScriptInterpreter *scripter =
- m_interpreter.GetDebugger().GetScriptInterpreter();
- if (!scripter || !m_cmd_obj_sp)
+ if (!m_cmd_interface_sp)
return;
- scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp);
+ m_cmd_interface_sp->OptionParsingStarted();
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -1292,7 +1277,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
return {};
return llvm::ArrayRef(m_options_definition_up.get(), m_num_options);
}
-
+
static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp,
size_t counter, uint32_t &usage_mask) {
// If the usage entry is not provided, we use LLDB_OPT_SET_ALL.
@@ -1726,10 +1711,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
OptionElementVector &option_vec,
int opt_element_index,
CommandInterpreter &interpreter) override {
- ScriptInterpreter *scripter =
- interpreter.GetDebugger().GetScriptInterpreter();
-
- if (!scripter)
+ if (!m_cmd_interface_sp)
return;
ExecutionContext exe_ctx = interpreter.GetExecutionContext();
@@ -1746,9 +1728,8 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
// regular option completer handle that:
StructuredData::DictionarySP completion_dict_sp;
if (!is_enum)
- completion_dict_sp =
- scripter->HandleOptionArgumentCompletionForScriptedCommand(
- m_cmd_obj_sp, option_name, request.GetCursorCharPos());
+ completion_dict_sp = m_cmd_interface_sp->HandleOptionArgumentCompletion(
+ option_name, request.GetCursorCharPos());
if (!completion_dict_sp) {
Options::HandleOptionArgumentCompletion(request, option_vec,
@@ -1810,18 +1791,17 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
std::vector<std::vector<OptionEnumValueElement>> m_enum_vector;
std::vector<std::string> m_usage_container;
CommandInterpreter &m_interpreter;
- StructuredData::GenericSP m_cmd_obj_sp;
+ lldb::ScriptedCommandInterfaceSP m_cmd_interface_sp;
static std::unordered_set<std::string> g_string_storer;
};
public:
- static CommandObjectSP Create(CommandInterpreter &interpreter,
- std::string name,
- StructuredData::GenericSP cmd_obj_sp,
- ScriptedCommandSynchronicity synch,
- CommandReturnObject &result) {
+ static CommandObjectSP
+ Create(CommandInterpreter &interpreter, std::string name,
+ lldb::ScriptedCommandInterfaceSP cmd_interface_sp,
+ ScriptedCommandSynchronicity synch, CommandReturnObject &result) {
CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed(
- interpreter, name, cmd_obj_sp, synch));
+ interpreter, name, cmd_interface_sp, synch));
CommandObjectScriptingObjectParsed *parsed_cmd
= static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get());
@@ -1843,34 +1823,33 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
return new_cmd_sp;
}
- CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter,
- std::string name,
- StructuredData::GenericSP cmd_obj_sp,
- ScriptedCommandSynchronicity synch)
- : CommandObjectParsed(interpreter, name.c_str()),
- m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch),
- m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false),
+ CommandObjectScriptingObjectParsed(
+ CommandInterpreter &interpreter, std::string name,
+ lldb::ScriptedCommandInterfaceSP cmd_interface_sp,
+ ScriptedCommandSynchronicity synch)
+ : CommandObjectParsed(interpreter, name.c_str()),
+ m_cmd_interface_sp(cmd_interface_sp), m_synchro(synch),
+ m_options(interpreter, cmd_interface_sp), m_fetched_help_short(false),
m_fetched_help_long(false) {
StreamString stream;
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter) {
+ if (!m_cmd_interface_sp) {
m_options_error = Status::FromErrorString("No script interpreter");
return;
}
// Set the flags:
- GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
+ GetFlags().Set(m_cmd_interface_sp->GetFlags());
// Now set up the options definitions from the options:
- StructuredData::ObjectSP options_object_sp
- = scripter->GetOptionsForCommandObject(cmd_obj_sp);
+ StructuredData::ObjectSP options_object_sp =
+ m_cmd_interface_sp->GetOptionsDefinition();
// It's okay not to have an options dict.
if (options_object_sp) {
// The options come as a dictionary of dictionaries. The key of the
// outer dict is the long option name (since that's required). The
// value holds all the other option specification bits.
- StructuredData::Dictionary *options_dict
- = options_object_sp->GetAsDictionary();
+ StructuredData::Dictionary *options_dict =
+ options_object_sp->GetAsDictionary();
// but if it exists, it has to be an array.
if (options_dict) {
m_options_error = m_options.SetOptionsFromArray(*(options_dict));
@@ -1884,8 +1863,8 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
}
// Then fetch the args. Since the arguments can have usage masks you need
// an array of arrays.
- StructuredData::ObjectSP args_object_sp
- = scripter->GetArgumentsForCommandObject(cmd_obj_sp);
+ StructuredData::ObjectSP args_object_sp =
+ m_cmd_interface_sp->GetArgumentsDefinition();
if (args_object_sp) {
StructuredData::Array *args_array = args_object_sp->GetAsArray();
if (!args_array) {
@@ -2017,9 +1996,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
public:
void HandleArgumentCompletion(CompletionRequest &request,
OptionElementVector &option_vec) override {
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
-
- if (!scripter)
+ if (!m_cmd_interface_sp)
return;
// Set up the options values on the scripted side:
@@ -2057,8 +2034,8 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
args_elem_pos--;
}
StructuredData::DictionarySP completion_dict_sp =
- scripter->HandleArgumentCompletionForScriptedCommand(
- m_cmd_obj_sp, args_vec, args_elem_pos, request.GetCursorCharPos());
+ m_cmd_interface_sp->HandleArgumentCompletion(
+ args_vec, args_elem_pos, request.GetCursorCharPos());
if (!completion_dict_sp) {
CommandObject::HandleArgumentCompletion(request, option_vec);
@@ -2074,22 +2051,19 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
std::optional<std::string> GetRepeatCommand(Args &args,
uint32_t index) override {
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter)
+ if (!m_cmd_interface_sp)
return std::nullopt;
- return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args);
+ return m_cmd_interface_sp->GetRepeatCommand(args);
}
llvm::StringRef GetHelp() override {
if (m_fetched_help_short)
return CommandObjectParsed::GetHelp();
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter)
+ if (!m_cmd_interface_sp)
return CommandObjectParsed::GetHelp();
std::string docstring;
- m_fetched_help_short =
- scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring);
+ m_fetched_help_short = m_cmd_interface_sp->GetShortHelp(docstring);
if (!docstring.empty())
SetHelp(docstring);
@@ -2100,13 +2074,11 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
if (m_fetched_help_long)
return CommandObjectParsed::GetHelpLong();
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
- if (!scripter)
+ if (!m_cmd_interface_sp)
return CommandObjectParsed::GetHelpLong();
std::string docstring;
- m_fetched_help_long =
- scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring);
+ m_fetched_help_long = m_cmd_interface_sp->GetLongHelp(docstring);
if (!docstring.empty())
SetHelpLong(docstring);
return CommandObjectParsed::GetHelpLong();
@@ -2121,17 +2093,13 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
}
protected:
- void DoExecute(Args &args,
- CommandReturnObject &result) override {
- ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
-
+ void DoExecute(Args &args, CommandReturnObject &result) override {
Status error;
result.SetStatus(eReturnStatusInvalid);
-
- if (!scripter ||
- !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args,
- m_synchro, result, error, m_exe_ctx)) {
+
+ if (!m_cmd_interface_sp || !m_cmd_interface_sp->RunParsedCommand(
+ args, m_synchro, result, error, m_exe_ctx)) {
result.AppendError(error.AsCString());
} else {
// Don't change the status if the command already set it...
@@ -2145,7 +2113,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
}
private:
- StructuredData::GenericSP m_cmd_obj_sp;
+ lldb::ScriptedCommandInterfaceSP m_cmd_interface_sp;
ScriptedCommandSynchronicity m_synchro;
CommandOptions m_options;
Status m_options_error;
@@ -2513,22 +2481,32 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
return;
}
- auto cmd_obj_sp = interpreter->CreateScriptCommandObject(
- m_options.m_class_name.c_str());
- if (!cmd_obj_sp) {
+ lldb::ScriptedCommandInterfaceSP cmd_interface_sp =
+ interpreter->CreateScriptedCommandInterface();
+ if (!cmd_interface_sp) {
+ result.AppendError("cannot create ScriptedCommandInterface");
+ return;
+ }
+
+ auto obj_or_err = cmd_interface_sp->CreatePluginObject(
+ m_options.m_class_name, GetDebugger().shared_from_this());
+ if (!obj_or_err) {
result.AppendErrorWithFormatv("cannot create helper object for: "
- "'{0}'", m_options.m_class_name);
+ "'{0}': {1}",
+ m_options.m_class_name,
+ llvm::toString(obj_or_err.takeError()));
return;
}
-
+
if (m_options.m_parsed_command) {
- new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter,
- m_cmd_name, cmd_obj_sp, m_synchronicity, result);
+ new_cmd_sp = CommandObjectScriptingObjectParsed::Create(
+ m_interpreter, m_cmd_name, cmd_interface_sp, m_synchronicity,
+ result);
if (!result.Succeeded())
return;
} else
new_cmd_sp = std::make_shared<CommandObjectScriptingObjectRaw>(
- m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity,
+ m_interpreter, m_cmd_name, cmd_interface_sp, m_synchronicity,
m_completion_type);
}
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 6436d8161583d..68bcdd0b039f4 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -214,6 +214,10 @@ ScriptInterpreter::ExtensionToString(lldb::ScriptedExtension extension) {
return "ScriptedFrame";
case eScriptedExtensionScriptedStackFrameRecognizer:
return "ScriptedStackFrameRecognizer";
+ case eScriptedExtensionScriptedCommand:
+ return "ScriptedCommand";
+ case eScriptedExtensionParsedCommand:
+ return "ParsedCommand";
}
llvm_unreachable("unhandled ScriptedExtension");
}
@@ -234,6 +238,8 @@ ScriptInterpreter::StringToExtension(llvm::StringRef string) {
.CaseLower("ScriptedFrame", eScriptedExtensionScriptedFrame)
.CaseLower("ScriptedStackFrameRecognizer",
eScriptedExtensionScriptedStackFrameRecognizer)
+ .CaseLower("ScriptedCommand", eScriptedExtensionScriptedCommand)
+ .CaseLower("ParsedCommand", eScriptedExtensionParsedCommand)
.Default(eScriptedExtensionInvalid);
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 201574da72a19..d3dc5773eb0af 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -32,6 +32,7 @@ set(python_plugin_sources
Interfaces/ScriptedPythonInterface.cpp
Interfaces/ScriptedHookPythonInterface.cpp
Interfaces/ScriptedBreakpointPythonInterface.cpp
+ Interfaces/ScriptedCommandPythonInterface.cpp
Interfaces/ScriptedStackFrameRecognizerPythonInterface.cpp
Interfaces/ScriptedThreadPlanPythonInterface.cpp
Interfaces/ScriptedThreadPythonInterface.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
index 8914f6b239023..2c8e0ef8bbeb0 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
@@ -30,6 +30,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
ScriptedThreadPythonInterface::Initialize();
ScriptedFramePythonInterface::Initialize();
ScriptedStackFrameRecognizerPythonInterface::Initialize();
+ ScriptedCommandPythonInterface::Initialize();
}
void ScriptInterpreterPythonInterfaces::Terminate() {
@@ -43,4 +44,5 @@ void ScriptInterpreterPythonInterfaces::Terminate() {
ScriptedThreadPythonInterface::Terminate();
ScriptedFramePythonInterface::Terminate();
ScriptedStackFrameRecognizerPythonInterface::Terminate();
+ ScriptedCommandPythonInterface::Terminate();
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 03d747e63a592..7ddf7ec0e5ae5 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -14,6 +14,7 @@
#include "OperatingSystemPythonInterface.h"
#include "ScriptedBreakpointPythonInterface.h"
+#include "ScriptedCommandPythonInterface.h"
#include "ScriptedFrameProviderPythonInterface.h"
#include "ScriptedFramePythonInterface.h"
#include "ScriptedHookPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.cpp
new file mode 100644
index 0000000000000..da2b869ccf934
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.cpp
@@ -0,0 +1,233 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../lldb-python.h"
+
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "../SWIGPythonBridge.h"
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedCommandPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedCommandPythonInterface::ScriptedCommandPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedCommandInterface(), ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedCommandPythonInterface::CreatePluginObject(
+ llvm::StringRef class_name, lldb::DebuggerSP debugger_sp) {
+ if (class_name.empty())
+ return llvm::createStringError("empty class name");
+
+ if (!debugger_sp)
+ return llvm::createStringError("invalid Debugger pointer");
+
+ m_debugger_sp = debugger_sp;
+ ScriptedMetadata scripted_metadata(class_name,
+ StructuredData::DictionarySP());
+ return ScriptedPythonInterface::CreatePluginObject(
+ scripted_metadata, /*script_obj=*/nullptr, debugger_sp);
+}
+
+bool ScriptedCommandPythonInterface::RunRawCommand(
+ llvm::StringRef args, ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) {
+ if (!m_object_instance_sp || !m_object_instance_sp->IsValid()) {
+ error = Status::FromErrorString("no function to execute");
+ return false;
+ }
+
+ lldb::DebuggerSP debugger_sp = m_debugger_sp;
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
+
+ if (!debugger_sp) {
+ error = Status::FromErrorString("invalid Debugger pointer");
+ return false;
+ }
+
+ // Outer Locker sets up the session (with conditional NoSTDIN for
+ // interactive commands and TearDownSession on exit) that Dispatch's inner
+ // Locker doesn't provide. Nested locks are safe.
+ Locker py_lock(&m_interpreter,
+ Locker::AcquireLock | Locker::InitSession |
+ (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN),
+ Locker::FreeLock | Locker::TearDownSession);
+ ScriptInterpreterPythonImpl::SynchronicityHandler synch_handler(
+ debugger_sp, synchronicity);
+
+ auto cmd_retobj_arg = SWIGBridge::ToSWIGWrapper(cmd_retobj);
+ Dispatch<StructuredData::ObjectSP>("__call__", error, debugger_sp, args,
+ exe_ctx_ref_sp, cmd_retobj_arg.obj());
+
+ if (cmd_retobj.GetStatus() == eReturnStatusFailed)
+ return false;
+
+ error.Clear();
+ return true;
+}
+
+bool ScriptedCommandPythonInterface::RunParsedCommand(
+ Args &args, ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) {
+ if (!m_object_instance_sp || !m_object_instance_sp->IsValid()) {
+ error = Status::FromErrorString("no function to execute");
+ return false;
+ }
+
+ lldb::DebuggerSP debugger_sp = m_debugger_sp;
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
+
+ if (!debugger_sp) {
+ error = Status::FromErrorString("invalid Debugger pointer");
+ return false;
+ }
+
+ Locker py_lock(&m_interpreter,
+ Locker::AcquireLock | Locker::InitSession |
+ (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN),
+ Locker::FreeLock | Locker::TearDownSession);
+ ScriptInterpreterPythonImpl::SynchronicityHandler synch_handler(
+ debugger_sp, synchronicity);
+
+ StructuredData::ArraySP args_arr_sp(new StructuredData::Array());
+ for (const Args::ArgEntry &entry : args)
+ args_arr_sp->AddStringItem(entry.ref());
+ StructuredDataImpl args_impl(args_arr_sp);
+
+ auto cmd_retobj_arg = SWIGBridge::ToSWIGWrapper(cmd_retobj);
+ Dispatch<StructuredData::ObjectSP>("__call__", error, debugger_sp, args_impl,
+ exe_ctx_ref_sp, cmd_retobj_arg.obj());
+
+ if (cmd_retobj.GetStatus() == eReturnStatusFailed)
+ return false;
+
+ error.Clear();
+ return true;
+}
+
+std::optional<std::string>
+ScriptedCommandPythonInterface::GetRepeatCommand(Args &args) {
+ std::string command;
+ args.GetQuotedCommandString(command);
+ Status error;
+ return Dispatch<std::optional<std::string>>("get_repeat_command", error,
+ llvm::StringRef(command));
+}
+
+StructuredData::DictionarySP
+ScriptedCommandPythonInterface::HandleArgumentCompletion(
+ std::vector<llvm::StringRef> &args, size_t args_pos, size_t char_in_arg) {
+ Status error;
+ return Dispatch<StructuredData::DictionarySP>(
+ "handle_argument_completion", error, args, args_pos, char_in_arg);
+}
+
+StructuredData::DictionarySP
+ScriptedCommandPythonInterface::HandleOptionArgumentCompletion(
+ llvm::StringRef &long_option, size_t char_in_arg) {
+ Status error;
+ StructuredData::ObjectSP result_sp = Dispatch<StructuredData::ObjectSP>(
+ "handle_option_argument_completion", error, long_option, char_in_arg);
+ if (!result_sp)
+ return {};
+
+ // A boolean return means: True → completion handled but no completions;
+ // False → completion not handled (fall back to default).
+ if (result_sp->GetType() == lldb::eStructuredDataTypeBoolean) {
+ if (!result_sp->GetBooleanValue())
+ return {};
+ StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary());
+ dict_sp->AddBooleanItem("no-completion", true);
+ return dict_sp;
+ }
+
+ StructuredData::DictionarySP dict_sp(
+ new StructuredData::Dictionary(result_sp));
+ if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
+ return {};
+ return dict_sp;
+}
+
+bool ScriptedCommandPythonInterface::GetShortHelp(std::string &dest) {
+ dest.clear();
+ Status error;
+ std::string result = Dispatch<std::string>("get_short_help", error);
+ if (!error.Success() || result.empty())
+ return false;
+ dest = std::move(result);
+ return true;
+}
+
+bool ScriptedCommandPythonInterface::GetLongHelp(std::string &dest) {
+ dest.clear();
+ Status error;
+ std::string result = Dispatch<std::string>("get_long_help", error);
+ if (!error.Success() || result.empty())
+ return false;
+ dest = std::move(result);
+ return true;
+}
+
+uint32_t ScriptedCommandPythonInterface::GetFlags() {
+ Status error;
+ return Dispatch<uint32_t>("get_flags", error);
+}
+
+StructuredData::ObjectSP
+ScriptedCommandPythonInterface::GetOptionsDefinition() {
+ Status error;
+ return Dispatch<StructuredData::DictionarySP>("get_options_definition",
+ error);
+}
+
+StructuredData::ObjectSP
+ScriptedCommandPythonInterface::GetArgumentsDefinition() {
+ Status error;
+ return Dispatch<StructuredData::ArraySP>("get_args_definition", error);
+}
+
+void ScriptedCommandPythonInterface::OptionParsingStarted() {
+ Status error;
+ Dispatch<StructuredData::ObjectSP>("option_parsing_started", error);
+}
+
+bool ScriptedCommandPythonInterface::SetOptionValue(ExecutionContext *exe_ctx,
+ llvm::StringRef long_option,
+ llvm::StringRef value) {
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp;
+ if (exe_ctx)
+ exe_ctx_ref_sp = std::make_shared<ExecutionContextRef>(exe_ctx);
+ Status error;
+ return Dispatch<bool>("set_option_value", error, exe_ctx_ref_sp, long_option,
+ value);
+}
+
+void ScriptedCommandPythonInterface::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ "Implement a custom command, used by 'command script add -c'/'-P'",
+ CreateInstance, eScriptedExtensionScriptedCommand, eScriptLanguagePython,
+ {});
+}
+
+void ScriptedCommandPythonInterface::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.h
new file mode 100644
index 0000000000000..d2bb5386a69ab
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.h
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDCOMMANDPYTHONINTERFACE_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDCOMMANDPYTHONINTERFACE_H
+
+#include "lldb/Interpreter/Interfaces/ScriptedCommandInterface.h"
+
+#include "ScriptedPythonInterface.h"
+namespace lldb_private {
+
+class ScriptedCommandPythonInterface : public ScriptedCommandInterface,
+ public ScriptedPythonInterface,
+ public PluginInterface {
+public:
+ ScriptedCommandPythonInterface(ScriptInterpreterPythonImpl &interpreter);
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name,
+ lldb::DebuggerSP debugger_sp) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return llvm::SmallVector<AbstractMethodRequirement>();
+ }
+
+ bool RunRawCommand(llvm::StringRef args,
+ ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) override;
+
+ bool RunParsedCommand(Args &args, ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) override;
+
+ std::optional<std::string> GetRepeatCommand(Args &args) override;
+
+ StructuredData::DictionarySP
+ HandleArgumentCompletion(std::vector<llvm::StringRef> &args, size_t args_pos,
+ size_t char_in_arg) override;
+
+ StructuredData::DictionarySP
+ HandleOptionArgumentCompletion(llvm::StringRef &long_option,
+ size_t char_in_arg) override;
+
+ bool GetShortHelp(std::string &dest) override;
+
+ bool GetLongHelp(std::string &dest) override;
+
+ uint32_t GetFlags() override;
+
+ StructuredData::ObjectSP GetOptionsDefinition() override;
+
+ StructuredData::ObjectSP GetArgumentsDefinition() override;
+
+ void OptionParsingStarted() override;
+
+ bool SetOptionValue(ExecutionContext *exe_ctx, llvm::StringRef long_option,
+ llvm::StringRef value) override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedCommandPythonInterface";
+ }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+ lldb::DebuggerSP m_debugger_sp;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDCOMMANDPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 61ceb40dd9d32..e5790ce2ca450 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -33,6 +33,60 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
return result_list.CreateStructuredArray();
}
+template <>
+std::optional<std::string>
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+ std::optional<std::string>>(python::PythonObject &p, Status &error) {
+ if (!p.IsAllocated() || p.IsNone())
+ return std::nullopt;
+ return p.Str().GetString().str();
+}
+
+template <>
+std::string ScriptedPythonInterface::ExtractValueFromPythonObject<std::string>(
+ python::PythonObject &p, Status &error) {
+ if (!p.IsAllocated() || p.IsNone())
+ return {};
+ if (!python::PythonString::Check(p.get())) {
+ error =
+ Status::FromErrorString("expected a string return value from Python");
+ return {};
+ }
+ python::PythonString py_string(python::PyRefType::Borrowed, p.get());
+ return py_string.GetString().str();
+}
+
+template <>
+uint32_t ScriptedPythonInterface::ExtractValueFromPythonObject<uint32_t>(
+ python::PythonObject &p, Status &error) {
+ if (!p.IsAllocated() || p.IsNone())
+ return 0;
+ if (!python::PythonInteger::Check(p.get())) {
+ error =
+ Status::FromErrorString("expected an integer return value from Python");
+ return 0;
+ }
+ auto value_or_err = p.AsLongLong();
+ if (!value_or_err) {
+ error = Status::FromError(value_or_err.takeError());
+ return 0;
+ }
+ return static_cast<uint32_t>(*value_or_err);
+}
+
+template <>
+bool ScriptedPythonInterface::ExtractValueFromPythonObject<bool>(
+ python::PythonObject &p, Status &error) {
+ if (!p.IsAllocated() || p.IsNone())
+ return false;
+ if (!python::PythonBoolean::Check(p.get())) {
+ error =
+ Status::FromErrorString("expected a boolean return value from Python");
+ return false;
+ }
+ return python::PythonBoolean(python::PyRefType::Borrowed, p.get()).GetValue();
+}
+
template <>
StructuredData::DictionarySP
ScriptedPythonInterface::ExtractValueFromPythonObject<
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 7d0d4cdd3c6d1..ca59ff954fad6 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -663,6 +663,25 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(lldb::DebuggerSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
+ python::PythonObject Transform(llvm::StringRef arg) {
+ return python::PythonString(arg);
+ }
+
+ python::PythonObject Transform(size_t arg) {
+ return python::PythonInteger(arg);
+ }
+
+ python::PythonObject Transform(const std::vector<llvm::StringRef> &arg) {
+ python::PythonList list(python::PyInitialValue::Empty);
+ for (llvm::StringRef s : arg)
+ list.AppendItem(python::PythonString(s));
+ return list;
+ }
+
template <typename T, typename U>
void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
// If U is not a PythonObject, don't touch it!
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 07e0da1dcf70d..97f53b2f435fa 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -143,11 +143,6 @@ class SWIGBridge {
const char *session_dictionary_name,
const lldb::ValueObjectSP &valobj_sp);
- static python::PythonObject
- LLDBSwigPythonCreateCommandObject(const char *python_class_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP debugger_sp);
-
static size_t LLDBSwigPython_CalculateNumChildren(PyObject *implementor,
uint32_t max);
@@ -176,30 +171,6 @@ class SWIGBridge {
lldb_private::CommandReturnObject &cmd_retobj,
lldb::ExecutionContextRefSP exe_ctx_ref_sp);
- static bool
- LLDBSwigPythonCallCommandObject(PyObject *implementor,
- lldb::DebuggerSP debugger, const char *args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp);
- static bool LLDBSwigPythonCallParsedCommandObject(
- PyObject *implementor, lldb::DebuggerSP debugger,
- StructuredDataImpl &args_impl,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp);
-
- static std::optional<std::string>
- LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor,
- std::string &command);
-
- static StructuredData::DictionarySP
- LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(
- PyObject *implementor, std::vector<llvm::StringRef> &args_impl,
- size_t args_pos, size_t pos_in_arg);
-
- static StructuredData::DictionarySP
- LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(
- PyObject *implementor, llvm::StringRef &long_option, size_t pos_in_arg);
-
static bool LLDBSwigPythonCallModuleInit(const char *python_module_name,
const char *session_dictionary_name,
lldb::DebuggerSP debugger);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index a153563b4534b..f63cc5e145aa2 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -1644,6 +1644,11 @@ ScriptInterpreterPythonImpl::CreateScriptedStackFrameRecognizerInterface() {
return std::make_shared<ScriptedStackFrameRecognizerPythonInterface>(*this);
}
+ScriptedCommandInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedCommandInterface() {
+ return std::make_shared<ScriptedCommandPythonInterface>(*this);
+}
+
ScriptedThreadInterfaceSP
ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() {
return std::make_shared<ScriptedThreadPythonInterface>(*this);
@@ -1758,28 +1763,6 @@ ScriptInterpreterPythonImpl::CreateSyntheticScriptedProvider(
new StructuredPythonObject(std::move(ret_val)));
}
-StructuredData::GenericSP
-ScriptInterpreterPythonImpl::CreateScriptCommandObject(const char *class_name) {
- DebuggerSP debugger_sp(m_debugger.shared_from_this());
-
- if (class_name == nullptr || class_name[0] == '\0')
- return StructuredData::GenericSP();
-
- if (!debugger_sp.get())
- return StructuredData::GenericSP();
-
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateCommandObject(
- class_name, m_dictionary_name.c_str(), debugger_sp);
-
- if (ret_val.IsValid())
- return StructuredData::GenericSP(
- new StructuredPythonObject(std::move(ret_val)));
- else
- return {};
-}
-
bool ScriptInterpreterPythonImpl::GenerateTypeScriptFunction(
const char *oneliner, std::string &output, const void *name_token) {
StringList input;
@@ -2628,166 +2611,6 @@ bool ScriptInterpreterPythonImpl::RunScriptBasedCommand(
return ret_val;
}
-bool ScriptInterpreterPythonImpl::RunScriptBasedCommand(
- StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,
- ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Status &error,
- const lldb_private::ExecutionContext &exe_ctx) {
- if (!impl_obj_sp || !impl_obj_sp->IsValid()) {
- error = Status::FromErrorString("no function to execute");
- return false;
- }
-
- lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this();
- lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
-
- if (!debugger_sp.get()) {
- error = Status::FromErrorString("invalid Debugger pointer");
- return false;
- }
-
- bool ret_val = false;
-
- {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession |
- (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN),
- Locker::FreeLock | Locker::TearDownSession);
-
- SynchronicityHandler synch_handler(debugger_sp, synchronicity);
-
- std::string args_str = args.str();
- ret_val = SWIGBridge::LLDBSwigPythonCallCommandObject(
- static_cast<PyObject *>(impl_obj_sp->GetValue()), debugger_sp,
- args_str.c_str(), cmd_retobj, exe_ctx_ref_sp);
- }
-
- if (!ret_val)
- error = Status::FromErrorString("unable to execute script function");
- else if (cmd_retobj.GetStatus() == eReturnStatusFailed)
- return false;
-
- error.Clear();
- return ret_val;
-}
-
-bool ScriptInterpreterPythonImpl::RunScriptBasedParsedCommand(
- StructuredData::GenericSP impl_obj_sp, Args &args,
- ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Status &error,
- const lldb_private::ExecutionContext &exe_ctx) {
- if (!impl_obj_sp || !impl_obj_sp->IsValid()) {
- error = Status::FromErrorString("no function to execute");
- return false;
- }
-
- lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this();
- lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
-
- if (!debugger_sp.get()) {
- error = Status::FromErrorString("invalid Debugger pointer");
- return false;
- }
-
- bool ret_val = false;
-
- {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession |
- (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN),
- Locker::FreeLock | Locker::TearDownSession);
-
- SynchronicityHandler synch_handler(debugger_sp, synchronicity);
-
- StructuredData::ArraySP args_arr_sp(new StructuredData::Array());
-
- for (const Args::ArgEntry &entry : args) {
- args_arr_sp->AddStringItem(entry.ref());
- }
- StructuredDataImpl args_impl(args_arr_sp);
-
- ret_val = SWIGBridge::LLDBSwigPythonCallParsedCommandObject(
- static_cast<PyObject *>(impl_obj_sp->GetValue()), debugger_sp,
- args_impl, cmd_retobj, exe_ctx_ref_sp);
- }
-
- if (!ret_val)
- error = Status::FromErrorString("unable to execute script function");
- else if (cmd_retobj.GetStatus() == eReturnStatusFailed)
- return false;
-
- error.Clear();
- return ret_val;
-}
-
-std::optional<std::string>
-ScriptInterpreterPythonImpl::GetRepeatCommandForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, Args &args) {
- if (!impl_obj_sp || !impl_obj_sp->IsValid())
- return std::nullopt;
-
- lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this();
-
- if (!debugger_sp.get())
- return std::nullopt;
-
- std::optional<std::string> ret_val;
-
- {
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN,
- Locker::FreeLock);
-
- StructuredData::ArraySP args_arr_sp(new StructuredData::Array());
-
- // For scripting commands, we send the command string:
- std::string command;
- args.GetQuotedCommandString(command);
- ret_val = SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedCommand(
- static_cast<PyObject *>(impl_obj_sp->GetValue()), command);
- }
- return ret_val;
-}
-
-StructuredData::DictionarySP
-ScriptInterpreterPythonImpl::HandleArgumentCompletionForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, std::vector<llvm::StringRef> &args,
- size_t args_pos, size_t char_in_arg) {
- StructuredData::DictionarySP completion_dict_sp;
- if (!impl_obj_sp || !impl_obj_sp->IsValid())
- return completion_dict_sp;
-
- {
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN,
- Locker::FreeLock);
-
- completion_dict_sp =
- SWIGBridge::LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(
- static_cast<PyObject *>(impl_obj_sp->GetValue()), args, args_pos,
- char_in_arg);
- }
- return completion_dict_sp;
-}
-
-StructuredData::DictionarySP
-ScriptInterpreterPythonImpl::HandleOptionArgumentCompletionForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, llvm::StringRef &long_option,
- size_t char_in_arg) {
- StructuredData::DictionarySP completion_dict_sp;
- if (!impl_obj_sp || !impl_obj_sp->IsValid())
- return completion_dict_sp;
-
- {
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN,
- Locker::FreeLock);
-
- completion_dict_sp = SWIGBridge::
- LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(
- static_cast<PyObject *>(impl_obj_sp->GetValue()), long_option,
- char_in_arg);
- }
- return completion_dict_sp;
-}
-
/// In Python, a special attribute __doc__ contains the docstring for an object
/// (function, method, class, ...) if any is defined Otherwise, the attribute's
/// value is None.
@@ -2821,322 +2644,6 @@ bool ScriptInterpreterPythonImpl::GetDocumentationForItem(const char *item,
return false;
}
-bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject(
- StructuredData::GenericSP cmd_obj_sp, std::string &dest) {
- dest.clear();
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- if (!cmd_obj_sp)
- return false;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return false;
-
- llvm::Expected<PythonObject> expected_py_return =
- implementor.CallMethod("get_short_help");
-
- if (!expected_py_return) {
- llvm::consumeError(expected_py_return.takeError());
- return false;
- }
-
- PythonObject py_return = std::move(expected_py_return.get());
-
- if (py_return.IsAllocated() && PythonString::Check(py_return.get())) {
- PythonString py_string(PyRefType::Borrowed, py_return.get());
- llvm::StringRef return_data(py_string.GetString());
- dest.assign(return_data.data(), return_data.size());
- return true;
- }
-
- return false;
-}
-
-uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject(
- StructuredData::GenericSP cmd_obj_sp) {
- uint32_t result = 0;
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- static char callee_name[] = "get_flags";
-
- if (!cmd_obj_sp)
- return result;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return result;
-
- PythonObject pmeth(PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), callee_name));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return result;
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return result;
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- long long py_return = unwrapOrSetPythonException(
- As<long long>(implementor.CallMethod(callee_name)));
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- } else {
- result = py_return;
- }
-
- return result;
-}
-
-StructuredData::ObjectSP
-ScriptInterpreterPythonImpl::GetOptionsForCommandObject(
- StructuredData::GenericSP cmd_obj_sp) {
- StructuredData::ObjectSP result = {};
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- static char callee_name[] = "get_options_definition";
-
- if (!cmd_obj_sp)
- return result;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return result;
-
- PythonObject pmeth(PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), callee_name));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return result;
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return result;
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- PythonDictionary py_return = unwrapOrSetPythonException(
- As<PythonDictionary>(implementor.CallMethod(callee_name)));
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return {};
- }
- return py_return.CreateStructuredObject();
-}
-
-StructuredData::ObjectSP
-ScriptInterpreterPythonImpl::GetArgumentsForCommandObject(
- StructuredData::GenericSP cmd_obj_sp) {
- StructuredData::ObjectSP result = {};
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- static char callee_name[] = "get_args_definition";
-
- if (!cmd_obj_sp)
- return result;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return result;
-
- PythonObject pmeth(PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), callee_name));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return result;
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return result;
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- PythonList py_return = unwrapOrSetPythonException(
- As<PythonList>(implementor.CallMethod(callee_name)));
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return {};
- }
- return py_return.CreateStructuredObject();
-}
-
-void ScriptInterpreterPythonImpl::OptionParsingStartedForCommandObject(
- StructuredData::GenericSP cmd_obj_sp) {
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- static char callee_name[] = "option_parsing_started";
-
- if (!cmd_obj_sp)
- return;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return;
-
- PythonObject pmeth(PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), callee_name));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return;
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return;
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- // option_parsing_starting doesn't return anything, ignore anything but
- // python errors.
- unwrapOrSetPythonException(As<bool>(implementor.CallMethod(callee_name)));
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return;
- }
-}
-
-bool ScriptInterpreterPythonImpl::SetOptionValueForCommandObject(
- StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx,
- llvm::StringRef long_option, llvm::StringRef value) {
- StructuredData::ObjectSP result = {};
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- static char callee_name[] = "set_option_value";
-
- if (!cmd_obj_sp)
- return false;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return false;
-
- PythonObject pmeth(PyRefType::Owned,
- PyObject_GetAttrString(implementor.get(), callee_name));
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- if (!pmeth.IsAllocated())
- return false;
-
- if (PyCallable_Check(pmeth.get()) == 0) {
- if (PyErr_Occurred())
- PyErr_Clear();
- return false;
- }
-
- if (PyErr_Occurred())
- PyErr_Clear();
-
- lldb::ExecutionContextRefSP exe_ctx_ref_sp;
- if (exe_ctx)
- exe_ctx_ref_sp = std::make_shared<ExecutionContextRef>(exe_ctx);
- PythonObject ctx_ref_obj = SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp);
-
- bool py_return = unwrapOrSetPythonException(As<bool>(
- implementor.CallMethod(callee_name, ctx_ref_obj,
- long_option.str().c_str(), value.str().c_str())));
-
- // if it fails, print the error but otherwise go on
- if (PyErr_Occurred()) {
- PyErr_Print();
- PyErr_Clear();
- return false;
- }
- return py_return;
-}
-
-bool ScriptInterpreterPythonImpl::GetLongHelpForCommandObject(
- StructuredData::GenericSP cmd_obj_sp, std::string &dest) {
- dest.clear();
-
- Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
-
- if (!cmd_obj_sp)
- return false;
-
- PythonObject implementor(PyRefType::Borrowed,
- (PyObject *)cmd_obj_sp->GetValue());
-
- if (!implementor.IsAllocated())
- return false;
-
- llvm::Expected<PythonObject> expected_py_return =
- implementor.CallMethod("get_long_help");
-
- if (!expected_py_return) {
- llvm::consumeError(expected_py_return.takeError());
- return false;
- }
-
- PythonObject py_return = std::move(expected_py_return.get());
-
- bool got_string = false;
- if (py_return.IsAllocated() && PythonString::Check(py_return.get())) {
- PythonString str(PyRefType::Borrowed, py_return.get());
- llvm::StringRef str_data(str.GetString());
- dest.assign(str_data.data(), str_data.size());
- got_string = true;
- }
-
- return got_string;
-}
-
std::unique_ptr<ScriptInterpreterLocker>
ScriptInterpreterPythonImpl::AcquireInterpreterLock() {
std::unique_ptr<ScriptInterpreterLocker> py_lock(new Locker(
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index d8a817198253f..51b373afbb9f4 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -70,9 +70,6 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
CreateSyntheticScriptedProvider(const char *class_name,
lldb::ValueObjectSP valobj) override;
- StructuredData::GenericSP
- CreateScriptCommandObject(const char *class_name) override;
-
StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) override;
@@ -86,6 +83,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
lldb::ScriptedStackFrameRecognizerInterfaceSP
CreateScriptedStackFrameRecognizerInterface() override;
+ lldb::ScriptedCommandInterfaceSP CreateScriptedCommandInterface() override;
+
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
@@ -137,30 +136,6 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
Status &error,
const lldb_private::ExecutionContext &exe_ctx) override;
- bool RunScriptBasedCommand(
- StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,
- ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Status &error,
- const lldb_private::ExecutionContext &exe_ctx) override;
-
- bool RunScriptBasedParsedCommand(
- StructuredData::GenericSP impl_obj_sp, Args &args,
- ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Status &error,
- const lldb_private::ExecutionContext &exe_ctx) override;
-
- std::optional<std::string>
- GetRepeatCommandForScriptedCommand(StructuredData::GenericSP impl_obj_sp,
- Args &args) override;
-
- StructuredData::DictionarySP HandleArgumentCompletionForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, std::vector<llvm::StringRef> &args,
- size_t args_pos, size_t char_in_arg) override;
-
- StructuredData::DictionarySP HandleOptionArgumentCompletionForScriptedCommand(
- StructuredData::GenericSP impl_obj_sp, llvm::StringRef &long_options,
- size_t char_in_arg) override;
-
Status GenerateFunction(const char *signature, const StringList &input,
bool is_callback) override;
@@ -183,29 +158,6 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
bool GetDocumentationForItem(const char *item, std::string &dest) override;
- bool GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
- std::string &dest) override;
-
- uint32_t
- GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;
-
- bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
- std::string &dest) override;
-
- StructuredData::ObjectSP
- GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;
-
- StructuredData::ObjectSP
- GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override;
-
- bool SetOptionValueForCommandObject(StructuredData::GenericSP cmd_obj_sp,
- ExecutionContext *exe_ctx,
- llvm::StringRef long_option,
- llvm::StringRef value) override;
-
- void OptionParsingStartedForCommandObject(
- StructuredData::GenericSP cmd_obj_sp) override;
-
bool CheckObjectExists(const char *name) override {
if (!name || !name[0])
return false;
diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index c9298191ec3c1..72310075a0d81 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -73,13 +73,6 @@ lldb_private::python::SWIGBridge::LLDBSwigPythonCreateSyntheticProvider(
return python::PythonObject();
}
-python::PythonObject
-lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject(
- const char *python_class_name, const char *session_dictionary_name,
- lldb::DebuggerSP debugger_sp) {
- return python::PythonObject();
-}
-
size_t lldb_private::python::SWIGBridge::LLDBSwigPython_CalculateNumChildren(
PyObject *implementor, uint32_t max) {
return 0;
@@ -207,40 +200,6 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommand(
return false;
}
-bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommandObject(
- PyObject *implementor, lldb::DebuggerSP debugger, const char *args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp) {
- return false;
-}
-
-bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject(
- PyObject *implementor, lldb::DebuggerSP debugger,
- StructuredDataImpl &args_impl,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp) {
- return false;
-}
-
-std::optional<std::string>
-LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor,
- std::string &command) {
- return std::nullopt;
-}
-
-StructuredData::DictionarySP
-LLDBSwigPythonHandleArgumentCompletionForScriptedCommand(
- PyObject *implementor, std::vector<llvm::StringRef> &args, size_t args_pos,
- size_t pos_in_arg) {
- return {};
-}
-
-StructuredData::DictionarySP
-LLDBSwigPythonHandleOptionArgumentCompletionForScriptedCommand(
- PyObject *implementor, llvm::StringRef &long_options, size_t char_in_arg) {
- return {};
-}
-
bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit(
const char *python_module_name, const char *session_dictionary_name,
lldb::DebuggerSP debugger) {
More information about the lldb-commits
mailing list