Add support for reading frame registers to Python API.
authorSasha Smundak <asmundak@google.com>
Wed, 3 Sep 2014 23:34:47 +0000 (16:34 -0700)
committerDoug Evans <dje@google.com>
Wed, 3 Sep 2014 23:34:47 +0000 (16:34 -0700)
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  <asmundak@google.com>

* python/py-frame.c (frapy_read_register): New function.

gdb/doc/ChangeLog:

2014-08-26  Sasha Smundak  <asmundak@google.com>

* python.texi (Frames in Python): Add read_register description.

gdb/testsuite/ChangeLog:

2014-08-26  Sasha Smundak  <asmundak@google.com>

* gdb.python/py-frame.exp: Test Frame.read_register.

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/python.texi
gdb/python/py-frame.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/py-frame.exp

index ad1a87b78214d87b1309e0dd809f307a11162589..7348bfb223d84cb9db1c3a067e9627c9e5e0ba68 100644 (file)
@@ -1,3 +1,7 @@
+2014-09-03  Sasha Smundak  <asmundak@google.com>
+
+       * python/py-frame.c (frapy_read_register): New function.
+
 2014-09-03  James Hogan  <james.hogan@imgtec.com>
 
        * mips-linux-nat.c (mips_linux_read_description): Reset errno to 0
index d603cf75d14d305902dfe70eee42368b026700ba..46c6a8746b2ecd3934eb5bfa3550e4586e388a47 100644 (file)
--- 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
index 2bf94bc82a9c047342903f096d3bb26232ff999c..767a598c0bd004f8b43f80aae6b9e04dfbcced5f 100644 (file)
@@ -1,3 +1,7 @@
+2014-09-03  Sasha Smundak  <asmundak@google.com>
+
+       * python.texi (Frames in Python): Add read_register description.
+
 2014-08-04  Tom Tromey  <tromey@redhat.com>
 
        * gdb.texinfo (Debugging Output): Update for change to "set debug
index 4688783e40a3437179a6f37c371df143506f99c1..3cb6bf8b28bc6ae81fbda0a32525ca3f7d2a48c0 100644 (file)
@@ -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
index 120e147e656b33ed47b0db9c8bf3e4a0d0de7baf..859d11589645b0937b323a4b1d2ec20524d50051 100644 (file)
@@ -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", &regnum_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." },
index d6db24be57bb96108c45111b822922b1ff46a1a6..10d27b3c0a1468d530874e353c9b55342b03ac4a 100644 (file)
@@ -1,3 +1,7 @@
+2014-09-03  Sasha Smundak  <asmundak@google.com>
+
+       * gdb.python/py-frame.exp: Test Frame.read_register.
+
 2014-09-03  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        PR python/16699
index 3517824b3d742491d9d0b02d09b67d8912c0dba4..e47f3407e1947c984aa30bc1bdc2f685f69fdd2e 100644 (file)
@@ -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)"
+}