On 28/07/2026 23:50, David Malcolm wrote:
On Thu, 2026-07-02 at 09:57 +0100, Andrew Stubbs wrote:
Ping.
Thanks for the patch, sorry about the delay in reviewing this.
Testing this is usually a bit of a pain. You don't happen to have a
precanned way of doing this by any chance? :)
I do not have any sort of testsuite. I just did some manual checks.
Given that I rarely touch the world of rtx, you're probably in a better
position to assess this patch than me. Mostly looks good...
+def reg_name(regno):
+ val_reg_names = gdb.parse_and_eval('reg_names')
+ try:
+ return val_reg_names[regno].string()
+ except:
+ return "pseudo"
I discovered that "reg_names" is actually defined as a macro, which
means it only works in GDB in some contexts (assuming that GCC was even
built with -g3, which might be just me). The attached patch fixes this
issue, I hope, by inlining both the internal definitions of the macro.
+ if name == 'insn' or name == 'call_insn' or name ==
'jump_insn':
+ result += ' %d' % self.gdbval['u2']['insn_uid']
+ icode = self.rtx.XINT(5)
(might want a trailing comment here: # INSN_CODE)
Good idea; done.
+ if icode != -1:
+ result += ' %s' % get_insn_name(icode)
+ else:
+ result += ' <unrecognized>'
+ elif name == 'reg':
+ regno = self.gdbval['u']['reg']['regno']
+ mode = mode_name(self.gdbval['mode'])
+ result += ':%s %d %s' % (mode, regno, reg_name(regno))
+ #else:
+ #format_ = GET_RTX_FORMAT(code)
+ #for i in range(GET_RTX_LENGTH(code)):
+ # print(format_[i])
...though I see that you're commenting out my old implementation for
this case. How well does it work? Should we just remove it? Is any
of it worth saving? IIRC I tried it, had issues with it, and found the
kludge easier, but that was 13 years ago.
This code only printed the format letters (direct to the GDB console,
without any indication of what they signified), and did not contribute
anything to the pretty-print string. It was vaguely useful for
developing this code, but not useful to the end user. The new patch has
removed it.
One other nit: please update the multiline string at the top of the
file, in particular the "RTL expressions use a kludge" part, which is
no longer true with your improvement.
Now updated with new examples. I've left a reference to the
print-rtl.cc printer because it is so much more comprehensive than these
basic summaries. I think there's room for both.
Is the new patch OK?
Thanks
Andrew
From a227aa028d2d58c0db31b3905404540a0b73b608 Mon Sep 17 00:00:00 2001
From: Andrew Stubbs <[email protected]>
Date: Fri, 26 Jun 2026 14:40:50 +0000
Subject: [PATCH] Improved GDB RTX printing hooks
Adds new features to the GDB Python script that prints GCC internals.
- Improved output for rtx_def types.
- Also enable printing for rtx, const_rtx, rtx_insn, etc.
- Add icode details for rtx_insn.
- Add register details for REG nodes.
Examples:
<rtx_def 0x12345678 (mem)>
<rtx_def 0x12345678 (reg:DI 685 pseudo)>
<rtx_def 0x12345678 (reg:DI 1 r1)>
<rtx_def 0x12345678 (insn 160 movdi_symbol)>
gcc/ChangeLog:
* gdbhooks.py (Rtx): Decode more things.
(RtxPrinter): Improve output.
(build_pretty_printer): Match more rtx types.
---
gcc/gdbhooks.py | 76 +++++++++++++++++++++++++++++++++----------------
1 file changed, 51 insertions(+), 25 deletions(-)
diff --git a/gcc/gdbhooks.py b/gcc/gdbhooks.py
index 616fc605f62..a2dfb707aba 100644
--- a/gcc/gdbhooks.py
+++ b/gcc/gdbhooks.py
@@ -92,15 +92,20 @@ running in gdb, rather than in the inferior:
For usability, the type is printed first (e.g. "function_decl"), rather
than just "tree".
-RTL expressions use a kludge: they are pretty-printed by injecting
-calls into print-rtl.c into the inferior:
- Value returned is $1 = (note 9 8 10 [bb 3] NOTE_INSN_BASIC_BLOCK)
- (gdb) p $1
- $2 = (note 9 8 10 [bb 3] NOTE_INSN_BASIC_BLOCK)
- (gdb) p /r $1
- $3 = (rtx_def *) 0x7ffff043e140
-This won't work for coredumps, and probably in other circumstances, but
-it's a quick way of getting lots of debuggability quickly.
+RTL expressions show at least the rtx code in parenthesis:
+ (gdb) p pattern
+ $11 = <rtx_def 0x7ffff78f1798 (set)>
+Insns show the unique number and machine description name, if an icode is
+recorded ("<unrecognised>" otherwise):
+ (gdb) p insn
+ $12 = <rtx_def 0x7ffff7ae2380 (insn 1 <unrecognized>)>
+ (gdb) p insn
+ $17 = <rtx_def 0x7ffff78dc690 (call_insn 6 *call_value)>
+Registers show the mode, number, and either the hardreg name or "pseudo":
+ (gdb) p x
+ $13 = <rtx_def 0x7ffff78f1708 (reg:SI 98 pseudo)>
+For all other cases, use "pp x" to print full RTL expressions via the print-rtl.c
+routines (not available for coredumps).
Callgraph nodes are printed with the name of the function decl, if
available:
@@ -423,6 +428,9 @@ class Rtx:
def GET_CODE(self):
return self.gdbval['code']
+ def XINT(self, n):
+ return self.gdbval['u']['fld'][n]['rt_int']
+
def GET_RTX_LENGTH(code):
val_rtx_length = gdb.parse_and_eval('rtx_length')
return intptr(val_rtx_length[code])
@@ -435,30 +443,44 @@ def GET_RTX_FORMAT(code):
val_rtx_format = gdb.parse_and_eval('rtx_format')
return val_rtx_format[code].string()
+def get_insn_name(icode):
+ return gdb.parse_and_eval('insn_data')[icode]['name'].string()
+
+def reg_name(regno):
+ try:
+ val_reg_names = gdb.parse_and_eval('this_target_hard_regs->x_reg_names')
+ except:
+ val_reg_names = gdb.parse_and_eval('default_target_hard_regs.x_reg_names')
+ try:
+ return val_reg_names[regno].string()
+ except:
+ return "pseudo"
+
+def mode_name(mode):
+ return gdb.parse_and_eval('mode_name')[mode].string()
+
class RtxPrinter:
def __init__(self, gdbval):
self.gdbval = gdbval
self.rtx = Rtx(gdbval)
def to_string (self):
- """
- For now, a cheap kludge: invoke the inferior's print
- function to get a string to use the user, and return an empty
- string for gdb
- """
- # We use print_inline_rtx to avoid a trailing newline
- gdb.execute('call print_inline_rtx (stderr, (const_rtx) %s, 0)'
- % intptr(self.gdbval))
- return ''
-
- # or by hand; based on gcc/print-rtl.c:print_rtx
result = ('<rtx_def 0x%x'
% (intptr(self.gdbval)))
code = self.rtx.GET_CODE()
- result += ' (%s' % GET_RTX_NAME(code)
- format_ = GET_RTX_FORMAT(code)
- for i in range(GET_RTX_LENGTH(code)):
- print(format_[i])
+ name = GET_RTX_NAME(code)
+ result += ' (%s' % name
+ if name == 'insn' or name == 'call_insn' or name == 'jump_insn':
+ result += ' %d' % self.gdbval['u2']['insn_uid']
+ icode = self.rtx.XINT(5) # INSN_CODE
+ if icode != -1:
+ result += ' %s' % get_insn_name(icode)
+ else:
+ result += ' <unrecognized>'
+ elif name == 'reg':
+ regno = self.gdbval['u']['reg']['regno']
+ mode = mode_name(self.gdbval['mode'])
+ result += ':%s %d %s' % (mode, regno, reg_name(regno))
result += ')>'
return result
@@ -661,7 +683,11 @@ def build_pretty_printer():
pp.add_printer_for_types(['edge', 'edge_def *'],
'edge',
CfgEdgePrinter)
- pp.add_printer_for_types(['rtx_def *'], 'rtx_def', RtxPrinter)
+ pp.add_printer_for_types(['rtx_def *', 'rtx', 'const_rtx', 'rtx_insn *',
+ 'const rtx_insn *', 'rtx_jump_insn *',
+ 'const rtx_jump_insn *', 'rtx_call_insn *',
+ 'const rtx_call_insn *'],
+ 'rtx_def', RtxPrinter)
pp.add_printer_for_types(['opt_pass *'], 'opt_pass', PassPrinter)
pp.add_printer_for_regex(r'vec<(\S+), (\S+), (\S+)> \*',
--
2.54.0