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

Peter Bergner bergner@vnet.ibm.com
Mon Oct 10 23:28:00 GMT 2016


On 10/7/16 2:21 PM, Ulrich Weigand wrote:
> There's a second use of disassemble_init_for_target, which probably needs
> the same treatment.  In fact, maybe the nicest way would be to call the
> callback "gdbarch_disassemble_init_for_target", with a default of simply
> disassemble_init_for_target, but which targets can override to do extra
> stuff before (or after) calling disassemble_init_for_target in there.
> GDB common code would then just call gdbarch_disassemble_init_for_target
> everywhere it currently calls disassemble_init_for_target.

Ok, I think this resolves all of your last suggestions.  Is this better?

Peter



include/
	* dis-asm.h (ppc_verify_disassembler_options): New prototype.

opcodes/
	* ppc-dis.c (parse_ppc_dis_option): New function.
	(ppc_verify_disassembler_options): Likewise.
	(powerpc_init_dialect): Use parse_ppc_dis_option().

gdb/
	* gdbarch.sh (gdbarch_disassemble_init_for_target): New function.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Likewise.
	* disasm.c (gdb_disassemble_info): Use it.
	(gdb_buffered_insn_length_init_dis): Likewise.
	* rs6000-tdep.c: (gdb_disassembler_cpu): New static declaration.
	(prospective_cpu): Likewise.
	(gdb_disassemble_init_for_ppc): New function.
	(set_disassembler_cpu): Likewise.
	(show_disassembler_cpu): Likewise.
	(rs6000_gdbarch_init): Setup callback for gdb_disassemble_init_for_ppc.
	(_initialize_rs6000_tdep): Setup callbacks for set_disassembler_cpu()
	and show_disassembler_cpu().
	* 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/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,
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 07c3abe..b6d573e 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -785,7 +785,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 +901,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
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4d8ef18..c0ff86b 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -337,6 +337,7 @@ 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;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -443,6 +444,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 +693,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of gcc_target_options, invalid_p == 0 */
   /* Skip verify of gnu_triplet_regexp, invalid_p == 0 */
   /* Skip verify of addressable_memory_unit_size, invalid_p == 0 */
+  /* Skip verify of disassemble_init_for_target, invalid_p == 0 */
   buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
   if (length > 0)
@@ -871,6 +874,9 @@ 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: gdbarch_displaced_step_copy_insn_p() = %d\n",
                       gdbarch_displaced_step_copy_insn_p (gdbarch));
   fprintf_unfiltered (file,
@@ -4918,6 +4924,23 @@ 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;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules.  */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index cd01718..e90931d 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1530,6 +1530,12 @@ 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);
 
+/* Function 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);
+
 /* 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..d0234c1 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1152,6 +1152,9 @@ 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
 
+# Function 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
+
 EOF
 }
 
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index ca4d668..a52e7a9 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -127,6 +127,10 @@ static const char *const powerpc_vector_strings[] =
 static enum powerpc_vector_abi powerpc_vector_abi_global = POWERPC_VEC_AUTO;
 static const char *powerpc_vector_abi_string = "auto";
 
+/* This is the variable that is set with "set powerpc disassembler".  */
+static char *gdb_disassembler_cpu;
+static char *prospective_cpu;
+
 /* To be used by skip_prologue.  */
 
 struct rs6000_framedata
@@ -5924,6 +5928,14 @@ UNKNOWN_OP:
   return 0;
 }
 
+static void
+gdb_disassemble_init_for_ppc (struct gdbarch *gdbarch,
+			      disassemble_info *info)
+{
+  info->disassembler_options = gdb_disassembler_cpu;
+  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 +6609,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   else
     register_ppc_ravenscar_ops (gdbarch);
 
+  set_gdbarch_disassemble_init_for_target (gdbarch, gdb_disassemble_init_for_ppc);
+
   return gdbarch;
 }
 
@@ -6676,6 +6690,32 @@ show_powerpc_exact_watchpoints (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value);
 }
 
+static void
+set_disassembler_cpu (char *args, int from_tty, struct cmd_list_element *c)
+{
+  char *opt;
+  if ((opt = ppc_verify_disassembler_options (prospective_cpu)) != NULL)
+    {
+      fprintf_filtered (gdb_stdlog,
+			_("Invalid disasembler-cpu value: '%s'.\n"), opt);
+      return;
+    }
+  if (gdb_disassembler_cpu)
+    free (gdb_disassembler_cpu);
+  gdb_disassembler_cpu = strdup (prospective_cpu);
+}
+
+static void
+show_disassembler_cpu (struct ui_file *file, int from_tty,
+		       struct cmd_list_element *c, const char *value)
+{
+  const char *cpu = (gdb_disassembler_cpu) ? gdb_disassembler_cpu : "default";
+  fprintf_filtered (file, _("\
+The current disassembler cpu is '%s'\n\n\
+See objdump's -M<cpu> option for the list of supported PPC specific\n\
+disassembler options.\n"), cpu);
+}
+
 /* Read a PPC instruction from memory.  */
 
 static unsigned int
@@ -6796,6 +6836,17 @@ _initialize_rs6000_tdep (void)
 				powerpc_set_soft_float, NULL,
 				&setpowerpccmdlist, &showpowerpccmdlist);
 
+  /* Add the command that controls the disassembler cpu.  */
+  add_setshow_string_cmd ("disassembler", no_class,
+			  &prospective_cpu, _("\
+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_cpu,
+			show_disassembler_cpu,
+			&setpowerpccmdlist, &showpowerpccmdlist);
+
   add_setshow_enum_cmd ("vector-abi", class_support, powerpc_vector_strings,
 			&powerpc_vector_abi_string,
 			_("Set the vector ABI."),
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 05bfa37..15573d9 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -337,6 +337,7 @@ 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 *ppc_verify_disassembler_options (char *);
 
 /* 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..feac2bf 100644
--- a/opcodes/ppc-dis.c
+++ b/opcodes/ppc-dis.c
@@ -271,6 +271,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 *
+ppc_verify_disassembler_options (char *options)
+{
+  static char opt[32];
+  while (options != NULL)
+    {
+      unsigned int i;
+      options = parse_ppc_dis_option (opt, options);
+
+      for (i = 0; ppc_opts[i].opt; 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 +368,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)
+      if ((new_cpu = ppc_parse_cpu (dialect, &sticky, opt)) != 0)
 	dialect = new_cpu;
-      else if (strcmp (arg, "32") == 0)
+      else 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
-	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;





More information about the Binutils mailing list