aboutsummaryrefslogtreecommitdiff
path: root/gdb/disasm.c
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2021-10-25 17:26:57 +0100
committerAndrew Burgess <aburgess@redhat.com>2022-02-14 09:53:04 +0000
commite867795e8bcd6571c785e5e1d872fff0a5c7b290 (patch)
tree7676974d2132823f012a95413cf12d52dfcd7efe /gdb/disasm.c
parent20ea3acc727f3be6322dfbd881e506873535231d (diff)
downloadgdb-e867795e8bcd6571c785e5e1d872fff0a5c7b290.zip
gdb-e867795e8bcd6571c785e5e1d872fff0a5c7b290.tar.gz
gdb-e867795e8bcd6571c785e5e1d872fff0a5c7b290.tar.bz2
gdb: use python to colorize disassembler output
This commit adds styling support to the disassembler output, as such two new commands are added to GDB: set style disassembler enabled on|off show style disassembler enabled In this commit I make use of the Python Pygments package to provide the styling. I did investigate making use of libsource-highlight, however, I found the highlighting results to be inferior to those of Pygments; only some mnemonics were highlighted, and highlighting of register names such as r9d and r8d (on x86-64) was incorrect. To enable disassembler highlighting via Pygments, I've added a new extension language hook, which is then implemented for Python. This hook is very similar to the existing hook for source code colorization. One possibly odd choice I made with the new hook is to pass a gdb.Architecture through, even though this is currently unused. The reason this argument is not used is that, currently, styling is performed identically for all architectures. However, even though the Python function used to perform styling of disassembly output is not part of any documented API, I don't want to close the door on a user overriding this function to provide architecture specific styling. To do this, the user would inevitably require access to the gdb.Architecture, and so I decided to add this field now. The styling is applied within gdb_disassembler::print_insn, to achieve this, gdb_disassembler now writes its output into a temporary buffer, styling is then applied to the contents of this buffer. Finally the gdb_disassembler buffer is copied out to its final destination stream. There's a new test to check that the disassembler output includes some escape sequences, though I don't check for specific colours; the precise colors will depend on which instructions are in the disassembler output, and, I guess, how pygments is configured. The only negative change with this commit is how we currently style addresses in GDB. Currently, when the disassembler wants to print an address, we call back into GDB, and GDB prints the address value using the `address` styling, and the symbol name using `function` styling. After this commit, if pygments is used, then all disassembler styling is done through pygments, and this include the address and symbol name parts of the disassembler output. I don't know how much of an issue this will be for people. There's already some precedent for this in GDB when we look at source styling. For example, function names in styled source listings are not styled using the `function` style, but instead, either GNU Source Highlight, or pygments gets to decide how the function name should be styled. If the Python pygments library is not present then GDB will continue to behave as it always has, the disassembler output is mostly unstyled, but the address and symbols are styled using the `address` and `function` styles, as they are today. However, if the user does `set style disassembler enabled off`, then all disassembler styling is switched off. This obviously covers the use of pygments, but also includes the minimal styling done by GDB when pygments is not available.
Diffstat (limited to 'gdb/disasm.c')
-rw-r--r--gdb/disasm.c58
1 files changed, 56 insertions, 2 deletions
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 44c702a..b4cde80 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -782,9 +782,12 @@ get_all_disassembler_options (struct gdbarch *gdbarch)
gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
struct ui_file *file,
di_read_memory_ftype read_memory_func)
- : m_gdbarch (gdbarch)
+ : m_gdbarch (gdbarch),
+ m_buffer (!use_ext_lang_colorization_p && disassembler_styling
+ && file->can_emit_style_escape ()),
+ m_dest (file)
{
- init_disassemble_info (&m_di, file, dis_asm_fprintf);
+ init_disassemble_info (&m_di, &m_buffer, dis_asm_fprintf);
m_di.flavour = bfd_target_unknown_flavour;
m_di.memory_error_func = dis_asm_memory_error;
m_di.print_address_func = dis_asm_print_address;
@@ -813,14 +816,65 @@ gdb_disassembler::~gdb_disassembler ()
disassemble_free_target (&m_di);
}
+/* See disasm.h. */
+
+bool gdb_disassembler::use_ext_lang_colorization_p = true;
+
+/* See disasm.h. */
+
int
gdb_disassembler::print_insn (CORE_ADDR memaddr,
int *branch_delay_insns)
{
m_err_memaddr.reset ();
+ m_buffer.clear ();
int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+ /* If we have successfully disassembled an instruction, styling is on, we
+ think that the extension language might be able to perform styling for
+ us, and the destination can support styling, then lets call into the
+ extension languages in order to style this output. */
+ if (length > 0 && disassembler_styling
+ && use_ext_lang_colorization_p
+ && m_dest->can_emit_style_escape ())
+ {
+ gdb::optional<std::string> ext_contents;
+ ext_contents = ext_lang_colorize_disasm (m_buffer.string (), arch ());
+ if (ext_contents.has_value ())
+ m_buffer = std::move (*ext_contents);
+ else
+ {
+ /* The extension language failed to add styling to the
+ disassembly output. Set the static flag so that next time we
+ disassemble we don't even bother attempting to use the
+ extension language for styling. */
+ use_ext_lang_colorization_p = false;
+
+ /* The instruction we just disassembled, and the extension
+ languages failed to style, might have otherwise had some
+ minimal styling applied by GDB. To regain that styling we
+ need to recreate m_buffer, but this time with styling support.
+
+ To do this we perform an in-place new, but this time turn on
+ the styling support, then we can re-disassembly the
+ instruction, and gain any minimal styling GDB might add. */
+ gdb_static_assert ((std::is_same<decltype (m_buffer),
+ string_file>::value));
+ gdb_assert (!m_buffer.term_out ());
+ m_buffer.~string_file ();
+ new (&m_buffer) string_file (true);
+ length = gdbarch_print_insn (arch (), memaddr, &m_di);
+ gdb_assert (length > 0);
+ }
+ }
+
+ /* Push any disassemble output to the real destination stream. We do
+ this even if the disassembler reported failure (-1) as the
+ disassembler may have printed something to its output stream. */
+ m_di.fprintf_func (m_dest, "%s", m_buffer.c_str ());
+
+ /* If the disassembler failed then report an appropriate error. */
if (length < 0)
{
if (m_err_memaddr.has_value ())