[Lldb-commits] [lldb] [lldb/script] Migrate ParsedCommand & raw commands onto ScriptedPythonInterface (PR #210430)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 27 20:33:44 PDT 2026
https://github.com/medismailben updated https://github.com/llvm/llvm-project/pull/210430
>From a6d6b2faf5f7dccb914df1c7e3628a87fa0b4ad8 Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Mon, 27 Jul 2026 20:16:58 -0700
Subject: [PATCH] [lldb/script] Migrate ParsedCommand & raw commands onto
ScriptedPythonInterface
Give both `command script add -c` (raw class) and `-p` (ParsedCommand) a
single, shared `ScriptedCommandInterface`/`ScriptedCommandPythonInterface`,
built on the existing `ScriptedPythonInterface` machinery: `CreatePluginObject`
delegates to the base template, and every other method goes through `Dispatch`.
Add a lighter `ScriptedCommand` ABC template (`scripted_command.py`) for raw
mode; the existing `ParsedCommand`/`LLDBOptionValueParser` classes are kept
as-is.
Extend `ScriptedPythonInterface` with a few `Transform` overloads
(`DebuggerSP`, `std::vector<std::string>`, `CommandReturnObject &`) so those
argument types route through `Dispatch` without extra plumbing.
Delete the standalone SWIG bridge functions this plugin was the sole caller
of. `CommandObjectScriptingObjectRaw` and `CommandObjectScriptingObjectParsed`
now hold a `ScriptedCommandInterfaceSP` instead of a raw
`StructuredData::GenericSP`; `command script add`'s `DoExecute` constructs
the interface once via `CreateScriptedCommandInterface()->CreatePluginObject`
for either flag.
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
lldb/bindings/python/CMakeLists.txt | 1 +
lldb/bindings/python/python-wrapper.swig | 184 +------
lldb/docs/CMakeLists.txt | 1 +
.../python/templates/scripted_command.py | 86 +++
lldb/include/lldb/API/SBCommandReturnObject.h | 2 +
lldb/include/lldb/API/SBDebugger.h | 1 +
.../Interfaces/ScriptedCommandInterface.h | 78 +++
.../lldb/Interpreter/ScriptInterpreter.h | 88 +--
lldb/include/lldb/lldb-enumerations.h | 4 +-
lldb/include/lldb/lldb-forward.h | 3 +
lldb/source/API/SBCommandReturnObject.cpp | 50 +-
lldb/source/API/SBCommandReturnObjectImpl.h | 31 ++
.../source/Commands/CommandObjectCommands.cpp | 202 +++----
lldb/source/Interpreter/ScriptInterpreter.cpp | 19 +
.../ScriptInterpreter/Python/CMakeLists.txt | 1 +
.../ScriptInterpreterPythonInterfaces.cpp | 2 +
.../ScriptInterpreterPythonInterfaces.h | 1 +
.../ScriptedCommandPythonInterface.cpp | 248 +++++++++
.../ScriptedCommandPythonInterface.h | 81 +++
.../Interfaces/ScriptedPythonInterface.cpp | 52 ++
.../Interfaces/ScriptedPythonInterface.h | 36 ++
.../Python/SWIGPythonBridge.h | 33 +-
.../Python/ScriptInterpreterPython.cpp | 506 +-----------------
.../Python/ScriptInterpreterPythonImpl.h | 52 +-
.../Python/PythonTestSuite.cpp | 51 +-
25 files changed, 818 insertions(+), 995 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/API/SBCommandReturnObjectImpl.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..c4071b3f7b5b1 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(
@@ -497,6 +478,32 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBError(PyObject * data
return sb_ptr;
}
+void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBCommandReturnObject(
+ PyObject *data) {
+ lldb::SBCommandReturnObject *sb_ptr = nullptr;
+
+ int valid_cast = SWIG_ConvertPtr(
+ data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBCommandReturnObject, 0);
+
+ if (valid_cast == -1)
+ return NULL;
+
+ return sb_ptr;
+}
+
+void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBDebugger(
+ PyObject *data) {
+ lldb::SBDebugger *sb_ptr = nullptr;
+
+ int valid_cast =
+ SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBDebugger, 0);
+
+ if (valid_cast == -1)
+ return NULL;
+
+ return sb_ptr;
+}
+
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBEvent(PyObject * data) {
lldb::SBEvent *sb_ptr = nullptr;
@@ -639,145 +646,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/API/SBCommandReturnObject.h b/lldb/include/lldb/API/SBCommandReturnObject.h
index 6386bd250afa5..b80a11b52c77f 100644
--- a/lldb/include/lldb/API/SBCommandReturnObject.h
+++ b/lldb/include/lldb/API/SBCommandReturnObject.h
@@ -17,6 +17,7 @@
namespace lldb_private {
class CommandPluginInterfaceImplementation;
+class CommandReturnObject;
class SBCommandReturnObjectImpl;
namespace python {
class SWIGBridge;
@@ -144,6 +145,7 @@ class LLDB_API SBCommandReturnObject {
friend class lldb_private::CommandPluginInterfaceImplementation;
friend class lldb_private::python::SWIGBridge;
+ friend class lldb_private::ScriptInterpreter;
SBCommandReturnObject(lldb_private::CommandReturnObject &ref);
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index 14b8350902811..3e302f121f5ec 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -678,6 +678,7 @@ class LLDB_API SBDebugger {
protected:
friend class lldb_private::CommandPluginInterfaceImplementation;
friend class lldb_private::python::SWIGBridge;
+ friend class lldb_private::ScriptInterpreter;
friend class lldb_private::SystemInitializerFull;
SBDebugger(const lldb::DebuggerSP &debugger_sp);
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h
new file mode 100644
index 0000000000000..29f4d273e49f0
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedCommandInterface.h
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 {
+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<std::string> &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 0e65cb4b8ac4a..9d3e7e6f32ff5 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -263,11 +263,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();
@@ -394,42 +389,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) {
@@ -468,43 +427,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
@@ -586,6 +508,10 @@ class ScriptInterpreter : public PluginInterface {
return {};
}
+ virtual lldb::ScriptedCommandInterfaceSP CreateScriptedCommandInterface() {
+ return {};
+ }
+
virtual StructuredData::ObjectSP
CreateStructuredDataFromScriptObject(ScriptObject obj) {
return {};
@@ -658,6 +584,12 @@ class ScriptInterpreter : public PluginInterface {
lldb::BreakpointLocationSP GetOpaqueTypeFromSBBreakpointLocation(
const lldb::SBBreakpointLocation &break_loc) const;
+ CommandReturnObject *GetOpaqueTypeFromSBCommandReturnObject(
+ const lldb::SBCommandReturnObject &cmd_retobj) const;
+
+ lldb::DebuggerSP
+ GetOpaqueTypeFromSBDebugger(const lldb::SBDebugger &debugger) const;
+
lldb::ProcessAttachInfoSP
GetOpaqueTypeFromSBAttachInfo(const lldb::SBAttachInfo &attach_info) const;
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/API/SBCommandReturnObject.cpp b/lldb/source/API/SBCommandReturnObject.cpp
index 62cc7a1f05573..b63f91e9712f4 100644
--- a/lldb/source/API/SBCommandReturnObject.cpp
+++ b/lldb/source/API/SBCommandReturnObject.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/API/SBCommandReturnObject.h"
+#include "SBCommandReturnObjectImpl.h"
#include "Utils.h"
#include "lldb/API/SBError.h"
#include "lldb/API/SBFile.h"
@@ -25,30 +26,27 @@
using namespace lldb;
using namespace lldb_private;
-class lldb_private::SBCommandReturnObjectImpl {
-public:
- SBCommandReturnObjectImpl() : m_ptr(new CommandReturnObject(false)) {}
- SBCommandReturnObjectImpl(CommandReturnObject &ref)
- : m_ptr(&ref), m_owned(false) {}
- SBCommandReturnObjectImpl(const SBCommandReturnObjectImpl &rhs)
- : m_ptr(new CommandReturnObject(*rhs.m_ptr)), m_owned(rhs.m_owned) {}
- SBCommandReturnObjectImpl &operator=(const SBCommandReturnObjectImpl &rhs) {
- SBCommandReturnObjectImpl copy(rhs);
- std::swap(*this, copy);
- return *this;
- }
- // rvalue ctor+assignment are not used by SBCommandReturnObject.
- ~SBCommandReturnObjectImpl() {
- if (m_owned)
- delete m_ptr;
- }
+SBCommandReturnObjectImpl::SBCommandReturnObjectImpl()
+ : m_ptr(new CommandReturnObject(false)) {}
- CommandReturnObject &operator*() const { return *m_ptr; }
+SBCommandReturnObjectImpl::SBCommandReturnObjectImpl(CommandReturnObject &ref)
+ : m_ptr(&ref), m_owned(false) {}
-private:
- CommandReturnObject *m_ptr;
- bool m_owned = true;
-};
+SBCommandReturnObjectImpl::SBCommandReturnObjectImpl(
+ const SBCommandReturnObjectImpl &rhs)
+ : m_ptr(new CommandReturnObject(*rhs.m_ptr)), m_owned(rhs.m_owned) {}
+
+SBCommandReturnObjectImpl &
+SBCommandReturnObjectImpl::operator=(const SBCommandReturnObjectImpl &rhs) {
+ SBCommandReturnObjectImpl copy(rhs);
+ std::swap(*this, copy);
+ return *this;
+}
+
+SBCommandReturnObjectImpl::~SBCommandReturnObjectImpl() {
+ if (m_owned)
+ delete m_ptr;
+}
SBCommandReturnObject::SBCommandReturnObject()
: m_opaque_up(new SBCommandReturnObjectImpl()) {
@@ -221,19 +219,19 @@ void SBCommandReturnObject::AppendWarning(const char *message) {
}
CommandReturnObject *SBCommandReturnObject::operator->() const {
- return &**m_opaque_up;
+ return m_opaque_up->get();
}
CommandReturnObject *SBCommandReturnObject::get() const {
- return &**m_opaque_up;
+ return m_opaque_up->get();
}
CommandReturnObject &SBCommandReturnObject::operator*() const {
- return **m_opaque_up;
+ return *m_opaque_up->get();
}
CommandReturnObject &SBCommandReturnObject::ref() const {
- return **m_opaque_up;
+ return *m_opaque_up->get();
}
bool SBCommandReturnObject::GetDescription(SBStream &description) {
diff --git a/lldb/source/API/SBCommandReturnObjectImpl.h b/lldb/source/API/SBCommandReturnObjectImpl.h
new file mode 100644
index 0000000000000..e0a90bd1e12bd
--- /dev/null
+++ b/lldb/source/API/SBCommandReturnObjectImpl.h
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_API_SBCOMMANDRETURNOBJECTIMPL_H
+#define LLDB_SOURCE_API_SBCOMMANDRETURNOBJECTIMPL_H
+
+namespace lldb_private {
+class CommandReturnObject;
+
+class SBCommandReturnObjectImpl {
+public:
+ SBCommandReturnObjectImpl();
+ SBCommandReturnObjectImpl(CommandReturnObject &ref);
+ SBCommandReturnObjectImpl(const SBCommandReturnObjectImpl &rhs);
+ SBCommandReturnObjectImpl &operator=(const SBCommandReturnObjectImpl &rhs);
+ ~SBCommandReturnObjectImpl();
+
+ CommandReturnObject *get() const { return m_ptr; }
+
+private:
+ CommandReturnObject *m_ptr;
+ bool m_owned = true;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_API_SBCOMMANDRETURNOBJECTIMPL_H
diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp
index 8f006768ecc9a..2acbbda4e8553 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,15 @@ 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(lldb::ScriptedCommandInterfaceSP cmd_interface_sp)
+ : 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 +1254,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 +1265,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 +1276,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 +1710,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 +1727,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,
@@ -1809,19 +1789,17 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
std::vector<std::vector<EnumValueStorage>> m_enum_storage;
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 +1821,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(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 +1861,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 +1994,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:
@@ -2044,7 +2019,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
option_slots.insert(elem.opt_arg_pos);
}
- std::vector<llvm::StringRef> args_vec;
+ std::vector<std::string> args_vec;
Args &args = request.GetParsedLine();
size_t num_args = args.GetArgumentCount();
size_t cursor_idx = request.GetCursorIndex();
@@ -2052,13 +2027,13 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
for (size_t idx = 0; idx < num_args; idx++) {
if (option_slots.count(idx) == 0)
- args_vec.push_back(args[idx].ref());
+ args_vec.push_back(args[idx].ref().str());
else if (idx < cursor_idx)
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 +2049,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 +2072,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 +2091,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 +2111,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 +2479,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 4f6095d097d10..04ec3f5421981 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -7,6 +7,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "API/SBCommandReturnObjectImpl.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBDebugger.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Pipe.h"
@@ -96,6 +99,16 @@ ScriptInterpreter::GetOpaqueTypeFromSBBreakpointLocation(
return break_loc.m_opaque_wp.lock();
}
+CommandReturnObject *ScriptInterpreter::GetOpaqueTypeFromSBCommandReturnObject(
+ const lldb::SBCommandReturnObject &cmd_retobj) const {
+ return cmd_retobj.m_opaque_up->get();
+}
+
+lldb::DebuggerSP ScriptInterpreter::GetOpaqueTypeFromSBDebugger(
+ const lldb::SBDebugger &debugger) const {
+ return debugger.m_opaque_sp;
+}
+
lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
const lldb::SBAttachInfo &attach_info) const {
return attach_info.m_opaque_sp;
@@ -221,6 +234,10 @@ ScriptInterpreter::ExtensionToString(lldb::ScriptedExtension extension) {
return "ScriptedFrame";
case eScriptedExtensionScriptedStackFrameRecognizer:
return "ScriptedStackFrameRecognizer";
+ case eScriptedExtensionScriptedCommand:
+ return "ScriptedCommand";
+ case eScriptedExtensionParsedCommand:
+ return "ParsedCommand";
}
llvm_unreachable("unhandled ScriptedExtension");
}
@@ -241,6 +258,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..defc29bb6864c
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedCommandPythonInterface.cpp
@@ -0,0 +1,248 @@
+//===----------------------------------------------------------------------===//
+//
+// 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) {
+ lldb::DebuggerSP debugger_sp = m_debugger_sp;
+ if (!debugger_sp) {
+ error = Status::FromErrorString("invalid Debugger pointer");
+ return false;
+ }
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
+
+ // Outer Locker sets up the session (with conditional NoSTDIN for
+ // interactive commands and TearDownSession on exit) that Dispatch's inner
+ // Locker doesn't provide. Nesting is only safe because Dispatch's own
+ // Locker never requests InitSession itself.
+ 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);
+
+ std::string args_str = args.str();
+ Dispatch("__call__", error, debugger_sp, args_str.c_str(), exe_ctx_ref_sp,
+ &cmd_retobj);
+
+ if (!error.Success() || cmd_retobj.GetStatus() == eReturnStatusFailed)
+ return false;
+
+ return true;
+}
+
+bool ScriptedCommandPythonInterface::RunParsedCommand(
+ Args &args, ScriptedCommandSynchronicity synchronicity,
+ CommandReturnObject &cmd_retobj, Status &error,
+ const ExecutionContext &exe_ctx) {
+ lldb::DebuggerSP debugger_sp = m_debugger_sp;
+ if (!debugger_sp) {
+ error = Status::FromErrorString("invalid Debugger pointer");
+ return false;
+ }
+ lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx));
+
+ 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);
+
+ Dispatch("__call__", error, debugger_sp, args_impl, exe_ctx_ref_sp,
+ &cmd_retobj);
+
+ if (!error.Success() || cmd_retobj.GetStatus() == eReturnStatusFailed)
+ return false;
+
+ return true;
+}
+
+std::optional<std::string>
+ScriptedCommandPythonInterface::GetRepeatCommand(Args &args) {
+ std::string command;
+ args.GetQuotedCommandString(command);
+ Status error;
+ StructuredData::ObjectSP obj =
+ Dispatch("get_repeat_command", error, command.c_str());
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+ return obj->GetStringValue().str();
+}
+
+StructuredData::DictionarySP
+ScriptedCommandPythonInterface::HandleArgumentCompletion(
+ std::vector<std::string> &args, size_t args_pos, size_t char_in_arg) {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("handle_argument_completion", error,
+ args, args_pos, char_in_arg);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+ StructuredData::DictionarySP dict_sp(new StructuredData::Dictionary(obj));
+ if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
+ return {};
+ return dict_sp;
+}
+
+StructuredData::DictionarySP
+ScriptedCommandPythonInterface::HandleOptionArgumentCompletion(
+ llvm::StringRef &long_option, size_t char_in_arg) {
+ Status error;
+ std::string long_option_str = long_option.str();
+ StructuredData::ObjectSP obj =
+ Dispatch("handle_option_argument_completion", error,
+ long_option_str.c_str(), char_in_arg);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ // A boolean return means: True means completion handled but no
+ // completions; False means completion not handled (fall back to default).
+ if (obj->GetType() == lldb::eStructuredDataTypeBoolean) {
+ if (!obj->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(obj));
+ if (dict_sp->GetType() == lldb::eStructuredDataTypeInvalid)
+ return {};
+ return dict_sp;
+}
+
+bool ScriptedCommandPythonInterface::GetShortHelp(std::string &dest) {
+ dest.clear();
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_short_help", error);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+ dest = obj->GetStringValue().str();
+ return !dest.empty();
+}
+
+bool ScriptedCommandPythonInterface::GetLongHelp(std::string &dest) {
+ dest.clear();
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_long_help", error);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+ dest = obj->GetStringValue().str();
+ return !dest.empty();
+}
+
+uint32_t ScriptedCommandPythonInterface::GetFlags() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_flags", error);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return 0;
+ return static_cast<uint32_t>(obj->GetUnsignedIntegerValue());
+}
+
+StructuredData::ObjectSP
+ScriptedCommandPythonInterface::GetOptionsDefinition() {
+ Status error;
+ return Dispatch("get_options_definition", error);
+}
+
+StructuredData::ObjectSP
+ScriptedCommandPythonInterface::GetArgumentsDefinition() {
+ Status error;
+ return Dispatch("get_args_definition", error);
+}
+
+void ScriptedCommandPythonInterface::OptionParsingStarted() {
+ Status error;
+ Dispatch("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;
+ std::string long_option_str = long_option.str();
+ std::string value_str = value.str();
+ StructuredData::ObjectSP obj =
+ Dispatch("set_option_value", error, exe_ctx_ref_sp,
+ long_option_str.c_str(), value_str.c_str());
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+ return obj->GetBooleanValue();
+}
+
+void ScriptedCommandPythonInterface::Initialize() {
+ const std::vector<llvm::StringRef> ci_usages = {
+ "command script add -c <ClassName> <cmd>",
+ "command script add -p <ClassName> <cmd>"};
+ const std::vector<llvm::StringRef> api_usages = {};
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ "Implement a raw or parsed custom command backed by a Python class.",
+ CreateInstance, eScriptedExtensionScriptedCommand, eScriptLanguagePython,
+ ScriptedInterfaceUsages(ci_usages, api_usages));
+}
+
+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..8aecb58ddce67
--- /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<std::string> &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..96391f7be8da0 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -8,6 +8,7 @@
#include "../lldb-python.h"
+#include "lldb/API/SBDebugger.h"
#include "lldb/Host/Config.h"
#include "lldb/Utility/Log.h"
#include "lldb/lldb-enumerations.h"
@@ -65,6 +66,21 @@ Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(
return nullptr;
}
+template <>
+CommandReturnObject *
+ScriptedPythonInterface::ExtractValueFromPythonObject<CommandReturnObject *>(
+ python::PythonObject &p, Status &error) {
+ if (lldb::SBCommandReturnObject *sb_cmd_retobj =
+ reinterpret_cast<lldb::SBCommandReturnObject *>(
+ python::LLDBSWIGPython_CastPyObjectToSBCommandReturnObject(
+ p.get())))
+ return m_interpreter.GetOpaqueTypeFromSBCommandReturnObject(*sb_cmd_retobj);
+ error =
+ Status::FromErrorString("couldn't cast lldb::SBCommandReturnObject to "
+ "lldb_private::CommandReturnObject.");
+ return nullptr;
+}
+
template <>
lldb::StreamSP
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
@@ -380,3 +396,39 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
return static_cast<ValueType>(unmasked | flags);
}
+
+template <>
+lldb::DebuggerSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DebuggerSP>(
+ python::PythonObject &p, Status &error) {
+ if (lldb::SBDebugger *sb_dbg = reinterpret_cast<lldb::SBDebugger *>(
+ python::LLDBSWIGPython_CastPyObjectToSBDebugger(p.get())))
+ return m_interpreter.GetOpaqueTypeFromSBDebugger(*sb_dbg);
+ error = Status::FromErrorString(
+ "couldn't cast lldb::SBDebugger to lldb::DebuggerSP.");
+ return {};
+}
+
+template <>
+std::vector<std::string>
+ScriptedPythonInterface::ExtractValueFromPythonObject<std::vector<std::string>>(
+ python::PythonObject &p, Status &error) {
+ std::vector<std::string> result;
+ python::PythonList list(python::PyRefType::Borrowed, p.get());
+ if (!list.IsValid()) {
+ error = Status::FromErrorString(
+ "couldn't extract std::vector<std::string>: not a Python list.");
+ return result;
+ }
+
+ const uint32_t size = list.GetSize();
+ result.reserve(size);
+ for (uint32_t i = 0; i < size; ++i) {
+ python::PythonString item(python::PyRefType::Borrowed,
+ list.GetItemAtIndex(i).get());
+ if (!item.IsValid())
+ continue;
+ result.push_back(item.GetString().str());
+ }
+ return result;
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index aaa0b6a0f7a59..d82a59738a7db 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -15,6 +15,7 @@
#include <type_traits>
#include <utility>
+#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/Interpreter/Interfaces/ScriptedInterface.h"
#include "lldb/Utility/DataBufferHeap.h"
@@ -668,6 +669,22 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(lldb::DebuggerSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
+ python::PythonObject Transform(const std::vector<std::string> &arg) {
+ python::PythonList list(python::PyInitialValue::Empty);
+ for (const std::string &s : arg)
+ list.AppendItem(python::PythonString(s));
+ return list;
+ }
+
+ python::ScopedPythonObject<lldb::SBCommandReturnObject>
+ Transform(CommandReturnObject *arg) {
+ return python::SWIGBridge::ToSWIGWrapper(*arg);
+ }
+
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!
@@ -708,6 +725,15 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
ReverseTransform(original_arg, transformed_arg, error);
}
+ // ScopedPythonObject is non-copyable — passing it through the generic
+ // TransformBack would trigger the deleted copy ctor. It manages its own
+ // cleanup via the destructor when the transformed-args tuple destructs, so
+ // there is nothing to reverse-transform back into the original arg.
+ template <typename T, typename SB>
+ void TransformBack(T &original_arg,
+ python::ScopedPythonObject<SB> &transformed_arg,
+ Status &error) {}
+
template <std::size_t... I, typename... Ts, typename... Us>
bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,
std::tuple<Us...> &transformed_args,
@@ -846,6 +872,16 @@ std::optional<lldb::ValueType>
ScriptedPythonInterface::ExtractValueFromPythonObject<
std::optional<lldb::ValueType>>(python::PythonObject &p, Status &error);
+template <>
+lldb::DebuggerSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DebuggerSP>(
+ python::PythonObject &p, Status &error);
+
+template <>
+std::vector<std::string>
+ScriptedPythonInterface::ExtractValueFromPythonObject<std::vector<std::string>>(
+ python::PythonObject &p, Status &error);
+
} // namespace lldb_private
#endif // LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 07e0da1dcf70d..9c5391e754396 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -39,7 +39,7 @@ python::PythonObject ToSWIGHelper(void *obj, swig_type_info *info);
/// A class that automatically clears an SB object when it goes out of scope.
/// Use for cases where the SB object points to a temporary/unowned entity.
-template <typename T> class ScopedPythonObject : PythonObject {
+template <typename T> class ScopedPythonObject : public PythonObject {
public:
ScopedPythonObject(T *sb, swig_type_info *info)
: PythonObject(ToSWIGHelper(sb, info)), m_sb(sb) {}
@@ -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);
@@ -247,6 +218,8 @@ void *LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBCommandReturnObject(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBDebugger(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBThread(PyObject *data);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 7b1bd9d8411c5..bb8871e234bc1 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -289,6 +289,9 @@ llvm::Expected<std::string> ScriptInterpreterPython::ExtensionToImportPath(
return "lldb.plugins.scripted_process";
case eScriptedExtensionScriptedStackFrameRecognizer:
return "lldb.plugins.scripted_stackframe_recognizer";
+ case eScriptedExtensionScriptedCommand:
+ case eScriptedExtensionParsedCommand:
+ return "lldb.plugins.scripted_command";
case eScriptedExtensionInvalid:
return llvm::createStringError("invalid extension name");
}
@@ -2003,6 +2006,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);
@@ -2117,28 +2125,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;
@@ -2987,166 +2973,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.
@@ -3180,322 +3006,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..808bb6157e5b8 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;
@@ -126,6 +119,16 @@ lldb_private::python::LLDBSWIGPython_CastPyObjectToSBError(PyObject *data) {
return nullptr;
}
+void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBCommandReturnObject(
+ PyObject *data) {
+ return nullptr;
+}
+
+void *
+lldb_private::python::LLDBSWIGPython_CastPyObjectToSBDebugger(PyObject *data) {
+ return nullptr;
+}
+
void *
lldb_private::python::LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data) {
return nullptr;
@@ -207,40 +210,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