* [PATCH] gdb/python: allow Architecture.disassemble to give styled output
@ 2026-03-20 15:31 Andrew Burgess
2026-03-20 15:48 ` Eli Zaretskii
2026-03-20 17:54 ` Tom Tromey
0 siblings, 2 replies; 4+ messages in thread
From: Andrew Burgess @ 2026-03-20 15:31 UTC (permalink / raw)
To: gdb-patches; +Cc: Andrew Burgess
Extend the Architecture.disassemble API to allow the user to request
styled disassembler output via a new styling argument. A user can now
write:
insn = arch.disassemble(address, styling = True)
The instruction strings returned within INSN will contain ANSI escape
sequences so long as 'set style enabled on' is in effect. This means
that the user's personal settings (disabling styling) will override a
GDB extension that requests styled disassembler output. I think this
makes sense.
The default for the styling argument is False, this maintains the
current unstyled output as default.
---
gdb/NEWS | 5 +
gdb/doc/python.texi | 7 +-
gdb/python/py-arch.c | 11 +-
.../gdb.python/py-arch-disasm-style.c | 52 ++++++++
.../gdb.python/py-arch-disasm-style.exp | 119 ++++++++++++++++++
5 files changed, 189 insertions(+), 5 deletions(-)
create mode 100644 gdb/testsuite/gdb.python/py-arch-disasm-style.c
create mode 100644 gdb/testsuite/gdb.python/py-arch-disasm-style.exp
diff --git a/gdb/NEWS b/gdb/NEWS
index e46a5108272..da74c248c54 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -229,6 +229,11 @@ qExecAndArgs
the appropriate user setting is enabled, and GDB knows how to
style this source file.
+ ** The Architecture.disassemble method accepts a new 'styling'
+ argument, which defaults to False. When set to True the 'asm'
+ strings in the disassembler output can contain ANSI escape
+ sequences to indicate styling.
+
* Guile API
** Procedures 'memory-port-read-buffer-size',
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 2df3b7c0423..e9ca0d67792 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -7632,7 +7632,7 @@ Architectures In Python
Return the name (string value) of the architecture.
@end defun
-@defun Architecture.disassemble (start_pc @r{[}, end_pc @r{[}, count@r{]]})
+@defun Architecture.disassemble (start_pc @r{[}, end_pc @r{[}, count@r{]]} @w{@r{[}, styling = @code{False}@r{]}})
Return a list of disassembled instructions starting from the memory
address @var{start_pc}. The optional arguments @var{end_pc} and
@var{count} determine the number of instructions in the returned list.
@@ -7661,6 +7661,11 @@ Architectures In Python
language flavor used is the same as that specified by the current CLI
variable @code{disassembly-flavor}. @xref{Machine Code}.
+When the optional argument @var{styling} is @code{True} the @var{asm}
+string can contain ANSI terminal escape sequences if styling is
+enabled (@pxref{Output Styling}). When @var{styling} is @code{False},
+which is the default, then no styling will be applied to @var{asm}.
+
@item length
The value corresponding to this key is the length (integer value) of the
instruction in bytes.
diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c
index f40d7da1763..4031f925b04 100644
--- a/gdb/python/py-arch.c
+++ b/gdb/python/py-arch.c
@@ -124,18 +124,21 @@ archpy_name (PyObject *self, PyObject *args)
static PyObject *
archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
{
- static const char *keywords[] = { "start_pc", "end_pc", "count", NULL };
+ static const char *keywords[] = {
+ "start_pc", "end_pc", "count", "styling", nullptr
+ };
CORE_ADDR start = 0, end = 0;
CORE_ADDR pc;
long count = 0, i;
PyObject *start_obj = nullptr, *end_obj = nullptr, *count_obj = nullptr;
struct gdbarch *gdbarch = NULL;
+ int styling_p = 0;
ARCHPY_REQUIRE_VALID (self, gdbarch);
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|OO",
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O|OOp",
keywords, &start_obj, &end_obj,
- &count_obj))
+ &count_obj, &styling_p))
return NULL;
if (get_addr_from_python (start_obj, &start) < 0)
@@ -190,7 +193,7 @@ archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
if (PyList_Append (result_list.get (), insn_dict.get ()))
return NULL; /* PyList_Append Sets the exception. */
- string_file stb;
+ string_file stb (styling_p);
try
{
diff --git a/gdb/testsuite/gdb.python/py-arch-disasm-style.c b/gdb/testsuite/gdb.python/py-arch-disasm-style.c
new file mode 100644
index 00000000000..ec2ae965552
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-arch-disasm-style.c
@@ -0,0 +1,52 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 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/>. */
+
+volatile int global_var = 0;
+
+/* This only exists so we can call it from main. */
+
+void
+worker_func (void)
+{
+ global_var = global_var + 2;
+ global_var = global_var + 2;
+ global_var = global_var + 2;
+ global_var = global_var + 2;
+}
+
+/* It's all nonsense in this function. We just want 'main' to be more than
+ 10 instructions long. */
+
+int
+main (void)
+{
+ int i;
+
+ global_var = global_var + 2;
+
+ for (int i = 0; i < 10; ++i)
+ global_var = global_var + i;
+
+ worker_func ();
+
+ global_var = global_var + 2;
+ global_var = global_var + 2;
+ global_var = global_var + 2;
+ global_var = global_var + 2;
+
+ return global_var;
+}
diff --git a/gdb/testsuite/gdb.python/py-arch-disasm-style.exp b/gdb/testsuite/gdb.python/py-arch-disasm-style.exp
new file mode 100644
index 00000000000..2c38a62b80e
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-arch-disasm-style.exp
@@ -0,0 +1,119 @@
+# Copyright 2026 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/>.
+
+# Test styling for the Architecture.disassemble method.
+
+load_lib gdb-python.exp
+require allow_python_tests
+
+standard_testfile
+
+if { [build_executable "failed to build" ${testfile} ${srcfile}] } {
+ return
+}
+
+with_ansi_styling_terminal {
+ clean_restart $testfile
+}
+
+if {![runto_main]} {
+ return
+}
+
+# A new command 'py-disasm' which takes an address and disassembles 10
+# instructions starting from that address. The disassembly will
+# include styling.
+gdb_test_multiline "python disasm command" \
+ "python" "" \
+ "class py_disasm_cmd(gdb.Command):" "" \
+ " def __init__(self):" "" \
+ " super().__init__(\"py-disasm\", gdb.COMMAND_OBSCURE)" "" \
+ " def invoke(self, args, from_tty):" "" \
+ " argv = gdb.string_to_argv(args)" "" \
+ " inf = gdb.selected_inferior ()" "" \
+ " arch = inf.architecture ()" "" \
+ " addr = gdb.parse_and_eval(argv\[0\])" "" \
+ " insn = arch.disassemble(addr.address, count = 10, styling = True)" "" \
+ " for i in insn:" "" \
+ " formatted_addr = gdb.format_address(i\['addr'\])" "" \
+ " print(\"0x%x: \t %s\" % (i\['addr'\], i\['asm'\]))" "" \
+ "py_disasm_cmd()" "" \
+ "end" ""
+
+# Run CMD which will disassemble 10 instructions. Capture those
+# instructions into a list where each list item is itself a list of
+# the form [ADDRESS, STRING], where STRING is the disassembled
+# instruction.
+#
+# Returns the list of disassembled instructions, which should be 10
+# elements long if this worked.
+#
+# This proc emits a pass/fail on whether 10 instructions were captured
+# using TESTNAME.
+proc disassemble_and_gather_insn { cmd testname } {
+ set insn {}
+ gdb_test_multiple $cmd $testname {
+ -re "^[string_to_regexp $cmd]\r\n" {
+ exp_continue
+ }
+
+ -re "^\[^:\r\n]*($::hex)\[^:\r\n\]*:\\s+(\[^\r\n\]+)\r\n" {
+ set addr $expect_out(1,string)
+ set asm $expect_out(2,string)
+ lappend insn [list $addr $asm]
+ exp_continue
+ }
+
+ -re "^$::gdb_prompt $" {
+ gdb_assert {[llength $insn] == 10} $gdb_test_name
+ }
+ }
+
+ return $insn
+}
+
+# Capture the instructions, with styling, using GDB's CLI
+# disassembler.
+set expected_insn [disassemble_and_gather_insn "x/10i *main" \
+ "disassemble some instructions"]
+
+# Now disassemble using our Python disassemble command. Capture these
+# instructions.
+set py_insn [disassemble_and_gather_insn "py-disasm *main" \
+ "disassemble instructions via python"]
+
+# Check we got the same disassembled output, including styling, in
+# both cases.
+gdb_assert { $expected_insn eq $py_insn } \
+ "instructions, with styling, are the same"
+
+# Disable styling.
+gdb_test_no_output "set style enabled off"
+
+# Run the Python disassembled again. Now that styling is disabled
+# there should be no escape sequences in the disassembler output.
+set py_insn [disassemble_and_gather_insn "py-disasm *main" \
+ "disassemble instructions via python, no styling"]
+
+# Check for escape sequences. There should be none.
+set found_escape false
+foreach insn $py_insn {
+ set asm [lindex $insn 1]
+ if {[string first "\033" $asm] != -1} {
+ set found_escape true
+ }
+}
+gdb_assert { !$found_escape } \
+ "no escape sequences in unstyled disassembler output"
base-commit: e5425f2687d66034a8d3fe94264cf99b42c1cb1a
--
2.25.4
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] gdb/python: allow Architecture.disassemble to give styled output
2026-03-20 15:31 [PATCH] gdb/python: allow Architecture.disassemble to give styled output Andrew Burgess
@ 2026-03-20 15:48 ` Eli Zaretskii
2026-03-23 10:17 ` Andrew Burgess
2026-03-20 17:54 ` Tom Tromey
1 sibling, 1 reply; 4+ messages in thread
From: Eli Zaretskii @ 2026-03-20 15:48 UTC (permalink / raw)
To: Andrew Burgess; +Cc: gdb-patches
> From: Andrew Burgess <aburgess@redhat.com>
> Cc: Andrew Burgess <aburgess@redhat.com>
> Date: Fri, 20 Mar 2026 15:31:11 +0000
>
> Extend the Architecture.disassemble API to allow the user to request
> styled disassembler output via a new styling argument. A user can now
> write:
>
> insn = arch.disassemble(address, styling = True)
>
> The instruction strings returned within INSN will contain ANSI escape
> sequences so long as 'set style enabled on' is in effect. This means
> that the user's personal settings (disabling styling) will override a
> GDB extension that requests styled disassembler output. I think this
> makes sense.
>
> The default for the styling argument is False, this maintains the
> current unstyled output as default.
> ---
> gdb/NEWS | 5 +
> gdb/doc/python.texi | 7 +-
> gdb/python/py-arch.c | 11 +-
> .../gdb.python/py-arch-disasm-style.c | 52 ++++++++
> .../gdb.python/py-arch-disasm-style.exp | 119 ++++++++++++++++++
> 5 files changed, 189 insertions(+), 5 deletions(-)
> create mode 100644 gdb/testsuite/gdb.python/py-arch-disasm-style.c
> create mode 100644 gdb/testsuite/gdb.python/py-arch-disasm-style.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index e46a5108272..da74c248c54 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -229,6 +229,11 @@ qExecAndArgs
> the appropriate user setting is enabled, and GDB knows how to
> style this source file.
>
> + ** The Architecture.disassemble method accepts a new 'styling'
> + argument, which defaults to False. When set to True the 'asm'
> + strings in the disassembler output can contain ANSI escape
> + sequences to indicate styling.
> +
> * Guile API
This part is okay.
> --- a/gdb/doc/python.texi
> +++ b/gdb/doc/python.texi
> @@ -7632,7 +7632,7 @@ Architectures In Python
> Return the name (string value) of the architecture.
> @end defun
>
> -@defun Architecture.disassemble (start_pc @r{[}, end_pc @r{[}, count@r{]]})
> +@defun Architecture.disassemble (start_pc @r{[}, end_pc @r{[}, count@r{]]} @w{@r{[}, styling = @code{False}@r{]}})
> Return a list of disassembled instructions starting from the memory
> address @var{start_pc}. The optional arguments @var{end_pc} and
> @var{count} determine the number of instructions in the returned list.
> @@ -7661,6 +7661,11 @@ Architectures In Python
> language flavor used is the same as that specified by the current CLI
> variable @code{disassembly-flavor}. @xref{Machine Code}.
>
> +When the optional argument @var{styling} is @code{True} the @var{asm}
> +string can contain ANSI terminal escape sequences if styling is
> +enabled (@pxref{Output Styling}). When @var{styling} is @code{False},
> +which is the default, then no styling will be applied to @var{asm}.
> +
This is also okay, but I don't think @var is correct for "asm", since
those are literal strings, not symbols that stand for something else.
Thanks.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] gdb/python: allow Architecture.disassemble to give styled output
2026-03-20 15:31 [PATCH] gdb/python: allow Architecture.disassemble to give styled output Andrew Burgess
2026-03-20 15:48 ` Eli Zaretskii
@ 2026-03-20 17:54 ` Tom Tromey
1 sibling, 0 replies; 4+ messages in thread
From: Tom Tromey @ 2026-03-20 17:54 UTC (permalink / raw)
To: Andrew Burgess; +Cc: gdb-patches
>>>>> "Andrew" == Andrew Burgess <aburgess@redhat.com> writes:
Andrew> Extend the Architecture.disassemble API to allow the user to request
Andrew> styled disassembler output via a new styling argument. A user can now
Andrew> write:
Andrew> insn = arch.disassemble(address, styling = True)
Andrew> The instruction strings returned within INSN will contain ANSI escape
Andrew> sequences so long as 'set style enabled on' is in effect. This means
Andrew> that the user's personal settings (disabling styling) will override a
Andrew> GDB extension that requests styled disassembler output. I think this
Andrew> makes sense.
Andrew> The default for the styling argument is False, this maintains the
Andrew> current unstyled output as default.
Looks good to me. Thank you.
Approved-By: Tom Tromey <tom@tromey.com>
Tom
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] gdb/python: allow Architecture.disassemble to give styled output
2026-03-20 15:48 ` Eli Zaretskii
@ 2026-03-23 10:17 ` Andrew Burgess
0 siblings, 0 replies; 4+ messages in thread
From: Andrew Burgess @ 2026-03-23 10:17 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Andrew Burgess <aburgess@redhat.com>
>> Cc: Andrew Burgess <aburgess@redhat.com>
>> Date: Fri, 20 Mar 2026 15:31:11 +0000
>>
>> Extend the Architecture.disassemble API to allow the user to request
>> styled disassembler output via a new styling argument. A user can now
>> write:
>>
>> insn = arch.disassemble(address, styling = True)
>>
>> The instruction strings returned within INSN will contain ANSI escape
>> sequences so long as 'set style enabled on' is in effect. This means
>> that the user's personal settings (disabling styling) will override a
>> GDB extension that requests styled disassembler output. I think this
>> makes sense.
>>
>> The default for the styling argument is False, this maintains the
>> current unstyled output as default.
>> ---
>> gdb/NEWS | 5 +
>> gdb/doc/python.texi | 7 +-
>> gdb/python/py-arch.c | 11 +-
>> .../gdb.python/py-arch-disasm-style.c | 52 ++++++++
>> .../gdb.python/py-arch-disasm-style.exp | 119 ++++++++++++++++++
>> 5 files changed, 189 insertions(+), 5 deletions(-)
>> create mode 100644 gdb/testsuite/gdb.python/py-arch-disasm-style.c
>> create mode 100644 gdb/testsuite/gdb.python/py-arch-disasm-style.exp
>>
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index e46a5108272..da74c248c54 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -229,6 +229,11 @@ qExecAndArgs
>> the appropriate user setting is enabled, and GDB knows how to
>> style this source file.
>>
>> + ** The Architecture.disassemble method accepts a new 'styling'
>> + argument, which defaults to False. When set to True the 'asm'
>> + strings in the disassembler output can contain ANSI escape
>> + sequences to indicate styling.
>> +
>> * Guile API
>
> This part is okay.
>
>> --- a/gdb/doc/python.texi
>> +++ b/gdb/doc/python.texi
>> @@ -7632,7 +7632,7 @@ Architectures In Python
>> Return the name (string value) of the architecture.
>> @end defun
>>
>> -@defun Architecture.disassemble (start_pc @r{[}, end_pc @r{[}, count@r{]]})
>> +@defun Architecture.disassemble (start_pc @r{[}, end_pc @r{[}, count@r{]]} @w{@r{[}, styling = @code{False}@r{]}})
>> Return a list of disassembled instructions starting from the memory
>> address @var{start_pc}. The optional arguments @var{end_pc} and
>> @var{count} determine the number of instructions in the returned list.
>> @@ -7661,6 +7661,11 @@ Architectures In Python
>> language flavor used is the same as that specified by the current CLI
>> variable @code{disassembly-flavor}. @xref{Machine Code}.
>>
>> +When the optional argument @var{styling} is @code{True} the @var{asm}
>> +string can contain ANSI terminal escape sequences if styling is
>> +enabled (@pxref{Output Styling}). When @var{styling} is @code{False},
>> +which is the default, then no styling will be applied to @var{asm}.
>> +
>
> This is also okay, but I don't think @var is correct for "asm", since
> those are literal strings, not symbols that stand for something else.
I changed to use @samp{...}, this seemed like the most appropriate
option, and pushed this patch.
Thanks,
Andrew
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-03-23 10:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-20 15:31 [PATCH] gdb/python: allow Architecture.disassemble to give styled output Andrew Burgess
2026-03-20 15:48 ` Eli Zaretskii
2026-03-23 10:17 ` Andrew Burgess
2026-03-20 17:54 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox