Skip to content

Commit e4ba69a

Browse files
committed
[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.
1 parent c6c08ee commit e4ba69a

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

lldb/bindings/python/python-typemaps.swig

Lines changed: 26 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,32 @@ 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+
// FIXME (filcab): We can't currently check if our callback is already
486+
// LLDBSwigPythonCallPythonSBDebuggerTerminateCallback (to DECREF the previous
487+
// baton) nor can we just remove all traces of a callback, if we want to
488+
// revert to a file logging mechanism.
489+
490+
// Don't lose the callback reference
491+
Py_INCREF($input);
492+
$1 = LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback;
493+
$2 = $input;
494+
}
495+
496+
%typemap(typecheck) (lldb::CommandOverrideCallback callback,
497+
498+
void *baton) {
499+
500+
$1 = $input == Py_None;
501+
$1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
502+
}
503+
479504
%typemap(in) lldb::FileSP {
480505
PythonFile py_file(PyRefType::Borrowed, $input);
481506
if (!py_file) {

lldb/bindings/python/python-wrapper.swig

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

1102+
static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) {
1103+
bool b = false;
1104+
if (baton != Py_None) {
1105+
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
1106+
PyObject *result = PyObject_CallFunction(
1107+
reinterpret_cast<PyObject *>(baton), const_cast<char *>("s"), argv); // WRONG!!!!!
1108+
b = result ? PyObject_IsTrue(result) : false;
1109+
Py_XDECREF(result);
1110+
SWIG_PYTHON_THREAD_END_BLOCK;
1111+
}
1112+
return b;
1113+
}
1114+
11021115
static SBError LLDBSwigPythonCallLocateModuleCallback(
11031116
void *callback_baton, const SBModuleSpec &module_spec_sb,
11041117
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: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
class CommandOverrideCallback(TestBase):
8+
def setUp(self):
9+
TestBase.setUp(self)
10+
self.line = line_number("main.c", "Hello world.")
11+
12+
def test_command_override_callback(self):
13+
self.build()
14+
exe = self.getBuildArtifact("a.out")
15+
16+
# Create a target by the debugger.
17+
target = self.dbg.CreateTarget(exe)
18+
self.assertTrue(target, VALID_TARGET)
19+
20+
# Retrieve the associated command interpreter from our debugger.
21+
ci = self.dbg.GetCommandInterpreter()
22+
self.assertTrue(ci, VALID_COMMAND_INTERPRETER)
23+
24+
override_string = "what"
25+
def foo(string):
26+
nonlocal override_string
27+
override_string = string
28+
return False
29+
30+
self.assertTrue(ci.SetCommandOverrideCallback("breakpoint", foo))

0 commit comments

Comments
 (0)