This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/2] Add support for setting disassembler-options in GDB for POWER, ARM and S390


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;
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]