public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 20/22] Use method children instead of to_string in pretty printers
       [not found] <20210306174450.21718-1-ssbssa.ref@yahoo.de>
@ 2021-03-06 17:44 ` Hannes Domani
  2021-03-06 17:44   ` [PATCH 21/22] Implement memory TUI window Hannes Domani
                     ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Hannes Domani @ 2021-03-06 17:44 UTC (permalink / raw)
  To: gdb-patches

With '-pretty on' the output is basically the same, but like this the
pointer members can be expanded in the TUI variable windows.
---
 gdb/gdb-gdb.py.in | 153 ++++++++++++++++++++++------------------------
 1 file changed, 74 insertions(+), 79 deletions(-)

diff --git a/gdb/gdb-gdb.py.in b/gdb/gdb-gdb.py.in
index 2b1c7ded4b6..498a297aebd 100644
--- a/gdb/gdb-gdb.py.in
+++ b/gdb/gdb-gdb.py.in
@@ -107,16 +107,14 @@ class StructTypePrettyPrinter:
     def __init__(self, val):
         self.val = val
 
-    def to_string(self):
-        fields = []
-        fields.append("pointer_type = %s" % self.val['pointer_type'])
-        fields.append("reference_type = %s" % self.val['reference_type'])
-        fields.append("chain = %s" % self.val['reference_type'])
-        fields.append("instance_flags = %s"
-                      % TypeFlagsPrinter(self.val['m_instance_flags']))
-        fields.append("length = %d" % self.val['length'])
-        fields.append("main_type = %s" % self.val['main_type'])
-        return "\n{" + ",\n ".join(fields) + "}"
+    def children(self):
+        for f in self.val.type.fields():
+            name = f.name
+            val = self.val[f]
+            if name == "m_instance_flags":
+                name = "instance_flags"
+                val = str(TypeFlagsPrinter(val))
+            yield (name, val)
 
 
 class StructMainTypePrettyPrinter:
@@ -143,43 +141,9 @@ class StructMainTypePrettyPrinter:
         """Return an image of component "owner".
         """
         if self.val['flag_objfile_owned'] != 0:
-            return "%s (objfile)" % self.val['owner']['objfile']
-        else:
-            return "%s (gdbarch)" % self.val['owner']['gdbarch']
-
-    def struct_field_location_img(self, field_val):
-        """Return an image of the loc component inside the given field
-        gdb.Value.
-        """
-        loc_val = field_val['loc']
-        loc_kind = str(field_val['loc_kind'])
-        if loc_kind == "FIELD_LOC_KIND_BITPOS":
-            return 'bitpos = %d' % loc_val['bitpos']
-        elif loc_kind == "FIELD_LOC_KIND_ENUMVAL":
-            return 'enumval = %d' % loc_val['enumval']
-        elif loc_kind == "FIELD_LOC_KIND_PHYSADDR":
-            return 'physaddr = 0x%x' % loc_val['physaddr']
-        elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
-            return 'physname = %s' % loc_val['physname']
-        elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
-            return 'dwarf_block = %s' % loc_val['dwarf_block']
+            return ("owner.objfile", self.val['owner']['objfile'])
         else:
-            return 'loc = ??? (unsupported loc_kind value)'
-
-    def struct_field_img(self, fieldno):
-        """Return an image of the main_type field number FIELDNO.
-        """
-        f = self.val['flds_bnds']['fields'][fieldno]
-        label = "flds_bnds.fields[%d]:" % fieldno
-        if f['artificial']:
-            label += " (artificial)"
-        fields = []
-        fields.append("name = %s" % f['name'])
-        fields.append("type = %s" % f['m_type'])
-        fields.append("loc_kind = %s" % f['loc_kind'])
-        fields.append("bitsize = %d" % f['bitsize'])
-        fields.append(self.struct_field_location_img(f))
-        return label + "\n" + "  {" + ",\n   ".join(fields) + "}"
+            return ("owner.gdbarch", self.val['owner']['gdbarch'])
 
     def bound_img(self, bound_name):
         """Return an image of the given main_type's bound."""
@@ -203,10 +167,10 @@ class StructMainTypePrettyPrinter:
         low = self.bound_img('low')
         high = self.bound_img('high')
 
-        img = "flds_bnds.bounds = {%s, %s}" % (low, high)
+        img = "{%s, %s}" % (low, high)
         if b['flag_bound_evaluated']:
             img += ' [evaluated]'
-        return img
+        return ("flds_bnds.bounds", img)
 
     def type_specific_img(self):
         """Return a string image of the main_type type_specific union.
@@ -216,47 +180,76 @@ class StructMainTypePrettyPrinter:
         type_specific_kind = str(self.val['type_specific_field'])
         type_specific = self.val['type_specific']
         if type_specific_kind == "TYPE_SPECIFIC_NONE":
-            img = 'type_specific_field = %s' % type_specific_kind
+            return ("type_specific_field", type_specific_kind)
         elif type_specific_kind == "TYPE_SPECIFIC_CPLUS_STUFF":
-            img = "cplus_stuff = %s" % type_specific['cplus_stuff']
+            return ("cplus_stuff", type_specific['cplus_stuff'])
         elif type_specific_kind == "TYPE_SPECIFIC_GNAT_STUFF":
-            img = ("gnat_stuff = {descriptive_type = %s}"
-                   % type_specific['gnat_stuff']['descriptive_type'])
+            return ("gnat_stuff.descriptive_type",
+                    type_specific['gnat_stuff']['descriptive_type'])
         elif type_specific_kind == "TYPE_SPECIFIC_FLOATFORMAT":
-            img = "floatformat[0..1] = %s" % type_specific['floatformat']
+            return ("floatformat[0..1]", type_specific['floatformat'])
         elif type_specific_kind == "TYPE_SPECIFIC_FUNC":
-            img = ("calling_convention = %d"
-                   % type_specific['func_stuff']['calling_convention'])
+            return ("calling_convention",
+                    type_specific['func_stuff']['calling_convention'])
             # tail_call_list is not printed.
         elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE":
-            img = "self_type = %s" % type_specific['self_type']
+            return ("self_type", type_specific['self_type'])
         elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT":
-            # The scaling factor is an opaque structure, so we cannot
-            # decode its value from Python (not without insider knowledge).
-            img = ('scaling_factor: <opaque> (call __gmpz_dump with '
-                   ' _mp_num and _mp_den fields if needed)')
-        else:
-            img = ("type_specific = ??? (unknown type_secific_kind: %s)"
-                   % type_specific_kind)
-        return img
-
-    def to_string(self):
-        """Return a pretty-printed image of our main_type.
-        """
-        fields = []
-        fields.append("name = %s" % self.val['name'])
-        fields.append("code = %s" % self.val['code'])
-        fields.append("flags = [%s]" % self.flags_to_string())
-        fields.append("owner = %s" % self.owner_to_string())
-        fields.append("target_type = %s" % self.val['target_type'])
+            return ("scaling_factor",
+                    ("<opaque> (call __gmpz_dump with "
+                     "_mp_num and _mp_den fields if needed)"))
+        return ("type_specific",
+                "??? (unknown type_secific_kind: %s)" % type_specific_kind)
+
+    def children(self):
+        yield ("name", self.val['name'])
+        yield ("code", self.val['code'])
+        yield ("flags", "[%s]" % self.flags_to_string())
+        yield self.owner_to_string()
+        yield ("target_type", self.val['target_type'])
         if self.val['nfields'] > 0:
-            for fieldno in range(self.val['nfields']):
-                fields.append(self.struct_field_img(fieldno))
+            fields = self.val['flds_bnds']['fields']
+            field_array_type = fields.type.target().array(self.val['nfields']
+                                                          - 1).pointer()
+            yield ("flds_bnds.fields",
+                   fields.cast(field_array_type).dereference())
         if self.val['code'] == gdb.TYPE_CODE_RANGE:
-            fields.append(self.bounds_img())
-        fields.append(self.type_specific_img())
+            yield self.bounds_img()
+        yield self.type_specific_img()
+
+
+class StructFieldPrettyPrinter:
+    """Pretty-print an objet of type field"""
+
+    def __init__(self, val):
+        self.val = val
+
+    def location_img(self):
+        """Return an image of the loc component
+        """
+        loc_val = self.val['loc']
+        loc_kind = str(self.val['loc_kind'])
+        if loc_kind == "FIELD_LOC_KIND_BITPOS":
+            return ("bitpos", loc_val['bitpos'])
+        elif loc_kind == "FIELD_LOC_KIND_ENUMVAL":
+            return ("enumval", loc_val['enumval'])
+        elif loc_kind == "FIELD_LOC_KIND_PHYSADDR":
+            return ("physaddr", loc_val['physaddr'])
+        elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
+            return ("physname", loc_val['physname'])
+        elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
+            return ("dwarf_block", loc_val['dwarf_block'])
+        else:
+            return ("loc", "??? (unsupported loc_kind value)")
 
-        return "\n{" + ",\n ".join(fields) + "}"
+    def children(self):
+        if self.val['artificial']:
+            yield ("artificial", self.val['artificial'])
+        yield ("name", self.val['name'])
+        yield ("type", self.val['m_type'])
+        yield ("loc_kind", self.val['loc_kind'])
+        yield ("bitsize", self.val['bitsize'])
+        yield self.location_img()
 
 
 class CoreAddrPrettyPrinter:
@@ -277,6 +270,8 @@ def type_lookup_function(val):
         return StructTypePrettyPrinter(val)
     elif val.type.tag == "main_type":
         return StructMainTypePrettyPrinter(val)
+    elif val.type.tag == "field":
+        return StructFieldPrettyPrinter(val)
     elif val.type.name == 'CORE_ADDR':
         return CoreAddrPrettyPrinter(val)
     return None
-- 
2.30.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 21/22] Implement memory TUI window
  2021-03-06 17:44 ` [PATCH 20/22] Use method children instead of to_string in pretty printers Hannes Domani
@ 2021-03-06 17:44   ` Hannes Domani
  2021-03-06 17:44   ` [PATCH 22/22] Copy variable value to clipboard on middle-click Hannes Domani
  2021-03-11 21:55   ` [PATCH 20/22] Use method children instead of to_string in pretty printers Tom Tromey
  2 siblings, 0 replies; 4+ messages in thread
From: Hannes Domani @ 2021-03-06 17:44 UTC (permalink / raw)
  To: gdb-patches

---
 gdb/python/lib/gdb/command/tui_windows.py | 57 +++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/gdb/python/lib/gdb/command/tui_windows.py b/gdb/python/lib/gdb/command/tui_windows.py
index 92a7a2b2f01..45ba9502878 100644
--- a/gdb/python/lib/gdb/command/tui_windows.py
+++ b/gdb/python/lib/gdb/command/tui_windows.py
@@ -712,10 +712,65 @@ class FramesWindow(TextWindow):
             var_change_handler()
 
 
+class MemoryWindow(TextWindow):
+    def __init__(self, win):
+        super(MemoryWindow, self).__init__(win, "memory")
+        self.pointer = 0
+
+    def refill(self):
+        if not self.win.is_valid():
+            return
+        self.lines = []
+        pointer = self.pointer
+        try:
+            mem = gdb.selected_inferior().read_memory(pointer, 16 * self.win.height)
+            ptr_hex_count = int(gdb.lookup_type("void").pointer().sizeof) * 2
+            ofs = 0
+            for h in range(self.win.height):
+                l = "0x%0*x  " % (ptr_hex_count, pointer + ofs)
+                l += " ".join(["%02x%02x" % (ord(mem[ofs + i]), ord(mem[ofs + i + 1])) for i in range(0, 16, 2)])
+                l += "  "
+                l += "".join([self.printable(mem[ofs + i]) for i in range(16)])
+                self.lines.append(l)
+                ofs += 16
+        except:
+            self.lines = [str(sys.exc_info()[1])]
+        self.redraw()
+
+    def vscroll(self, num):
+        self.pointer += num * 16
+        if self.pointer < 0:
+            self.pointer = 0
+        self.refill()
+
+    def printable(self, c):
+        o = ord(c)
+        if o < 0x20 or o >= 0x7f:
+            return "."
+        return c
+
+class MemoryCommand(gdb.Command):
+    """Set start pointer for memory window."""
+
+    def __init__(self):
+        super(MemoryCommand, self).__init__("memory", gdb.COMMAND_TUI, gdb.COMPLETE_EXPRESSION)
+
+    def invoke(self, arg, from_tty):
+        self.dont_repeat()
+        global custom_windows
+        if 'memory' not in custom_windows or not custom_windows['memory'].win.is_valid():
+            gdb.execute("layout memory")
+        memory_window = custom_windows['memory']
+        memory_window.pointer = long(gdb.parse_and_eval(arg))
+
+MemoryCommand()
+
+
 gdb.register_window_type("locals", LocalsWindow)
 gdb.register_window_type("display", DisplayWindow)
 gdb.register_window_type("threads", ThreadsWindow)
 gdb.register_window_type("frames", FramesWindow)
+gdb.register_window_type("memory", MemoryWindow)
 
 
 class CustomCommandWindow(TextWindow):
@@ -778,6 +833,7 @@ gdb.execute("tui new-layout locals-frames {-horizontal src 2 {locals 2 frames 1}
 gdb.execute("tui new-layout display-frames {-horizontal src 2 {display 2 frames 1} 1} 2 status 0 cmd 1")
 gdb.execute("tui new-layout locals-display-frames {-horizontal src 2 {locals 2 display 2 frames 1} 1} 3 status 0 cmd 1")
 gdb.execute("tui new-layout threads-locals-frames-display {-horizontal src 3 {threads 1 locals 2} 1 {frames 1 display 2} 1} 3 status 0 cmd 1")
+gdb.execute("tui new-layout memory memory 1 src 2 status 0 cmd 1")
 gdb.execute("tui new-layout all {-horizontal {{-horizontal asm 1 regs 1} 1 src 2} 3 {threads 1 locals 2} 1 {frames 1 display 2} 1} 3 status 0 cmd 1")
 
 gdb.execute("alias ll = layout locals")
@@ -790,4 +846,5 @@ gdb.execute("alias llf = layout locals-frames")
 gdb.execute("alias ldf = layout display-frames")
 gdb.execute("alias lldf = layout locals-display-frames")
 gdb.execute("alias ltlfd = layout threads-locals-frames-display")
+gdb.execute("alias lm = layout memory")
 gdb.execute("alias la = layout all")
-- 
2.30.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 22/22] Copy variable value to clipboard on middle-click
  2021-03-06 17:44 ` [PATCH 20/22] Use method children instead of to_string in pretty printers Hannes Domani
  2021-03-06 17:44   ` [PATCH 21/22] Implement memory TUI window Hannes Domani
@ 2021-03-06 17:44   ` Hannes Domani
  2021-03-11 21:55   ` [PATCH 20/22] Use method children instead of to_string in pretty printers Tom Tromey
  2 siblings, 0 replies; 4+ messages in thread
From: Hannes Domani @ 2021-03-06 17:44 UTC (permalink / raw)
  To: gdb-patches

For variables that don't have children, or the children tree is closed, its
text representation is copied.
If the variable has children, and the children tree is opened, the text
representation of the children is copied instead (each on a separate line).

I could imagine customizable actions on middle-click on VariableWindow
variables, like some kind of callback function.

I chose the clipboard myself because I relatively often have classes for
graphical objects like lines and arcs.
For easier readability, I created simple pretty printers, like:

    LINE 0 0 100 0
    ARC 50 0 50 0 3.1415

So a middle-click on an opened vector containing these objects copies their
text representation to the clipboard.

I have another tool that is notified whenever the clipboard contents change,
and if they are in this specific format, immediately visualizes them.

The result is a relatively convenient way to visualize these graphical objects
from the debugger, with a single mouse-click.
---
 gdb/python/lib/gdb/command/tui_windows.py | 76 +++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/gdb/python/lib/gdb/command/tui_windows.py b/gdb/python/lib/gdb/command/tui_windows.py
index 45ba9502878..050ef4d1ddf 100644
--- a/gdb/python/lib/gdb/command/tui_windows.py
+++ b/gdb/python/lib/gdb/command/tui_windows.py
@@ -23,6 +23,62 @@ PY3 = sys.version_info[0] == 3
 custom_windows = {}
 
 
+if sys.platform == 'win32':
+    import ctypes
+    import ctypes.wintypes as w
+
+    CF_TEXT = 1
+
+    u32 = ctypes.WinDLL('user32')
+    k32 = ctypes.WinDLL('kernel32')
+
+    OpenClipboard = u32.OpenClipboard
+    OpenClipboard.argtypes = w.HWND,
+    OpenClipboard.restype = w.BOOL
+
+    EmptyClipboard = u32.EmptyClipboard
+    EmptyClipboard.restype = w.BOOL
+
+    SetClipboardData = u32.SetClipboardData
+    SetClipboardData.argtypes = w.UINT, w.HANDLE,
+    SetClipboardData.restype = w.HANDLE
+
+    CloseClipboard = u32.CloseClipboard
+    CloseClipboard.restype = w.BOOL
+
+    GHND = 0x0042
+
+    GlobalAlloc = k32.GlobalAlloc
+    GlobalAlloc.argtypes = w.UINT, ctypes.c_size_t,
+    GlobalAlloc.restype = w.HGLOBAL
+
+    GlobalLock = k32.GlobalLock
+    GlobalLock.argtypes = w.HGLOBAL,
+    GlobalLock.restype = w.LPVOID
+
+    GlobalUnlock = k32.GlobalUnlock
+    GlobalUnlock.argtypes = w.HGLOBAL,
+    GlobalUnlock.restype = w.BOOL
+
+    def set_clipboard_text(s):
+        if OpenClipboard(None):
+            s = s.encode('utf-8')
+            EmptyClipboard()
+            h = GlobalAlloc(GHND, len(s) + 1)
+            p = GlobalLock(h)
+            ctypes.memmove(p, s, len(s))
+            GlobalUnlock(h)
+            SetClipboardData(CF_TEXT, h)
+            CloseClipboard()
+
+else:
+    import base64
+
+    def set_clipboard_text(s):
+        b64 = base64.b64encode(s.encode('utf-8')).decode()
+        sys.__stdout__.write("\x1b]52;c;" + b64 + "\x07")
+
+
 col_esc_seq_re = re.compile('(\033\[[0-9;]*m)')
 def escaped_substr(s, n, c):
     col_esc_seq = False
@@ -189,6 +245,26 @@ class VariableWindow(TextWindow):
                 if prev is not None and prev[3] is not None:
                     gdb.set_convenience_variable(self.convenience_name, prev[3])
                     self.refill(True)
+        elif button == 2 and line < len(self.line_names):
+            name = self.line_names[line]
+            if name:
+                prev = self.prev_vals[name]
+                if prev is not None:
+                    if prev[0]:
+                        name2 = name + ":"
+                        child_texts = []
+                        for l in range(line + 1, len(self.line_names)):
+                            child_name = self.line_names[l]
+                            if not child_name:
+                                continue
+                            if not child_name.startswith(name2):
+                                break
+                            child = self.prev_vals[child_name]
+                            if child is not None and child[1] != False:
+                                child_texts.append(child[1])
+                        set_clipboard_text("\n".join(child_texts))
+                    elif prev[1] != False:
+                        set_clipboard_text(prev[1])
 
     def refill(self, keep_prev=False):
         if not self.win.is_valid():
-- 
2.30.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 20/22] Use method children instead of to_string in pretty printers
  2021-03-06 17:44 ` [PATCH 20/22] Use method children instead of to_string in pretty printers Hannes Domani
  2021-03-06 17:44   ` [PATCH 21/22] Implement memory TUI window Hannes Domani
  2021-03-06 17:44   ` [PATCH 22/22] Copy variable value to clipboard on middle-click Hannes Domani
@ 2021-03-11 21:55   ` Tom Tromey
  2 siblings, 0 replies; 4+ messages in thread
From: Tom Tromey @ 2021-03-11 21:55 UTC (permalink / raw)
  To: Hannes Domani via Gdb-patches

>>>>> "Hannes" == Hannes Domani via Gdb-patches <gdb-patches@sourceware.org> writes:

Hannes> With '-pretty on' the output is basically the same, but like this the
Hannes> pointer members can be expanded in the TUI variable windows.

This seems like something that could go in separately.
It's how this code is intended to be written.

Tom

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-03-11 21:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20210306174450.21718-1-ssbssa.ref@yahoo.de>
2021-03-06 17:44 ` [PATCH 20/22] Use method children instead of to_string in pretty printers Hannes Domani
2021-03-06 17:44   ` [PATCH 21/22] Implement memory TUI window Hannes Domani
2021-03-06 17:44   ` [PATCH 22/22] Copy variable value to clipboard on middle-click Hannes Domani
2021-03-11 21:55   ` [PATCH 20/22] Use method children instead of to_string in pretty printers Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).