[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