diff --git a/gdb/NEWS b/gdb/NEWS index ec3058ea118..f9485520438 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -10,6 +10,13 @@ maint show backtrace-on-fatal-signal fatal signal. This only supported on some platforms where the backtrace and backtrace_symbols_fd functions are available. +* Python API + + ** New function gdb.add_history(), which takes a gdb.Value object + and adds the value it represents to GDB's history list. An + integer, the index of the new item in the history list, is + returned. + *** Changes in GDB 11 * The 'set disassembler-options' command now supports specifying options diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index f4865b3d6a6..d8f682a091c 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -346,6 +346,20 @@ If no exception is raised, the return value is always an instance of @code{gdb.Value} (@pxref{Values From Inferior}). @end defun +@defun gdb.add_history (value) +Takes @var{value}, an instance of @code{gdb.Value} (@pxref{Values From +Inferior}), and appends the value this object represents to +@value{GDBN}'s value history (@pxref{Value History}), and return an +integer, its history number. If @var{value} is not a +@code{gdb.Value}, it is is converted using the @code{gdb.Value} +constructor. If @var{value} can't be converted to a @code{gdb.Value} +then a @code{TypeError} is raised. + +When a command implemented in Python prints a single @code{gdb.Value} +as its result, then placing the value into the history will allow the +user convenient access to those values via CLI history facilities. +@end defun + @findex gdb.convenience_variable @defun gdb.convenience_variable (name) Return the value of the convenience variable (@pxref{Convenience diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 8df8a15f8d6..26d5940f842 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -1960,6 +1960,33 @@ gdbpy_history (PyObject *self, PyObject *args) return value_to_value_object (res_val); } +/* Add a gdb.Value into GDB's history, and return (as an integer) the + position of the newly added value. */ +PyObject * +gdbpy_add_history (PyObject *self, PyObject *args) +{ + PyObject *value_obj; + + if (!PyArg_ParseTuple (args, "O", &value_obj)) + return nullptr; + + struct value *value = convert_value_from_python (value_obj); + if (value == nullptr) + return nullptr; + + try + { + int idx = record_latest_value (value); + return gdb_py_object_from_longest (idx).release (); + } + catch (const gdb_exception &except) + { + GDB_PY_HANDLE_EXCEPTION (except); + } + + return nullptr; +} + /* Return the value of a convenience variable. */ PyObject * gdbpy_convenience_variable (PyObject *self, PyObject *args) diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 690d2fb43c0..0e140f1af61 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -412,6 +412,7 @@ extern enum ext_lang_rc gdbpy_get_matching_xmethod_workers PyObject *gdbpy_history (PyObject *self, PyObject *args); +PyObject *gdbpy_add_history (PyObject *self, PyObject *args); PyObject *gdbpy_convenience_variable (PyObject *self, PyObject *args); PyObject *gdbpy_set_convenience_variable (PyObject *self, PyObject *args); PyObject *gdbpy_breakpoints (PyObject *, PyObject *); diff --git a/gdb/python/python.c b/gdb/python/python.c index e42cbc4fd5e..6af9c722e7b 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -2076,6 +2076,8 @@ PyMethodDef python_GdbMethods[] = { { "history", gdbpy_history, METH_VARARGS, "Get a value from history" }, + { "add_history", gdbpy_add_history, METH_VARARGS, + "Add a value to the value history list" }, { "execute", (PyCFunction) execute_gdb_command, METH_VARARGS | METH_KEYWORDS, "execute (command [, from_tty] [, to_string]) -> [String]\n\ Evaluate command, a string, as a gdb CLI command. Optionally returns\n\ diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp index eca4a474727..d9f1a76a388 100644 --- a/gdb/testsuite/gdb.python/py-value.exp +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -575,6 +575,31 @@ proc test_value_from_buffer {} { "attempt to construct value with string as type" } +# Test the gdb.add_history API. +proc test_add_to_history {} { + # Add a gdb.Value to the value history list. + gdb_test_no_output "python idx = gdb.add_history(gdb.Value(42))" \ + "add value 42 to the history list" + gdb_test "python print (\"$%d = %s\" % (idx, gdb.history (idx)))" \ + " = 42" "print value 42 from the history list" + set idx [get_python_valueof "idx" "**DEFAULT**" "get idx for value 42"] + gdb_test "print \$${idx}" " = 42" + + # Add something to the history list that can be converted into a + # gdb.Value. + gdb_test_no_output "python idx = gdb.add_history(84)" \ + "add value to 84 to the history list" + gdb_test "python print (\"$%d = %s\" % (idx, gdb.history (idx)))" \ + " = 84" "print value 84 from the history list" + set idx [get_python_valueof "idx" "**DEFAULT**" "get idx for value 84"] + gdb_test "print \$${idx}" " = 84" + + # Try adding something that can't be converted to a gdb.Value, + # this should give an error. + gdb_test "python idx = gdb.add_history(gdb.GdbError(\"an error\"))" \ + "TypeError: Could not convert Python object: .*" +} + # Build C version of executable. C++ is built later. if { [build_inferior "${binfile}" "c"] < 0 } { return -1 @@ -594,6 +619,7 @@ test_objfiles test_parse_and_eval test_value_hash test_float_conversion +test_add_to_history # The following tests require execution.