This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 1/2] Add support for setting disassembler-options in GDB for POWER, ARM and S390
- From: Peter Bergner <bergner at vnet dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Cc: Ulrich Weigand <uweigand at de dot ibm dot com>, Pedro Alves <palves at redhat dot com>, Alan Modra <amodra at gmail dot com>, binutils <binutils at sourceware dot org>
- Date: Thu, 17 Nov 2016 13:18:56 -0600
- Subject: [PATCH 1/2] Add support for setting disassembler-options in GDB for POWER, ARM and S390
- Authentication-results: sourceware.org; auth=none
Ping. This is the same as my last patch posted here:
https://sourceware.org/ml/binutils/2016-11/msg00029.html
...except for that we no longer output "default" for a NULL
disassembler_options value, and instead just output ''.
I will note that doing "set disassembler-options" does reset
the disassembler_options value to NULL.
I'll shortly post a follow-on patch that splits the huge ppc
disassembly test case into multiple test cases which uses the
"set disassembler-options ..." command to correctly choose
the disassembly cpu/ISA to disassemble the tests with.
Is this version ok?
Peter
include/
* dis-asm.h (parse_arm_disassembler_option): Remove prototype.
(set_arm_regname_option): Likewise.
(disassemble_init_s390): New prototype.
(disassembler_options_names_powerpc): Likewise.
(disassembler_options_names_arm): Likewise.
(disassembler_options_desc_arm): Likewise.
(disassembler_options_names_s390): Likewise.
(disassembler_options_desc_s390): Likewise.
opcodes/
* disassemble.c (disassemble_init_for_target): Handle s390 init.
* ppc-dis.c: Include "libiberty.h".
(ppc_opts): Add "32" and "64" entries.
(parse_ppc_dis_option): New function.
(disassembler_options_names_powerpc): Likewise.
(powerpc_init_dialect): Use parse_ppc_dis_option().
Add break to switch statement.
(print_ppc_disassembler_options): Remove printing of "32" and "64".
* arm-dis.c: Include "libiberty.h".
(struct arm_regname): Add 'long_name' field.
(regnames): Initialize it.
(set_arm_regname_option): Remove function.
(parse_arm_disassembler_option): Make static.
(disassembler_options_names_arm): New function.
(disassembler_options_desc_arm): Likewise.
* s390-dis.c: Include "libiberty.h".
(struct options_t): New structure type.
(options): New structure.
(init_disasm): Rename from this...
(disassemble_init_s390): ...to this. Add initializations for
current_arch_mask and option_use_insn_len_bits_p. Remove init_flag.
(disassembler_options_names_s390): New function.
(disassembler_options_desc_s390): Likewise.
(print_s390_disassembler_options): Print using information from
struct 'options'.
gdb/
* gdbarch.sh (gdbarch_disassembler_options): New variable.
(gdbarch_disassembler_options_names): Likewise.
(gdbarch_disassembler_options_descriptions): Likewise.
* gdbarch.c: Regenerate.
* gdbarch.h: Likewise.
* disasm.c: Include "arch-utils.h", "gdbcmd.h", "gdbcmd.h" and
"safe-ctype.h".
(gdb_disassemble_info): Initilize di.disassembler_options.
(gdb_buffered_insn_length_init_dis): Initilize di->application_data
and di->disassembler_options.
(cleanup_disassembler_options): New function.
(parse_disassembler_options): Likewise.
(set_disassembler_options): Likewise.
(show_disassembler_options): Likewise.
(disassembler_options_completer): Likewise.
(_initialize_disasm): Likewise.
* disasm.h (set_disassembler_options): New prototype.
(show_disassembler_options): Likewise.
* rs6000-tdep.c (rs6000_gdbarch_init): Call
set_gdbarch_disassembler_options_names.
* arm-tdep.c: Include "disasm.h" and "cli/cli-decode.h".
(disassembly_style): Delete static variable.
(set_disassembly_style): Delete function and prototype.
(show_disassembly_style_sfunc): New function.
(set_disassembly_style_sfunc): Call set_disassembler_options.
(arm_gdbarch_init): Call set_gdbarch_disassembler_options,
set_gdbarch_disassembler_options_names and
set_gdbarch_disassembler_options_descriptions.
(_initialize_arm_tdep): New static variable 'disassembly_style';
Remove calls to parse_arm_disassembler_option & set_arm_regname_option.
Pass show_disassembly_style_sfunc to the "disassembler" setshow command.
* s390-tdep.c (s390_gdbarch_init): Call functions
set_gdbarch_disassembler_options_names and
set_gdbarch_disassembler_options_descriptions.
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 2cefff4..a6b61e2 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -331,14 +331,18 @@ extern void print_ppc_disassembler_options (FILE *);
extern void print_riscv_disassembler_options (FILE *);
extern void print_arm_disassembler_options (FILE *);
extern void print_arc_disassembler_options (FILE *);
-extern void parse_arm_disassembler_option (char *);
extern void print_s390_disassembler_options (FILE *);
extern int get_arm_regname_num_options (void);
-extern int set_arm_regname_option (int);
extern int get_arm_regnames (int, const char **, const char **, const char *const **);
extern bfd_boolean aarch64_symbol_is_valid (asymbol *, struct disassemble_info *);
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 const char **disassembler_options_names_powerpc (void);
+extern const char **disassembler_options_names_arm (void);
+extern const char **disassembler_options_desc_arm (void);
+extern const char **disassembler_options_names_s390 (void);
+extern const char **disassembler_options_desc_s390 (void);
/* Fetch the disassembler for a given BFD, if that support is available. */
extern disassembler_ftype disassembler (bfd *);
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index e1fb65c..6418ada 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -643,6 +643,11 @@ disassemble_init_for_target (struct disassemble_info * info)
disassemble_init_powerpc (info);
break;
#endif
+#ifdef ARCH_s390
+ case bfd_arch_s390:
+ disassemble_init_s390 (info);
+ break;
+#endif
default:
break;
}
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index da1301e..af8c756 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -26,6 +26,7 @@
#include "elf/ppc.h"
#include "opintl.h"
#include "opcode/ppc.h"
+#include "libiberty.h"
/* This file provides several disassembler functions, all of which use
the disassembler interface defined in dis-asm.h. Several functions
@@ -172,8 +173,12 @@ struct ppc_mopt ppc_opts[] = {
0 },
{ "ppc32", PPC_OPCODE_PPC,
0 },
+ { "32", PPC_OPCODE_PPC,
+ 0 },
{ "ppc64", PPC_OPCODE_PPC | PPC_OPCODE_64,
0 },
+ { "64", PPC_OPCODE_PPC | PPC_OPCODE_64,
+ 0 },
{ "ppc64bridge", PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE,
0 },
{ "ppcps", PPC_OPCODE_PPC | PPC_OPCODE_PPCPS,
@@ -271,6 +276,27 @@ ppc_parse_cpu (ppc_cpu_t ppc_cpu, ppc_cpu_t *sticky, const char *arg)
return ppc_cpu;
}
+/* Parse the OPTIONS argument looking for ',' seperated cpu names.
+ Return the length of the current option, or 0 if there are no more.
+ Update OPTIONS to point to the next option, or NULL otherwise. */
+
+static char *
+parse_ppc_dis_option (char *cpu, const char *options)
+{
+ char *next = strchr (options, ',');
+
+ if (next != NULL)
+ {
+ strncpy (cpu, options, (size_t) (next - options));
+ cpu[(size_t) (next - options)] = 0;
+ next++;
+ }
+ else
+ strcpy (cpu, options);
+
+ return next;
+}
+
/* Determine which set of machines to disassemble for. */
static void
@@ -324,29 +350,24 @@ powerpc_init_dialect (struct disassemble_info *info)
break;
default:
dialect = ppc_parse_cpu (dialect, &sticky, "power9") | PPC_OPCODE_ANY;
+ break;
}
arg = info->disassembler_options;
while (arg != NULL)
{
ppc_cpu_t new_cpu = 0;
- char *end = strchr (arg, ',');
+ char opt[64];
+ arg = parse_ppc_dis_option (opt, arg);
- if (end != NULL)
- *end = 0;
-
- if ((new_cpu = ppc_parse_cpu (dialect, &sticky, arg)) != 0)
- dialect = new_cpu;
- else if (strcmp (arg, "32") == 0)
+ if (strcmp (opt, "32") == 0)
dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
- else if (strcmp (arg, "64") == 0)
+ else if (strcmp (opt, "64") == 0)
dialect |= PPC_OPCODE_64;
+ else if ((new_cpu = ppc_parse_cpu (dialect, &sticky, opt)) != 0)
+ dialect = new_cpu;
else
- fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), arg);
-
- if (end != NULL)
- *end++ = ',';
- arg = end;
+ fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), opt);
}
info->private_data = priv;
@@ -767,6 +788,24 @@ print_insn_powerpc (bfd_vma memaddr,
return 4;
}
+const char **
+disassembler_options_names_powerpc (void)
+{
+ static const char **options = NULL;
+
+ if (options == NULL)
+ {
+ size_t i;
+ size_t num_options = sizeof (ppc_opts) / sizeof (ppc_opts[0]);
+ options = XNEWVEC (const char *, num_options + 1);
+ for (i = 0; i < num_options; i++)
+ options[i] = ppc_opts[i].opt;
+ options[i] = NULL;
+ }
+
+ return options;
+}
+
void
print_ppc_disassembler_options (FILE *stream)
{
@@ -785,5 +824,5 @@ the -M switch:\n"));
col = 0;
}
}
- fprintf (stream, " 32, 64\n");
+ fprintf (stream, "\n");
}
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index 87d4930..939005d 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -26,6 +26,7 @@
#include "opcode/arm.h"
#include "opintl.h"
#include "safe-ctype.h"
+#include "libiberty.h"
#include "floatformat.h"
/* FIXME: This shouldn't be done here. */
@@ -3164,6 +3165,7 @@ static const char *const arm_shift[] =
typedef struct
{
const char *name;
+ const char *long_name;
const char *description;
const char *reg_names[16];
}
@@ -3171,17 +3173,17 @@ arm_regname;
static const arm_regname regnames[] =
{
- { "raw" , "Select raw register names",
+ { "raw" , "reg-names-raw", "Select raw register names",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
- { "gcc", "Select register names used by GCC",
+ { "gcc", "reg-names-gcc", "Select register names used by GCC",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
- { "std", "Select register names used in ARM's ISA documentation",
+ { "std", "reg-names-std", "Select register names used in ARM's ISA documentation",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
- { "apcs", "Select register names used in the APCS",
+ { "apcs", "reg-names-apcs", "Select register names used in the APCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
- { "atpcs", "Select register names used in the ATPCS",
+ { "atpcs", "reg-names-atpcs", "Select register names used in the ATPCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
- { "special-atpcs", "Select special register names used in the ATPCS",
+ { "special-atpcs", "reg-names-special-atpcs", "Select special register names used in the ATPCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }},
};
@@ -3234,14 +3236,6 @@ get_arm_regname_num_options (void)
}
int
-set_arm_regname_option (int option)
-{
- int old = regname_selected;
- regname_selected = option;
- return old;
-}
-
-int
get_arm_regnames (int option,
const char **setname,
const char **setdescription,
@@ -6094,7 +6088,7 @@ arm_symbol_is_valid (asymbol * sym,
/* Parse an individual disassembler option. */
-void
+static void
parse_arm_disassembler_option (char *option)
{
if (option == NULL)
@@ -6810,6 +6804,46 @@ print_insn_little_arm (bfd_vma pc, struct disassemble_info *info)
return print_insn (pc, info, TRUE);
}
+const char **
+disassembler_options_names_arm (void)
+{
+ static const char **options = NULL;
+
+ if (options == NULL)
+ {
+ size_t i;
+ size_t num_options = NUM_ARM_REGNAMES + 2;
+ options = XNEWVEC (const char *, num_options + 1);
+ for (i = 0; i < NUM_ARM_REGNAMES; i++)
+ options[i] = regnames[i].long_name;
+ options[i++] = "force-thumb";
+ options[i++] = "no-force-thumb";
+ options[i] = NULL;
+ }
+
+ return options;
+}
+
+const char **
+disassembler_options_desc_arm (void)
+{
+ static const char **desc = NULL;
+
+ if (desc == NULL)
+ {
+ size_t i;
+ size_t num_desc = NUM_ARM_REGNAMES + 2;
+ desc = XNEWVEC (const char *, num_desc + 1);
+ for (i = 0; i < NUM_ARM_REGNAMES; i++)
+ desc[i] = regnames[i].description;
+ desc[i++] = "Assume all insns are Thumb insns";
+ desc[i++] = "Examine preceding label to determine an insn's type";
+ desc[i] = NULL;
+ }
+
+ return desc;
+}
+
void
print_arm_disassembler_options (FILE *stream)
{
diff --git a/opcodes/s390-dis.c b/opcodes/s390-dis.c
index 8134073..f6e85de 100644
--- a/opcodes/s390-dis.c
+++ b/opcodes/s390-dis.c
@@ -25,16 +25,30 @@
#include "dis-asm.h"
#include "opintl.h"
#include "opcode/s390.h"
+#include "libiberty.h"
-static int init_flag = 0;
static int opc_index[256];
static int current_arch_mask = 0;
static int option_use_insn_len_bits_p = 0;
+typedef struct
+{
+ const char *name;
+ const char *description;
+} options_t;
+
+static const options_t options[] =
+{
+ { "esa" , "Disassemble in ESA architecture mode" },
+ { "zarch", "Disassemble in z/Architecture mode" },
+ { "insnlength", "Print unknown instructions according to "
+ "length from first two bits" }
+};
+
/* Set up index table for first opcode byte. */
-static void
-init_disasm (struct disassemble_info *info)
+void
+disassemble_init_s390 (struct disassemble_info *info)
{
int i;
const char *p;
@@ -46,6 +60,9 @@ init_disasm (struct disassemble_info *info)
for (i = s390_num_opcodes; i--; )
opc_index[s390_opcodes[i].opcode[0]] = i;
+ current_arch_mask = 1 << S390_OPCODE_ZARCH;
+ option_use_insn_len_bits_p = 0;
+
for (p = info->disassembler_options; p != NULL; )
{
if (CONST_STRNEQ (p, "esa"))
@@ -61,11 +78,6 @@ init_disasm (struct disassemble_info *info)
if (p != NULL)
p++;
}
-
- if (!current_arch_mask)
- current_arch_mask = 1 << S390_OPCODE_ZARCH;
-
- init_flag = 1;
}
/* Derive the length of an instruction from its first byte. */
@@ -266,9 +278,6 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
unsigned int value;
int status, opsize, bufsize, bytes_to_dump, i;
- if (init_flag == 0)
- init_disasm (info);
-
/* The output looks better if we put 6 bytes on a line. */
info->bytes_per_line = 6;
@@ -360,15 +369,58 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
return 0;
}
+const char **
+disassembler_options_names_s390 (void)
+{
+ static const char **opts = NULL;
+
+ if (opts == NULL)
+ {
+ size_t i, num_options = sizeof (options) / sizeof (options[0]);
+ opts = XNEWVEC (const char *, num_options);
+ for (i = 0; i < num_options; i++)
+ opts[i] = options[i].name;
+ opts[i] = NULL;
+ }
+
+ return opts;
+}
+
+const char **
+disassembler_options_desc_s390 (void)
+{
+ static const char **desc = NULL;
+
+ if (desc == NULL)
+ {
+ size_t i, num_options = sizeof (options) / sizeof (options[0]);
+ desc = XNEWVEC (const char *, num_options + 1);
+ for (i = 0; i < num_options; i++)
+ desc[i] = options[i].description;
+ desc[i] = NULL;
+ }
+
+ return desc;
+}
+
void
print_s390_disassembler_options (FILE *stream)
{
+ unsigned int i, max_len = 0;
fprintf (stream, _("\n\
The following S/390 specific disassembler options are supported for use\n\
with the -M switch (multiple options should be separated by commas):\n"));
- fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
- fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
- fprintf (stream, _(" insnlength Print unknown instructions according "
- "to length from first two bits\n"));
+ for (i = 0; sizeof (options) / sizeof (options[0]); i++)
+ {
+ unsigned int len = strlen (options[i].name);
+ if (max_len < len)
+ max_len = len;
+ }
+
+ for (i = 0, max_len++; sizeof (options) / sizeof (options[0]); i++)
+ fprintf (stream, " %s%*c %s",
+ options[i].name,
+ (int)(max_len - strlen (options[i].name)), ' ',
+ options[i].description);
}
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 28a3478..deba9db 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1163,6 +1163,11 @@ m:const char *:gnu_triplet_regexp:void:::default_gnu_triplet_regexp::0
# each address in memory.
m:int:addressable_memory_unit_size:void:::default_addressable_memory_unit_size::0
+# Functions for allowing a target to modify its disassembler options.
+v:char *:disassembler_options:::0:0::0:pstring (gdbarch->disassembler_options)
+v:const char **:disassembler_options_names:::0:0::0:pstring (*gdbarch->disassembler_options_names)
+v:const char **:disassembler_options_descriptions:::0:0::0:pstring (*gdbarch->disassembler_options_descriptions)
+
EOF
}
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 07b3ce5..7bc9806 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -339,6 +339,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;
+ char * disassembler_options;
+ const char ** disassembler_options_names;
+ const char ** disassembler_options_descriptions;
};
/* Create a new ``struct gdbarch'' based on information provided by
@@ -696,6 +699,9 @@ 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, invalid_p == 0 */
+ /* Skip verify of disassembler_options_names, invalid_p == 0 */
+ /* Skip verify of disassembler_options_descriptions, invalid_p == 0 */
std::string buf = ui_file_as_string (log);
if (!buf.empty ())
internal_error (__FILE__, __LINE__,
@@ -881,6 +887,15 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: deprecated_function_start_offset = %s\n",
core_addr_to_string_nz (gdbarch->deprecated_function_start_offset));
fprintf_unfiltered (file,
+ "gdbarch_dump: disassembler_options = %s\n",
+ pstring (gdbarch->disassembler_options));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: disassembler_options_descriptions = %s\n",
+ pstring (*gdbarch->disassembler_options_descriptions));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: disassembler_options_names = %s\n",
+ pstring (*gdbarch->disassembler_options_names));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_displaced_step_copy_insn_p() = %d\n",
gdbarch_displaced_step_copy_insn_p (gdbarch));
fprintf_unfiltered (file,
@@ -4962,6 +4977,57 @@ set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch,
gdbarch->addressable_memory_unit_size = addressable_memory_unit_size;
}
+char *
+gdbarch_disassembler_options (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of disassembler_options, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options called\n");
+ return gdbarch->disassembler_options;
+}
+
+void
+set_gdbarch_disassembler_options (struct gdbarch *gdbarch,
+ char * disassembler_options)
+{
+ gdbarch->disassembler_options = disassembler_options;
+}
+
+const char **
+gdbarch_disassembler_options_names (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of disassembler_options_names, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_names called\n");
+ return gdbarch->disassembler_options_names;
+}
+
+void
+set_gdbarch_disassembler_options_names (struct gdbarch *gdbarch,
+ const char ** disassembler_options_names)
+{
+ gdbarch->disassembler_options_names = disassembler_options_names;
+}
+
+const char **
+gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of disassembler_options_descriptions, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_descriptions called\n");
+ return gdbarch->disassembler_options_descriptions;
+}
+
+void
+set_gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch,
+ const char ** disassembler_options_descriptions)
+{
+ gdbarch->disassembler_options_descriptions = disassembler_options_descriptions;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index cc95914..ee82677 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1545,6 +1545,17 @@ typedef int (gdbarch_addressable_memory_unit_size_ftype) (struct gdbarch *gdbarc
extern int gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch);
extern void set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch, gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size);
+/* Functions for allowing a target to modify its disassembler options. */
+
+extern char * gdbarch_disassembler_options (struct gdbarch *gdbarch);
+extern void set_gdbarch_disassembler_options (struct gdbarch *gdbarch, char * disassembler_options);
+
+extern const char ** gdbarch_disassembler_options_names (struct gdbarch *gdbarch);
+extern void set_gdbarch_disassembler_options_names (struct gdbarch *gdbarch, const char ** disassembler_options_names);
+
+extern const char ** gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch);
+extern void set_gdbarch_disassembler_options_descriptions (struct gdbarch *gdbarch, const char ** disassembler_options_descriptions);
+
/* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1)
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 07c3abe..cb039bab 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -18,13 +18,17 @@
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 "cli/cli-decode.h"
#include "source.h"
+#include "safe-ctype.h"
#include <algorithm>
/* Disassemble functions.
@@ -785,6 +789,7 @@ gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
di.endian = gdbarch_byte_order (gdbarch);
di.endian_code = gdbarch_byte_order_for_code (gdbarch);
di.application_data = gdbarch;
+ di.disassembler_options = gdbarch_disassembler_options (gdbarch);
disassemble_init_for_target (&di);
return di;
}
@@ -901,6 +906,8 @@ 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->application_data = gdbarch;
+ di->disassembler_options = gdbarch_disassembler_options (gdbarch);
disassemble_init_for_target (di);
}
@@ -917,3 +924,222 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch,
return gdbarch_print_insn (gdbarch, addr, &di);
}
+
+/* Remove whitespace and consecutive commas from OPTIONS. */
+
+char *
+cleanup_disassembler_options (char *options)
+{
+ char *str;
+ size_t i, len;
+
+ if (options == NULL)
+ return NULL;
+
+ /* Strip off all trailing whitespace and commas. */
+ for (len = strlen (options); len > 0; len--)
+ {
+ if (!ISSPACE (options[len - 1]) && options[len - 1] != ',')
+ break;
+ options[len - 1] = '\0';
+ }
+
+ /* Convert all remaining whitespace to commas. */
+ for (i = 0; options[i] != '\0'; i++)
+ if (ISSPACE (options[i]))
+ options[i] = ',';
+
+ /* Remove consecutive commas. */
+ for (str = options; *str != '\0'; str++)
+ if (*str == ',' && *(str + 1) == ',')
+ {
+ char *next = str++;
+ while (*next == ',')
+ next++;
+ len = strlen (next);
+ memmove (str, next, len);
+ next[len - (size_t)(next - str)] = '\0';
+ }
+ return (strlen (options) != 0) ? options : NULL;
+}
+
+/* Parse OPTIONS looking for ',' seperated disassembler options and
+ verify each option is valid. Return NULL if all options are valid.
+ Otherwise, return a pointer to the first invalid disassembler option. */
+
+static char *
+parse_disassembler_options (const char *options, const char **valid_names)
+{
+ static char opt[256];
+ size_t i;
+
+ if (options == NULL)
+ return NULL;
+
+ while (*options)
+ {
+ /* Copy the current disassembler option into OPT. */
+ const char *separator = strchr (options, ',');
+ if (separator != NULL)
+ {
+ strncpy (opt, options, (size_t) (separator - options));
+ opt[(size_t) (separator - options)] = 0;
+ options = separator;
+ /* Skip to the next disassembler option. */
+ while (*options == ',')
+ options++;
+ }
+ else
+ options = stpcpy (opt, options);
+
+ /* Verify OPT is a valid disassembler option. */
+ for (i = 0; valid_names[i] != NULL; i++)
+ if (strcmp (opt, valid_names[i]) == 0)
+ break;
+ if (valid_names[i] == NULL)
+ return opt;
+ }
+
+ return NULL;
+}
+
+void
+set_disassembler_options (char *args, int from_tty, struct cmd_list_element *c)
+{
+ struct gdbarch *gdbarch = get_current_arch ();
+ const char **valid_names = gdbarch_disassembler_options_names (gdbarch);
+ if (valid_names == NULL)
+ {
+ fprintf_filtered (gdb_stdlog, _("\
+'set disassembler' is not supported on this architecture.\n"));
+ return;
+ }
+
+ char *options = *(char **)c->var;
+ options = cleanup_disassembler_options (options);
+ char *opt = parse_disassembler_options (options, valid_names);
+ if (opt != NULL)
+ {
+ fprintf_filtered (gdb_stdlog,
+ _("Invalid disassembler option value: '%s'.\n"), opt);
+ return;
+ }
+
+ free (gdbarch_disassembler_options (gdbarch));
+ if (options != NULL)
+ set_gdbarch_disassembler_options (gdbarch, xstrdup (options));
+ else
+ set_gdbarch_disassembler_options (gdbarch, NULL);
+}
+
+void
+show_disassembler_options (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ struct gdbarch *gdbarch = get_current_arch ();
+
+ const char *options = gdbarch_disassembler_options (gdbarch);
+ if (options == NULL)
+ options = "";
+
+ fprintf_filtered (file, _("The current disassembler options are '%s'\n"),
+ options);
+
+ const char **names = gdbarch_disassembler_options_names (gdbarch);
+ const char **desc = gdbarch_disassembler_options_descriptions (gdbarch);
+
+ if (names == NULL)
+ return;
+
+ fprintf_filtered (file, _("\n\
+The following disassembler options are supported for use with\n\
+the 'set disassembler-options <option>[,<option>...]' command:\n"));
+
+ if (desc != NULL)
+ {
+ size_t i, max_len = 0;
+ for (i = 0; names[i] != NULL; i++)
+ {
+ size_t len = strlen (names[i]);
+ if (max_len < len)
+ max_len = len;
+ }
+
+ for (i = 0, max_len++; names[i] != NULL; i++)
+ {
+ fprintf_filtered (file, " %s", names[i]);
+ if (desc[i] != NULL)
+ fprintf_filtered (file, "%*c %s",
+ (int)(max_len - strlen (names[i])), ' ',
+ desc[i]);
+ fprintf_filtered (file, "\n");
+ }
+ }
+ else
+ {
+ size_t i, col;
+ for (i = 0, col = 0; names[i] != NULL; i++)
+ {
+ /* Include the " " and "," we print below. */
+ size_t len = strlen (names[i]) + 2;
+ if (col + len > 80)
+ {
+ fprintf_filtered (file, "\n");
+ col = 0;
+ }
+ if (col == 0)
+ fprintf_filtered (file, " %s", names[i]);
+ else
+ fprintf_filtered (file, ", %s", names[i]);
+ col += len;
+ }
+ 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 char **options = gdbarch_disassembler_options_names (gdbarch);
+
+ if (options != NULL)
+ {
+ /* Only attempt to complete on the last option text. */
+ const char *separator = strrchr (text, ',');
+ if (separator != NULL)
+ text = separator + 1;
+ while (ISSPACE (*text))
+ text++;
+ return complete_on_enum (options, text, word);
+ }
+ return NULL;
+}
+
+
+/* Initialization code. */
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_disasm;
+
+void
+_initialize_disasm (void)
+{
+ static char *prospective_options = NULL;
+ 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>\n\n\
+See: show disassembler' for valid option values.\n"), _("\
+Show the disassembler options."), NULL,
+ set_disassembler_options,
+ show_disassembler_options,
+ &setlist, &showlist);
+ set_cmd_completer (cmd, disassembler_options_completer);
+}
diff --git a/gdb/disasm.h b/gdb/disasm.h
index a2b72b9..ec1de8b 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -83,4 +83,8 @@ extern int gdb_buffered_insn_length (struct gdbarch *gdbarch,
const gdb_byte *insn, int max_len,
CORE_ADDR memaddr);
+extern void set_disassembler_options (char *, int, struct cmd_list_element *);
+extern void show_disassembler_options (struct ui_file *, int,
+ struct cmd_list_element *, const char *);
+
#endif
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 5e10893..8262b76 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -6594,6 +6594,9 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
else
register_ppc_ravenscar_ops (gdbarch);
+ set_gdbarch_disassembler_options_names
+ (gdbarch, disassembler_options_names_powerpc ());
+
return gdbarch;
}
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 78fc264..7685977 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -27,6 +27,8 @@
#include "gdbcmd.h"
#include "gdbcore.h"
#include "dis-asm.h" /* For register styles. */
+#include "disasm.h"
+#include "cli/cli-decode.h"
#include "regcache.h"
#include "reggroups.h"
#include "doublest.h"
@@ -210,14 +212,13 @@ static const char *const arm_register_names[] =
/* Valid register name styles. */
static const char **valid_disassembly_styles;
-/* Disassembly style to use. Default to "std" register names. */
-static const char *disassembly_style;
-
/* This is used to keep the bfd arch_info in sync with the disassembly
style. */
static void set_disassembly_style_sfunc(char *, int,
struct cmd_list_element *);
-static void set_disassembly_style (void);
+static void show_disassembly_style_sfunc (struct ui_file *, int,
+ struct cmd_list_element *,
+ const char *);
static void convert_from_extended (const struct floatformat *, const void *,
void *, int);
@@ -8536,9 +8537,27 @@ arm_show_force_mode (struct ui_file *file, int from_tty,
static void
set_disassembly_style_sfunc (char *args, int from_tty,
- struct cmd_list_element *c)
+ struct cmd_list_element *c)
+{
+ /* Convert the short style name into the long style name (eg, reg-names-*)
+ before calling the generic set_disassembler_options() function. */
+ char long_name[256], *style = long_name;
+ snprintf (style, 256, "reg-names-%s", *(char **)c->var);
+ c->var = &style;
+ set_disassembler_options (args, from_tty, c);
+}
+
+static void
+show_disassembly_style_sfunc (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
{
- set_disassembly_style ();
+ struct gdbarch *gdbarch = get_current_arch ();
+ const char *style = gdbarch_disassembler_options (gdbarch);
+ if (style == NULL)
+ style = "default";
+ else if (CONST_STRNEQ (style, "reg-names-"))
+ style += strlen ("reg-names-");
+ fprintf_unfiltered (file, "The disassembly style is \"%s\".\n", style);
}
/* Return the ARM register name corresponding to register I. */
@@ -8579,21 +8598,6 @@ arm_register_name (struct gdbarch *gdbarch, int i)
return arm_register_names[i];
}
-static void
-set_disassembly_style (void)
-{
- int current;
-
- /* Find the style that the user wants. */
- for (current = 0; current < num_disassembly_options; current++)
- if (disassembly_style == valid_disassembly_styles[current])
- break;
- gdb_assert (current < num_disassembly_options);
-
- /* Synchronize the disassembler. */
- set_arm_regname_option (current);
-}
-
/* Test whether the coff symbol specific value corresponds to a Thumb
function. */
@@ -9558,6 +9562,12 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
user_reg_add (gdbarch, arm_register_aliases[i].name,
value_of_arm_user_reg, &arm_register_aliases[i].regnum);
+ set_gdbarch_disassembler_options (gdbarch, xstrdup ("reg-names-std"));
+ set_gdbarch_disassembler_options_names (gdbarch,
+ disassembler_options_names_arm ());
+ set_gdbarch_disassembler_options_descriptions
+ (gdbarch, disassembler_options_desc_arm ());
+
return gdbarch;
}
@@ -9578,6 +9588,9 @@ extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
void
_initialize_arm_tdep (void)
{
+ /* Disassembly style to use. Default to "std" register names. */
+ static const char *disassembly_style;
+
struct ui_file *stb;
long length;
const char *setname;
@@ -9624,9 +9637,6 @@ _initialize_arm_tdep (void)
_("Various ARM-specific commands."),
&showarmcmdlist, "show arm ", 0, &showlist);
- /* Sync the opcode insn printer with our register viewer. */
- parse_arm_disassembler_option ("reg-names-std");
-
/* Initialize the array that will be passed to
add_setshow_enum_cmd(). */
valid_disassembly_styles = XNEWVEC (const char *,
@@ -9638,13 +9648,6 @@ _initialize_arm_tdep (void)
length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
rdptr += length;
rest -= length;
- /* When we find the default names, tell the disassembler to use
- them. */
- if (!strcmp (setname, "std"))
- {
- disassembly_style = setname;
- set_arm_regname_option (i);
- }
}
/* Mark the end of valid options. */
valid_disassembly_styles[num_disassembly_options] = NULL;
@@ -9664,8 +9667,7 @@ _initialize_arm_tdep (void)
_("Show the disassembly style."),
helptext.c_str (),
set_disassembly_style_sfunc,
- NULL, /* FIXME: i18n: The disassembly style is
- \"%s\". */
+ show_disassembly_style_sfunc,
&setarmcmdlist, &showarmcmdlist);
add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c
index 885aadd..f2305c5 100644
--- a/gdb/s390-linux-tdep.c
+++ b/gdb/s390-linux-tdep.c
@@ -8114,6 +8114,11 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
s390_init_linux_record_tdep (&s390_linux_record_tdep, ABI_LINUX_S390);
s390_init_linux_record_tdep (&s390x_linux_record_tdep, ABI_LINUX_ZSERIES);
+ set_gdbarch_disassembler_options_names (gdbarch,
+ disassembler_options_names_s390 ());
+ set_gdbarch_disassembler_options_descriptions
+ (gdbarch, disassembler_options_desc_s390 ());
+
return gdbarch;
}