python: Provide textual representation for Inferior and Objfile
authorSimon Marchi <simon.marchi@ericsson.com>
Thu, 13 Sep 2018 15:53:22 +0000 (11:53 -0400)
committerSimon Marchi <simon.marchi@ericsson.com>
Thu, 13 Sep 2018 15:54:38 +0000 (11:54 -0400)
Printing a GDB Python object is notoriously not helpful:

>>> print(gdb.selected_inferior())
<gdb.Inferior object at 0x7fea59aed198>
>>> print(gdb.objfiles())
[<gdb.Objfile object at 0x7fea59b57c90>]

This makes printing debug traces more difficult than it should be.  This
patch provides some repr() implementation for these two types (more to
come if people agree with the idea, but I want to test the water first).
Here's the same example as above, but with this patch:

>>> print(gdb.selected_inferior())
<gdb.Inferior num=1>
>>> print(gdb.objfiles())
[<gdb.Objfile filename=/home/emaisin/build/binutils-gdb-gcc-git/gdb/test>]

I implemented repr rather than str, because when printing a list (or
another container I suppose), Python calls the repr method of the
elements.  This is useful when printing a list of inferiors or objfiles.
The print(gdb.objfiles()) above would not have worked if I had
implemented str.

I found this post useful to understand the difference between repr and
str:

  https://stackoverflow.com/questions/1436703/difference-between-str-and-repr

gdb/ChangeLog:

* python/py-inferior.c (infpy_repr): New.
(inferior_object_type): Register infpy_repr.
* python/py-objfile.c (objfpy_repr): New.
(objfile_object_type): Register objfpy_repr.

gdb/testsuite/ChangeLog:

* gdb.python/py-inferior.exp: Test repr() of gdb.Inferior.
* gdb.python/py-objfile.exp: Test repr() of gdb.Objfile.
* gdb.python/py-symtab.exp: Update test printing an objfile.

gdb/doc/ChangeLog:

* python.texi (Basic Python): Mention the string representation
of GDB Python objects.

gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/python.texi
gdb/python/py-inferior.c
gdb/python/py-objfile.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/py-inferior.exp
gdb/testsuite/gdb.python/py-objfile.exp
gdb/testsuite/gdb.python/py-symtab.exp

index 454c45f9ad4f1e1d5c09672adcdeacb44fdaec19..50a651910531c471cc0b4ea013f218de92f03ec3 100644 (file)
@@ -1,3 +1,10 @@
+2018-09-13  Simon Marchi  <simon.marchi@ericsson.com>
+
+       * python/py-inferior.c (infpy_repr): New.
+       (inferior_object_type): Register infpy_repr.
+       * python/py-objfile.c (objfpy_repr): New.
+       (objfile_object_type): Register objfpy_repr.
+
 2018-09-12  John Baldwin  <jhb@FreeBSD.org>
 
        * fbsd-nat.c (fbsd_nat_target::info_proc): Remove unused variable.
index f04dca4283543c7ab33eb13567045122ca05e9d9..1c965087af65d8dec04067625fb6b9c173ef9ad5 100644 (file)
@@ -1,3 +1,8 @@
+2018-09-13  Simon Marchi  <simon.marchi@ericsson.com>
+
+       * python.texi (Basic Python): Mention the string representation
+       of GDB Python objects.
+
 2018-09-12  Simon Marchi  <simon.marchi@ericsson.com>
 
        * gdb.texinfo (Skipping Over Functions and Files): Document
index 5e2ab76d2bc8a6c0c1c176d234065e5d664890b8..6e2bf5c9effaa6735748a3c752d8c6fee8d7fb7d 100644 (file)
@@ -207,6 +207,10 @@ methods and classes added by @value{GDBN} are placed in this module.
 @value{GDBN} automatically @code{import}s the @code{gdb} module for
 use in all scripts evaluated by the @code{python} command.
 
+Some types of the @code{gdb} module come with a textual representation
+(accessible through the @code{repr} or @code{str} functions).  These are
+offered for debugging purposes only, expect them to change over time.
+
 @findex gdb.PYTHONDIR
 @defvar gdb.PYTHONDIR
 A string containing the python directory (@pxref{Python}).
index 1cf37296973b69b3f17b869fbb3870319b612335..56019bf9e05902768662c72027ed2937145e8025 100644 (file)
@@ -860,6 +860,21 @@ infpy_thread_from_thread_handle (PyObject *self, PyObject *args, PyObject *kw)
   return result;
 }
 
+/* Implement repr() for gdb.Inferior.  */
+
+static PyObject *
+infpy_repr (PyObject *obj)
+{
+  inferior_object *self = (inferior_object *) obj;
+  inferior *inf = self->inferior;
+
+  if (inf == nullptr)
+    return PyString_FromString ("<gdb.Inferior (invalid)>");
+
+  return PyString_FromFormat ("<gdb.Inferior num=%d, pid=%d>",
+                             inf->num, inf->pid);
+}
+
 
 static void
 infpy_dealloc (PyObject *obj)
@@ -991,7 +1006,7 @@ PyTypeObject inferior_object_type =
   0,                             /* tp_getattr */
   0,                             /* tp_setattr */
   0,                             /* tp_compare */
-  0,                             /* tp_repr */
+  infpy_repr,                    /* tp_repr */
   0,                             /* tp_as_number */
   0,                             /* tp_as_sequence */
   0,                             /* tp_as_mapping */
index c2b40ff5352150c9610890f45f72be47356d2ca7..61d3a15819866daa8f9c5ffd0e8adadf71b5bf62 100644 (file)
@@ -456,6 +456,21 @@ objfpy_add_separate_debug_file (PyObject *self, PyObject *args, PyObject *kw)
   Py_RETURN_NONE;
 }
 
+/* Implement repr() for gdb.Objfile.  */
+
+static PyObject *
+objfpy_repr (PyObject *self_)
+{
+  objfile_object *self = (objfile_object *) self_;
+  objfile *obj = self->objfile;
+
+  if (obj == nullptr)
+    return PyString_FromString ("<gdb.Objfile (invalid)>");
+
+  return PyString_FromFormat ("<gdb.Objfile filename=%s>",
+                             objfile_filename (obj));
+}
+
 /* Subroutine of gdbpy_lookup_objfile_by_build_id to simplify it.
    Return non-zero if STRING is a potentially valid build id.  */
 
@@ -709,7 +724,7 @@ PyTypeObject objfile_object_type =
   0,                             /*tp_getattr*/
   0,                             /*tp_setattr*/
   0,                             /*tp_compare*/
-  0,                             /*tp_repr*/
+  objfpy_repr,                   /*tp_repr*/
   0,                             /*tp_as_number*/
   0,                             /*tp_as_sequence*/
   0,                             /*tp_as_mapping*/
index 949f1ae210a1c7450023bc6adb7f27aaf7eb5810..db9c21419905c7741c3e55bec0a8840a1baf966a 100644 (file)
@@ -1,3 +1,9 @@
+2018-09-13  Simon Marchi  <simon.marchi@ericsson.com>
+
+       * gdb.python/py-inferior.exp: Test repr() of gdb.Inferior.
+       * gdb.python/py-objfile.exp: Test repr() of gdb.Objfile.
+       * gdb.python/py-symtab.exp: Update test printing an objfile.
+
 2018-09-12  Simon Marchi  <simon.marchi@ericsson.com>
 
        * gdb.python/py-inferior.exp: Test using an invalid gdb.Inferior
index 055dd87c6d84544f3f66e5d6d0dad875929c2620..7ec81930ff0cdb40fca637565163300f80c0973b 100644 (file)
@@ -45,7 +45,8 @@ if ![runto_main] then {
 # Test basic gdb.Inferior attributes and methods.
 
 gdb_py_test_silent_cmd "python inferiors = gdb.inferiors ()" "get inferiors list" 1
-gdb_test "python print (inferiors)" "\\(<gdb.Inferior object at 0x\[\[:xdigit:\]\]+>,\\)" "verify inferiors list"
+gdb_test "python print (inferiors)" \
+    "\\(<gdb.Inferior num=1, pid=$decimal>,\\)" "verify inferiors list"
 gdb_py_test_silent_cmd "python i0 = inferiors\[0\]" "get first inferior" 0
 
 gdb_test "python print ('result = %s' % (i0 == inferiors\[0\]))" " = True" "test equality comparison (true)"
@@ -279,3 +280,17 @@ with_test_prefix "selected_inferior" {
     gdb_test "inferior 1" ".*" "switch back to first inferior"
     gdb_test_no_output "remove-inferiors 3" "remove second inferior"
 }
+
+# Test repr()/str()
+with_test_prefix "__repr__" {
+    gdb_test "add-inferior" "Added inferior 4" "add inferior 4"
+    gdb_py_test_silent_cmd "python infs = gdb.inferiors()" "get inferior list" 1
+    gdb_test "python print (infs\[0\])" "<gdb.Inferior num=1, pid=$decimal>"
+    gdb_test "python print (infs)" \
+       "\\\(<gdb.Inferior num=1, pid=$decimal>, <gdb.Inferior num=4, pid=$decimal>\\\)" \
+       "print all inferiors 1"
+    gdb_test_no_output "remove-inferiors 4"
+    gdb_test "python print (infs)" \
+       "\\\(<gdb.Inferior num=1, pid=$decimal>, <gdb.Inferior \\\(invalid\\\)>\\\)" \
+       "print all inferiors 2"
+}
index 6e81750cfe9bf707cd6f5daafbb68390076d218a..ce24b56d2b4dc23542d40c4a4e603444f3fb0b9c 100644 (file)
@@ -45,6 +45,9 @@ gdb_test "python print (objfile.filename)" "${testfile}" \
 gdb_test "python print (objfile.username)" "${testfile}" \
   "Get objfile user name"
 
+gdb_test "python print (objfile)" \
+    "<gdb.Objfile filename=[string_to_regexp ${binfile}]>"
+
 gdb_test_no_output "python dir(objfile)"
 
 gdb_test "python print (gdb.lookup_objfile (\"${testfile}\").filename)" \
@@ -149,3 +152,9 @@ if [remote_file host exists "${symlink_binary}"] {
     gdb_test "python print (gdb.lookup_objfile (\"${symlink_binary}\").filename)" \
        "${testfile}" "gdb.lookup_objfile of symlinked binary"
 }
+
+# Test printing an Objfile object that is no longer valid.
+gdb_py_test_silent_cmd "python objfile = gdb.objfiles()\[0\]" \
+    "get first objfile" 1
+gdb_file_cmd ${binfile}
+gdb_test "python print(objfile)" "<gdb.Objfile \\\(invalid\\\)>"
\ No newline at end of file
index f504362526fdd7b4161cb916bb8557f380d4fa3b..545fe95764a808081cd9268eb43b7880d51345db 100644 (file)
@@ -66,7 +66,8 @@ gdb_test "python print (sal.is_valid())" "True" "test sal.is_valid"
 
 # Test symbol table.
 gdb_test "python print (symtab.filename)" ".*${py_symbol_c}" "test symtab.filename"
-gdb_test "python print (symtab.objfile)" "<gdb.Objfile object at ${hex}>" "test symtab.objfile"
+gdb_test "python print (symtab.objfile)" "<gdb.Objfile filename=${binfile}>" \
+    "test symtab.objfile"
 gdb_test "python print (symtab.fullname())" ".*${full_py_symbol_c}" "test symtab.fullname"
 gdb_test "python print (symtab.is_valid())" "True" "test symtab.is_valid()"
 gdb_test "python print (\"qq\" in global_symbols)" "True" "test qq in global symbols"