https://github.com/chelcassanova created https://github.com/llvm/llvm-project/pull/94518
`SBCommandInterpreter::CommandOverrideCallback` was not being exposed to the Python API has no coverage in the API test suite, so this commits exposes and adds a test for it. Doing this involves also adding a typemap for the callback used for this function so that it matches the functionality of other callback functions that are exposed to Python. >From 90602ed1b2f27fecb9e1fc28419587cf6bcb04bf Mon Sep 17 00:00:00 2001 From: Chelsea Cassanova <chelsea_cassan...@apple.com> Date: Wed, 5 Jun 2024 11:24:01 -0700 Subject: [PATCH] [lldb][api-test] Add API test for SBCommandInterpreter::CommandOverrideCallback `SBCommandInterpreter::CommandOverrideCallback` was not being exposed to the Python API has no coverage in the API test suite, so this commits exposes and adds a test for it. Doing this involves also adding a typemap for the callback used for this function so that it matches the functionality of other callback functions that are exposed to Python. --- lldb/bindings/python/python-typemaps.swig | 27 ++++++++++++++++- lldb/bindings/python/python-wrapper.swig | 13 ++++++++ lldb/include/lldb/API/SBCommandInterpreter.h | 2 -- .../TestCommandOverrideCallback.py | 30 +++++++++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig index 8d4b740e5f35c..1bf93c59fbc7b 100644 --- a/lldb/bindings/python/python-typemaps.swig +++ b/lldb/bindings/python/python-typemaps.swig @@ -427,7 +427,6 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) { free($1); } - // For Log::LogOutputCallback %typemap(in) (lldb::LogOutputCallback log_callback, void *baton) { if (!($input == Py_None || @@ -476,6 +475,32 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) { $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); } +%typemap(in) (lldb::CommandOverrideCallback callback, void *baton) { + if (!($input == Py_None || + PyCallable_Check(reinterpret_cast<PyObject *>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + SWIG_fail; + } + + // FIXME (filcab): We can't currently check if our callback is already + // LLDBSwigPythonCallPythonSBDebuggerTerminateCallback (to DECREF the previous + // baton) nor can we just remove all traces of a callback, if we want to + // revert to a file logging mechanism. + + // Don't lose the callback reference + Py_INCREF($input); + $1 = LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback; + $2 = $input; +} + +%typemap(typecheck) (lldb::CommandOverrideCallback callback, + + void *baton) { + + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); +} + %typemap(in) lldb::FileSP { PythonFile py_file(PyRefType::Borrowed, $input); if (!py_file) { diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig index 1370afc885d43..0a332cb0a2ff4 100644 --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -1099,6 +1099,19 @@ static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t } } +static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) { + bool b = false; + if (baton != Py_None) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyObject *result = PyObject_CallFunction( + reinterpret_cast<PyObject *>(baton), const_cast<char *>("s"), argv); // WRONG!!!!! + b = result ? PyObject_IsTrue(result) : false; + Py_XDECREF(result); + SWIG_PYTHON_THREAD_END_BLOCK; + } + return b; +} + static SBError LLDBSwigPythonCallLocateModuleCallback( void *callback_baton, const SBModuleSpec &module_spec_sb, SBFileSpec &module_file_spec_sb, SBFileSpec &symbol_file_spec_sb) { diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h index 8ac36344b3a79..084b6d9adb703 100644 --- a/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/lldb/include/lldb/API/SBCommandInterpreter.h @@ -265,11 +265,9 @@ class SBCommandInterpreter { // Catch commands before they execute by registering a callback that will get // called when the command gets executed. This allows GUI or command line // interfaces to intercept a command and stop it from happening -#ifndef SWIG bool SetCommandOverrideCallback(const char *command_name, lldb::CommandOverrideCallback callback, void *baton); -#endif /// Return true if the command interpreter is the active IO handler. /// diff --git a/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py b/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py new file mode 100644 index 0000000000000..067f37f88096d --- /dev/null +++ b/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py @@ -0,0 +1,30 @@ +from typing_extensions import override +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class CommandOverrideCallback(TestBase): + def setUp(self): + TestBase.setUp(self) + self.line = line_number("main.c", "Hello world.") + + def test_command_override_callback(self): + self.build() + exe = self.getBuildArtifact("a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # Retrieve the associated command interpreter from our debugger. + ci = self.dbg.GetCommandInterpreter() + self.assertTrue(ci, VALID_COMMAND_INTERPRETER) + + override_string = "what" + def foo(string): + nonlocal override_string + override_string = string + return False + + self.assertTrue(ci.SetCommandOverrideCallback("breakpoint", foo)) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits