diff options
author | Andrew Burgess <aburgess@redhat.com> | 2022-02-14 14:40:52 +0000 |
---|---|---|
committer | Andrew Burgess <aburgess@redhat.com> | 2022-07-11 12:02:54 +0100 |
commit | 4cbe4ca5da5cd7e1e6331ce11f024bf3c07b9744 (patch) | |
tree | 8c0bf2715ee9bc1c477005ba81c50cc22c59990e /gdb/disasm.c | |
parent | 81384924cdcc9eb2676dd9084b76845d7d0e0759 (diff) | |
download | gdb-4cbe4ca5da5cd7e1e6331ce11f024bf3c07b9744.zip gdb-4cbe4ca5da5cd7e1e6331ce11f024bf3c07b9744.tar.gz gdb-4cbe4ca5da5cd7e1e6331ce11f024bf3c07b9744.tar.bz2 |
gdb: add support for disassembler styling using libopcodes
This commit extends GDB to make use of libopcodes styling support
where available, currently this is just i386 based architectures, and
RISC-V.
For architectures that don't support styling using libopcodes GDB will
fall back to using the Python Pygments package, when the package is
available.
The new libopcodes based styling has the disassembler identify parts
of the disassembled instruction, e.g. registers, immediates,
mnemonics, etc, and can style these components differently.
Additionally, as the styling is now done in GDB we can add settings to
allow the user to configure which colours are used right from the GDB
CLI.
There's some new maintenance commands:
maintenance set libopcodes-styling enabled on|off
maintenance show libopcodes-styling
These can be used to manually disable use of libopcodes styling. This
is a maintenance command as it's not anticipated that a user should
need to do this. But, this could be useful for testing, or, in some
rare cases, a user might want to override the Python hook used for
disassembler styling, and then disable libopcode styling so that GDB
falls back to using Python. Right now I would consider this second
use case a rare situation, which is why I think a maintenance command
is appropriate.
When libopcodes is being used for styling then the user can make use
of the following new styles:
set/show style disassembler comment
set/show style disassembler immediate
set/show style disassembler mnemonic
set/show style disassembler register
The disassembler also makes use of the 'address' and 'function'
styles to style some parts of the disassembler output. I have also
added the following aliases though:
set/show style disassembler address
set/show style disassembler symbol
these are aliases for:
set/show style address
set/show style function
respectively, and exist to make it easier for users to discover
disassembler related style settings. The 'address' style is used to
style numeric addresses in the disassembler output, while the 'symbol'
or 'function' style is used to style the names of symbols in
disassembler output.
As not every architecture supports libopcodes styling, the maintenance
setting 'libopcodes-styling enabled' has an "auto-off" type behaviour.
Consider this GDB session:
(gdb) show architecture
The target architecture is set to "auto" (currently "i386:x86-64").
(gdb) maintenance show libopcodes-styling enabled
Use of libopcodes styling support is "on".
the setting defaults to "on" for architectures that support libopcodes
based styling.
(gdb) set architecture sparc
The target architecture is set to "sparc".
(gdb) maintenance show libopcodes-styling enabled
Use of libopcodes styling support is "off" (not supported on architecture "sparc")
the setting will show as "off" if the user switches to an architecture
that doesn't support libopcodes styling. The underlying setting is
still "on" at this point though, if the user switches back to
i386:x86-64 then the setting would go back to being "on".
(gdb) maintenance set libopcodes-styling enabled off
(gdb) maintenance show libopcodes-styling enabled
Use of libopcodes styling support is "off".
now the setting is "off" for everyone, even if the user switches back
to i386:x86-64 the setting will still show as "off".
(gdb) maintenance set libopcodes-styling enabled on
Use of libopcodes styling not supported on architecture "sparc".
(gdb) maintenance show libopcodes-styling enabled
Use of libopcodes styling support is "off".
attempting to switch the setting "on" for an unsupported architecture
will give an error, and the setting will remain "off".
(gdb) set architecture auto
The target architecture is set to "auto" (currently "i386:x86-64").
(gdb) maintenance show libopcodes-styling enabled
Use of libopcodes styling support is "off".
(gdb) maintenance set libopcodes-styling enabled on
(gdb) maintenance show libopcodes-styling enabled
Use of libopcodes styling support is "on".
the user will need to switch back to a supported architecture before
they can one again turn this setting "on".
Diffstat (limited to 'gdb/disasm.c')
-rw-r--r-- | gdb/disasm.c | 184 |
1 files changed, 177 insertions, 7 deletions
diff --git a/gdb/disasm.c b/gdb/disasm.c index 6c64c14..cf27a32 100644 --- a/gdb/disasm.c +++ b/gdb/disasm.c @@ -41,6 +41,63 @@ which is set by the "set disassembler_options" command. */ static std::string prospective_options; +/* When this is true we will try to use libopcodes to provide styling to + the disassembler output. */ + +static bool use_libopcodes_styling = true; + +/* To support the set_use_libopcodes_styling function we have a second + variable which is connected to the actual set/show option. */ + +static bool use_libopcodes_styling_option = use_libopcodes_styling; + +/* The "maint show libopcodes-styling enabled" command. */ + +static void +show_use_libopcodes_styling (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + gdb_non_printing_memory_disassembler dis (target_gdbarch ()); + bool supported = dis.disasm_info ()->created_styled_output; + + if (supported || !use_libopcodes_styling) + gdb_printf (file, _("Use of libopcodes styling support is \"%s\".\n"), + value); + else + { + /* Use of libopcodes styling is not supported, and the user has this + turned on! */ + gdb_printf (file, _("Use of libopcodes styling support is \"off\"" + " (not supported on architecture \"%s\")\n"), + gdbarch_bfd_arch_info (target_gdbarch ())->printable_name); + } +} + +/* The "maint set libopcodes-styling enabled" command. */ + +static void +set_use_libopcodes_styling (const char *args, int from_tty, + struct cmd_list_element *c) +{ + gdb_non_printing_memory_disassembler dis (target_gdbarch ()); + bool supported = dis.disasm_info ()->created_styled_output; + + /* If the current architecture doesn't support libopcodes styling then we + give an error here, but leave the underlying setting enabled. This + means that if the user switches to an architecture that does support + libopcodes styling the setting will be enabled. */ + + if (use_libopcodes_styling_option && !supported) + { + use_libopcodes_styling_option = use_libopcodes_styling; + error (_("Use of libopcodes styling not supported on architecture \"%s\"."), + gdbarch_bfd_arch_info (target_gdbarch ())->printable_name); + } + else + use_libopcodes_styling = use_libopcodes_styling_option; +} + /* This structure is used to store line number information for the deprecated /m option. We need a different sort of line table from the normal one cuz we can't @@ -160,7 +217,26 @@ gdb_disassembler::dis_asm_print_address (bfd_vma addr, gdb_disassembler *self = static_cast<gdb_disassembler *>(info->application_data); - print_address (self->arch (), addr, self->stream ()); + if (self->in_comment_p ()) + { + /* Calling 'print_address' might add styling to the output (based on + the properties of the stream we're writing too). This is usually + fine, but if we are in an assembler comment then we'd prefer to + have the comment style, rather than the default address style. + + Print the address into a temporary buffer which doesn't support + styling, then reprint this unstyled address with the default text + style. + + As we are inside a comment right now, the standard print routine + will ensure that the comment is printed to the user with a + suitable comment style. */ + string_file tmp; + print_address (self->arch (), addr, &tmp); + self->fprintf_styled_func (self, dis_style_text, "%s", tmp.c_str ()); + } + else + print_address (self->arch (), addr, self->stream ()); } /* See disasm.h. */ @@ -202,11 +278,54 @@ gdb_printing_disassembler::fprintf_styled_func (void *dis_info, const char *format, ...) { ui_file *stream = stream_from_gdb_disassemble_info (dis_info); + gdb_printing_disassembler *dis = (gdb_printing_disassembler *) dis_info; va_list args; va_start (args, format); - gdb_vprintf (stream, format, args); + std::string content = string_vprintf (format, args); va_end (args); + + /* Once in a comment then everything should be styled as a comment. */ + if (style == dis_style_comment_start) + dis->set_in_comment (true); + if (dis->in_comment_p ()) + style = dis_style_comment_start; + + /* Now print the content with the correct style. */ + const char *txt = content.c_str (); + switch (style) + { + case dis_style_mnemonic: + case dis_style_assembler_directive: + fputs_styled (txt, disasm_mnemonic_style.style (), stream); + break; + + case dis_style_register: + fputs_styled (txt, disasm_register_style.style (), stream); + break; + + case dis_style_immediate: + case dis_style_address_offset: + fputs_styled (txt, disasm_immediate_style.style (), stream); + break; + + case dis_style_address: + fputs_styled (txt, address_style.style (), stream); + break; + + case dis_style_symbol: + fputs_styled (txt, function_name_style.style (), stream); + break; + + case dis_style_comment_start: + fputs_styled (txt, disasm_comment_style.style (), stream); + break; + + case dis_style_text: + gdb_puts (txt, stream); + break; + } + /* Something non -ve. */ return 0; } @@ -818,7 +937,20 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch, read_memory_ftype func) : gdb_printing_disassembler (gdbarch, &m_buffer, func, dis_asm_memory_error, dis_asm_print_address), - m_buffer (!use_ext_lang_colorization_p && disassembler_styling + /* The use of m_di.created_styled_output here is a bit of a cheat, but + it works fine for now. Currently, for all targets that support + libopcodes styling, this field is set during the call to + disassemble_init_for_target, which was called as part of the + initialization of gdb_printing_disassembler. And so, we are able to + spot if a target supports libopcodes styling, and create m_buffer in + the correct styling mode. + + If there's ever a target that only sets created_styled_output during + the actual disassemble phase, then the logic here will have to + change. */ + m_buffer ((!use_ext_lang_colorization_p + || (use_libopcodes_styling && m_di.created_styled_output)) + && disassembler_styling && file->can_emit_style_escape ()), m_dest (file) { /* Nothing. */ } @@ -903,14 +1035,17 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr, { m_err_memaddr.reset (); m_buffer.clear (); + this->set_in_comment (false); int length = gdb_print_insn_1 (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 we have successfully disassembled an instruction, disassembler + styling using the extension language is on, and libopcodes hasn't + already styled the output for us, and, if the destination can support + styling, then lets call into the extension languages in order to style + this output. */ if (length > 0 && disassembler_styling + && (!m_di.created_styled_output || !use_libopcodes_styling) && use_ext_lang_colorization_p && m_dest->can_emit_style_escape ()) { @@ -1311,4 +1446,39 @@ Show the disassembler options."), NULL, show_disassembler_options_sfunc, &setlist, &showlist); set_cmd_completer (set_show_disas_opts.set, disassembler_options_completer); + + + /* All the 'maint set|show libopcodes-styling' sub-commands. */ + static struct cmd_list_element *maint_set_libopcodes_styling_cmdlist; + static struct cmd_list_element *maint_show_libopcodes_styling_cmdlist; + + /* Adds 'maint set|show libopcodes-styling'. */ + add_setshow_prefix_cmd ("libopcodes-styling", class_maintenance, + _("Set libopcodes-styling specific variables."), + _("Show libopcodes-styling specific variables."), + &maint_set_libopcodes_styling_cmdlist, + &maint_show_libopcodes_styling_cmdlist, + &maintenance_set_cmdlist, + &maintenance_show_cmdlist); + + /* Adds 'maint set|show gnu-source-highlight enabled'. */ + add_setshow_boolean_cmd ("enabled", class_maintenance, + &use_libopcodes_styling_option, _("\ +Set whether the libopcodes styling support should be used."), _("\ +Show whether the libopcodes styling support should be used."),_("\ +When enabled, GDB will try to make use of the builtin libopcodes styling\n\ +support, to style the disassembler output. Not every architecture has\n\ +styling support within libopcodes, so enabling this is not a guarantee\n\ +that libopcodes styling will be available.\n\ +\n\ +When this option is disabled, GDB will make use of the Python Pygments\n\ +package (if available) to style the disassembler output.\n\ +\n\ +All disassembler styling can be disabled with:\n\ +\n\ + set style disassembler enabled off"), + set_use_libopcodes_styling, + show_use_libopcodes_styling, + &maint_set_libopcodes_styling_cmdlist, + &maint_show_libopcodes_styling_cmdlist); } |