diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 374d113..2a3ae65 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -19029,7 +19029,24 @@ can access its @code{foo} element with: bar = some_val['foo'] @end smallexample -Again, @code{bar} will also be a @code{gdb.Value} object. +@code{bar} will be a @code{gdb.Value} object. + +Inferior values that represent a function or a function pointer can be +called by supplying the arguments to the function in brackets, and +calling the value in Python. For example, if @code{some_val} is a +@code{gdb.Value} instance holding a function or function pointer that +takes two integers as arguments, you may execute that function and +store its return value, if any, like so: + +@smallexample +result = some_val (10,20) +@end smallexample + +Again, @code{result} will be a @code{gdb.Value} object. + +The arguments provided must match the function prototype of the +function or the call will fail. Any errors generated from the +inferior function call will be raised as an exception. The following attributes are provided: diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c index 159c118..3a83e3f 100644 --- a/gdb/python/python-value.c +++ b/gdb/python/python-value.c @@ -25,6 +25,7 @@ #include "language.h" #include "dfp.h" #include "valprint.h" +#include "infcall.h" #ifdef HAVE_PYTHON @@ -346,6 +347,48 @@ valpy_setitem (PyObject *self, PyObject *key, PyObject *value) return -1; } +/* Called by the Python interpreter to perform an inferior function + call on the value in question. */ +static PyObject * +valpy_call (PyObject *self, PyObject *args, PyObject *keywords) +{ + struct value *return_value; + Py_ssize_t args_count; + volatile struct gdb_exception except; + struct value *function = ((value_object *) self)->value; + struct value **vargs = NULL; + + args_count = PyTuple_Size (args); + if (args_count > 0) + { + int i; + vargs = alloca (sizeof (struct value *) * args_count); + for (i = 0; i < args_count; i++) + { + vargs[i] = convert_value_from_python (PyTuple_GetItem (args, i)); + /* Check each argument converstion for any exceptions that + may have been raised during converstion. If any one + of the arguments raised an exception during converstion, + then the call should be aborted. */ + if (PyErr_Occurred ()) + { + PyErr_SetString (PyExc_RuntimeError, + _("An error was encountered while " + "converting an argument for an inferior " + "function call. Call aborted.")); + return NULL; + } + } + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + return_value = call_function_by_hand (function, args_count, vargs); + } + GDB_PY_HANDLE_EXCEPTION (except); + return value_to_value_object (return_value); +} + /* Called by the Python interpreter to obtain string representation of the object. */ static PyObject * @@ -1070,7 +1113,7 @@ PyTypeObject value_object_type = { 0, /*tp_as_sequence*/ &value_object_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash */ - 0, /*tp_call*/ + (ternaryfunc)valpy_call, /*tp_call*/ valpy_str, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c index adf66b5..8d69d25 100644 --- a/gdb/testsuite/gdb.python/python-prettyprint.c +++ b/gdb/testsuite/gdb.python/python-prettyprint.c @@ -16,6 +16,7 @@ along with this program. If not, see . */ #include +#include struct s { @@ -80,6 +81,26 @@ class Derived : public Vbase1, public Vbase2, public Vbase3 } }; +class InferiorCall +{ + private: + int value; + + public: + InferiorCall () + { + value = 0; + } + + int add (int i) + { + value += i; /* Inferior breakpoint here. */ + if (value > 20) + raise (SIGABRT); + + return value; + } +}; #endif typedef struct string_repr @@ -200,7 +221,9 @@ main () SSS& ref (sss); Derived derived; - + InferiorCall inf; + inf.add (10); + #endif add_item (&c, 23); /* MI breakpoint here */ diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp index b2dc85d..24f06ad 100644 --- a/gdb/testsuite/gdb.python/python-prettyprint.exp +++ b/gdb/testsuite/gdb.python/python-prettyprint.exp @@ -76,6 +76,13 @@ proc run_lang_tests {lang} { gdb_test "print derived" \ " = \{.* = pp class name: Vbase1.* = \{.* = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.* = \{.*members of Vbase3.*members of Derived:.*value = 2.*" gdb_test "print ns " "\"embedded\\\\000null\\\\000string\"" + gdb_test "print inf" "Total is: 20.*" + gdb_test "print inf" "RuntimeError: The program being debugged was signaled while in a function called from GDB.*" + runto [gdb_get_line_number "break to inspect"] + gdb_test "b [gdb_get_line_number {Inferior breakpoint here} ${testfile}.c ]" \ + ".*Breakpoint.*" + gdb_test "print inf" "RuntimeError: The program being debugged stopped while in a function called from GDB.*" + runto [gdb_get_line_number "break to inspect"] } gdb_test "print x" " = $hex \"this is x\"" diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py index c3e0dc4..821317d 100644 --- a/gdb/testsuite/gdb.python/python-prettyprint.py +++ b/gdb/testsuite/gdb.python/python-prettyprint.py @@ -92,6 +92,13 @@ class pp_vbase1: def to_string (self): return "pp class name: " + self.val.type.tag +class pp_inferiorcall: + def __init__ (self, val): + self.val = val + + def to_string (self): + return "Total is: %s" % (self.val['add'](self.val.address, 10)) + class pp_nullstr: def __init__(self, val): self.val = val @@ -156,6 +163,8 @@ def register_pretty_printers (): pretty_printers_dict[re.compile ('^VirtualTest$')] = pp_multiple_virtual pretty_printers_dict[re.compile ('^Vbase1$')] = pp_vbase1 + pretty_printers_dict[re.compile ('^InferiorCall$')] = pp_inferiorcall + pretty_printers_dict[re.compile ('^struct nullstr$')] = pp_nullstr pretty_printers_dict[re.compile ('^nullstr$')] = pp_nullstr diff --git a/gdb/testsuite/gdb.python/python-value.c b/gdb/testsuite/gdb.python/python-value.c index f3d6284..bc3fb24 100644 --- a/gdb/testsuite/gdb.python/python-value.c +++ b/gdb/testsuite/gdb.python/python-value.c @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include + struct s { int a; @@ -37,6 +39,16 @@ typedef struct s *PTR; enum e evalue = TWO; +void func1 () +{ + printf ("void function called\n"); +} + +int func2 (int arg1, int arg2) +{ + return arg1 + arg2; +} + int main (int argc, char *argv[]) { @@ -46,10 +58,13 @@ main (int argc, char *argv[]) PTR x = &s; char st[17] = "divide et impera"; char nullst[17] = "divide\0et\0impera"; + void (*fp1) (void) = &func1; + int (*fp2) (int, int) = &func2; s.a = 3; s.b = 5; u.a = 7; - + (*fp1) (); + (*fp2) (10,20); return 0; /* break to inspect struct and union */ } diff --git a/gdb/testsuite/gdb.python/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp index ccf438f..30aae27 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -218,6 +218,18 @@ proc test_value_in_inferior {} { gdb_test "python print repr(nullst)" "u'divide\\\\x00et'" } +proc test_inferior_function_call {} { + global gdb_prompt hex + gdb_test "p/x fp1" " = $hex.*" + gdb_py_test_silent_cmd "python fp1 = gdb.history (0)" "get value from history" 1 + gdb_test "python result = fp1()" "" + gdb_test "python print result" "void" + gdb_test "p/x fp2" " = $hex.*" + gdb_py_test_silent_cmd "python fp2 = gdb.history (0)" "get value from history" 1 + gdb_test "python result2 = fp2(10,20)" "" + gdb_test "python print result2" "30" +} + # A few objfile tests. proc test_objfiles {} { gdb_test "python\nok=False\nfor file in gdb.objfiles():\n if 'python-value' in file.filename:\n ok=True\nprint ok\nend" "True" @@ -300,5 +312,6 @@ if ![runto_main] then { } test_value_in_inferior +test_inferior_function_call test_value_after_death test_cast_regression