gdb/python: implement __repr__ methods for py-disasm.c types
authorAndrew Burgess <aburgess@redhat.com>
Tue, 24 Jan 2023 15:03:25 +0000 (15:03 +0000)
committerAndrew Burgess <aburgess@redhat.com>
Fri, 12 May 2023 17:24:24 +0000 (18:24 +0100)
Add a __repr__ method for the DisassembleInfo and DisassemblerResult
types, and add some tests for these new methods.

gdb/python/py-disasm.c
gdb/testsuite/gdb.python/py-disasm.exp
gdb/testsuite/gdb.python/py-disasm.py

index 6b19b556d0d2fd809c153f661d658a909782eea1..eeb16d8650cbd0663c4b4cb21bf64af1ed6f925e 100644 (file)
@@ -247,6 +247,21 @@ disasm_info_dealloc (PyObject *self)
   Py_TYPE (self)->tp_free (self);
 }
 
+/* Implement __repr__ for the DisassembleInfo type.  */
+
+static PyObject *
+disasmpy_info_repr (PyObject *self)
+{
+  disasm_info_object *obj = (disasm_info_object *) self;
+
+  const char *arch_name
+    = (gdbarch_bfd_arch_info (obj->gdbarch))->printable_name;
+  return PyUnicode_FromFormat ("<%s address=%s architecture=%s>",
+                              Py_TYPE (obj)->tp_name,
+                              core_addr_to_string_nz (obj->address),
+                              arch_name);
+}
+
 /* Implement DisassembleInfo.is_valid(), really just a wrapper around the
    disasm_info_object_is_valid function above.  */
 
@@ -653,6 +668,21 @@ disasmpy_result_init (PyObject *self, PyObject *args, PyObject *kwargs)
   return 0;
 }
 
+/* Implement __repr__ for the DisassemblerResult type.  */
+
+static PyObject *
+disasmpy_result_repr (PyObject *self)
+{
+  disasm_result_object *obj = (disasm_result_object *) self;
+
+  gdb_assert (obj->content != nullptr);
+
+  return PyUnicode_FromFormat ("<%s length=%d string=\"%s\">",
+                              Py_TYPE (obj)->tp_name,
+                              obj->length,
+                              obj->content->string ().c_str ());
+}
+
 /* Implement memory_error_func callback for disassemble_info.  Extract the
    underlying DisassembleInfo Python object, and set a memory error on
    it.  */
@@ -1069,7 +1099,7 @@ PyTypeObject disasm_info_object_type = {
   0,                                           /*tp_getattr*/
   0,                                           /*tp_setattr*/
   0,                                           /*tp_compare*/
-  0,                                           /*tp_repr*/
+  disasmpy_info_repr,                          /*tp_repr*/
   0,                                           /*tp_as_number*/
   0,                                           /*tp_as_sequence*/
   0,                                           /*tp_as_mapping*/
@@ -1111,7 +1141,7 @@ PyTypeObject disasm_result_object_type = {
   0,                                           /*tp_getattr*/
   0,                                           /*tp_setattr*/
   0,                                           /*tp_compare*/
-  0,                                           /*tp_repr*/
+  disasmpy_result_repr,                                /*tp_repr*/
   0,                                           /*tp_as_number*/
   0,                                           /*tp_as_sequence*/
   0,                                           /*tp_as_mapping*/
index 38a2b766320e08abb13b1c2739906ba4e6f56c2d..854cdbbce1e5dafcdf47abc367ea923da15538a5 100644 (file)
@@ -73,6 +73,9 @@ set test_plans \
     [list \
         [list "" "${base_pattern}\r\n.*"] \
         [list "GlobalNullDisassembler" "${base_pattern}\r\n.*"] \
+        [list "ShowInfoRepr" "${base_pattern}\\s+## <gdb.disassembler.DisassembleInfo address=$hex architecture=\[^>\]+>\r\n.*"] \
+        [list "ShowInfoSubClassRepr" "${base_pattern}\\s+## <MyInfo address=$hex architecture=\[^>\]+>\r\n.*"] \
+        [list "ShowResultRepr" "${base_pattern}\\s+## <gdb.disassembler.DisassemblerResult length=$decimal string=\"\[^\r\n\]+\">\r\n.*"] \
         [list "GlobalPreInfoDisassembler" "${base_pattern}\\s+## ad = $hex, ar = ${curr_arch}\r\n.*"] \
         [list "GlobalPostInfoDisassembler" "${base_pattern}\\s+## ad = $hex, ar = ${curr_arch}\r\n.*"] \
         [list "GlobalReadDisassembler" "${base_pattern}\\s+## bytes =( $hex)+\r\n.*"] \
index 0ee883a5e5ea5f0c5b491eb253c23ea404d72434..977cdbf3c37f7c613159208c9ee22b5471fcf85a 100644 (file)
@@ -64,6 +64,55 @@ class TestDisassembler(Disassembler):
         raise NotImplementedError("override the disassemble method")
 
 
+class ShowInfoRepr(TestDisassembler):
+    """Call the __repr__ method on the DisassembleInfo, convert the result
+    to a string, and incude it in a comment in the disassembler output."""
+
+    def disassemble(self, info):
+        comment = "\t## " + repr(info)
+        result = gdb.disassembler.builtin_disassemble(info)
+        string = result.string + comment
+        length = result.length
+        return DisassemblerResult(length=length, string=string)
+
+
+class ShowInfoSubClassRepr(TestDisassembler):
+    """Create a sub-class of DisassembleInfo.  Create an instace of this
+    sub-class and call the __repr__ method on it.  Convert the result
+    to a string, and incude it in a comment in the disassembler
+    output.  The DisassembleInfo sub-class does not override __repr__
+    so we are calling the implementation on the parent class."""
+
+    class MyInfo(gdb.disassembler.DisassembleInfo):
+        """A wrapper around DisassembleInfo, doesn't add any new
+        functionality, just gives a new name in order to check the
+        __repr__ functionality."""
+
+        def __init__(self, info):
+            super().__init__(info)
+
+    def disassemble(self, info):
+        info = self.MyInfo(info)
+        comment = "\t## " + repr(info)
+        result = gdb.disassembler.builtin_disassemble(info)
+        string = result.string + comment
+        length = result.length
+        return DisassemblerResult(length=length, string=string)
+
+
+class ShowResultRepr(TestDisassembler):
+    """Call the __repr__ method on the DisassemblerResult, convert the
+    result to a string, and incude it in a comment in the disassembler
+    output."""
+
+    def disassemble(self, info):
+        result = gdb.disassembler.builtin_disassemble(info)
+        comment = "\t## " + repr(result)
+        string = result.string + comment
+        length = result.length
+        return DisassemblerResult(length=length, string=string)
+
+
 class GlobalPreInfoDisassembler(TestDisassembler):
     """Check the attributes of DisassembleInfo before disassembly has occurred."""