Skip to content

Commit 6fb6eba

Browse files
[lldb][api-test] Add API test for SBCommandInterpreter::CommandOverrideCallback (llvm#94518)
`SBCommandInterpreter::CommandOverrideCallback` was not being exposed to the Python API and 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.
1 parent 0fb216f commit 6fb6eba

File tree

4 files changed

+70
-3
lines changed

4 files changed

+70
-3
lines changed

lldb/bindings/python/python-typemaps.swig

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,6 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
427427
free($1);
428428
}
429429

430-
431430
// For Log::LogOutputCallback
432431
%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) {
433432
if (!($input == Py_None ||
@@ -476,6 +475,23 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
476475
$1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
477476
}
478477

478+
%typemap(in) (lldb::CommandOverrideCallback callback, void *baton) {
479+
if (!($input == Py_None ||
480+
PyCallable_Check(reinterpret_cast<PyObject *>($input)))) {
481+
PyErr_SetString(PyExc_TypeError, "Need a callable object or None!");
482+
SWIG_fail;
483+
}
484+
485+
// Don't lose the callback reference.
486+
Py_INCREF($input);
487+
$1 = LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback;
488+
$2 = $input;
489+
}
490+
%typemap(typecheck) (lldb::CommandOverrideCallback callback, void *baton) {
491+
$1 = $input == Py_None;
492+
$1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
493+
}
494+
479495
%typemap(in) lldb::FileSP {
480496
PythonFile py_file(PyRefType::Borrowed, $input);
481497
if (!py_file) {

lldb/bindings/python/python-wrapper.swig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,28 @@ static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t
10991099
}
11001100
}
11011101

1102+
static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) {
1103+
bool ret_val = false;
1104+
if (baton != Py_None) {
1105+
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
1106+
// Create a PyList of items since we're going to pass it to the callback as a tuple
1107+
// of arguments.
1108+
PyObject *py_argv = PyList_New(0);
1109+
for (const char **arg = argv; arg && *arg; arg++) {
1110+
std::string arg_string = *arg;
1111+
PyObject *py_string = PyUnicode_FromStringAndSize(arg_string.c_str(), arg_string.size());
1112+
PyList_Append(py_argv, py_string);
1113+
}
1114+
1115+
PyObject *result = PyObject_CallObject(
1116+
reinterpret_cast<PyObject *>(baton), PyList_AsTuple(py_argv));
1117+
ret_val = result ? PyObject_IsTrue(result) : false;
1118+
Py_XDECREF(result);
1119+
SWIG_PYTHON_THREAD_END_BLOCK;
1120+
}
1121+
return ret_val;
1122+
}
1123+
11021124
static SBError LLDBSwigPythonCallLocateModuleCallback(
11031125
void *callback_baton, const SBModuleSpec &module_spec_sb,
11041126
SBFileSpec &module_file_spec_sb, SBFileSpec &symbol_file_spec_sb) {

lldb/include/lldb/API/SBCommandInterpreter.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,9 @@ class SBCommandInterpreter {
265265
// Catch commands before they execute by registering a callback that will get
266266
// called when the command gets executed. This allows GUI or command line
267267
// interfaces to intercept a command and stop it from happening
268-
#ifndef SWIG
269268
bool SetCommandOverrideCallback(const char *command_name,
270269
lldb::CommandOverrideCallback callback,
271270
void *baton);
272-
#endif
273271

274272
/// Return true if the command interpreter is the active IO handler.
275273
///
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from typing_extensions import override
2+
import lldb
3+
from lldbsuite.test.decorators import *
4+
from lldbsuite.test.lldbtest import *
5+
from lldbsuite.test import lldbutil
6+
7+
8+
class CommandOverrideCallback(TestBase):
9+
def setUp(self):
10+
TestBase.setUp(self)
11+
self.line = line_number("main.c", "Hello world.")
12+
13+
def test_command_override_callback(self):
14+
self.build()
15+
exe = self.getBuildArtifact("a.out")
16+
17+
target = self.dbg.CreateTarget(exe)
18+
self.assertTrue(target, VALID_TARGET)
19+
20+
ci = self.dbg.GetCommandInterpreter()
21+
self.assertTrue(ci, VALID_COMMAND_INTERPRETER)
22+
23+
command_arg = ""
24+
25+
def foo(*command_args):
26+
nonlocal command_arg
27+
command_arg = command_args[0]
28+
29+
self.assertTrue(ci.SetCommandOverrideCallback("breakpoint set", foo))
30+
self.expect("breakpoint set -n main")
31+
self.assertTrue(command_arg == "breakpoint")

0 commit comments

Comments
 (0)