public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCHv2 1/2] Implement locals TUI window
       [not found] <20210604162400.3255-1-ssbssa.ref@yahoo.de>
@ 2021-06-04 16:23 ` Hannes Domani
  2021-06-04 16:24   ` [PATCHv2 2/2] Use method children instead of to_string in pretty printers Hannes Domani
  2023-11-13 20:07   ` [PATCHv2 1/2] Implement locals TUI window Tom Tromey
  0 siblings, 2 replies; 4+ messages in thread
From: Hannes Domani @ 2021-06-04 16:23 UTC (permalink / raw)
  To: gdb-patches

gdb/ChangeLog:

2021-06-04  Hannes Domani  <ssbssa@yahoo.de>

	PR tui/17849
	* data-directory/Makefile.in: Add tui_windows.py.
	* python/lib/gdb/command/tui_windows.py: New file.
---
v2:
- Added ChangeLog.
- The code changed a lot.
---
 gdb/data-directory/Makefile.in            |   1 +
 gdb/python/lib/gdb/command/tui_windows.py | 912 ++++++++++++++++++++++
 2 files changed, 913 insertions(+)
 create mode 100644 gdb/python/lib/gdb/command/tui_windows.py

diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index 8b65790cdd9..b8383ea7808 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -82,6 +82,7 @@ PYTHON_FILE_LIST = \
 	gdb/command/frame_filters.py \
 	gdb/command/pretty_printers.py \
 	gdb/command/prompt.py \
+	gdb/command/tui_windows.py \
 	gdb/command/type_printers.py \
 	gdb/command/unwinders.py \
 	gdb/command/xmethods.py \
diff --git a/gdb/python/lib/gdb/command/tui_windows.py b/gdb/python/lib/gdb/command/tui_windows.py
new file mode 100644
index 00000000000..4b75c7b9b7d
--- /dev/null
+++ b/gdb/python/lib/gdb/command/tui_windows.py
@@ -0,0 +1,912 @@
+# Additional TUI windows.
+# Copyright 2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import gdb
+import sys
+import re
+
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    basestring = str
+
+custom_windows = {}
+
+
+col_esc_seq_re = re.compile("(\033\[[0-9;]*m)")
+
+
+def colored_substr(text, offset, count):
+    """Returns a substring ignoring the color escape sequences in offset and
+    count, but keeping them in the returned string.
+
+    The returned string contains exactly count printable characters, filling
+    it with spaces if necessary."""
+
+    col_esc_seq = False
+    init_col_esc_seq = None
+    last_col_esc_seq = None
+    sub = ""
+    for p in col_esc_seq_re.split(text):
+        t = ""
+        if offset > 0:
+            if col_esc_seq:
+                init_col_esc_seq = p
+            else:
+                l = len(p)
+                if l <= offset:
+                    offset -= l
+                else:
+                    if init_col_esc_seq:
+                        sub += init_col_esc_seq
+                    t = p[offset:]
+                    offset = 0
+        else:
+            t = p
+        if count > 0:
+            if col_esc_seq:
+                sub += t
+            else:
+                l = len(t)
+                if l <= count:
+                    sub += t
+                    count -= l
+                else:
+                    sub += t[:count]
+                    count = 0
+        elif col_esc_seq:
+            last_col_esc_seq = p
+        col_esc_seq = not col_esc_seq
+    if last_col_esc_seq:
+        sub += last_col_esc_seq
+    if count > 0:
+        sub += " " * count
+    return sub
+
+
+class TextWindow(object):
+    """Base text window class which takes care of drawing and scrolling.
+
+    An inheriting class needs to implement the refill method which fills
+    the list self.lines with the lines that should be displayed.
+    This method will be called each time a prompt is presented to the user.
+    """
+
+    def __init__(self, win, title):
+        self.win = win
+        self.line_ofs = 0
+        self.col_ofs = 0
+        self.lines = []
+        win.title = title
+        global custom_windows
+        custom_windows[title] = self
+
+    def close(self):
+        global custom_windows
+        del custom_windows[self.win.title]
+
+    def render(self):
+        self.line_ofs = 0
+        self.col_ofs = 0
+
+    def hscroll(self, num):
+        prev_col_ofs = self.col_ofs
+        self.col_ofs = self.col_ofs + num
+        if self.col_ofs < 0:
+            self.col_ofs = 0
+        if self.col_ofs != prev_col_ofs:
+            self.redraw()
+
+    def vscroll(self, num):
+        prev_line_ofs = self.line_ofs
+        self.line_ofs = self.line_ofs + num
+        l = len(self.lines)
+        if self.line_ofs >= l:
+            self.line_ofs = l - 1
+        if self.line_ofs < 0:
+            self.line_ofs = 0
+        if self.line_ofs != prev_line_ofs:
+            self.redraw()
+
+    def redraw(self):
+        l = len(self.lines)
+        if self.line_ofs > 0 and self.line_ofs + self.win.height > l:
+            self.line_ofs = l - self.win.height
+            if self.line_ofs < 0:
+                self.line_ofs = 0
+        start = self.line_ofs
+        stop = self.line_ofs + self.win.height
+        if stop > l:
+            stop = l
+        if stop > start:
+            self.win.write(
+                "".join(
+                    [
+                        colored_substr(l, self.col_ofs, self.win.width)
+                        for l in self.lines[start:stop]
+                    ]
+                ),
+                True,
+            )
+        else:
+            self.win.erase()
+
+
+def val_cmp_color(prev, cur, sym_not_init, argument, empty=False):
+    """Returns the color escape sequences for variable name and value."""
+    var_col_s, var_col_e, val_col_s, val_col_e = "", "", "", ""
+    if empty:
+        # Variable without contents
+        var_col_s, var_col_e = "\033[1;30m", "\033[0m"
+    elif prev is None:
+        # New variable
+        var_col_s, var_col_e = "\033[1;32m", "\033[0m"
+    elif prev != cur:
+        # Variable contents changed
+        val_col_s, val_col_e = "\033[1;31m", "\033[0m"
+    if argument:
+        # Variable is a function argument
+        var_col_s, var_col_e = "\033[1;35m", "\033[0m"
+    elif sym_not_init:
+        # Variable was not yet initialized
+        var_col_s, var_col_e = "\033[33m", "\033[0m"
+    return (var_col_s, var_col_e, val_col_s, val_col_e)
+
+
+def octal_escape(s):
+    """Escape non-printable characters as octal string."""
+    return "".join(c if ord(c) < 128 else "\\%03o" % ord(c) for c in s)
+
+
+def value_string(valstr, hint):
+    """Convert value to string representation."""
+    if hint == "string":
+        is_lazy = type(valstr).__name__ == "LazyString"
+        if is_lazy:
+            l = valstr.length
+        elif not isinstance(valstr, basestring):
+            l = 1
+        else:
+            l = len(valstr)
+        if l == 0:
+            if is_lazy and str(valstr.type) == "wchar_t *":
+                valstr = 'L""'
+            else:
+                valstr = '""'
+        else:
+            valstr = gdb.Value(valstr).format_string(symbols=False, address=False)
+    if isinstance(valstr, gdb.Value):
+        valstr = valstr.format_string(symbols=False, address=False)
+    elif not type(valstr) is str:
+        valstr = str(valstr)
+    return valstr
+
+
+def is_typedef_of(valtype, name):
+    """Check for type variants."""
+    if valtype.name == name:
+        return True
+    while valtype.code == gdb.TYPE_CODE_TYPEDEF:
+        valtype = valtype.target()
+        if valtype.name == name:
+            return True
+    return False
+
+
+def is_string_element_type(t):
+    """Return if an array of this type is considered a string."""
+    target_type = t.target().strip_typedefs()
+    return target_type.code == gdb.TYPE_CODE_INT and (
+        target_type.name == "char" or is_typedef_of(t.target(), "wchar_t")
+    )
+
+
+class ArrayPrinter(object):
+    """Pretty printer for arrays."""
+
+    def __init__(self, v, t):
+        self.v = v
+        self.t = t
+
+    def to_string(self):
+        if is_string_element_type(self.t):
+            return self.v.format_string(symbols=False, raw=True, address=True)
+
+    def children(self):
+        (low, high) = self.t.range()
+        for i in range(low, high + 1):
+            yield "[%d]" % i, self.v[i]
+
+
+class StructPrinter(object):
+    """Pretty printer for structs/unions."""
+
+    def __init__(self, v, dyn_type, raw):
+        self.v = v
+        self.raw = raw
+        self.dyn_name = None
+        if dyn_type and v.type.code == gdb.TYPE_CODE_STRUCT:
+            try:
+                if v.type != v.dynamic_type:
+                    self.v = v.cast(v.dynamic_type)
+                    self.dyn_name = " <" + self.v.type.name + ">"
+            except:
+                pass
+
+    def to_string(self):
+        return self.dyn_name
+
+    def children(self):
+        fields = self.v.type.fields()
+        num = 1
+        for f in fields:
+            if not hasattr(f, "bitpos"):
+                continue
+            try:
+                n = f.name
+            except:
+                n = None
+            if not n:
+                n = "<anonymous>"
+            elif f.is_base_class:
+                n = "<" + n + ">"
+
+            child_v = self.v[f]
+
+            # Disable dynamic_type for base classes, to prevent infinite
+            # recursion.
+            if child_v.type.code == gdb.TYPE_CODE_STRUCT and f.is_base_class:
+                pp = None
+                if not self.raw:
+                    try:
+                        pp = gdb.default_visualizer(v)
+                    except:
+                        pass
+                if pp is None:
+                    child_v = StructPrinter(child_v, False, self.raw)
+
+            yield n, child_v
+
+    def address(self):
+        return self.v.address
+
+
+class PointerPrinter(object):
+    """Pretty printer for pointers."""
+
+    def __init__(self, v):
+        self.v = v
+
+    def to_string(self):
+        return self.v.format_string(symbols=False, raw=True, address=True)
+
+    def children(self):
+        try:
+            val = self.v.dereference()
+        except Exception as e:
+            val = e
+        yield "[0]", val
+
+
+class ValuePrinter(object):
+    """Pretty printer for value types that don't have children."""
+
+    def __init__(self, v, fmt):
+        self.v = v
+        self.fmt = fmt
+
+    def to_string(self):
+        if self.fmt:
+            return self.v.format_string(
+                symbols=False, raw=True, address=True, format=self.fmt
+            )
+        else:
+            return self.v.format_string(symbols=False, raw=True, address=True)
+
+
+class VariableWindow(TextWindow):
+    """Base variable window class for interactive expansion of child values.
+
+    An inheriting class needs to implement the variables method which returns
+    an iterable of objects (based on what FrameDecorator.frame_args returns).
+    These objects must implement a symbol method, returning either a Python
+    string of a gdb.Symbol.
+    And optionally they can implement these methods:
+    - value: Returns either a Python value, a gdb.Value, or a pretty-printer
+        (if not implemented, or returns None, and the symbol method returns a
+        gdb.Symbol, the value of the gdb.Symbol is used).
+    - undeclared: Returns a Boolean indicating if the declaration of this
+        variable was not yet reached (default=False).
+    - argument: Returns a Boolean indicating this variable is an argument
+        (default=False).
+    - number: If this returns a positive integer, it is shown before
+        symbol name (default=0).
+    - raw: Returns a Boolean indicating that no pretty-printers should be
+        used to format the value (default=False).
+    - format: Same as the format argument of Value.format_string.
+    - error: Python string indicating an error message that is shown if
+        method value returns None.
+    """
+
+    def __init__(self, win, title, convenience_name):
+        super(VariableWindow, self).__init__(win, title)
+        self.prev_vals = {}
+        self.line_names = []
+        self.convenience_name = convenience_name
+
+    def click(self, x, y, button):
+        line = y + self.line_ofs
+        if line < len(self.line_names):
+            name = self.line_names[line]
+            if name:
+                prev = self.prev_vals[name]
+                if button == 1:
+                    # On left-click, invert expansion of children.
+                    if prev is not None and prev[0] is not None:
+                        prev[0] = not prev[0]
+                        self.refill(True)
+                        self.redraw()
+                elif button == 3:
+                    # On right-click, set element for convenience variable.
+                    if prev is not None and prev[3] is not None:
+                        gdb.set_convenience_variable(self.convenience_name, prev[3])
+                        self.refill(True)
+                        self.redraw()
+
+    def refill(self, keep_prev=False):
+        self.lines = []
+        self.line_names = []
+        cur_vals = {}
+        frame = None
+        for v in self.variables():
+            symbol = v.symbol()
+            if isinstance(symbol, gdb.Symbol):
+                name = symbol.name
+            else:
+                name = symbol
+
+            value = None
+            if hasattr(v, "value"):
+                value = v.value()
+            if value is None and isinstance(symbol, gdb.Symbol):
+                if frame is None:
+                    frame = gdb.selected_frame()
+                value = symbol.value(frame)
+
+            sym_not_init = False
+            if hasattr(v, "undeclared"):
+                sym_not_init = v.undeclared()
+
+            argument = False
+            if hasattr(v, "argument"):
+                argument = v.argument()
+
+            num = 0
+            if hasattr(v, "number"):
+                num = v.number()
+
+            raw = False
+            if hasattr(v, "raw"):
+                raw = v.raw()
+
+            fmt = None
+            if hasattr(v, "format"):
+                fmt = v.format()
+
+            error = None
+            if hasattr(v, "error"):
+                error = v.error()
+
+            self.add_val(
+                name,
+                name,
+                value,
+                0,
+                num,
+                cur_vals,
+                keep_prev,
+                False,
+                sym_not_init,
+                argument,
+                raw,
+                fmt,
+                error,
+            )
+        self.prev_vals = cur_vals
+
+    def add_val(
+        self,
+        n,
+        fn,
+        v,
+        inset,
+        num,
+        cur_vals,
+        keep_prev,
+        def_expand,
+        sym_not_init,
+        argument,
+        raw,
+        fmt,
+        error,
+    ):
+        n2 = fn
+        if inset == 0:
+            if num == 0:
+                count = 1
+                while n2 in cur_vals:
+                    count += 1
+                    n2 = "%s:%d" % (n, count)
+            else:
+                n2 = "%d:%s" % (num, n)
+
+        cur_entry = [None, False, None, None]
+        cur_vals[n2] = cur_entry
+        expand = None
+        prev_val = None
+        if n2 in self.prev_vals:
+            pv = self.prev_vals[n2]
+            expand = pv[0]
+            if keep_prev:
+                prev_val = pv[2]
+            else:
+                prev_val = pv[1]
+            cur_entry[0] = expand
+            cur_entry[2] = prev_val
+
+        spaces = "  " * inset
+        if num > 0:
+            numstr = "%d: " % num
+        else:
+            numstr = ""
+
+        if isinstance(v, Exception):
+            error = v.message
+            v = None
+
+        if v is None:
+            if error is None:
+                (var_col_s, var_col_e, val_col_s, val_col_e) = val_cmp_color(
+                    False, False, sym_not_init, argument, empty=True
+                )
+                self.lines.append(spaces + numstr + "  " + var_col_s + n + var_col_e)
+            else:
+                (var_col_s, var_col_e, val_col_s, val_col_e) = val_cmp_color(
+                    False, False, sym_not_init, argument
+                )
+                self.lines.append(
+                    spaces
+                    + numstr
+                    + "  "
+                    + var_col_s
+                    + n
+                    + var_col_e
+                    + " = \033[1;30m<"
+                    + error
+                    + ">\033[0m"
+                )
+            self.line_names.append(n2)
+            return
+
+        if isinstance(v, basestring):
+            (var_col_s, var_col_e, val_col_s, val_col_e) = val_cmp_color(
+                prev_val, v, sym_not_init, argument
+            )
+            self.lines.append(
+                spaces
+                + numstr
+                + "  "
+                + var_col_s
+                + n
+                + var_col_e
+                + " = "
+                + val_col_s
+                + v
+                + val_col_e
+            )
+            self.line_names.append(n2)
+            cur_entry[1] = v
+            return
+
+        is_pp = hasattr(v, "to_string") or hasattr(v, "children")
+
+        v_addr = None
+        if is_pp:
+            if hasattr(v, "address"):
+                try:
+                    v_addr = v.address()
+                except:
+                    v_addr = None
+        elif isinstance(v, gdb.Value):
+            is_optimized_out = False
+            try:
+                if v.type.code in [gdb.TYPE_CODE_REF, gdb.TYPE_CODE_RVALUE_REF]:
+                    v = v.referenced_value()
+
+                is_optimized_out = v.is_optimized_out
+            except:
+                self.add_val(
+                    n,
+                    fn,
+                    None,
+                    inset,
+                    num,
+                    cur_vals,
+                    keep_prev,
+                    False,
+                    sym_not_init,
+                    argument,
+                    raw,
+                    fmt,
+                    str(sys.exc_info()[1]),
+                )
+                return
+
+            if is_optimized_out and v.type.strip_typedefs().code not in [
+                gdb.TYPE_CODE_STRUCT,
+                gdb.TYPE_CODE_UNION,
+            ]:
+                self.add_val(
+                    n,
+                    fn,
+                    None,
+                    inset,
+                    num,
+                    cur_vals,
+                    keep_prev,
+                    False,
+                    sym_not_init,
+                    argument,
+                    raw,
+                    fmt,
+                    "optimized out",
+                )
+                return
+
+            v_addr = v.address
+        else:
+            v = gdb.Value(v)
+
+        cv_str = ""
+        if v_addr is not None:
+            v_addr = v_addr.dereference().reference_value()
+            cur_entry[3] = v_addr
+            cv = gdb.convenience_variable(self.convenience_name)
+            if (
+                cv is not None
+                and cv.address == v_addr.address
+                and cv.type == v_addr.type
+            ):
+                cv_str = " = \033[1;36m$" + self.convenience_name + "\033[0m"
+
+        pp = None
+        if is_pp:
+            pp = v
+        elif not raw:
+            try:
+                pp = gdb.default_visualizer(v)
+            except:
+                pp = None
+
+        def_expand_child = False
+        if pp is None:
+            t = v.type.strip_typedefs()
+            if t.code == gdb.TYPE_CODE_PTR:
+                ptr_target_type = t.target().strip_typedefs().code
+                def_expand_child = ptr_target_type != gdb.TYPE_CODE_PTR
+
+            if t.code in [gdb.TYPE_CODE_ARRAY, gdb.TYPE_CODE_RANGE]:
+                pp = ArrayPrinter(v, t)
+            elif t.code in [gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION]:
+                pp = StructPrinter(v, True, raw)
+            elif t.code == gdb.TYPE_CODE_PTR and not ptr_target_type in [
+                gdb.TYPE_CODE_FUNC,
+                gdb.TYPE_CODE_METHOD,
+            ]:
+                pp = PointerPrinter(v)
+            else:
+                pp = ValuePrinter(v, fmt)
+
+        try:
+            if expand is None and hasattr(pp, "children"):
+                expand = def_expand
+                cur_entry[0] = expand
+            expand_str = "  "
+            if expand is not None:
+                if expand:
+                    expand_str = "- "
+                else:
+                    expand_str = "+ "
+            numstr += expand_str
+
+            valstr = None
+            if hasattr(pp, "to_string"):
+                valstr = pp.to_string()
+            hint = None
+            if hasattr(pp, "display_hint"):
+                hint = pp.display_hint()
+
+            if valstr is not None:
+                valstr = value_string(valstr, hint)
+                valstr = octal_escape(valstr)
+                sp = valstr.split("\n")
+                (var_col_s, var_col_e, val_col_s, val_col_e) = val_cmp_color(
+                    prev_val, valstr, sym_not_init, argument
+                )
+                self.lines.append(
+                    spaces
+                    + numstr
+                    + var_col_s
+                    + n
+                    + var_col_e
+                    + " = "
+                    + val_col_s
+                    + sp.pop(0)
+                    + val_col_e
+                    + cv_str
+                )
+                self.line_names.append(n2)
+                for extra in sp:
+                    self.lines.append(spaces + "    " + extra)
+                    self.line_names.append(None)
+                cur_entry[1] = valstr
+            else:
+                (var_col_s, var_col_e, val_col_s, val_col_e) = val_cmp_color(
+                    prev_val, False, sym_not_init, argument
+                )
+                self.lines.append(spaces + numstr + var_col_s + n + var_col_e + cv_str)
+                self.line_names.append(n2)
+
+            if expand:
+                childs = None
+                if hasattr(pp, "children"):
+                    childs = pp.children()
+                if childs:
+                    if hint == "map":
+                        # If key can be displayed in 1 line, show it as:
+                        #   [$KEY_STRING]
+                        #     $VALUE_CHILDREN
+                        # Otherwise, use key/value pairs:
+                        #   key
+                        #     $KEY_CHILDREN
+                        #   value
+                        #     $VALUE_CHILDREN
+                        count = 0
+                        key = None
+                        for c in childs:
+                            (nc, vc) = c
+                            count += 1
+                            fnc = ":".join([n2, nc])
+                            if (count % 2) == 1:
+                                key = None
+                                if isinstance(vc, basestring):
+                                    key = vc
+                                else:
+                                    vc_check = vc
+                                    if vc_check.type.code in [
+                                        gdb.TYPE_CODE_REF,
+                                        gdb.TYPE_CODE_RVALUE_REF,
+                                    ]:
+                                        vc_check = vc_check.referenced_value()
+                                    key_pp = gdb.default_visualizer(vc_check)
+                                    if key_pp:
+                                        if hasattr(key_pp, "to_string") and not hasattr(
+                                            key_pp, "children"
+                                        ):
+                                            vc_check = key_pp.to_string()
+                                            if vc_check is not None:
+                                                hint = None
+                                                if hasattr(key_pp, "display_hint"):
+                                                    hint = key_pp.display_hint()
+                                                key = value_string(vc_check, hint)
+                                    else:
+                                        t_check = vc_check.type.strip_typedefs()
+                                        if t_check.code in [
+                                            gdb.TYPE_CODE_ENUM,
+                                            gdb.TYPE_CODE_INT,
+                                            gdb.TYPE_CODE_FLT,
+                                            gdb.TYPE_CODE_BOOL,
+                                            gdb.TYPE_CODE_COMPLEX,
+                                            gdb.TYPE_CODE_DECFLOAT,
+                                        ]:
+                                            if fmt:
+                                                key = vc_check.format_string(
+                                                    symbols=False, raw=True, format=fmt
+                                                )
+                                            else:
+                                                key = vc_check.format_string(
+                                                    symbols=False, raw=True
+                                                )
+                                if key is not None and "\n" in key:
+                                    key = None
+                                if key is None:
+                                    self.add_val(
+                                        "key",
+                                        fnc,
+                                        vc,
+                                        inset + 1,
+                                        0,
+                                        cur_vals,
+                                        keep_prev,
+                                        False,
+                                        False,
+                                        False,
+                                        raw,
+                                        fmt,
+                                        None,
+                                    )
+                            else:
+                                if key is not None:
+                                    self.add_val(
+                                        "[" + str(key) + "]",
+                                        fnc,
+                                        vc,
+                                        inset + 1,
+                                        0,
+                                        cur_vals,
+                                        keep_prev,
+                                        False,
+                                        False,
+                                        False,
+                                        raw,
+                                        fmt,
+                                        None,
+                                    )
+                                else:
+                                    self.add_val(
+                                        "value",
+                                        fnc,
+                                        vc,
+                                        inset + 1,
+                                        0,
+                                        cur_vals,
+                                        keep_prev,
+                                        False,
+                                        False,
+                                        False,
+                                        raw,
+                                        fmt,
+                                        None,
+                                    )
+                    else:
+                        for c in childs:
+                            (nc, vc) = c
+                            fnc = ":".join([n2, nc])
+                            self.add_val(
+                                nc,
+                                fnc,
+                                vc,
+                                inset + 1,
+                                0,
+                                cur_vals,
+                                keep_prev,
+                                def_expand_child,
+                                False,
+                                False,
+                                raw,
+                                fmt,
+                                None,
+                            )
+        except:
+            self.add_val(
+                n,
+                fn,
+                None,
+                inset,
+                num,
+                cur_vals,
+                keep_prev,
+                False,
+                sym_not_init,
+                argument,
+                raw,
+                fmt,
+                str(sys.exc_info()[1]),
+            )
+
+
+class VarNameValue(object):
+    """Object returned by LocalsWindow.variables."""
+
+    def __init__(
+        self, sym, val=None, undecl=False, arg=False, num=0, r=False, fmt=None, err=None
+    ):
+        self.sym = sym
+        self.val = val
+        self.undecl = undecl
+        self.arg = arg
+        self.num = num
+        self.r = r
+        self.fmt = fmt
+        self.err = err
+
+    def symbol(self):
+        return self.sym
+
+    def value(self):
+        return self.val
+
+    def undeclared(self):
+        return self.undecl
+
+    def argument(self):
+        return self.arg
+
+    def number(self):
+        return self.num
+
+    def raw(self):
+        return self.r
+
+    def format(self):
+        return self.fmt
+
+    def error(self):
+        return self.err
+
+
+class LocalsWindow(VariableWindow):
+    """Window for local variables."""
+
+    def __init__(self, win):
+        super(LocalsWindow, self).__init__(win, "locals", "lv")
+
+    def variables(self):
+        thread = gdb.selected_thread()
+        thread_valid = thread and thread.is_valid()
+        if thread_valid:
+            frame = gdb.selected_frame()
+            cur_line = frame.find_sal().line
+            try:
+                block = frame.block()
+            except:
+                block = None
+            while block:
+                if not block.is_global:
+                    for symbol in block:
+                        if symbol.is_argument or symbol.is_variable:
+                            sym_not_init = (
+                                symbol.is_variable
+                                and symbol.line > 0
+                                and cur_line <= symbol.line
+                            )
+                            yield VarNameValue(
+                                symbol.name,
+                                val=symbol.value(frame),
+                                undecl=sym_not_init,
+                                arg=symbol.is_argument,
+                            )
+                if block.function:
+                    break
+                block = block.superblock
+
+
+gdb.register_window_type("locals", LocalsWindow)
+
+
+def before_prompt_handler(event=None):
+    """Refresh all TextWindow instances when user is presented a prompt."""
+    global custom_windows
+    for key, value in custom_windows.items():
+        if value.win.is_valid():
+            value.refill()
+            value.redraw()
+
+
+gdb.events.before_prompt.connect(before_prompt_handler)
+
+
+gdb.execute("tui new-layout locals {-horizontal src 2 locals 1} 2 status 0 cmd 1")
-- 
2.31.1


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

* [PATCHv2 2/2] Use method children instead of to_string in pretty printers
  2021-06-04 16:23 ` [PATCHv2 1/2] Implement locals TUI window Hannes Domani
@ 2021-06-04 16:24   ` Hannes Domani
  2021-07-17 19:19     ` Joel Brobecker
  2023-11-13 20:07   ` [PATCHv2 1/2] Implement locals TUI window Tom Tromey
  1 sibling, 1 reply; 4+ messages in thread
From: Hannes Domani @ 2021-06-04 16:24 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/ChangeLog:

2021-06-04  Hannes Domani  <ssbssa@yahoo.de>

	* gdb-gdb.py.in: Use method children in pretty printers.
---
v2:
- Added ChangeLog.
- Reformatted with black.
---
 gdb/gdb-gdb.py.in | 175 ++++++++++++++++++++--------------------------
 1 file changed, 77 insertions(+), 98 deletions(-)

diff --git a/gdb/gdb-gdb.py.in b/gdb/gdb-gdb.py.in
index af9fcfedc2f..1432d7bbcf8 100644
--- a/gdb/gdb-gdb.py.in
+++ b/gdb/gdb-gdb.py.in
@@ -107,17 +107,13 @@ 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":
+                val = str(TypeFlagsPrinter(val))
+            yield name, val
 
 
 class StructMainTypePrettyPrinter:
@@ -142,46 +138,6 @@ class StructMainTypePrettyPrinter:
         ]
         return "|".join(fields)
 
-    def owner_to_string(self):
-        """Return an image of component "owner"."""
-        if self.val["m_flag_objfile_owned"] != 0:
-            return "%s (objfile)" % self.val["m_owner"]["objfile"]
-        else:
-            return "%s (gdbarch)" % self.val["m_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"]
-        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) + "}"
-
     def bound_img(self, bound_name):
         """Return an image of the given main_type's bound."""
         bounds = self.val["flds_bnds"]["bounds"].dereference()
@@ -197,17 +153,6 @@ class StructMainTypePrettyPrinter:
                 info.append("upper_bound_is_count")
             return "{} ({})".format(str(b["m_data"]["baton"]), ",".join(info))
 
-    def bounds_img(self):
-        """Return an image of the main_type bounds."""
-        b = self.val["flds_bnds"]["bounds"].dereference()
-        low = self.bound_img("low")
-        high = self.bound_img("high")
-
-        img = "flds_bnds.bounds = {%s, %s}" % (low, high)
-        if b["flag_bound_evaluated"]:
-            img += " [evaluated]"
-        return img
-
     def type_specific_img(self):
         """Return a string image of the main_type type_specific union.
         Only the relevant component of that union is printed (based on
@@ -216,54 +161,86 @@ 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"]
-        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
+            return "self_type", type_specific["self_type"]
+        return (
+            "type_specific",
+            "??? (unknown type_secific_kind: %s)" % type_specific_kind,
+        )
 
-    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"])
+    def children(self):
+        yield "name", self.val["name"].format_string(symbols=False, address=False)
+        yield "code", self.val["code"]
+        yield "flags", "[%s]" % self.flags_to_string()
+        if self.val["m_flag_objfile_owned"] != 0:
+            yield "owner.objfile", self.val["m_owner"]["objfile"]
+        else:
+            yield "owner.gdbarch", self.val["m_owner"]["gdbarch"]
+        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())
+            b = self.val["flds_bnds"]["bounds"].dereference()
+            low = self.bound_img("low")
+            high = self.bound_img("high")
+
+            img = "{%s, %s}" % (low, high)
+            if b["flag_bound_evaluated"]:
+                img += " [evaluated]"
+            yield "flds_bnds.bounds", img
+        yield self.type_specific_img()
+
+
+class StructFieldPrettyPrinter:
+    """Pretty-print an objet of type field"""
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        if self.val["artificial"]:
+            yield "artificial", self.val["artificial"]
+        yield "name", self.val["name"].format_string(symbols=False, address=False)
+        yield "type", self.val["m_type"]
+        yield "loc_kind", self.val["loc_kind"]
+        yield "bitsize", self.val["bitsize"]
 
-        return "\n{" + ",\n ".join(fields) + "}"
+        loc_val = self.val["loc"]
+        loc_kind = str(self.val["loc_kind"])
+        if loc_kind == "FIELD_LOC_KIND_BITPOS":
+            yield "bitpos", loc_val["bitpos"]
+        elif loc_kind == "FIELD_LOC_KIND_ENUMVAL":
+            yield "enumval", loc_val["enumval"]
+        elif loc_kind == "FIELD_LOC_KIND_PHYSADDR":
+            yield "physaddr", loc_val["physaddr"]
+        elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
+            yield "physname", loc_val["physname"].format_string(
+                symbols=False, address=False
+            )
+        elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
+            yield "dwarf_block", loc_val["dwarf_block"]
+        else:
+            yield "loc", "???"
 
 
 class CoreAddrPrettyPrinter:
@@ -284,6 +261,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.31.1


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

* Re: [PATCHv2 2/2] Use method children instead of to_string in pretty printers
  2021-06-04 16:24   ` [PATCHv2 2/2] Use method children instead of to_string in pretty printers Hannes Domani
@ 2021-07-17 19:19     ` Joel Brobecker
  0 siblings, 0 replies; 4+ messages in thread
From: Joel Brobecker @ 2021-07-17 19:19 UTC (permalink / raw)
  To: Hannes Domani via Gdb-patches; +Cc: Joel Brobecker

Hi Hannes,

On Fri, Jun 04, 2021 at 06:24:00PM +0200, Hannes Domani via Gdb-patches wrote:
> With '-pretty on' the output is basically the same, but like this the
> pointer members can be expanded in the TUI variable windows.
> 
> gdb/ChangeLog:
> 
> 2021-06-04  Hannes Domani  <ssbssa@yahoo.de>
> 
> 	* gdb-gdb.py.in: Use method children in pretty printers.

It looks like no one has reviewed this patch, yet, so I took a look.

Overall, this looks good to me, except for one area:

> ---
> v2:
> - Added ChangeLog.
> - Reformatted with black.
> ---
>  gdb/gdb-gdb.py.in | 175 ++++++++++++++++++++--------------------------
>  1 file changed, 77 insertions(+), 98 deletions(-)
> 
> diff --git a/gdb/gdb-gdb.py.in b/gdb/gdb-gdb.py.in
> index af9fcfedc2f..1432d7bbcf8 100644
> --- a/gdb/gdb-gdb.py.in
> +++ b/gdb/gdb-gdb.py.in
> @@ -107,17 +107,13 @@ 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":
> +                val = str(TypeFlagsPrinter(val))
> +            yield name, val
>  
>  
>  class StructMainTypePrettyPrinter:
> @@ -142,46 +138,6 @@ class StructMainTypePrettyPrinter:
>          ]
>          return "|".join(fields)
>  
> -    def owner_to_string(self):
> -        """Return an image of component "owner"."""
> -        if self.val["m_flag_objfile_owned"] != 0:
> -            return "%s (objfile)" % self.val["m_owner"]["objfile"]
> -        else:
> -            return "%s (gdbarch)" % self.val["m_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"]
> -        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) + "}"
> -
>      def bound_img(self, bound_name):
>          """Return an image of the given main_type's bound."""
>          bounds = self.val["flds_bnds"]["bounds"].dereference()
> @@ -197,17 +153,6 @@ class StructMainTypePrettyPrinter:
>                  info.append("upper_bound_is_count")
>              return "{} ({})".format(str(b["m_data"]["baton"]), ",".join(info))
>  
> -    def bounds_img(self):
> -        """Return an image of the main_type bounds."""
> -        b = self.val["flds_bnds"]["bounds"].dereference()
> -        low = self.bound_img("low")
> -        high = self.bound_img("high")
> -
> -        img = "flds_bnds.bounds = {%s, %s}" % (low, high)
> -        if b["flag_bound_evaluated"]:
> -            img += " [evaluated]"
> -        return img
> -
>      def type_specific_img(self):
>          """Return a string image of the main_type type_specific union.
>          Only the relevant component of that union is printed (based on
> @@ -216,54 +161,86 @@ 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"]
> -        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
> +            return "self_type", type_specific["self_type"]
> +        return (
> +            "type_specific",
> +            "??? (unknown type_secific_kind: %s)" % type_specific_kind,
> +        )

It looks to me like you collapsed the case of TYPE_SPECIFIC_FIXED_POINT
with the "else:" part. While we are unable to print the actual data
in both cases, I still think it's worth showing preserving the current
behavior, because it confirms the type-specific kind, and also shows
to the user that the value is opaque, with a tipe on how to get it
in practice.

The rest looked good to me.

>  
> -    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"])
> +    def children(self):
> +        yield "name", self.val["name"].format_string(symbols=False, address=False)
> +        yield "code", self.val["code"]
> +        yield "flags", "[%s]" % self.flags_to_string()
> +        if self.val["m_flag_objfile_owned"] != 0:
> +            yield "owner.objfile", self.val["m_owner"]["objfile"]
> +        else:
> +            yield "owner.gdbarch", self.val["m_owner"]["gdbarch"]
> +        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())
> +            b = self.val["flds_bnds"]["bounds"].dereference()
> +            low = self.bound_img("low")
> +            high = self.bound_img("high")
> +
> +            img = "{%s, %s}" % (low, high)
> +            if b["flag_bound_evaluated"]:
> +                img += " [evaluated]"
> +            yield "flds_bnds.bounds", img
> +        yield self.type_specific_img()
> +
> +
> +class StructFieldPrettyPrinter:
> +    """Pretty-print an objet of type field"""
> +
> +    def __init__(self, val):
> +        self.val = val
> +
> +    def children(self):
> +        if self.val["artificial"]:
> +            yield "artificial", self.val["artificial"]
> +        yield "name", self.val["name"].format_string(symbols=False, address=False)
> +        yield "type", self.val["m_type"]
> +        yield "loc_kind", self.val["loc_kind"]
> +        yield "bitsize", self.val["bitsize"]
>  
> -        return "\n{" + ",\n ".join(fields) + "}"
> +        loc_val = self.val["loc"]
> +        loc_kind = str(self.val["loc_kind"])
> +        if loc_kind == "FIELD_LOC_KIND_BITPOS":
> +            yield "bitpos", loc_val["bitpos"]
> +        elif loc_kind == "FIELD_LOC_KIND_ENUMVAL":
> +            yield "enumval", loc_val["enumval"]
> +        elif loc_kind == "FIELD_LOC_KIND_PHYSADDR":
> +            yield "physaddr", loc_val["physaddr"]
> +        elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
> +            yield "physname", loc_val["physname"].format_string(
> +                symbols=False, address=False
> +            )
> +        elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
> +            yield "dwarf_block", loc_val["dwarf_block"]
> +        else:
> +            yield "loc", "???"
>  
>  
>  class CoreAddrPrettyPrinter:
> @@ -284,6 +261,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.31.1
> 

-- 
Joel

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

* Re: [PATCHv2 1/2] Implement locals TUI window
  2021-06-04 16:23 ` [PATCHv2 1/2] Implement locals TUI window Hannes Domani
  2021-06-04 16:24   ` [PATCHv2 2/2] Use method children instead of to_string in pretty printers Hannes Domani
@ 2023-11-13 20:07   ` Tom Tromey
  1 sibling, 0 replies; 4+ messages in thread
From: Tom Tromey @ 2023-11-13 20:07 UTC (permalink / raw)
  To: Hannes Domani via Gdb-patches; +Cc: Hannes Domani

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

I'm sorry about the extreme delay on this.

Hannes> gdb/ChangeLog:
Hannes> 2021-06-04  Hannes Domani  <ssbssa@yahoo.de>

Hannes> 	PR tui/17849
Hannes> 	* data-directory/Makefile.in: Add tui_windows.py.
Hannes> 	* python/lib/gdb/command/tui_windows.py: New file.

I recently became aware there was a v2 of this patch.  I must have
missed it when you originally sent it.

Hannes> +PY3 = sys.version_info[0] == 3
Hannes> +
Hannes> +if PY3:
Hannes> +    basestring = str

Can drop this now.

Hannes> +def val_cmp_color(prev, cur, sym_not_init, argument, empty=False):
Hannes> +    """Returns the color escape sequences for variable name and value."""
Hannes> +    var_col_s, var_col_e, val_col_s, val_col_e = "", "", "", ""
Hannes> +    if empty:
Hannes> +        # Variable without contents
Hannes> +        var_col_s, var_col_e = "\033[1;30m", "\033[0m"
Hannes> +    elif prev is None:
Hannes> +        # New variable
Hannes> +        var_col_s, var_col_e = "\033[1;32m", "\033[0m"
Hannes> +    elif prev != cur:
Hannes> +        # Variable contents changed
Hannes> +        val_col_s, val_col_e = "\033[1;31m", "\033[0m"
Hannes> +    if argument:
Hannes> +        # Variable is a function argument
Hannes> +        var_col_s, var_col_e = "\033[1;35m", "\033[0m"
Hannes> +    elif sym_not_init:
Hannes> +        # Variable was not yet initialized
Hannes> +        var_col_s, var_col_e = "\033[33m", "\033[0m"
Hannes> +    return (var_col_s, var_col_e, val_col_s, val_col_e)

Perhaps these should have 'set style' parameters?
Or reuse existing ones?

Hannes> +def is_string_element_type(t):
Hannes> +    """Return if an array of this type is considered a string."""
Hannes> +    target_type = t.target().strip_typedefs()
Hannes> +    return target_type.code == gdb.TYPE_CODE_INT and (
Hannes> +        target_type.name == "char" or is_typedef_of(t.target(), "wchar_t")
Hannes> +    )

There's a more direct way of doing some of this stuff now.
This code can probably reuse the work done for DAP.

Hannes> +class ArrayPrinter(object):
Hannes> +    """Pretty printer for arrays."""

Same for this and the other "no-op" printers.

Hannes> +class StructPrinter(object):
...
Hannes> +        for f in fields:
Hannes> +            if not hasattr(f, "bitpos"):
Hannes> +                continue

Oops, I think this points out a bug in NoOpStructPrinter.
I'll fix that.

Hannes> +            # Disable dynamic_type for base classes, to prevent infinite
Hannes> +            # recursion.
Hannes> +            if child_v.type.code == gdb.TYPE_CODE_STRUCT and f.is_base_class:
Hannes> +                pp = None
Hannes> +                if not self.raw:

Hmm I wonder if this is one as well.

Hannes> +                                if key is not None:
Hannes> +                                    self.add_val(
Hannes> +                                        "[" + str(key) + "]",
Hannes> +                                        fnc,
Hannes> +                                        vc,
Hannes> +                                        inset + 1,
Hannes> +                                        0,
Hannes> +                                        cur_vals,
Hannes> +                                        keep_prev,
Hannes> +                                        False,
Hannes> +                                        False,
Hannes> +                                        False,
Hannes> +                                        raw,
Hannes> +                                        fmt,
Hannes> +                                        None,
Hannes> +                                    )
Hannes> +                                else:
Hannes> +                                    self.add_val(
Hannes> +                                        "value",
Hannes> +                                        fnc,
Hannes> +                                        vc,
Hannes> +                                        inset + 1,
Hannes> +                                        0,
Hannes> +                                        cur_vals,
Hannes> +                                        keep_prev,
Hannes> +                                        False,
Hannes> +                                        False,
Hannes> +                                        False,
Hannes> +                                        raw,
Hannes> +                                        fmt,
Hannes> +                                        None,
Hannes> +                                    )

Some things like this could probably be simplified?

I found some of this code pretty hard to follow.

Tom

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

end of thread, other threads:[~2023-11-13 20:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20210604162400.3255-1-ssbssa.ref@yahoo.de>
2021-06-04 16:23 ` [PATCHv2 1/2] Implement locals TUI window Hannes Domani
2021-06-04 16:24   ` [PATCHv2 2/2] Use method children instead of to_string in pretty printers Hannes Domani
2021-07-17 19:19     ` Joel Brobecker
2023-11-13 20:07   ` [PATCHv2 1/2] Implement locals TUI window 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).