along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "arch-utils.h"
#include "target.h"
#include "value.h"
#include "ui-out.h"
#include "disasm.h"
#include "gdbcore.h"
+#include "gdbcmd.h"
#include "dis-asm.h"
#include "source.h"
+#include "safe-ctype.h"
#include <algorithm>
/* Disassemble functions.
FIXME: We should get rid of all the duplicate code in gdb that does
the same thing: disassemble_command() and the gdbtk variation. */
+/* This variable is used to hold the prospective disassembler_options value
+ which is set by the "set disassembler_options" command. */
+static char *prospective_options = NULL;
+
/* 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
gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
struct disassemble_info *info)
{
- memory_error (TARGET_XFER_E_IO, memaddr);
+ gdb_disassembler *self
+ = static_cast<gdb_disassembler *>(info->application_data);
+
+ self->m_err_memaddr = memaddr;
}
/* Wrapper of print_address. */
/* See disasm.h. */
int
-gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
- const struct disasm_insn *insn,
- int flags)
+gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout,
+ const struct disasm_insn *insn,
+ int flags)
{
/* parts of the symbolic representation of the address */
int unmapped;
char *filename = NULL;
char *name = NULL;
CORE_ADDR pc;
- struct ui_file *stb = stream ();
struct gdbarch *gdbarch = arch ();
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
if (name != NULL)
xfree (name);
- ui_file_rewind (stb);
+ m_insn_stb.clear ();
+
if (flags & DISASSEMBLY_RAW_INSN)
{
CORE_ADDR end_pc;
/* Build the opcodes using a temporary stream so we can
write them out in a single go for the MI. */
- struct ui_file *opcode_stream = mem_fileopen ();
- struct cleanup *cleanups =
- make_cleanup_ui_file_delete (opcode_stream);
+ m_opcode_stb.clear ();
- size = print_insn (pc);
+ size = m_di.print_insn (pc);
end_pc = pc + size;
for (;pc < end_pc; ++pc)
{
- err = m_di.read_memory_func (pc, &data, 1, &m_di);
- if (err != 0)
- m_di.memory_error_func (err, pc, &m_di);
- fprintf_filtered (opcode_stream, "%s%02x",
- spacer, (unsigned) data);
+ read_code (pc, &data, 1);
+ m_opcode_stb.printf ("%s%02x", spacer, (unsigned) data);
spacer = " ";
}
- uiout->field_stream ("opcodes", opcode_stream);
+ uiout->field_stream ("opcodes", m_opcode_stb);
uiout->text ("\t");
-
- do_cleanups (cleanups);
}
else
- size = print_insn (pc);
+ size = m_di.print_insn (pc);
- uiout->field_stream ("inst", stb);
- ui_file_rewind (stb);
+ uiout->field_stream ("inst", m_insn_stb);
do_cleanups (ui_out_chain);
uiout->text ("\n");
}
static int
-dump_insns (struct ui_out *uiout, gdb_disassembler *di,
- CORE_ADDR low, CORE_ADDR high,
- int how_many, int flags,
- CORE_ADDR *end_pc)
+dump_insns (struct gdbarch *gdbarch,
+ struct ui_out *uiout, CORE_ADDR low, CORE_ADDR high,
+ int how_many, int flags, CORE_ADDR *end_pc)
{
struct disasm_insn insn;
int num_displayed = 0;
memset (&insn, 0, sizeof (insn));
insn.addr = low;
+ gdb_pretty_print_disassembler disasm (gdbarch);
+
while (insn.addr < high && (how_many < 0 || num_displayed < how_many))
{
int size;
- size = di->pretty_print_insn (uiout, &insn, flags);
+ size = disasm.pretty_print_insn (uiout, &insn, flags);
if (size <= 0)
break;
static void
do_mixed_source_and_assembly_deprecated
- (struct ui_out *uiout,
- gdb_disassembler *di, struct symtab *symtab,
+ (struct gdbarch *gdbarch, struct ui_out *uiout,
+ struct symtab *symtab,
CORE_ADDR low, CORE_ADDR high,
int how_many, int flags)
{
= make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
}
- num_displayed += dump_insns (uiout, di,
+ num_displayed += dump_insns (gdbarch, uiout,
mle[i].start_pc, mle[i].end_pc,
how_many, flags, NULL);
static void
do_mixed_source_and_assembly (struct gdbarch *gdbarch,
struct ui_out *uiout,
- gdb_disassembler *di,
struct symtab *main_symtab,
CORE_ADDR low, CORE_ADDR high,
int how_many, int flags)
end_pc = std::min (sal.end, high);
else
end_pc = pc + 1;
- num_displayed += dump_insns (uiout, di, pc, end_pc,
+ num_displayed += dump_insns (gdbarch, uiout, pc, end_pc,
how_many, flags, &end_pc);
pc = end_pc;
}
static void
-do_assembly_only (struct ui_out *uiout,
- gdb_disassembler *di,
+do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
CORE_ADDR low, CORE_ADDR high,
int how_many, int flags)
{
ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
- dump_insns (uiout, di, low, high, how_many, flags, NULL);
+ dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL);
do_cleanups (ui_out_chain);
}
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_err_memaddr (0)
{
init_disassemble_info (&m_di, file, fprintf_disasm);
m_di.flavour = bfd_target_unknown_flavour;
m_di.endian = gdbarch_byte_order (gdbarch);
m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
m_di.application_data = this;
+ m_di.disassembler_options = get_disassembler_options (gdbarch);
disassemble_init_for_target (&m_di);
}
gdb_disassembler::print_insn (CORE_ADDR memaddr,
int *branch_delay_insns)
{
+ m_err_memaddr = 0;
+
int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+ if (length < 0)
+ memory_error (TARGET_XFER_E_IO, m_err_memaddr);
+
if (branch_delay_insns != NULL)
{
if (m_di.insn_info_valid)
void
gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- char *file_string, int flags, int how_many,
+ int flags, int how_many,
CORE_ADDR low, CORE_ADDR high)
{
- struct ui_file *stb = mem_fileopen ();
- struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
- gdb_disassembler di (gdbarch, stb);
struct symtab *symtab;
int nlines = -1;
if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
|| nlines <= 0)
- do_assembly_only (uiout, &di, low, high, how_many, flags);
+ do_assembly_only (gdbarch, uiout, low, high, how_many, flags);
else if (flags & DISASSEMBLY_SOURCE)
- do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
+ do_mixed_source_and_assembly (gdbarch, uiout, symtab, low, high,
how_many, flags);
else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
- do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
+ do_mixed_source_and_assembly_deprecated (gdbarch, uiout, symtab,
low, high, how_many, flags);
- do_cleanups (cleanups);
gdb_flush (gdb_stdout);
}
int
gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
{
- return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
+ return gdb_print_insn (gdbarch, addr, &null_stream, NULL);
}
/* fprintf-function for gdb_buffered_insn_length. This function is a
di->endian = gdbarch_byte_order (gdbarch);
di->endian_code = gdbarch_byte_order_for_code (gdbarch);
+ di->disassembler_options = get_disassembler_options (gdbarch);
disassemble_init_for_target (di);
}
return gdbarch_print_insn (gdbarch, addr, &di);
}
+
+char *
+get_disassembler_options (struct gdbarch *gdbarch)
+{
+ char **disassembler_options = gdbarch_disassembler_options (gdbarch);
+ if (disassembler_options == NULL)
+ return NULL;
+ return *disassembler_options;
+}
+
+void
+set_disassembler_options (char *prospective_options)
+{
+ struct gdbarch *gdbarch = get_current_arch ();
+ char **disassembler_options = gdbarch_disassembler_options (gdbarch);
+ const disasm_options_t *valid_options;
+ char *options = remove_whitespace_and_extra_commas (prospective_options);
+ char *opt;
+
+ /* Allow all architectures, even ones that do not support 'set disassembler',
+ to reset their disassembler options to NULL. */
+ if (options == NULL)
+ {
+ if (disassembler_options != NULL)
+ {
+ free (*disassembler_options);
+ *disassembler_options = NULL;
+ }
+ return;
+ }
+
+ valid_options = gdbarch_valid_disassembler_options (gdbarch);
+ if (valid_options == NULL)
+ {
+ fprintf_filtered (gdb_stdlog, _("\
+'set disassembler-options ...' is not supported on this architecture.\n"));
+ return;
+ }
+
+ /* Verify we have valid disassembler options. */
+ FOR_EACH_DISASSEMBLER_OPTION (opt, options)
+ {
+ size_t i;
+ for (i = 0; valid_options->name[i] != NULL; i++)
+ if (disassembler_options_cmp (opt, valid_options->name[i]) == 0)
+ break;
+ if (valid_options->name[i] == NULL)
+ {
+ fprintf_filtered (gdb_stdlog,
+ _("Invalid disassembler option value: '%s'.\n"),
+ opt);
+ return;
+ }
+ }
+
+ free (*disassembler_options);
+ *disassembler_options = xstrdup (options);
+}
+
+static void
+set_disassembler_options_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_disassembler_options (prospective_options);
+}
+
+static void
+show_disassembler_options_sfunc (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ struct gdbarch *gdbarch = get_current_arch ();
+ const disasm_options_t *valid_options;
+
+ const char *options = get_disassembler_options (gdbarch);
+ if (options == NULL)
+ options = "";
+
+ fprintf_filtered (file, _("The current disassembler options are '%s'\n"),
+ options);
+
+ valid_options = gdbarch_valid_disassembler_options (gdbarch);
+
+ if (valid_options == NULL)
+ return;
+
+ fprintf_filtered (file, _("\n\
+The following disassembler options are supported for use with the\n\
+'set disassembler-options <option>[,<option>...]' command:\n"));
+
+ if (valid_options->description != NULL)
+ {
+ size_t i, max_len = 0;
+
+ /* Compute the length of the longest option name. */
+ for (i = 0; valid_options->name[i] != NULL; i++)
+ {
+ size_t len = strlen (valid_options->name[i]);
+ if (max_len < len)
+ max_len = len;
+ }
+
+ for (i = 0, max_len++; valid_options->name[i] != NULL; i++)
+ {
+ fprintf_filtered (file, " %s", valid_options->name[i]);
+ if (valid_options->description[i] != NULL)
+ fprintf_filtered (file, "%*c %s",
+ (int)(max_len - strlen (valid_options->name[i])), ' ',
+ valid_options->description[i]);
+ fprintf_filtered (file, "\n");
+ }
+ }
+ else
+ {
+ size_t i;
+ fprintf_filtered (file, " ");
+ for (i = 0; valid_options->name[i] != NULL; i++)
+ {
+ fprintf_filtered (file, "%s", valid_options->name[i]);
+ if (valid_options->name[i + 1] != NULL)
+ fprintf_filtered (file, ", ");
+ wrap_here (" ");
+ }
+ fprintf_filtered (file, "\n");
+ }
+}
+
+/* A completion function for "set disassembler". */
+
+static VEC (char_ptr) *
+disassembler_options_completer (struct cmd_list_element *ignore,
+ const char *text, const char *word)
+{
+ struct gdbarch *gdbarch = get_current_arch ();
+ const disasm_options_t *opts = gdbarch_valid_disassembler_options (gdbarch);
+
+ if (opts != NULL)
+ {
+ /* Only attempt to complete on the last option text. */
+ const char *separator = strrchr (text, ',');
+ if (separator != NULL)
+ text = separator + 1;
+ text = skip_spaces_const (text);
+ return complete_on_enum (opts->name, text, word);
+ }
+ return NULL;
+}
+
+
+/* Initialization code. */
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_disasm;
+
+void
+_initialize_disasm (void)
+{
+ struct cmd_list_element *cmd;
+
+ /* Add the command that controls the disassembler options. */
+ cmd = add_setshow_string_noescape_cmd ("disassembler-options", no_class,
+ &prospective_options, _("\
+Set the disassembler options.\n\
+Usage: set disassembler-options <option>[,<option>...]\n\n\
+See: 'show disassembler-options' for valid option values.\n"), _("\
+Show the disassembler options."), NULL,
+ set_disassembler_options_sfunc,
+ show_disassembler_options_sfunc,
+ &setlist, &showlist);
+ set_cmd_completer (cmd, disassembler_options_completer);
+}