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]

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


On 10/28/16 1:47 PM, Ulrich Weigand wrote:
> Peter Bergner wrote:
>> On 10/28/16 9:15 AM, Ulrich Weigand wrote:
>>> It's probably not that important to exactly match objdump
>>> behavior here.  B.t.w. how do you even enter a space as
>>> separator with the -M option?
>>
>> bergner@genoa:~$ objdump -d -M'power5 power6' wait.o  | grep warning
>> warning: ignoring unknown -Mpower5 power6 option
> 
> OK, well :-)  As I said, it's probably not important to
> exactly match *this* detail in the GDB command ...

I actually ended up adding code to clean up white space and
extra commas (ala ARM's arm-dis.c handling).  I did this for
two reasons.  The first reason is that tab completion seems
to add some white space to the end of the disassembler option
and that was causing us to not match the expected string.
Secondly, I wanted a way for the user to go back to the default
(ie, NULL) disassembler option.  I could only do that first I
removed white space.  I added the comma cleanup since it was
easy.

I'll note I modified the completion function slightly.
On POWER, a disassembler_option value of "power8,any" is valid.
If I have typed "power8,a" and hit tab, I wasn't getting any
completions.  I modified the completion to complete only on
the text after the last ',', which allows me to complete "a"
to "any", even if I have "power8,a".



>> But not all arches have descriptions paired with the option name.
>> Looking at Pedro's objdump output from before:

[snip]

> Hmm, I see.  I guess we could have NULL description string for those,
> and then the common printing routine could choose the compact output ...

Ok, if an architecture registers a descriptions array, then they
get the long form.  Otherwise, we emit a compact form.

I ported ppc, arm and s390 over to use the new support.
S390 was fairly easy, but I had to modify the initialization
code in s390-dis.c, since the current code has no way to rest
the current_arch_mask and option_use_insn_len_bits_p values.
Without the current code, I was able to set and change them,
but there was no way to go back to the default values.

ARM was a little trickier, since it already has a "set arm disassembler"
command.  I had to make both commands set the same gdbarch value.
Note that the "set disassenbler-options ..." command uses long reg names
(eg, reg-names-std) rather than the short (eg, "std") names that
the "set arm disassembler ..." option uses.  I had to do this, since
arm-dis.c expects the info->disassembler_options string to contain
long names.  

How does this iteration of the patch look?

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/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 645825f..acdd0bb 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"
@@ -217,14 +219,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);
@@ -8508,9 +8509,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.  */
@@ -8551,21 +8570,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.  */
 
@@ -9529,6 +9533,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;
 }
 
@@ -9549,6 +9559,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;
@@ -9595,9 +9608,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 *,
@@ -9609,13 +9619,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;
@@ -9635,8 +9638,7 @@ _initialize_arm_tdep (void)
 		       _("Show the disassembly style."),
 		       helptext,
 		       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/disasm.c b/gdb/disasm.c
index 07c3abe..9a3d6af 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 = "default";
+
+  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/gdbarch.c b/gdb/gdbarch.c
index 4d8ef18..60a8a2c 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -337,6 +337,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
@@ -691,6 +694,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 */
   buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
   if (length > 0)
@@ -871,6 +877,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,
@@ -4918,6 +4933,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 cd01718..9d004e3 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1530,6 +1530,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/gdbarch.sh b/gdb/gdbarch.sh
index 1663156..aa2bf4f 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1152,6 +1152,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/rs6000-tdep.c b/gdb/rs6000-tdep.c
index ca4d668..7a36caf 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -6597,6 +6597,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/s390-linux-tdep.c b/gdb/s390-linux-tdep.c
index 399084a..c6f194f 100644
--- a/gdb/s390-linux-tdep.c
+++ b/gdb/s390-linux-tdep.c
@@ -8121,6 +8121,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;
 }
 
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 05bfa37..88dc67a 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -329,14 +329,18 @@ extern void print_mips_disassembler_options (FILE *);
 extern void print_ppc_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/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/disassemble.c b/opcodes/disassemble.c
index 45ae34e..bb45d5a 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -635,6 +635,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/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);
 }


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