* [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).