diff options
-rw-r--r-- | gdb/ChangeLog | 37 | ||||
-rw-r--r-- | gdb/NEWS | 3 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 3 | ||||
-rw-r--r-- | gdb/disasm.c | 127 | ||||
-rw-r--r-- | gdb/disasm.h | 5 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 2 | ||||
-rw-r--r-- | gdb/gdbarch.c | 28 | ||||
-rw-r--r-- | gdb/gdbarch.h | 7 | ||||
-rwxr-xr-x | gdb/gdbarch.sh | 3 | ||||
-rw-r--r-- | gdb/mips-tdep.c | 60 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/mips-disassembler-options.exp | 58 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/mips-disassembler-options.s | 30 | ||||
-rw-r--r-- | include/ChangeLog | 10 | ||||
-rw-r--r-- | include/dis-asm.h | 50 | ||||
-rw-r--r-- | opcodes/ChangeLog | 13 | ||||
-rw-r--r-- | opcodes/arm-dis.c | 16 | ||||
-rw-r--r-- | opcodes/mips-dis.c | 210 | ||||
-rw-r--r-- | opcodes/ppc-dis.c | 18 | ||||
-rw-r--r-- | opcodes/s390-dis.c | 16 |
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. @@ -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 |