From 5f3b99cfed3803f0b099152f54aac7cb90a2b926 Mon Sep 17 00:00:00 2001 From: Sasha Smundak Date: Wed, 3 Sep 2014 16:34:47 -0700 Subject: [PATCH] Add support for reading frame registers to Python API. The ability to read registers is needed to use Frame Filter API to display the frames created by JIT compilers. gdb/ChangeLog: 2014-08-29 Sasha Smundak * python/py-frame.c (frapy_read_register): New function. gdb/doc/ChangeLog: 2014-08-26 Sasha Smundak * python.texi (Frames in Python): Add read_register description. gdb/testsuite/ChangeLog: 2014-08-26 Sasha Smundak * gdb.python/py-frame.exp: Test Frame.read_register. --- gdb/ChangeLog | 4 +++ gdb/NEWS | 3 +++ gdb/doc/ChangeLog | 4 +++ gdb/doc/python.texi | 7 +++++ gdb/python/py-frame.c | 38 +++++++++++++++++++++++++++ gdb/testsuite/ChangeLog | 4 +++ gdb/testsuite/gdb.python/py-frame.exp | 17 ++++++++++++ 7 files changed, 77 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ad1a87b782..7348bfb223 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,7 @@ +2014-09-03 Sasha Smundak + + * python/py-frame.c (frapy_read_register): New function. + 2014-09-03 James Hogan * mips-linux-nat.c (mips_linux_read_description): Reset errno to 0 diff --git a/gdb/NEWS b/gdb/NEWS index d603cf75d1..46c6a8746b 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,9 @@ *** Changes since GDB 7.8 +* Python Scripting + You can now access frame registers from Python scripts. + * On resume, GDB now always passes the signal the program had stopped for to the thread the signal was sent to, even if the user changed threads before resuming. Previously GDB would often (but not diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 2bf94bc82a..767a598c0b 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2014-09-03 Sasha Smundak + + * python.texi (Frames in Python): Add read_register description. + 2014-08-04 Tom Tromey * gdb.texinfo (Debugging Output): Update for change to "set debug diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 4688783e40..3cb6bf8b28 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -3589,6 +3589,13 @@ Return the frame's symtab and line object. @xref{Symbol Tables In Python}. @end defun +@defun Frame.read_register (register) +Return the value of @var{register} in this frame. The @var{register} +argument must be a string (e.g., @code{'sp'} or @code{'rax'}). +Returns a @code{Gdb.Value} object. Throws an exception if @var{register} +does not exist. +@end defun + @defun Frame.read_var (variable @r{[}, block@r{]}) Return the value of @var{variable} in this frame. If the optional argument @var{block} is provided, search for the variable from that diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index 120e147e65..859d115896 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -28,6 +28,7 @@ #include "python-internal.h" #include "symfile.h" #include "objfiles.h" +#include "user-regs.h" typedef struct { PyObject_HEAD @@ -235,6 +236,40 @@ frapy_pc (PyObject *self, PyObject *args) return gdb_py_long_from_ulongest (pc); } +/* Implementation of gdb.Frame.read_register (self, register) -> gdb.Value. + Returns the value of a register in this frame. */ + +static PyObject * +frapy_read_register (PyObject *self, PyObject *args) +{ + volatile struct gdb_exception except; + const char *regnum_str; + struct value *val = NULL; + + if (!PyArg_ParseTuple (args, "s", ®num_str)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct frame_info *frame; + int regnum; + + FRAPY_REQUIRE_VALID (self, frame); + + regnum = user_reg_map_name_to_regnum (get_frame_arch (frame), + regnum_str, + strlen (regnum_str)); + if (regnum >= 0) + val = value_of_register (regnum, frame); + + if (val == NULL) + PyErr_SetString (PyExc_ValueError, _("Unknown register.")); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return val == NULL ? NULL : value_to_value_object (val); +} + /* Implementation of gdb.Frame.block (self) -> gdb.Block. Returns the frame's code block. */ @@ -674,6 +709,9 @@ Return the reason why it's not possible to find frames older than this." }, { "pc", frapy_pc, METH_NOARGS, "pc () -> Long.\n\ Return the frame's resume address." }, + { "read_register", frapy_read_register, METH_VARARGS, + "read_register (register_name) -> gdb.Value\n\ +Return the value of the register in the frame." }, { "block", frapy_block, METH_NOARGS, "block () -> gdb.Block.\n\ Return the frame's code block." }, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d6db24be57..10d27b3c0a 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2014-09-03 Sasha Smundak + + * gdb.python/py-frame.exp: Test Frame.read_register. + 2014-09-03 Sergio Durigan Junior PR python/16699 diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp index 3517824b3d..e47f3407e1 100644 --- a/gdb/testsuite/gdb.python/py-frame.exp +++ b/gdb/testsuite/gdb.python/py-frame.exp @@ -94,3 +94,20 @@ gdb_test "python print ('result = %s' % f0.read_var ('variable_which_surely_does gdb_test "python print ('result = %s' % f0.read_var ('a'))" " = 1" "test Frame.read_var - success" gdb_test "python print ('result = %s' % (gdb.selected_frame () == f1))" " = True" "test gdb.selected_frame" + +# Can read SP register. +gdb_test "python print ('result = %s' % (gdb.selected_frame ().read_register ('sp') == gdb.parse_and_eval ('\$sp')))" \ + " = True" \ + "test Frame.read_register(sp)" + +# PC value obtained via read_register is as expected. +gdb_test "python print ('result = %s' % (f0.read_register('pc') == f0.pc()))" \ + " = True" \ + "test Frame.read_register(pc)" + +# On x86-64, PC is in $rip register. +if {[istarget x86_64-*]} { + gdb_test "python print ('result = %s' % (f0.read_register('pc') == f0.read_register('rip')))" \ + " = True" \ + "test Frame.read_register(rip)" +} -- 2.34.1