[PATCH, RFC] Add support for choosing disassembler cpu in GDB for POWER.

Peter Bergner bergner@vnet.ibm.com
Thu Oct 27 00:04:00 GMT 2016


On 10/12/16 3:25 AM, Ulrich Weigand wrote:
> A platform-independent set_disassemble_options() (or whatever it is
> called) command should probably reside in disasm.c, and be installed
> via (a newly added) _initialize_disasm initializer routine there.
> 
> To get at the current gdbarch, you can use get_current_arch ().  This
> function should be rarely used, but the one place where it *is* fine
> is exactly in top-level command implementation routines.

Done.



> Another option might be to refactor the way disassembler options
> output is done in opcodes, e.g. by having platform-specific code
> only provide an array of tuples of option names and explanatory
> strings, and move the actual printing to common code.  Then those
> arrays could be exported to and reused by GDB.  (In particular,
> there's really no way to do a completer without such information.)

How about what I implemented below?



> You need to implement a completer callback and install it for
> your command via set_cmd_completer.  There's a couple of examples
> to look at, but for something like this where there is a predefined
> list of available options, you should probably simply use the
> complete_on_enum helper in your completer, like e.g. done in
> cp_abi_completer.

Done.


On 10/12/16 2:35 PM, Pedro Alves wrote:
> On 10/11/2016 07:48 PM, Peter Bergner wrote:
>> I'm fine going with whatever option name people prefer.  If you want
>> "disassembler-options" instead of just "disassembler", ok, but shouldn't
>> ARM be renamed then as well if it uses this mechanism?
> 
> I think so.  That wouldn't break anyone's scripts, since "disassembler" 
> is an unambiguous prefix of "disassembler-options", and thus gdb
> would still accept "disassembler".

I had a look at ARM's use of "set disassembler".  It isnt' what I thought
it was.  ARM doesn't have a way to change its disassembler cpu (ala -mcpu=...
gas option) anymore than ppc couldn't before this patch.  What ARM's
"set disassembler" is setting is the disassembly style, which I think
is similar to x86's "set disassembly-flavor" command.  When you said
that ARM could use this, were you speaking about adding new support
for changing the disassembler cpu like we're doing here for ppc or
did you want it to set the style using this generic hook?

Peter


include/
	* dis-asm.h (verify_disassembler_options_powerpc): New prototype.
	(num_disassembler_options_powerpc): Likewise.
	(get_disassembler_option_powerpc): Likewise.

opcodes/
	* ppc-dis.c (ppc_opts): Add "32" and "64" entries.
	(num_disassembler_options_powerpc): New function.
	(get_disassembler_option_powerpc): Likewise.
	(parse_ppc_dis_option): Likewise.
	(verify_disassembler_options_powerpc): Likewise.
	(powerpc_init_dialect): Use parse_ppc_dis_option().
	Add break to switch statement.

gdb/
	* gdbarch.sh (gdbarch_disassemble_init_for_target): New function.
	(gdbarch_set_disassembler_options): Likewise.
	(gdbarch_show_disassembler_options): Likewise.
	(gdbarch_disassembler_options_completer): Likewise.
	(gdbarch_disassembler_options): New variable.
	(gdbarch_disassembler_options_enums): New variable.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Likewise.
	* disasm.c: Include "arch-utils.h".
	(gdb_disassemble_info): Use gdbarch_disassemble_init_for_target.
	(gdb_buffered_insn_length_init_dis): Likewise.
	(set_disassembler_options): New static function.
	(show_disassembler_options): Likewise.
	(disassembler_options_completer): Likewise.
	(_initialize_disasm): New function and prototype.
	* rs6000-tdep.c: Include "cli/cli-decode.h".
	(set_disassembler_options): New static functions.
	(show_disassembler_options): Likewise.
	(disassembler_options_completer): Likewise.
	(disassemble_init_for_ppc): New static function.
	(rs6000_gdbarch_init): Setup callbacks for gdb_disassemble_init_for_ppc,
	gdbarch_set_disassembler_options, gdbarch_show_disassembler_options and
	gdbarch_disassembler_options_completer.
	(_initialize_rs6000_tdep): Setup callbacks for set_disassembler_options
	show_disassembler_options and disassembler_options_completer.
	* arch-utils.c: Include "dis-asm.h".
	(default_disassemble_init_for_target): New function.
	* arch-utils.h (default_disassemble_init_for_target): New Prototype.

diff --git a/include/dis-asm.h b/include/dis-asm.h
index 05bfa37..1c83582 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -337,6 +337,10 @@ extern int  get_arm_regnames (int, const char **, const char **, const char *con
 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 char *verify_disassembler_options_powerpc (char *);
+extern size_t num_disassembler_options_powerpc (void);
+extern const char *get_disassembler_option_powerpc (size_t);
+
 
 /* Fetch the disassembler for a given BFD, if that support is available.  */
 extern disassembler_ftype disassembler (bfd *);
diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c
index da1301e..43d858f 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -172,8 +172,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,
@@ -245,6 +249,18 @@ get_powerpc_dialect (struct disassemble_info *info)
     return dialect & ~ PPC_OPCODE_VLE;
 }
 
+size_t
+num_disassembler_options_powerpc (void)
+{
+  return sizeof (ppc_opts) / sizeof (ppc_opts[0]);
+}
+
+const char *
+get_disassembler_option_powerpc (size_t index)
+{
+  return ppc_opts[index].opt;
+}
+
 /* Handle -m and -M options that set cpu type, and .machine arg.  */
 
 ppc_cpu_t
@@ -271,6 +287,50 @@ 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.
+   The first cpu name is copied into CPU and a pointer to the
+   next name is returned or NULL if there are no more cpu names.
+   CPU must contain enough space to hold the cpu name.  */
+
+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;
+}
+
+/* Parse OPTIONS looking for ',' seperated cpu names and verify each name
+   is valid.  Return NULL if all names are valid.  Otherwise, return a
+   pointer to the first invalid cpu name.  */
+
+char *
+verify_disassembler_options_powerpc (char *options)
+{
+  static char opt[32];
+  while (options != NULL)
+    {
+      unsigned int i;
+      options = parse_ppc_dis_option (opt, options);
+
+      for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
+	if (strcmp (ppc_opts[i].opt, opt) == 0)
+	  break;
+      if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0]))
+	return opt;
+    }
+  return NULL;
+}
+
 /* Determine which set of machines to disassemble for.  */
 
 static void
@@ -324,29 +384,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, ',');
-
-      if (end != NULL)
-	*end = 0;
+      char opt[64];
+      arg = parse_ppc_dis_option (opt, arg);
 
-      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;
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 1663156..7217639 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1152,6 +1152,14 @@ 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.
+m:void:disassemble_init_for_target:struct disassemble_info *info:info:0:default_disassemble_init_for_target::0
+M:void:set_disassembler_options:char *args, int from_tty, struct cmd_list_element *c:args, from_tty, c
+M:void:show_disassembler_options:struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value:file, from_tty, c, value
+M:VEC (char_ptr) *:disassembler_options_completer:struct cmd_list_element *ignore,const char *text, const char *word:ignore, text, word
+v:char *:disassembler_options:::0:0::0:pstring (gdbarch->disassembler_options)
+v:const char **:disassembler_options_enums:::0:0::0:pstring (*gdbarch->disassembler_options_enums)
+
 EOF
 }
 
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4d8ef18..558f19f 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -337,6 +337,12 @@ 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;
+  gdbarch_disassemble_init_for_target_ftype *disassemble_init_for_target;
+  gdbarch_set_disassembler_options_ftype *set_disassembler_options;
+  gdbarch_show_disassembler_options_ftype *show_disassembler_options;
+  gdbarch_disassembler_options_completer_ftype *disassembler_options_completer;
+  char * disassembler_options;
+  const char ** disassembler_options_enums;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -443,6 +449,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->gcc_target_options = default_gcc_target_options;
   gdbarch->gnu_triplet_regexp = default_gnu_triplet_regexp;
   gdbarch->addressable_memory_unit_size = default_addressable_memory_unit_size;
+  gdbarch->disassemble_init_for_target = default_disassemble_init_for_target;
   /* gdbarch_alloc() */
 
   return gdbarch;
@@ -691,6 +698,12 @@ 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 disassemble_init_for_target, invalid_p == 0 */
+  /* Skip verify of set_disassembler_options, has predicate.  */
+  /* Skip verify of show_disassembler_options, has predicate.  */
+  /* Skip verify of disassembler_options_completer, has predicate.  */
+  /* Skip verify of disassembler_options, invalid_p == 0 */
+  /* Skip verify of disassembler_options_enums, invalid_p == 0 */
   buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
   if (length > 0)
@@ -871,6 +884,21 @@ 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: disassemble_init_for_target = <%s>\n",
+                      host_address_to_string (gdbarch->disassemble_init_for_target));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: disassembler_options = %s\n",
+                      pstring (gdbarch->disassembler_options));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_disassembler_options_completer_p() = %d\n",
+                      gdbarch_disassembler_options_completer_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: disassembler_options_completer = <%s>\n",
+                      host_address_to_string (gdbarch->disassembler_options_completer));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: disassembler_options_enums = %s\n",
+                      pstring (*gdbarch->disassembler_options_enums));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_displaced_step_copy_insn_p() = %d\n",
                       gdbarch_displaced_step_copy_insn_p (gdbarch));
   fprintf_unfiltered (file,
@@ -1300,9 +1328,21 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: sdb_reg_to_regnum = <%s>\n",
                       host_address_to_string (gdbarch->sdb_reg_to_regnum));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_set_disassembler_options_p() = %d\n",
+                      gdbarch_set_disassembler_options_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: set_disassembler_options = <%s>\n",
+                      host_address_to_string (gdbarch->set_disassembler_options));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: short_bit = %s\n",
                       plongest (gdbarch->short_bit));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_show_disassembler_options_p() = %d\n",
+                      gdbarch_show_disassembler_options_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: show_disassembler_options = <%s>\n",
+                      host_address_to_string (gdbarch->show_disassembler_options));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_single_step_through_delay_p() = %d\n",
                       gdbarch_single_step_through_delay_p (gdbarch));
   fprintf_unfiltered (file,
@@ -4918,6 +4958,129 @@ set_gdbarch_addressable_memory_unit_size (struct gdbarch *gdbarch,
   gdbarch->addressable_memory_unit_size = addressable_memory_unit_size;
 }
 
+void
+gdbarch_disassemble_init_for_target (struct gdbarch *gdbarch, struct disassemble_info *info)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->disassemble_init_for_target != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_disassemble_init_for_target called\n");
+  gdbarch->disassemble_init_for_target (gdbarch, info);
+}
+
+void
+set_gdbarch_disassemble_init_for_target (struct gdbarch *gdbarch,
+                                         gdbarch_disassemble_init_for_target_ftype disassemble_init_for_target)
+{
+  gdbarch->disassemble_init_for_target = disassemble_init_for_target;
+}
+
+int
+gdbarch_set_disassembler_options_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->set_disassembler_options != NULL;
+}
+
+void
+gdbarch_set_disassembler_options (struct gdbarch *gdbarch, char *args, int from_tty, struct cmd_list_element *c)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->set_disassembler_options != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_set_disassembler_options called\n");
+  gdbarch->set_disassembler_options (gdbarch, args, from_tty, c);
+}
+
+void
+set_gdbarch_set_disassembler_options (struct gdbarch *gdbarch,
+                                      gdbarch_set_disassembler_options_ftype set_disassembler_options)
+{
+  gdbarch->set_disassembler_options = set_disassembler_options;
+}
+
+int
+gdbarch_show_disassembler_options_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->show_disassembler_options != NULL;
+}
+
+void
+gdbarch_show_disassembler_options (struct gdbarch *gdbarch, struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->show_disassembler_options != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_show_disassembler_options called\n");
+  gdbarch->show_disassembler_options (gdbarch, file, from_tty, c, value);
+}
+
+void
+set_gdbarch_show_disassembler_options (struct gdbarch *gdbarch,
+                                       gdbarch_show_disassembler_options_ftype show_disassembler_options)
+{
+  gdbarch->show_disassembler_options = show_disassembler_options;
+}
+
+int
+gdbarch_disassembler_options_completer_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->disassembler_options_completer != NULL;
+}
+
+VEC (char_ptr) *
+gdbarch_disassembler_options_completer (struct gdbarch *gdbarch, struct cmd_list_element *ignore,const char *text, const char *word)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->disassembler_options_completer != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_completer called\n");
+  return gdbarch->disassembler_options_completer (gdbarch, ignore, text, word);
+}
+
+void
+set_gdbarch_disassembler_options_completer (struct gdbarch *gdbarch,
+                                            gdbarch_disassembler_options_completer_ftype disassembler_options_completer)
+{
+  gdbarch->disassembler_options_completer = disassembler_options_completer;
+}
+
+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_enums (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  /* Skip verify of disassembler_options_enums, invalid_p == 0 */
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_disassembler_options_enums called\n");
+  return gdbarch->disassembler_options_enums;
+}
+
+void
+set_gdbarch_disassembler_options_enums (struct gdbarch *gdbarch,
+                                        const char ** disassembler_options_enums)
+{
+  gdbarch->disassembler_options_enums = disassembler_options_enums;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules.  */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index cd01718..9cac65d 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1530,6 +1530,36 @@ 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. */
+
+typedef void (gdbarch_disassemble_init_for_target_ftype) (struct gdbarch *gdbarch, struct disassemble_info *info);
+extern void gdbarch_disassemble_init_for_target (struct gdbarch *gdbarch, struct disassemble_info *info);
+extern void set_gdbarch_disassemble_init_for_target (struct gdbarch *gdbarch, gdbarch_disassemble_init_for_target_ftype *disassemble_init_for_target);
+
+extern int gdbarch_set_disassembler_options_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_set_disassembler_options_ftype) (struct gdbarch *gdbarch, char *args, int from_tty, struct cmd_list_element *c);
+extern void gdbarch_set_disassembler_options (struct gdbarch *gdbarch, char *args, int from_tty, struct cmd_list_element *c);
+extern void set_gdbarch_set_disassembler_options (struct gdbarch *gdbarch, gdbarch_set_disassembler_options_ftype *set_disassembler_options);
+
+extern int gdbarch_show_disassembler_options_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_show_disassembler_options_ftype) (struct gdbarch *gdbarch, struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value);
+extern void gdbarch_show_disassembler_options (struct gdbarch *gdbarch, struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value);
+extern void set_gdbarch_show_disassembler_options (struct gdbarch *gdbarch, gdbarch_show_disassembler_options_ftype *show_disassembler_options);
+
+extern int gdbarch_disassembler_options_completer_p (struct gdbarch *gdbarch);
+
+typedef VEC (char_ptr) * (gdbarch_disassembler_options_completer_ftype) (struct gdbarch *gdbarch, struct cmd_list_element *ignore,const char *text, const char *word);
+extern VEC (char_ptr) * gdbarch_disassembler_options_completer (struct gdbarch *gdbarch, struct cmd_list_element *ignore,const char *text, const char *word);
+extern void set_gdbarch_disassembler_options_completer (struct gdbarch *gdbarch, gdbarch_disassembler_options_completer_ftype *disassembler_options_completer);
+
+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_enums (struct gdbarch *gdbarch);
+extern void set_gdbarch_disassembler_options_enums (struct gdbarch *gdbarch, const char ** disassembler_options_enums);
+
 /* 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..e8dfe44 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -18,11 +18,13 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "arch-utils.h"
 #include "target.h"
 #include "value.h"
 #include "ui-out.h"
 #include "disasm.h"
 #include "gdbcore.h"
+#include "gdbcmd.h"
 #include "dis-asm.h"
 #include "source.h"
 #include <algorithm>
@@ -785,7 +787,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;
-  disassemble_init_for_target (&di);
+  gdbarch_disassemble_init_for_target (gdbarch, &di);
   return di;
 }
 
@@ -901,7 +903,7 @@ gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
   di->endian = gdbarch_byte_order (gdbarch);
   di->endian_code = gdbarch_byte_order_for_code (gdbarch);
 
-  disassemble_init_for_target (di);
+  gdbarch_disassemble_init_for_target (gdbarch, di);
 }
 
 /* Return the length in bytes of INSN.  MAX_LEN is the size of the
@@ -917,3 +919,66 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch,
 
   return gdbarch_print_insn (gdbarch, addr, &di);
 }
+
+static void
+set_disassembler_options (char *args, int from_tty, struct cmd_list_element *c)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  if (gdbarch_set_disassembler_options_p (gdbarch))
+    {
+      gdbarch_set_disassembler_options (gdbarch, args, from_tty, c);
+      return;
+    }
+  fprintf_filtered (gdb_stdlog, _("\
+'set disassembler' is not supported on this architecture.\n"));
+}
+
+static 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 ();
+  if (gdbarch_show_disassembler_options_p (gdbarch))
+    {
+      gdbarch_show_disassembler_options (gdbarch, file, from_tty, c, value);
+      return;
+    }
+  fprintf_filtered (gdb_stdlog, _("\
+'show disassembler' is not supported on this architecture.\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 ();
+  if (gdbarch_disassembler_options_completer_p (gdbarch))
+    return gdbarch_disassembler_options_completer (gdbarch, ignore, 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/rs6000-tdep.c b/gdb/rs6000-tdep.c
index ca4d668..34a8f69 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -42,6 +42,7 @@
 #include "user-regs.h"
 #include "record-full.h"
 #include "auxv.h"
+#include "cli/cli-decode.h"
 
 #include "coff/internal.h"	/* for libcoff.h */
 #include "libcoff.h"		/* for xcoff_data */
@@ -5924,6 +5925,126 @@ UNKNOWN_OP:
   return 0;
 }
 
+static void
+set_disassembler_options (struct gdbarch *gdbarch, char *args,
+			  int from_tty, struct cmd_list_element *c)
+{
+  char *options = *(char **)c->var;
+  size_t len;
+
+  /* Strip trailing whitespace.  */
+  for (len = strlen (options); len > 0; len--)
+    {
+      if (options[len - 1] != ' ' && options[len - 1] != '\t')
+	break;
+      options[len - 1] = '\0';
+    }
+
+  if (len > 0)
+    {
+      char *opt = verify_disassembler_options_powerpc (options);
+      if (opt != NULL)
+	{
+	  fprintf_filtered (gdb_stdlog,
+			    _("Invalid disassembler option value: '%s'.\n"),
+			    opt);
+	  return;
+	}
+      options = strdup (options);
+    }
+  else
+    options = NULL;
+
+  free (gdbarch_disassembler_options (gdbarch));
+  set_gdbarch_disassembler_options (gdbarch, options);
+}
+
+static void
+set_disassembler_options (char *args, int from_tty, struct cmd_list_element *c)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  set_disassembler_options (gdbarch, args, from_tty, c);
+}
+
+static void
+show_disassembler_options (struct gdbarch *gdbarch, struct ui_file *file,
+			   int from_tty, struct cmd_list_element *c,
+			   const char *value)
+{
+  size_t i, col;
+  size_t n = num_disassembler_options_powerpc ();
+  const char *cpu = gdbarch_disassembler_options (gdbarch);
+  if (cpu == NULL)
+    cpu = "default";
+
+  fprintf_filtered (file, _("\
+The current disassembler cpu is '%s'\n\n\
+The following cpus are supported:\n"), cpu);
+
+  for (col = 0, i = 0; i < n; i++)
+    {
+      const char *opt = get_disassembler_option_powerpc (i);
+      fprintf_filtered (file, " %s,", opt);
+      col += strlen (opt) + 2;
+      if (col > 66)
+        {
+          fprintf_filtered (file, "\n");
+          col = 0;
+        }
+    }
+  fprintf_filtered (file, "\n");
+
+}
+
+static 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 ();
+  show_disassembler_options (gdbarch, file, from_tty, c, value);
+}
+
+/* A completion function for "set disassembler <options>".  */
+
+static VEC (char_ptr) *
+disassembler_options_completer (struct gdbarch *gdbarch,
+				struct cmd_list_element *ignore,
+				const char *text, const char *word)
+{
+  const char **enums = gdbarch_disassembler_options_enums (gdbarch);
+
+  if (enums == NULL)
+    {
+      size_t i;
+      size_t n = num_disassembler_options_powerpc ();
+
+      enums = XNEWVEC (const char *, n + 1);
+      for (i = 0; i < n; ++i)
+	enums[i] = get_disassembler_option_powerpc (i);
+      enums[i] = NULL;
+      set_gdbarch_disassembler_options_enums (gdbarch, enums);
+    }
+
+  return complete_on_enum (enums, text, word);
+}
+
+/* A completion function for "set powerpc disassembler <options>".  */
+
+static VEC (char_ptr) *
+disassembler_options_completer (struct cmd_list_element *ignore,
+				const char *text, const char *word)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  return disassembler_options_completer (gdbarch, ignore, text, word);
+}
+
+static void
+disassemble_init_for_ppc (struct gdbarch *gdbarch, disassemble_info *info)
+{
+  info->disassembler_options = gdbarch_disassembler_options (gdbarch);
+  disassemble_init_for_target (info);
+}
+
 /* Initialize the current architecture based on INFO.  If possible, re-use an
    architecture from ARCHES, which is a list of architectures already created
    during this debugging session.
@@ -6597,6 +6718,11 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   else
     register_ppc_ravenscar_ops (gdbarch);
 
+  set_gdbarch_disassemble_init_for_target (gdbarch, disassemble_init_for_ppc);
+  set_gdbarch_set_disassembler_options (gdbarch, set_disassembler_options);
+  set_gdbarch_show_disassembler_options (gdbarch, show_disassembler_options);
+  set_gdbarch_disassembler_options_completer (gdbarch,
+					      disassembler_options_completer);
   return gdbarch;
 }
 
@@ -6753,6 +6879,9 @@ extern initialize_file_ftype _initialize_rs6000_tdep;
 void
 _initialize_rs6000_tdep (void)
 {
+  static char *prospective_options = NULL;
+  struct cmd_list_element *cmd;
+
   gdbarch_register (bfd_arch_rs6000, rs6000_gdbarch_init, rs6000_dump_tdep);
   gdbarch_register (bfd_arch_powerpc, rs6000_gdbarch_init, rs6000_dump_tdep);
 
@@ -6796,6 +6925,19 @@ _initialize_rs6000_tdep (void)
 				powerpc_set_soft_float, NULL,
 				&setpowerpccmdlist, &showpowerpccmdlist);
 
+  /* Add the command that controls the disassembler options.  */
+  cmd = add_setshow_string_noescape_cmd ("disassembler-options", no_class,
+					 &prospective_options, _("\
+Set the disassembler cpu.\n\
+Usage: set powerpc disassembler <cpu>[,<cpu>]*\n\
+See objdump's -M option for the valid <cpu> names."), _("\
+Show the disassembler cpu."), NULL,
+					 set_disassembler_options,
+					 show_disassembler_options,
+					 &setpowerpccmdlist,
+					 &showpowerpccmdlist);
+  set_cmd_completer (cmd, disassembler_options_completer);
+
   add_setshow_enum_cmd ("vector-abi", class_support, powerpc_vector_strings,
 			&powerpc_vector_abi_string,
 			_("Set the vector ABI."),
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index 776dabc..68fc610 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -32,6 +32,7 @@
 #include "objfiles.h"
 #include "language.h"
 #include "symtab.h"
+#include "dis-asm.h"
 
 #include "version.h"
 
@@ -931,6 +932,15 @@ default_addressable_memory_unit_size (struct gdbarch *gdbarch)
   return 1;
 }
 
+/* Default method for gdbarch_disassemble_init_for_target.  */
+
+void
+default_disassemble_init_for_target (struct gdbarch *gdbarch,
+				     struct disassemble_info *info)
+{
+  disassemble_init_for_target (info);
+}
+
 void
 default_guess_tracepoint_registers (struct gdbarch *gdbarch,
 				    struct regcache *regcache,
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index bbb0878..94da918 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -211,6 +211,8 @@ extern void default_infcall_munmap (CORE_ADDR addr, CORE_ADDR size);
 extern char *default_gcc_target_options (struct gdbarch *gdbarch);
 extern const char *default_gnu_triplet_regexp (struct gdbarch *gdbarch);
 extern int default_addressable_memory_unit_size (struct gdbarch *gdbarch);
+extern void default_disassemble_init_for_target (struct gdbarch *,
+						 struct disassemble_info *);
 
 extern void default_guess_tracepoint_registers (struct gdbarch *gdbarch,
 						struct regcache *regcache,






More information about the Binutils mailing list