gdb: add __repr__() implementation to a few Python types
authorMatheus Branco Borella <dark.ryu.550@gmail.com>
Thu, 18 May 2023 03:33:57 +0000 (00:33 -0300)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 4 Jul 2023 11:07:16 +0000 (12:07 +0100)
Only a few types in the Python API currently have __repr__()
implementations.  This patch adds a few more of them. specifically: it
adds __repr__() implementations to gdb.Symbol, gdb.Architecture,
gdb.Block, gdb.Breakpoint, gdb.BreakpointLocation, and gdb.Type.

This makes it easier to play around the GDB Python API in the Python
interpreter session invoked with the 'pi' command in GDB, giving more
easily accessible tipe information to users.

An example of how this would look like:

  (gdb) pi
  >> gdb.lookup_type("char")
  <gdb.Type code=TYPE_CODE_INT name=char>
  >> gdb.lookup_global_symbol("main")
  <gdb.Symbol print_name=main>

The gdb.Block.__repr__() method shows the first 5 symbols from the
block, and then a message to show how many more were elided (if any).

12 files changed:
gdb/python/py-arch.c
gdb/python/py-block.c
gdb/python/py-breakpoint.c
gdb/python/py-symbol.c
gdb/python/py-type.c
gdb/testsuite/gdb.python/py-arch.exp
gdb/testsuite/gdb.python/py-block.c
gdb/testsuite/gdb.python/py-block.exp
gdb/testsuite/gdb.python/py-bp-locations.exp
gdb/testsuite/gdb.python/py-breakpoint.exp
gdb/testsuite/gdb.python/py-symbol.exp
gdb/testsuite/gdb.python/py-type.exp

index 4d133d1fe144fac1a1e5e5cd10db8f02f6f46945..ac519331f18d5c02f4b4dec9553657cc21054e94 100644 (file)
@@ -319,6 +319,21 @@ archpy_integer_type (PyObject *self, PyObject *args, PyObject *kw)
   return type_to_type_object (type);
 }
 
+/* __repr__ implementation for gdb.Architecture.  */
+
+static PyObject *
+archpy_repr (PyObject *self)
+{
+  const auto gdbarch = arch_object_to_gdbarch (self);
+  if (gdbarch == nullptr)
+    return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+
+  auto arch_info = gdbarch_bfd_arch_info (gdbarch);
+  return PyUnicode_FromFormat ("<%s arch_name=%s printable_name=%s>",
+                              Py_TYPE (self)->tp_name, arch_info->arch_name,
+                              arch_info->printable_name);
+}
+
 /* Implementation of gdb.architecture_names().  Return a list of all the
    BFD architecture names that GDB understands.  */
 
@@ -395,7 +410,7 @@ PyTypeObject arch_object_type = {
   0,                                  /* tp_getattr */
   0,                                  /* tp_setattr */
   0,                                  /* tp_compare */
-  0,                                  /* tp_repr */
+  archpy_repr,                        /* tp_repr */
   0,                                  /* tp_as_number */
   0,                                  /* tp_as_sequence */
   0,                                  /* tp_as_mapping */
index 09fa74d862cac5779d3cb484252b9852e31528cd..dd6d6d278a037db7376d9f0ae1fa9be97ff947f1 100644 (file)
@@ -418,6 +418,41 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
   Py_RETURN_TRUE;
 }
 
+/* __repr__ implementation for gdb.Block.  */
+
+static PyObject *
+blpy_repr (PyObject *self)
+{
+  const auto block = block_object_to_block (self);
+  if (block == nullptr)
+    return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+
+  const auto name = block->function () ?
+    block->function ()->print_name () : "<anonymous>";
+
+  std::string str;
+  unsigned int written_symbols = 0;
+  const int len = mdict_size (block->multidict ());
+  static constexpr int SYMBOLS_TO_SHOW = 5;
+  for (struct symbol *symbol : block_iterator_range (block))
+    {
+      if (written_symbols == SYMBOLS_TO_SHOW)
+       {
+         const int remaining = len - SYMBOLS_TO_SHOW;
+         if (remaining == 1)
+           str += string_printf ("... (%d more symbol)", remaining);
+         else
+           str += string_printf ("... (%d more symbols)", remaining);
+         break;
+       }
+      str += symbol->print_name ();
+      if (++written_symbols < len)
+       str += ", ";
+    }
+  return PyUnicode_FromFormat ("<%s %s {%s}>", Py_TYPE (self)->tp_name,
+                              name, str.c_str ());
+}
+
 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_blocks (void)
 {
@@ -482,7 +517,7 @@ PyTypeObject block_object_type = {
   0,                             /*tp_getattr*/
   0,                             /*tp_setattr*/
   0,                             /*tp_compare*/
-  0,                             /*tp_repr*/
+  blpy_repr,                      /*tp_repr*/
   0,                             /*tp_as_number*/
   0,                             /*tp_as_sequence*/
   &block_object_as_mapping,      /*tp_as_mapping*/
index d11fc64df2042f17cfca39308227f32f26d1f5fa..fa1570e1a049cb3a2caeb87e7bf9a2d04cb0962b 100644 (file)
@@ -33,6 +33,7 @@
 #include "location.h"
 #include "py-event.h"
 #include "linespec.h"
+#include "gdbsupport/common-utils.h"
 
 extern PyTypeObject breakpoint_location_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("breakpoint_location_object");
@@ -981,6 +982,31 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
   return 0;
 }
 
+/* __repr__ implementation for gdb.Breakpoint.  */
+
+static PyObject *
+bppy_repr (PyObject *self)
+{
+  const auto bp = (struct gdbpy_breakpoint_object*) self;
+  if (bp->bp == nullptr)
+    return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+
+  std::string str = " ";
+  if (bp->bp->thread != -1)
+    str += string_printf ("thread=%d ", bp->bp->thread);
+  if (bp->bp->task > 0)
+    str += string_printf ("task=%d ", bp->bp->task);
+  if (bp->bp->enable_count > 0)
+    str += string_printf ("enable_count=%d ", bp->bp->enable_count);
+  str.pop_back ();
+
+  return PyUnicode_FromFormat ("<%s%s number=%d hits=%d%s>",
+                              Py_TYPE (self)->tp_name,
+                              (bp->bp->enable_state == bp_enabled
+                               ? "" : " disabled"), bp->bp->number,
+                              bp->bp->hit_count, str.c_str ());
+}
+
 /* Append to LIST the breakpoint Python object associated to B.
 
    Return true on success.  Return false on failure, with the Python error
@@ -1406,7 +1432,7 @@ PyTypeObject breakpoint_object_type =
   0,                             /*tp_getattr*/
   0,                             /*tp_setattr*/
   0,                             /*tp_compare*/
-  0,                             /*tp_repr*/
+  bppy_repr,                     /*tp_repr*/
   0,                             /*tp_as_number*/
   0,                             /*tp_as_sequence*/
   0,                             /*tp_as_mapping*/
@@ -1624,6 +1650,43 @@ bplocpy_dealloc (PyObject *py_self)
   Py_TYPE (py_self)->tp_free (py_self);
 }
 
+/* __repr__ implementation for gdb.BreakpointLocation.  */
+
+static PyObject *
+bplocpy_repr (PyObject *py_self)
+{
+  const auto self = (gdbpy_breakpoint_location_object *) py_self;
+  if (self->owner == nullptr || self->owner->bp == nullptr
+    || self->owner->bp != self->bp_loc->owner)
+    return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+
+  const auto enabled = self->bp_loc->enabled ? "enabled" : "disabled";
+
+  std::string str (enabled);
+
+  str += string_printf (" address=%s",
+                       paddress (self->bp_loc->owner->gdbarch,
+                                 self->bp_loc->address));
+
+  if (self->bp_loc->requested_address != self->bp_loc->address)
+    str += string_printf (" requested_address=%s",
+                         paddress (self->bp_loc->owner->gdbarch,
+                                   self->bp_loc->requested_address));
+  if (self->bp_loc->symtab != nullptr)
+    str += string_printf (" source=%s:%d", self->bp_loc->symtab->filename,
+                         self->bp_loc->line_number);
+
+  const auto fn_name = self->bp_loc->function_name.get ();
+  if (fn_name != nullptr)
+    {
+      str += " in ";
+      str += fn_name;
+    }
+
+  return PyUnicode_FromFormat ("<%s %s>", Py_TYPE (self)->tp_name,
+                              str.c_str ());
+}
+
 /* Attribute get/set Python definitions. */
 
 static gdb_PyGetSetDef bp_location_object_getset[] = {
@@ -1655,7 +1718,7 @@ PyTypeObject breakpoint_location_object_type =
   0,                                   /*tp_getattr*/
   0,                                   /*tp_setattr*/
   0,                                   /*tp_compare*/
-  0,                                   /*tp_repr*/
+  bplocpy_repr,                        /*tp_repr*/
   0,                                   /*tp_as_number*/
   0,                                   /*tp_as_sequence*/
   0,                                   /*tp_as_mapping*/
index ff3d18504e77a7ff353cae3ba219dd6f7c16a6bd..ee863aa4df4e582c1e8e83ad8c155e1ec5540a42 100644 (file)
@@ -378,6 +378,19 @@ sympy_dealloc (PyObject *obj)
   Py_TYPE (obj)->tp_free (obj);
 }
 
+/* __repr__ implementation for gdb.Symbol.  */
+
+static PyObject *
+sympy_repr (PyObject *self)
+{
+  const auto symbol = symbol_object_to_symbol (self);
+  if (symbol == nullptr)
+    return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
+
+  return PyUnicode_FromFormat ("<%s print_name=%s>", Py_TYPE (self)->tp_name,
+                              symbol->print_name ());
+}
+
 /* Implementation of
    gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)
    A tuple with 2 elements is always returned.  The first is the symbol
@@ -741,7 +754,7 @@ PyTypeObject symbol_object_type = {
   0,                             /*tp_getattr*/
   0,                             /*tp_setattr*/
   0,                             /*tp_compare*/
-  0,                             /*tp_repr*/
+  sympy_repr,                    /*tp_repr*/
   0,                             /*tp_as_number*/
   0,                             /*tp_as_sequence*/
   0,                             /*tp_as_mapping*/
index b9fa741177f87118cf277b57a6d9ae4d906429d3..b4d1e230b3b1ea6ba25aeb1f51977cf319c3e331 100644 (file)
@@ -1028,6 +1028,34 @@ typy_template_argument (PyObject *self, PyObject *args)
   return result;
 }
 
+/* __repr__ implementation for gdb.Type.  */
+
+static PyObject *
+typy_repr (PyObject *self)
+{
+  const auto type = type_object_to_type (self);
+  if (type == nullptr)
+    return PyUnicode_FromFormat ("<%s (invalid)>",
+                                Py_TYPE (self)->tp_name);
+
+  const char *code = pyty_codes[type->code ()].name;
+  string_file type_name;
+  try
+    {
+      current_language->print_type (type, "", &type_name, -1, 0,
+                                   &type_print_raw_options);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+  auto py_typename = PyUnicode_Decode (type_name.c_str (), type_name.size (),
+                                      host_charset (), NULL);
+
+  return PyUnicode_FromFormat ("<%s code=%s name=%U>", Py_TYPE (self)->tp_name,
+                              code, py_typename);
+}
+
 static PyObject *
 typy_str (PyObject *self)
 {
@@ -1617,7 +1645,7 @@ PyTypeObject type_object_type =
   0,                             /*tp_getattr*/
   0,                             /*tp_setattr*/
   0,                             /*tp_compare*/
-  0,                             /*tp_repr*/
+  typy_repr,                     /*tp_repr*/
   &type_object_as_number,        /*tp_as_number*/
   0,                             /*tp_as_sequence*/
   &typy_mapping,                 /*tp_as_mapping*/
index 4f4b4aa766f5b1699d1012b90180ad9b49dd1433..597943ff6828bb43b8541ac2f552d41b2e21cbe2 100644 (file)
@@ -27,6 +27,8 @@ if ![runto_main] {
 # Test python/15461.  Invalid architectures should not trigger an
 # internal GDB assert.
 gdb_py_test_silent_cmd "python empty = gdb.Architecture()" "get empty arch" 0
+gdb_test "python print(repr (empty))" "<gdb\\.Architecture \\(invalid\\)>" \
+    "Test empty achitecture __repr__ does not trigger an assert"
 gdb_test "python print(empty.name())" ".*Architecture is invalid.*" \
     "Test empty architecture.name does not trigger an assert"
 gdb_test "python print(empty.disassemble())" ".*Architecture is invalid.*" \
@@ -44,6 +46,10 @@ gdb_py_test_silent_cmd "python insn_list3 = arch.disassemble(pc, count=1)" \
 gdb_py_test_silent_cmd "python insn_list4 = arch.disassemble(gdb.Value(pc))" \
   "disassemble no end no count" 0
 
+gdb_test "python print (repr (arch))" \
+    "<gdb.Architecture arch_name=.* printable_name=.*>" \
+    "test __repr__ for architecture"
+
 gdb_test "python print (len(insn_list1))" "1" "test number of instructions 1"
 gdb_test "python print (len(insn_list2))" "1" "test number of instructions 2"
 gdb_test "python print (len(insn_list3))" "1" "test number of instructions 3"
index a0c6e1656059d6006ecd3111ee994af5e5b56d75..dd2e195af4a272634e82b5e51de7738ae726c1bc 100644 (file)
@@ -30,9 +30,40 @@ int block_func (void)
   }
 }
 
+/* A function with no locals.  Used for testing gdb.Block.__repr__().  */
+int no_locals_func (void)
+{
+  return block_func ();
+}
+
+/* A function with 5 locals.  Used for testing gdb.Block.__repr__().  */
+int few_locals_func (void)
+{
+  int i = 0;
+  int j = 0;
+  int k = 0;
+  int x = 0;
+  int y = 0;
+  return block_func ();
+}
+
+/* A function with 6 locals.  Used for testing gdb.Block.__repr__().  */
+int many_locals_func (void)
+{
+  int i = 0;
+  int j = 0;
+  int k = 0;
+  int x = 0;
+  int y = 0;
+  int z = 0;
+  return block_func ();
+}
 
 int main (int argc, char *argv[])
 {
   block_func ();
+  no_locals_func ();
+  few_locals_func ();
+  many_locals_func ();
   return 0; /* Break at end. */
 }
index 3bdf97294aead443582ee0961e103bd07a64eb87..37e3105b4e3c0729a7df4bfa507734adf8b379bd 100644 (file)
@@ -38,7 +38,8 @@ gdb_continue_to_breakpoint "Block break here."
 gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0
 gdb_py_test_silent_cmd "python block = frame.block()" \
     "Get block, initial innermost block" 0
-gdb_test "python print (block)" "<gdb.Block object at $hex>" "check block not None"
+gdb_test "python print (block)" "<gdb.Block <anonymous> \{i, f, b\}>" \
+    "check block not None"
 gdb_test "python print (block.function)" "None" "first anonymous block"
 gdb_test "python print (block.start)" "${decimal}" "check start not None"
 gdb_test "python print (block.end)" "${decimal}" "check end not None"
@@ -68,15 +69,46 @@ gdb_test_no_output "python block = block.superblock" "get superblock 2"
 gdb_test "python print (block.function)" "block_func" \
          "Print superblock 2 function"
 
+# Switch frames, then test block for no_locals_func.
+gdb_test "continue" ".*" "continue to no_locals_func breakpoint"
+gdb_test "up" ".*" "up to no_locals_func"
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame 2" 0
+gdb_py_test_silent_cmd "python block = frame.block()" "Get Frame 2's block" 0
+gdb_test "python print (repr (block))" "<gdb.Block no_locals_func \{\}>" \
+    "Check block in no_locals_func"
+gdb_test "python print (block.function)" "no_locals_func" \
+    "no_locals_func block"
+
+# Switch frames, then test block for few_locals_func.
+gdb_test "continue" ".*" "continue to few_locals_func breakpoint"
+gdb_test "up" ".*" "up to few_locals_func"
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame 2" 0
+gdb_py_test_silent_cmd "python block = frame.block()" "Get Frame 2's block" 0
+gdb_test "python print (repr (block))" \
+    "<gdb.Block few_locals_func \{i, j, k, x, y\}>" \
+    "Check block in few_locals_func"
+gdb_test "python print (block.function)" "few_locals_func" \
+    "few_locals_func block"
+
+# Switch frames, then test block for many_locals_func.
+gdb_test "continue" ".*" "continue to many_locals_func breakpoint"
+gdb_test "up" ".*" "up to many_locals_func"
+gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame 2" 0
+gdb_py_test_silent_cmd "python block = frame.block()" "Get Frame 2's block" 0
+gdb_test "python print (repr (block))" \
+    "<gdb.Block many_locals_func \{i, j, k, x, y, \\.\\.\\. \\(1 more symbol\\)\}>" \
+    "Check block in many_locals_func"
+gdb_test "python print (block.function)" "many_locals_func" \
+    "many_locals_func block"
+
 # Switch frames, then test for main block.
 gdb_test "up" ".*"
 gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame 2" 0
 gdb_py_test_silent_cmd "python block = frame.block()" "Get Frame 2's block" 0
-gdb_test "python print (block)" "<gdb.Block object at $hex>" \
+gdb_test "python print (repr (block))" "<gdb.Block main \{.*\}>" \
          "Check Frame 2's block not None"
 gdb_test "python print (block.function)" "main" "main block"
 
-
 # Test Block is_valid.  This must always be the last test in this
 # testcase as it unloads the object file.
 delete_breakpoints
index f8649f6c105fe83d51393fdd1b81eecc8a0bba1e..b3a8c83bc0a5072a7cf1af8e6fab3368d98af25f 100644 (file)
@@ -31,6 +31,30 @@ if ![runto_main] {
     return -1
 }
 
+# Build a regexp string that represents the __repr__ of a
+# gdb.BreakpointLocation object.  Accepts arguments -enabled, -address,
+# -source, -line, and -func.
+proc build_bpl_regexp { args } {
+    parse_args [list {enabled True} [list address "$::hex"] {source ".*"} \
+                   [list line "$::decimal"] {func ""}]
+
+    set pattern "<gdb.BreakpointLocation"
+
+    if {$enabled} {
+       set pattern "$pattern enabled"
+    } else {
+       set pattern "$pattern disabled"
+    }
+
+    set pattern "$pattern address=${address}(?: requested_address=$::hex)?"
+    set pattern "$pattern source=${source}:${line}"
+    if {$func ne ""} {
+       set pattern "$pattern in ${func}"
+    }
+    set pattern "$pattern>"
+    return $pattern
+}
+
 # Set breakpoint with 2 locations.
 gdb_breakpoint "add"
 
@@ -42,9 +66,17 @@ gdb_test "python print(gdb.breakpoints()\[1\].locations\[0\].source)" \
         ".*('.*py-bp-locations.c', $expected_line_a).*"
 gdb_test "python print(gdb.breakpoints()\[1\].locations\[1\].source)" \
         ".*('.*py-bp-locations.c', $expected_line_b).*"
+gdb_test "python print(gdb.breakpoints()\[1\].locations\[1\])" \
+    [build_bpl_regexp -enabled True -source ".*py-bp-locations.c" \
+        -line "$expected_line_b" -func ".*"] \
+    "check repr of enabled breakpoint location"
 
 # Disable first location and make sure we don't hit it.
 gdb_test "python gdb.breakpoints()\[1\].locations\[0\].enabled = False" ""
+gdb_test "python print(gdb.breakpoints()\[1\].locations\[0\])" \
+    [build_bpl_regexp -enabled False -source ".*py-bp-locations.c" \
+        -line "$expected_line_a" -func ".*"] \
+    "check repr of disabled breakpoint location"
 gdb_continue_to_breakpoint "" ".*25.*"
 
 if ![runto_main] {
index 76094c95d107f9324ee67428b50b09a7d874d925..df17d646b28c6e67c2010c1f4c21427278f60895 100644 (file)
@@ -38,6 +38,36 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${options}]
 
 set past_throw_catch_line [gdb_get_line_number "Past throw-catch."]
 
+# Build a regexp string that can match against the repr of a gdb.Breakpoint
+# object.  Accepts arguments -enabled, -number, -hits, -thread, -task, and
+# -enable_count.  The -enabled argument is a boolean, while all of the others
+# take a regexp string.
+proc build_bp_repr { args } {
+    parse_args [list {enabled True} [list number "-?$::decimal"] \
+                   [list hits $::decimal] {thread ""} {task ""} \
+                   {enable_count ""}]
+
+    set pattern "<gdb\\.Breakpoint"
+
+    if {!$enabled} {
+       set pattern "$pattern disabled"
+    }
+
+    set pattern "$pattern number=$number hits=$hits"
+
+    if {$thread ne ""} {
+       set pattern "$pattern thread=$thread"
+    }
+    if {$task ne ""} {
+       set pattern "$pattern task=$task"
+    }
+    if {$enable_count ne ""} {
+       set pattern "$pattern enable_count=$enable_count"
+    }
+    set pattern "${pattern}>"
+    return $pattern
+}
+
 proc_with_prefix test_bkpt_basic { } {
     global srcfile testfile hex decimal
 
@@ -54,8 +84,8 @@ proc_with_prefix test_bkpt_basic { } {
     # Now there should be one breakpoint: main.
     gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" \
        "Get Breakpoint List" 0
-    gdb_test "python print (blist\[0\])" \
-       "<gdb.Breakpoint object at $hex>" "Check obj exists @main"
+    gdb_test "python print (repr (blist\[0\]))" \
+       [build_bp_repr -number 1 -hits 1] "Check obj exists @main"
     gdb_test "python print (blist\[0\].location)" \
        "main" "Check breakpoint location @main"
     gdb_test "python print (blist\[0\].pending)" "False" \
@@ -72,12 +102,12 @@ proc_with_prefix test_bkpt_basic { } {
        "Get Breakpoint List" 0
     gdb_test "python print (len(blist))" \
        "2" "Check for two breakpoints"
-    gdb_test "python print (blist\[0\])" \
-       "<gdb.Breakpoint object at $hex>" "Check obj exists @main 2"
+    gdb_test "python print (repr (blist\[0\]))" \
+       [build_bp_repr -number 1 -hits 1] "Check obj exists @main 2"
     gdb_test "python print (blist\[0\].location)" \
        "main" "Check breakpoint location @main 2"
-    gdb_test "python print (blist\[1\])" \
-       "<gdb.Breakpoint object at $hex>" "Check obj exists @mult_line"
+    gdb_test "python print (repr (blist\[1\]))" \
+       [build_bp_repr -number 2 -hits 1] "Check obj exists @mult_line"
 
     gdb_test "python print (blist\[1\].location)" \
        "py-breakpoint\.c:${mult_line}*" \
@@ -102,6 +132,9 @@ proc_with_prefix test_bkpt_basic { } {
        "True" "Check breakpoint enabled."
     gdb_py_test_silent_cmd  "python blist\[1\].enabled = False" \
        "Set breakpoint disabled." 0
+    gdb_test "python print (repr (blist\[1\]))" \
+       [build_bp_repr -enabled False -number 2 -hits 6] \
+       "Check repr for a disabled breakpoint"
     gdb_continue_to_breakpoint "Break at add 2" ".*Break at add.*"
     gdb_py_test_silent_cmd  "python blist\[1\].enabled = True" \
        "Set breakpoint enabled." 0
@@ -113,6 +146,13 @@ proc_with_prefix test_bkpt_basic { } {
        "Get Breakpoint List" 0
     gdb_test "python print (blist\[1\].thread)" \
        "None" "Check breakpoint thread"
+    gdb_py_test_silent_cmd "python blist\[1\].thread = 1" \
+       "set breakpoint thread" 0
+    gdb_test "python print (repr (blist\[1\]))" \
+       [build_bp_repr -number 2 -hits 7 -thread 1] \
+       "Check repr for a thread breakpoint"
+    gdb_py_test_silent_cmd "python blist\[1\].thread = None" \
+       "clear breakpoint thread" 0
     gdb_test "python print (blist\[1\].type == gdb.BP_BREAKPOINT)" \
        "True" "Check breakpoint type"
     gdb_test "python print (blist\[0\].number)" \
@@ -231,8 +271,8 @@ proc_with_prefix test_bkpt_invisible { } {
        "Set invisible breakpoint" 0
     gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" \
        "Get Breakpoint List" 0
-    gdb_test "python print (ilist\[0\])" \
-       "<gdb.Breakpoint object at $hex>" "Check invisible bp obj exists 1"
+    gdb_test "python print (repr (ilist\[0\]))" \
+       [build_bp_repr -number 2 -hits 0] "Check invisible bp obj exists 1"
     gdb_test "python print (ilist\[0\].location)" \
        "py-breakpoint\.c:$ibp_location*" "Check breakpoint location 1"
     gdb_test "python print (ilist\[0\].visible)" \
@@ -244,8 +284,9 @@ proc_with_prefix test_bkpt_invisible { } {
        "Set invisible breakpoint" 0
     gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" \
        "Get Breakpoint List" 0
-    gdb_test "python print (ilist\[0\])" \
-       "<gdb.Breakpoint object at $hex>" "Check invisible bp obj exists 2"
+    gdb_test "python print (repr (ilist\[0\]))" \
+       [build_bp_repr -number "-$decimal" -hits 0] \
+       "Check invisible bp obj exists 2"
     gdb_test "python print (ilist\[0\].location)" \
        "py-breakpoint\.c:$ibp_location*" "Check breakpoint location 2"
     gdb_test "python print (ilist\[0\].visible)" \
@@ -835,6 +876,14 @@ proc_with_prefix test_bkpt_auto_disable { } {
     set mult_line [gdb_get_line_number "Break at multiply."]
     gdb_breakpoint ${mult_line}
     gdb_test_no_output "enable count 1 2" "one shot enable"
+
+    # Find the Python gdb.Breakpoint object for breakpoint #2.
+    gdb_py_test_silent_cmd \
+       "python bp = \[b for b in gdb.breakpoints() if b.number == 2\]\[0\]" \
+       "Get breakpoint number 2" 0
+    gdb_test "python print (repr (bp))" \
+       [build_bp_repr -number 2 -hits 0 -enable_count 1]
+
     # Python 2 doesn't support print in lambda function, so use a named
     # function instead.
     gdb_test_multiline "Define print_bp_enabled" \
index 9ec2f44e9c0da0acd441809940fda795a78d129d..9bd5a35ed1c4baa05fe7cf2770ba0c0ee1f0ea98 100644 (file)
@@ -43,6 +43,8 @@ clean_restart ${binfile}
 # point where we don't have a current frame, and we don't want to
 # require one.
 gdb_py_test_silent_cmd "python main_func = gdb.lookup_global_symbol(\"main\")" "Lookup main" 1
+gdb_test "python print (repr (main_func))" "<gdb.Symbol print_name=main>" \
+    "test main_func.__repr__"
 gdb_test "python print (main_func.is_function)" "True" "test main_func.is_function"
 gdb_test "python print (gdb.lookup_global_symbol(\"junk\"))" "None" "test lookup_global_symbol(\"junk\")"
 
index c245d41a1ac516ab13e093f7a9508989551d5257..918216ddd69f9970829f0615597d55f9430332d7 100644 (file)
@@ -388,3 +388,7 @@ if { [build_inferior "${binfile}-cxx" "c++"] == 0 } {
       test_type_equality
   }
 }
+
+# Test __repr__().
+gdb_test "python print (repr (gdb.lookup_type ('char')))" \
+      "<gdb.Type code=TYPE_CODE_INT name=char>" "test __repr__()"