aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog37
-rw-r--r--gdb/NEWS3
-rw-r--r--gdb/arm-tdep.c3
-rw-r--r--gdb/disasm.c127
-rw-r--r--gdb/disasm.h5
-rw-r--r--gdb/doc/ChangeLog6
-rw-r--r--gdb/doc/gdb.texinfo2
-rw-r--r--gdb/gdbarch.c28
-rw-r--r--gdb/gdbarch.h7
-rwxr-xr-xgdb/gdbarch.sh3
-rw-r--r--gdb/mips-tdep.c60
-rw-r--r--gdb/testsuite/ChangeLog6
-rw-r--r--gdb/testsuite/gdb.arch/mips-disassembler-options.exp58
-rw-r--r--gdb/testsuite/gdb.arch/mips-disassembler-options.s30
-rw-r--r--include/ChangeLog10
-rw-r--r--include/dis-asm.h50
-rw-r--r--opcodes/ChangeLog13
-rw-r--r--opcodes/arm-dis.c16
-rw-r--r--opcodes/mips-dis.c210
-rw-r--r--opcodes/ppc-dis.c18
-rw-r--r--opcodes/s390-dis.c16
21 files changed, 575 insertions, 133 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0f601bd..7bb4100 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,40 @@
+2018-07-02 Maciej W. Rozycki <macro@mips.com>
+ Simon Marchi <simon.marchi@polymtl.ca>
+
+ PR tdep/8282
+ * disasm.h (gdb_disassembler): Add
+ `m_disassembler_options_holder'. member
+ * disasm.c (get_all_disassembler_options): New function.
+ (gdb_disassembler::gdb_disassembler): Use it.
+ (gdb_buffered_insn_length_init_dis): Likewise.
+ (gdb_buffered_insn_length): Adjust accordingly.
+ (set_disassembler_options): Handle options with arguments.
+ (show_disassembler_options_sfunc): Likewise. Add a leading new
+ line if showing options with descriptions.
+ (disassembler_options_completer): Adapt to using the
+ `disasm_options_and_args_t' structure.
+ * mips-tdep.c (mips_disassembler_options): New variable.
+ (mips_disassembler_options_o32): Likewise.
+ (mips_disassembler_options_n32): Likewise.
+ (mips_disassembler_options_n64): Likewise.
+ (gdb_print_insn_mips): Don't set `disassembler_options'.
+ (gdb_print_insn_mips_n32, gdb_print_insn_mips_n64): Remove
+ functions.
+ (mips_gdbarch_init): Always set `gdbarch_print_insn' to
+ `gdb_print_insn_mips'. Set `gdbarch_disassembler_options',
+ `gdbarch_disassembler_options_implicit' and
+ `gdbarch_valid_disassembler_options'.
+ * arm-tdep.c (_initialize_arm_tdep): Adapt to using the
+ `disasm_options_and_args_t' structure.
+ * gdbarch.sh (disassembler_options_implicit): New `gdbarch'
+ method.
+ (valid_disassembler_options): Switch from `disasm_options_t' to
+ the `disasm_options_and_args_t' structure.
+ * NEWS: Document `set disassembler-options' support for the MIPS
+ target.
+ * gdbarch.h: Regenerate.
+ * gdbarch.c: Regenerate.
+
2018-07-02 Sebastian Huber <sebastian.huber@embedded-brains.de>
* riscv-tdep.c (riscv_register_aliases): Swap "fp" and "s0" entries.
diff --git a/gdb/NEWS b/gdb/NEWS
index 839466e..ab7632c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
*** Changes since GDB 8.1
+* The 'set disassembler-options' command now supports specifying options
+ for the MIPS target.
+
* The 'symbol-file' command now accepts an '-o' option to add a relative
offset to all sections.
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 3ea0e79..fdfb360 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -9572,7 +9572,8 @@ _initialize_arm_tdep (void)
arm_disassembler_options = xstrdup ("reg-names-std");
- const disasm_options_t *disasm_options = disassembler_options_arm ();
+ const disasm_options_t *disasm_options
+ = &disassembler_options_arm ()->options;
int num_disassembly_styles = 0;
for (i = 0; disasm_options->name[i] != NULL; i++)
if (CONST_STRNEQ (disasm_options->name[i], "reg-names-"))
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 6983903..11793df 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -722,6 +722,31 @@ fprintf_disasm (void *stream, const char *format, ...)
return 0;
}
+/* Combine implicit and user disassembler options and return them
+ in a newly-created string. */
+
+static std::string
+get_all_disassembler_options (struct gdbarch *gdbarch)
+{
+ const char *implicit = gdbarch_disassembler_options_implicit (gdbarch);
+ const char *options = get_disassembler_options (gdbarch);
+ const char *comma = ",";
+
+ if (implicit == nullptr)
+ {
+ implicit = "";
+ comma = "";
+ }
+
+ if (options == nullptr)
+ {
+ options = "";
+ comma = "";
+ }
+
+ return string_printf ("%s%s%s", implicit, comma, options);
+}
+
gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
struct ui_file *file,
di_read_memory_ftype read_memory_func)
@@ -746,7 +771,9 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
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);
+ m_disassembler_options_holder = get_all_disassembler_options (gdbarch);
+ if (!m_disassembler_options_holder.empty ())
+ m_di.disassembler_options = m_disassembler_options_holder.c_str ();
disassemble_init_for_target (&m_di);
}
@@ -833,13 +860,16 @@ gdb_buffered_insn_length_fprintf (void *stream, const char *format, ...)
return 0;
}
-/* Initialize a struct disassemble_info for gdb_buffered_insn_length. */
+/* Initialize a struct disassemble_info for gdb_buffered_insn_length.
+ Upon return, *DISASSEMBLER_OPTIONS_HOLDER owns the string pointed
+ to by DI.DISASSEMBLER_OPTIONS. */
static void
gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
struct disassemble_info *di,
const gdb_byte *insn, int max_len,
- CORE_ADDR addr)
+ CORE_ADDR addr,
+ std::string *disassembler_options_holder)
{
init_disassemble_info (di, NULL, gdb_buffered_insn_length_fprintf);
@@ -855,7 +885,9 @@ gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
di->endian = gdbarch_byte_order (gdbarch);
di->endian_code = gdbarch_byte_order_for_code (gdbarch);
- di->disassembler_options = get_disassembler_options (gdbarch);
+ *disassembler_options_holder = get_all_disassembler_options (gdbarch);
+ if (!disassembler_options_holder->empty ())
+ di->disassembler_options = disassembler_options_holder->c_str ();
disassemble_init_for_target (di);
}
@@ -867,8 +899,10 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch,
const gdb_byte *insn, int max_len, CORE_ADDR addr)
{
struct disassemble_info di;
+ std::string disassembler_options_holder;
- gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr);
+ gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr,
+ &disassembler_options_holder);
return gdbarch_print_insn (gdbarch, addr, &di);
}
@@ -887,6 +921,7 @@ set_disassembler_options (char *prospective_options)
{
struct gdbarch *gdbarch = get_current_arch ();
char **disassembler_options = gdbarch_disassembler_options (gdbarch);
+ const disasm_options_and_args_t *valid_options_and_args;
const disasm_options_t *valid_options;
char *options = remove_whitespace_and_extra_commas (prospective_options);
const char *opt;
@@ -903,20 +938,42 @@ set_disassembler_options (char *prospective_options)
return;
}
- valid_options = gdbarch_valid_disassembler_options (gdbarch);
- if (valid_options == NULL)
+ valid_options_and_args = gdbarch_valid_disassembler_options (gdbarch);
+ if (valid_options_and_args == NULL)
{
fprintf_filtered (gdb_stdlog, _("\
'set disassembler-options ...' is not supported on this architecture.\n"));
return;
}
+ valid_options = &valid_options_and_args->options;
+
/* 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)
+ if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+ {
+ size_t len = strlen (valid_options->name[i]);
+ bool found = false;
+ const char *arg;
+ size_t j;
+
+ if (memcmp (opt, valid_options->name[i], len) != 0)
+ continue;
+ arg = opt + len;
+ for (j = 0; valid_options->arg[i]->values[j] != NULL; j++)
+ if (disassembler_options_cmp
+ (arg, valid_options->arg[i]->values[j]) == 0)
+ {
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+ else if (disassembler_options_cmp (opt, valid_options->name[i]) == 0)
break;
if (valid_options->name[i] == NULL)
{
@@ -943,6 +1000,8 @@ 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_and_args_t *valid_options_and_args;
+ const disasm_option_arg_t *valid_args;
const disasm_options_t *valid_options;
const char *options = get_disassembler_options (gdbarch);
@@ -952,11 +1011,13 @@ show_disassembler_options_sfunc (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("The current disassembler options are '%s'\n"),
options);
- valid_options = gdbarch_valid_disassembler_options (gdbarch);
+ valid_options_and_args = gdbarch_valid_disassembler_options (gdbarch);
- if (valid_options == NULL)
+ if (valid_options_and_args == NULL)
return;
+ valid_options = &valid_options_and_args->options;
+
fprintf_filtered (file, _("\n\
The following disassembler options are supported for use with the\n\
'set disassembler-options <option>[,<option>...]' command:\n"));
@@ -965,10 +1026,15 @@ The following disassembler options are supported for use with the\n\
{
size_t i, max_len = 0;
+ fprintf_filtered (file, "\n");
+
/* 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 (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+ len += strlen (valid_options->arg[i]->name);
if (max_len < len)
max_len = len;
}
@@ -976,10 +1042,17 @@ The following disassembler options are supported for use with the\n\
for (i = 0, max_len++; valid_options->name[i] != NULL; i++)
{
fprintf_filtered (file, " %s", valid_options->name[i]);
+ if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+ fprintf_filtered (file, "%s", valid_options->arg[i]->name);
if (valid_options->description[i] != NULL)
- fprintf_filtered (file, "%*c %s",
- (int)(max_len - strlen (valid_options->name[i])), ' ',
- valid_options->description[i]);
+ {
+ size_t len = strlen (valid_options->name[i]);
+
+ if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+ len += strlen (valid_options->arg[i]->name);
+ fprintf_filtered (file, "%*c %s", (int) (max_len - len), ' ',
+ valid_options->description[i]);
+ }
fprintf_filtered (file, "\n");
}
}
@@ -990,12 +1063,33 @@ The following disassembler options are supported for use with the\n\
for (i = 0; valid_options->name[i] != NULL; i++)
{
fprintf_filtered (file, "%s", valid_options->name[i]);
+ if (valid_options->arg != NULL && valid_options->arg[i] != NULL)
+ fprintf_filtered (file, "%s", valid_options->arg[i]->name);
if (valid_options->name[i + 1] != NULL)
fprintf_filtered (file, ", ");
wrap_here (" ");
}
fprintf_filtered (file, "\n");
}
+
+ valid_args = valid_options_and_args->args;
+ if (valid_args != NULL)
+ {
+ size_t i, j;
+
+ for (i = 0; valid_args[i].name != NULL; i++)
+ {
+ fprintf_filtered (file, _("\n\
+ For the options above, the following values are supported for \"%s\":\n "),
+ valid_args[i].name);
+ for (j = 0; valid_args[i].values[j] != NULL; j++)
+ {
+ fprintf_filtered (file, " %s", valid_args[i].values[j]);
+ wrap_here (" ");
+ }
+ fprintf_filtered (file, "\n");
+ }
+ }
}
/* A completion function for "set disassembler". */
@@ -1006,10 +1100,13 @@ 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);
+ const disasm_options_and_args_t *opts_and_args
+ = gdbarch_valid_disassembler_options (gdbarch);
- if (opts != NULL)
+ if (opts_and_args != NULL)
{
+ const disasm_options_t *opts = &opts_and_args->options;
+
/* Only attempt to complete on the last option text. */
const char *separator = strrchr (text, ',');
if (separator != NULL)
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 6aa046a..d71f113 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -66,6 +66,11 @@ private:
/* Stores data required for disassembling instructions in
opcodes. */
struct disassemble_info m_di;
+
+ /* If we own the string in `m_di.disassembler_options', we do so
+ using this field. */
+ std::string m_disassembler_options_holder;
+
CORE_ADDR m_err_memaddr;
static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 6954398..fbdab9b 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,9 @@
+2018-07-02 Maciej W. Rozycki <macro@mips.com>
+
+ PR tdep/8282
+ * gdb.texinfo (Source and Machine Code): Document `set
+ disassembler-options' support for the MIPS target.
+
2018-06-28 Petr Tesarik <ptesarik@suse.cz>
* gdb.texinfo (Files): Document "add-symbol-file -o offset".
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7fb6ac5..91ec219 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -8759,7 +8759,7 @@ The default value is the empty string.
If it is necessary to specify more than one disassembler option, then
multiple options can be placed together into a comma separated list.
-Currently this command is only supported on targets ARM, PowerPC
+Currently this command is only supported on targets ARM, MIPS, PowerPC
and S/390.
@kindex show disassembler-options
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 0c8d8ee..e2abf26 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -350,8 +350,9 @@ struct gdbarch
gdbarch_gcc_target_options_ftype *gcc_target_options;
gdbarch_gnu_triplet_regexp_ftype *gnu_triplet_regexp;
gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size;
+ const char * disassembler_options_implicit;
char ** disassembler_options;
- const disasm_options_t * valid_disassembler_options;
+ const disasm_options_and_args_t * valid_disassembler_options;
gdbarch_type_align_ftype *type_align;
};
@@ -707,6 +708,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of gcc_target_options, invalid_p == 0 */
/* Skip verify of gnu_triplet_regexp, invalid_p == 0 */
/* Skip verify of addressable_memory_unit_size, invalid_p == 0 */
+ /* Skip verify of disassembler_options_implicit, invalid_p == 0 */
/* Skip verify of disassembler_options, invalid_p == 0 */
/* Skip verify of valid_disassembler_options, invalid_p == 0 */
/* Skip verify of type_align, invalid_p == 0 */
@@ -902,6 +904,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: disassembler_options = %s\n",
pstring_ptr (gdbarch->disassembler_options));
fprintf_unfiltered (file,
+ "gdbarch_dump: disassembler_options_implicit = %s\n",
+ pstring (gdbarch->disassembler_options_implicit));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_displaced_step_copy_insn_p() = %d\n",
gdbarch_displaced_step_copy_insn_p (gdbarch));
fprintf_unfiltered (file,
@@ -5044,6 +5049,23 @@ set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch,
gdbarch->addressable_memory_unit_size = addressable_memory_unit_size;
}
+const char *
+gdbarch_disassembler_options_implicit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of disassembler_options_implicit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_implicit called\n");
+ return gdbarch->disassembler_options_implicit;
+}
+
+void
+set_gdbarch_disassembler_options_implicit (struct gdbarch *gdbarch,
+ const char * disassembler_options_implicit)
+{
+ gdbarch->disassembler_options_implicit = disassembler_options_implicit;
+}
+
char **
gdbarch_disassembler_options (struct gdbarch *gdbarch)
{
@@ -5061,7 +5083,7 @@ set_gdbarch_disassembler_options (struct gdbarch *gdbarch,
gdbarch->disassembler_options = disassembler_options;
}
-const disasm_options_t *
+const disasm_options_and_args_t *
gdbarch_valid_disassembler_options (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
@@ -5073,7 +5095,7 @@ gdbarch_valid_disassembler_options (struct gdbarch *gdbarch)
void
set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch,
- const disasm_options_t * valid_disassembler_options)
+ const disasm_options_and_args_t * valid_disassembler_options)
{
gdbarch->valid_disassembler_options = valid_disassembler_options;
}
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index d13672bd..0df1fd1 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1549,11 +1549,14 @@ extern void set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch, g
/* Functions for allowing a target to modify its disassembler options. */
+extern const char * gdbarch_disassembler_options_implicit (struct gdbarch *gdbarch);
+extern void set_gdbarch_disassembler_options_implicit (struct gdbarch *gdbarch, const char * disassembler_options_implicit);
+
extern char ** gdbarch_disassembler_options (struct gdbarch *gdbarch);
extern void set_gdbarch_disassembler_options (struct gdbarch *gdbarch, char ** disassembler_options);
-extern const disasm_options_t * gdbarch_valid_disassembler_options (struct gdbarch *gdbarch);
-extern void set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch, const disasm_options_t * valid_disassembler_options);
+extern const disasm_options_and_args_t * gdbarch_valid_disassembler_options (struct gdbarch *gdbarch);
+extern void set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch, const disasm_options_and_args_t * valid_disassembler_options);
/* Type alignment. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index c85444d..4473943 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1157,8 +1157,9 @@ m;const char *;gnu_triplet_regexp;void;;;default_gnu_triplet_regexp;;0
m;int;addressable_memory_unit_size;void;;;default_addressable_memory_unit_size;;0
# Functions for allowing a target to modify its disassembler options.
+v;const char *;disassembler_options_implicit;;;0;0;;0;pstring (gdbarch->disassembler_options_implicit)
v;char **;disassembler_options;;;0;0;;0;pstring_ptr (gdbarch->disassembler_options)
-v;const disasm_options_t *;valid_disassembler_options;;;0;0;;0;host_address_to_string (gdbarch->valid_disassembler_options)
+v;const disasm_options_and_args_t *;valid_disassembler_options;;;0;0;;0;host_address_to_string (gdbarch->valid_disassembler_options)
# Type alignment.
m;ULONGEST;type_align;struct type *type;type;;default_type_align;;0
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 32b2d40..36fae02 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -214,6 +214,18 @@ static unsigned int mips_debug = 0;
struct target_desc *mips_tdesc_gp32;
struct target_desc *mips_tdesc_gp64;
+/* The current set of options to be passed to the disassembler. */
+static char *mips_disassembler_options;
+
+/* Implicit disassembler options for individual ABIs. These tell
+ libopcodes to use general-purpose register names corresponding
+ to the ABI we have selected, perhaps via a `set mips abi ...'
+ override, rather than ones inferred from the ABI set in the ELF
+ headers of the binary file selected for debugging. */
+static const char mips_disassembler_options_o32[] = "gpr-names=32";
+static const char mips_disassembler_options_n32[] = "gpr-names=n32";
+static const char mips_disassembler_options_n64[] = "gpr-names=64";
+
const struct mips_regnum *
mips_regnum (struct gdbarch *gdbarch)
{
@@ -6990,40 +7002,9 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
memaddr &= (info->mach == bfd_mach_mips16
|| info->mach == bfd_mach_mips_micromips) ? ~1 : ~3;
- /* Set the disassembler options. */
- if (!info->disassembler_options)
- /* This string is not recognized explicitly by the disassembler,
- but it tells the disassembler to not try to guess the ABI from
- the bfd elf headers, such that, if the user overrides the ABI
- of a program linked as NewABI, the disassembly will follow the
- register naming conventions specified by the user. */
- info->disassembler_options = "gpr-names=32";
-
return default_print_insn (memaddr, info);
}
-static int
-gdb_print_insn_mips_n32 (bfd_vma memaddr, struct disassemble_info *info)
-{
- /* Set up the disassembler info, so that we get the right
- register names from libopcodes. */
- info->disassembler_options = "gpr-names=n32";
- info->flavour = bfd_target_elf_flavour;
-
- return gdb_print_insn_mips (memaddr, info);
-}
-
-static int
-gdb_print_insn_mips_n64 (bfd_vma memaddr, struct disassemble_info *info)
-{
- /* Set up the disassembler info, so that we get the right
- register names from libopcodes. */
- info->disassembler_options = "gpr-names=64";
- info->flavour = bfd_target_elf_flavour;
-
- return gdb_print_insn_mips (memaddr, info);
-}
-
/* Implement the breakpoint_kind_from_pc gdbarch method. */
static int
@@ -8727,12 +8708,19 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_print_registers_info (gdbarch, mips_print_registers_info);
- if (mips_abi == MIPS_ABI_N32)
- set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips_n32);
- else if (mips_abi == MIPS_ABI_N64)
- set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips_n64);
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips);
+ if (mips_abi == MIPS_ABI_N64)
+ set_gdbarch_disassembler_options_implicit
+ (gdbarch, (const char *) mips_disassembler_options_n64);
+ else if (mips_abi == MIPS_ABI_N32)
+ set_gdbarch_disassembler_options_implicit
+ (gdbarch, (const char *) mips_disassembler_options_n32);
else
- set_gdbarch_print_insn (gdbarch, gdb_print_insn_mips);
+ set_gdbarch_disassembler_options_implicit
+ (gdbarch, (const char *) mips_disassembler_options_o32);
+ set_gdbarch_disassembler_options (gdbarch, &mips_disassembler_options);
+ set_gdbarch_valid_disassembler_options (gdbarch,
+ disassembler_options_mips ());
/* FIXME: cagney/2003-08-29: The macros target_have_steppable_watchpoint,
HAVE_NONSTEPPABLE_WATCHPOINT, and target_have_continuable_watchpoint
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 93c849c..e802927 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2018-07-02 Maciej W. Rozycki <macro@mips.com>
+
+ PR tdep/8282
+ * gdb.arch/mips-disassembler-options.exp: New test.
+ * gdb.arch/mips-disassembler-options.s: New test source.
+
2018-06-29 Pedro Alves <palves@redhat.com>
* gdb.threads/names.exp: Adjust expected "info threads" output.
diff --git a/gdb/testsuite/gdb.arch/mips-disassembler-options.exp b/gdb/testsuite/gdb.arch/mips-disassembler-options.exp
new file mode 100644
index 0000000..8db3026
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/mips-disassembler-options.exp
@@ -0,0 +1,58 @@
+# Copyright 2018 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 MIPS disassembler options.
+
+if { ![istarget "mips*-*-*"] } then {
+ verbose "Skipping MIPS disassembler option tests."
+ return
+}
+
+standard_testfile .s
+set objfile [standard_output_file ${testfile}.o]
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {}] \
+ != "" } {
+ return
+}
+
+clean_restart ${objfile}
+
+proc mips_disassemble_test { func insn mesg } {
+ gdb_test "disassemble $func" \
+ "Dump of assembler code for function\
+ $func:\r\n\[^:\]+:\t$insn\r\nEnd of assembler dump\." \
+ $mesg
+}
+
+# Verify defaults.
+mips_disassemble_test foo "move\tv0,v1" "disassemble default"
+
+# Verify option overrides.
+gdb_test "set disassembler-options gpr-names=numeric"
+mips_disassemble_test foo "move\t\\\$2,\\\$3" "disassemble numeric, gpr-names"
+# Check multiple options too.
+gdb_test "set disassembler-options msa,reg-names=numeric,reg-names=r3000"
+mips_disassemble_test foo "move\t\\\$2,\\\$3" "disassemble numeric, reg-names"
+
+# Verify ABI overrides.
+mips_disassemble_test bar "move\t\\\$2,\\\$8" "disassemble ABI, numeric"
+gdb_test "set disassembler-options"
+gdb_test "set mips abi o32"
+mips_disassemble_test bar "move\tv0,t0" "disassemble ABI, o32"
+gdb_test "set mips abi n32"
+mips_disassemble_test bar "move\tv0,a4" "disassemble ABI, n32"
+gdb_test "set mips abi n64"
+mips_disassemble_test bar "move\tv0,a4" "disassemble ABI, n64"
diff --git a/gdb/testsuite/gdb.arch/mips-disassembler-options.s b/gdb/testsuite/gdb.arch/mips-disassembler-options.s
new file mode 100644
index 0000000..6bf48cc
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/mips-disassembler-options.s
@@ -0,0 +1,30 @@
+# This test is part of GDB, the GNU debugger.
+#
+# Copyright 2018 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/>.
+
+# Note: this is meant to be buildable as MIPS16 or microMIPS code too.
+
+ .globl foo
+ .ent foo
+foo:
+ move $2, $3
+ .end foo
+
+ .globl bar
+ .ent bar
+bar:
+ move $2, $8
+ .end bar
diff --git a/include/ChangeLog b/include/ChangeLog
index 8f11f79..de80801 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,13 @@
+2018-07-02 Maciej W. Rozycki <macro@mips.com>
+
+ PR tdep/8282
+ * dis-asm.h (disasm_option_arg_t): New typedef.
+ (disasm_options_and_args_t): Likewise.
+ (disasm_options_t): Add `arg' member, document members.
+ (disassembler_options_mips): New prototype.
+ (disassembler_options_arm, disassembler_options_powerpc)
+ (disassembler_options_s390): Update prototypes.
+
2018-06-29 Tamar Christina <tamar.christina@arm.com>
PR binutils/23192
diff --git a/include/dis-asm.h b/include/dis-asm.h
index cb72b7d..77b9e61 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -222,16 +222,53 @@ typedef struct disassemble_info
} disassemble_info;
-/* This struct is used to pass information about valid disassembler options
- and their descriptions from the target to the generic GDB functions that
- set and display them. */
+/* This struct is used to pass information about valid disassembler
+ option arguments from the target to the generic GDB functions
+ that set and display them. */
typedef struct
{
+ /* Option argument name to use in descriptions. */
+ const char *name;
+
+ /* Vector of acceptable option argument values, NULL-terminated. */
+ const char **values;
+} disasm_option_arg_t;
+
+/* This struct is used to pass information about valid disassembler
+ options, their descriptions and arguments from the target to the
+ generic GDB functions that set and display them. Options are
+ defined by tuples of vector entries at each index. */
+
+typedef struct
+{
+ /* Vector of option names, NULL-terminated. */
const char **name;
+
+ /* Vector of option descriptions or NULL if none to be shown. */
const char **description;
+
+ /* Vector of option argument information pointers or NULL if no
+ option accepts an argument. NULL entries denote individual
+ options that accept no argument. */
+ const disasm_option_arg_t **arg;
} disasm_options_t;
+/* This struct is used to pass information about valid disassembler
+ options and arguments from the target to the generic GDB functions
+ that set and display them. */
+
+typedef struct
+{
+ /* Valid disassembler options. Individual options that support
+ an argument will refer to entries in the ARGS vector. */
+ disasm_options_t options;
+
+ /* Vector of acceptable option arguments, NULL-terminated. This
+ collects all possible option argument choices, some of which
+ may be shared by different options from the OPTIONS member. */
+ disasm_option_arg_t *args;
+} disasm_options_and_args_t;
/* Standard disassemblers. Disassemble one instruction at the given
target address. Return number of octets processed. */
@@ -266,9 +303,10 @@ extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
extern void disassemble_init_powerpc (struct disassemble_info *);
extern void disassemble_init_s390 (struct disassemble_info *);
extern void disassemble_init_wasm32 (struct disassemble_info *);
-extern const disasm_options_t *disassembler_options_powerpc (void);
-extern const disasm_options_t *disassembler_options_arm (void);
-extern const disasm_options_t *disassembler_options_s390 (void);
+extern const disasm_options_and_args_t *disassembler_options_arm (void);
+extern const disasm_options_and_args_t *disassembler_options_mips (void);
+extern const disasm_options_and_args_t *disassembler_options_powerpc (void);
+extern const disasm_options_and_args_t *disassembler_options_s390 (void);
/* Fetch the disassembler for a given architecture ARC, endianess (big
endian if BIG is true), bfd_mach value MACH, and ABFD, if that support
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index fdc0e44..149737e 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,16 @@
+2018-07-02 Maciej W. Rozycki <macro@mips.com>
+
+ PR tdep/8282
+ * mips-dis.c (mips_option_arg_t): New enumeration.
+ (mips_options): New variable.
+ (disassembler_options_mips): New function.
+ (print_mips_disassembler_options): Reimplement in terms of
+ `disassembler_options_mips'.
+ * arm-dis.c (disassembler_options_arm): Adapt to using the
+ `disasm_options_and_args_t' structure.
+ * ppc-dis.c (disassembler_options_powerpc): Likewise.
+ * s390-dis.c (disassembler_options_s390): Likewise.
+
2018-07-02 Thomas Preud'homme <thomas.preudhomme@arm.com>
* testsuite/ld-arm/tls-descrelax-be8.d: Add architecture version in
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index da28837..8bcec13 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -6850,17 +6850,23 @@ print_insn_little_arm (bfd_vma pc, struct disassemble_info *info)
return print_insn (pc, info, TRUE);
}
-const disasm_options_t *
+const disasm_options_and_args_t *
disassembler_options_arm (void)
{
- static disasm_options_t *opts = NULL;
+ static disasm_options_and_args_t *opts_and_args;
- if (opts == NULL)
+ if (opts_and_args == NULL)
{
+ disasm_options_t *opts;
unsigned int i;
- opts = XNEW (disasm_options_t);
+
+ opts_and_args = XNEW (disasm_options_and_args_t);
+ opts_and_args->args = NULL;
+
+ opts = &opts_and_args->options;
opts->name = XNEWVEC (const char *, NUM_ARM_OPTIONS + 1);
opts->description = XNEWVEC (const char *, NUM_ARM_OPTIONS + 1);
+ opts->arg = NULL;
for (i = 0; i < NUM_ARM_OPTIONS; i++)
{
opts->name[i] = regnames[i].name;
@@ -6874,7 +6880,7 @@ disassembler_options_arm (void)
opts->description[i] = NULL;
}
- return opts;
+ return opts_and_args;
}
void
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c
index 4938f90..bbf2132 100644
--- a/opcodes/mips-dis.c
+++ b/opcodes/mips-dis.c
@@ -2552,72 +2552,178 @@ print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info)
return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
}
-void
-print_mips_disassembler_options (FILE *stream)
+/* Indices into option argument vector for options accepting an argument.
+ Use MIPS_OPTION_ARG_NONE for options accepting no argument. */
+typedef enum
{
- unsigned int i;
-
- fprintf (stream, _("\n\
-The following MIPS specific disassembler options are supported for use\n\
-with the -M switch (multiple options should be separated by commas):\n"));
-
- fprintf (stream, _("\n\
- no-aliases Use canonical instruction forms.\n"));
+ MIPS_OPTION_ARG_NONE = -1,
+ MIPS_OPTION_ARG_ABI,
+ MIPS_OPTION_ARG_ARCH,
+ MIPS_OPTION_ARG_SIZE
+} mips_option_arg_t;
+
+/* Valid MIPS disassembler options. */
+static struct
+{
+ const char *name;
+ const char *description;
+ mips_option_arg_t arg;
+} mips_options[] =
+{
+ { "no-aliases", N_("Use canonical instruction forms.\n"),
+ MIPS_OPTION_ARG_NONE },
+ { "msa", N_("Recognize MSA instructions.\n"),
+ MIPS_OPTION_ARG_NONE },
+ { "virt", N_("Recognize the virtualization ASE instructions.\n"),
+ MIPS_OPTION_ARG_NONE },
+ { "xpa", N_("Recognize the eXtended Physical Address (XPA) ASE\n\
+ instructions.\n"),
+ MIPS_OPTION_ARG_NONE },
+ { "ginv", N_("Recognize the Global INValidate (GINV) ASE "
+ "instructions.\n"),
+ MIPS_OPTION_ARG_NONE },
+ { "gpr-names=", N_("Print GPR names according to specified ABI.\n\
+ Default: based on binary being disassembled.\n"),
+ MIPS_OPTION_ARG_ABI },
+ { "fpr-names=", N_("Print FPR names according to specified ABI.\n\
+ Default: numeric.\n"),
+ MIPS_OPTION_ARG_ABI },
+ { "cp0-names=", N_("Print CP0 register names according to specified "
+ "architecture.\n\
+ Default: based on binary being disassembled.\n"),
+ MIPS_OPTION_ARG_ARCH },
+ { "hwr-names=", N_("Print HWR names according to specified architecture.\n\
+ Default: based on binary being disassembled.\n"),
+ MIPS_OPTION_ARG_ARCH },
+ { "reg-names=", N_("Print GPR and FPR names according to specified ABI.\n"),
+ MIPS_OPTION_ARG_ABI },
+ { "reg-names=", N_("Print CP0 register and HWR names according to "
+ "specified\n\
+ architecture."),
+ MIPS_OPTION_ARG_ARCH }
+};
- fprintf (stream, _("\n\
- msa Recognize MSA instructions.\n"));
+/* Build the structure representing valid MIPS disassembler options.
+ This is done dynamically for maintenance ease purpose; a static
+ initializer would be unreadable. */
- fprintf (stream, _("\n\
- virt Recognize the virtualization ASE instructions.\n"));
+const disasm_options_and_args_t *
+disassembler_options_mips (void)
+{
+ static disasm_options_and_args_t *opts_and_args;
- fprintf (stream, _("\n\
- xpa Recognize the eXtended Physical Address (XPA)\n\
- ASE instructions.\n"));
+ if (opts_and_args == NULL)
+ {
+ size_t num_options = ARRAY_SIZE (mips_options);
+ size_t num_args = MIPS_OPTION_ARG_SIZE;
+ disasm_option_arg_t *args;
+ disasm_options_t *opts;
+ size_t i;
+ size_t j;
+
+ args = XNEWVEC (disasm_option_arg_t, num_args + 1);
+
+ args[MIPS_OPTION_ARG_ABI].name = "ABI";
+ args[MIPS_OPTION_ARG_ABI].values
+ = XNEWVEC (const char *, ARRAY_SIZE (mips_abi_choices) + 1);
+ for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
+ args[MIPS_OPTION_ARG_ABI].values[i] = mips_abi_choices[i].name;
+ /* The array we return must be NULL terminated. */
+ args[MIPS_OPTION_ARG_ABI].values[i] = NULL;
+
+ args[MIPS_OPTION_ARG_ARCH].name = "ARCH";
+ args[MIPS_OPTION_ARG_ARCH].values
+ = XNEWVEC (const char *, ARRAY_SIZE (mips_arch_choices) + 1);
+ for (i = 0, j = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
+ if (*mips_arch_choices[i].name != '\0')
+ args[MIPS_OPTION_ARG_ARCH].values[j++] = mips_arch_choices[i].name;
+ /* The array we return must be NULL terminated. */
+ args[MIPS_OPTION_ARG_ARCH].values[j] = NULL;
+
+ /* The array we return must be NULL terminated. */
+ args[MIPS_OPTION_ARG_SIZE].name = NULL;
+ args[MIPS_OPTION_ARG_SIZE].values = NULL;
+
+ opts_and_args = XNEW (disasm_options_and_args_t);
+ opts_and_args->args = args;
+
+ opts = &opts_and_args->options;
+ opts->name = XNEWVEC (const char *, num_options + 1);
+ opts->description = XNEWVEC (const char *, num_options + 1);
+ opts->arg = XNEWVEC (const disasm_option_arg_t *, num_options + 1);
+ for (i = 0; i < num_options; i++)
+ {
+ opts->name[i] = mips_options[i].name;
+ opts->description[i] = _(mips_options[i].description);
+ if (mips_options[i].arg != MIPS_OPTION_ARG_NONE)
+ opts->arg[i] = &args[mips_options[i].arg];
+ else
+ opts->arg[i] = NULL;
+ }
+ /* The array we return must be NULL terminated. */
+ opts->name[i] = NULL;
+ opts->description[i] = NULL;
+ opts->arg[i] = NULL;
+ }
- fprintf (stream, _("\n\
- ginv Recognize the Global INValidate (GINV) ASE\n\
- instructions.\n"));
+ return opts_and_args;
+}
- fprintf (stream, _("\n\
- gpr-names=ABI Print GPR names according to specified ABI.\n\
- Default: based on binary being disassembled.\n"));
+void
+print_mips_disassembler_options (FILE *stream)
+{
+ const disasm_options_and_args_t *opts_and_args;
+ const disasm_option_arg_t *args;
+ const disasm_options_t *opts;
+ size_t max_len = 0;
+ size_t i;
+ size_t j;
- fprintf (stream, _("\n\
- fpr-names=ABI Print FPR names according to specified ABI.\n\
- Default: numeric.\n"));
+ opts_and_args = disassembler_options_mips ();
+ opts = &opts_and_args->options;
+ args = opts_and_args->args;
fprintf (stream, _("\n\
- cp0-names=ARCH Print CP0 register names according to\n\
- specified architecture.\n\
- Default: based on binary being disassembled.\n"));
+The following MIPS specific disassembler options are supported for use\n\
+with the -M switch (multiple options should be separated by commas):\n\n"));
- fprintf (stream, _("\n\
- hwr-names=ARCH Print HWR names according to specified \n\
- architecture.\n\
- Default: based on binary being disassembled.\n"));
+ /* Compute the length of the longest option name. */
+ for (i = 0; opts->name[i] != NULL; i++)
+ {
+ size_t len = strlen (opts->name[i]);
- fprintf (stream, _("\n\
- reg-names=ABI Print GPR and FPR names according to\n\
- specified ABI.\n"));
+ if (opts->arg[i] != NULL)
+ len += strlen (opts->arg[i]->name);
+ if (max_len < len)
+ max_len = len;
+ }
- fprintf (stream, _("\n\
- reg-names=ARCH Print CP0 register and HWR names according to\n\
- specified architecture.\n"));
+ for (i = 0, max_len++; opts->name[i] != NULL; i++)
+ {
+ fprintf (stream, " %s", opts->name[i]);
+ if (opts->arg[i] != NULL)
+ fprintf (stream, "%s", opts->arg[i]->name);
+ if (opts->description[i] != NULL)
+ {
+ size_t len = strlen (opts->name[i]);
- fprintf (stream, _("\n\
- For the options above, the following values are supported for \"ABI\":\n\
- "));
- for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
- fprintf (stream, " %s", mips_abi_choices[i].name);
- fprintf (stream, _("\n"));
+ if (opts->arg[i] != NULL)
+ len += strlen (opts->arg[i]->name);
+ fprintf (stream,
+ "%*c %s", (int) (max_len - len), ' ', opts->description[i]);
+ }
+ fprintf (stream, _("\n"));
+ }
- fprintf (stream, _("\n\
- For the options above, The following values are supported for \"ARCH\":\n\
- "));
- for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
- if (*mips_arch_choices[i].name != '\0')
- fprintf (stream, " %s", mips_arch_choices[i].name);
- fprintf (stream, _("\n"));
+ for (i = 0; args[i].name != NULL; i++)
+ {
+ fprintf (stream, _("\n\
+ For the options above, the following values are supported for \"%s\":\n "),
+ args[i].name);
+ for (j = 0; args[i].values[j] != NULL; j++)
+ fprintf (stream, " %s", args[i].values[j]);
+ fprintf (stream, _("\n"));
+ }
fprintf (stream, _("\n"));
}
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index 43f4ce8..bd6072e 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -810,24 +810,30 @@ print_insn_powerpc (bfd_vma memaddr,
return 4;
}
-const disasm_options_t *
+const disasm_options_and_args_t *
disassembler_options_powerpc (void)
{
- static disasm_options_t *opts = NULL;
+ static disasm_options_and_args_t *opts_and_args;
- if (opts == NULL)
+ if (opts_and_args == NULL)
{
size_t i, num_options = ARRAY_SIZE (ppc_opts);
- opts = XNEW (disasm_options_t);
+ disasm_options_t *opts;
+
+ opts_and_args = XNEW (disasm_options_and_args_t);
+ opts_and_args->args = NULL;
+
+ opts = &opts_and_args->options;
opts->name = XNEWVEC (const char *, num_options + 1);
+ opts->description = NULL;
+ opts->arg = NULL;
for (i = 0; i < num_options; i++)
opts->name[i] = ppc_opts[i].opt;
/* The array we return must be NULL terminated. */
opts->name[i] = NULL;
- opts->description = NULL;
}
- return opts;
+ return opts_and_args;
}
void
diff --git a/opcodes/s390-dis.c b/opcodes/s390-dis.c
index 6763d9f..79d9f53 100644
--- a/opcodes/s390-dis.c
+++ b/opcodes/s390-dis.c
@@ -379,17 +379,23 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
return 0;
}
-const disasm_options_t *
+const disasm_options_and_args_t *
disassembler_options_s390 (void)
{
- static disasm_options_t *opts = NULL;
+ static disasm_options_and_args_t *opts_and_args;
- if (opts == NULL)
+ if (opts_and_args == NULL)
{
size_t i, num_options = ARRAY_SIZE (options);
- opts = XNEW (disasm_options_t);
+ disasm_options_t *opts;
+
+ opts_and_args = XNEW (disasm_options_and_args_t);
+ opts_and_args->args = NULL;
+
+ opts = &opts_and_args->options;
opts->name = XNEWVEC (const char *, num_options + 1);
opts->description = XNEWVEC (const char *, num_options + 1);
+ opts->arg = NULL;
for (i = 0; i < num_options; i++)
{
opts->name[i] = options[i].name;
@@ -400,7 +406,7 @@ disassembler_options_s390 (void)
opts->description[i] = NULL;
}
- return opts;
+ return opts_and_args;
}
void