size_t buffer_length;
/* This variable may be set by the instruction decoder. It suggests
- the number of bytes objdump should display on a single line. If
- the instruction decoder sets this, it should always set it to
- the same value in order to get reasonable looking output. */
+ the number of bytes objdump should display on a single line. If
+ the instruction decoder sets this, it should always set it to
+ the same value in order to get reasonable looking output. */
int bytes_per_line;
/* The next two variables control the way objdump displays the raw data. */
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
- /* Command line options specific to the target disassembler. */
+ /* Command line options specific to the target disassembler.
+ Note that if this string contains multiple comma-separated
+ options, then it must not be in read-only memory. Commas may be
+ temporarily modified by the target disassembler when parsing
+ options. The string is const in the sense that on return from
+ the target disassembler the string will be exactly the same as
+ on entry. */
const char *disassembler_options;
/* If non-zero then try not disassemble beyond this address, even if
/* Remove whitespace and consecutive commas. */
extern char *remove_whitespace_and_extra_commas (char *);
-/* Like STRCMP, but treat ',' the same as '\0' so that we match
- strings like "foobar" against "foobar,xxyyzz,...". */
-extern int disassembler_options_cmp (const char *, const char *);
-
-/* A helper function for FOR_EACH_DISASSEMBLER_OPTION. */
-static inline const char *
-next_disassembler_option (const char *options)
-{
- const char *opt = strchr (options, ',');
- if (opt != NULL)
- opt++;
- return opt;
-}
-
-/* A macro for iterating over each comma separated option in OPTIONS. */
-#define FOR_EACH_DISASSEMBLER_OPTION(OPT, OPTIONS) \
- for ((OPT) = (OPTIONS); \
- (OPT) != NULL; \
- (OPT) = next_disassembler_option (OPT))
-
+/* Iterate over each comma separated option in disassembler_options. */
+extern bool for_each_disassembler_option (struct disassemble_info *,
+ bool (*) (const char *, void *),
+ void *);
\f
/* This block of definitions is for particular callers who read instructions
into a buffer before calling the instruction decoder. */
static void
parse_option (struct arc_disassemble_info *arc_infop, const char *option)
{
- if (disassembler_options_cmp (option, "dsp") == 0)
+ if (strcmp (option, "dsp") == 0)
add_to_decode (arc_infop, DSP, NONE);
- else if (disassembler_options_cmp (option, "spfp") == 0)
+ else if (strcmp (option, "spfp") == 0)
add_to_decode (arc_infop, FLOAT, SPX);
- else if (disassembler_options_cmp (option, "dpfp") == 0)
+ else if (strcmp (option, "dpfp") == 0)
add_to_decode (arc_infop, FLOAT, DPX);
- else if (disassembler_options_cmp (option, "quarkse_em") == 0)
+ else if (strcmp (option, "quarkse_em") == 0)
{
add_to_decode (arc_infop, FLOAT, DPX);
add_to_decode (arc_infop, FLOAT, SPX);
add_to_decode (arc_infop, FLOAT, QUARKSE2);
}
- else if (disassembler_options_cmp (option, "fpuda") == 0)
+ else if (strcmp (option, "fpuda") == 0)
add_to_decode (arc_infop, FLOAT, DPA);
- else if (disassembler_options_cmp (option, "nps400") == 0)
+ else if (strcmp (option, "nps400") == 0)
{
add_to_decode (arc_infop, ACL, NPS400);
add_to_decode (arc_infop, ARITH, NPS400);
add_to_decode (arc_infop, ULTRAIP, NPS400);
}
- else if (disassembler_options_cmp (option, "fpus") == 0)
+ else if (strcmp (option, "fpus") == 0)
{
add_to_decode (arc_infop, FLOAT, SP);
add_to_decode (arc_infop, FLOAT, CVT);
}
- else if (disassembler_options_cmp (option, "fpud") == 0)
+ else if (strcmp (option, "fpud") == 0)
{
add_to_decode (arc_infop, FLOAT, DP);
add_to_decode (arc_infop, FLOAT, CVT);
int i;
for (i = 0; cpu_types[i].name; ++i)
- {
- if (!disassembler_options_cmp (cpu_types[i].name, option))
- {
- return cpu_types[i].flags;
- }
- }
+ if (strcmp (cpu_types[i].name, option) == 0)
+ return cpu_types[i].flags;
/* xgettext:c-format */
opcodes_error_handler (_("unrecognised disassembler CPU option: %s"), option);
return ARC_OPCODE_NONE;
}
+static bool
+arc_parse_option (const char *option, void *data)
+{
+ struct arc_disassemble_info *arc_infop = data;
+
+ if (strncmp (option, "cpu=", 4) == 0)
+ /* Strip leading `cpu=`. */
+ arc_infop->isa_mask = parse_cpu_option (option + 4);
+ else
+ parse_option (arc_infop, option);
+ return true;
+}
+
/* Go over the options list and parse it. */
static void
parse_disassembler_options (struct disassemble_info *info)
{
struct arc_disassemble_info *arc_infop = info->private_data;
- const char *option;
arc_infop->isa_mask = ARC_OPCODE_NONE;
- FOR_EACH_DISASSEMBLER_OPTION (option, info->disassembler_options)
- {
- /* A CPU option? Cannot use STRING_COMMA_LEN because strncmp is also a
- preprocessor macro. */
- if (strncmp (option, "cpu=", 4) == 0)
- /* Strip leading `cpu=`. */
- arc_infop->isa_mask = parse_cpu_option (option + 4);
- else
- parse_option (arc_infop, option);
- }
+ for_each_disassembler_option (info, arc_parse_option, arc_infop);
/* Figure out CPU type, unless it was enforced via disassembler options. */
if (arc_infop->isa_mask == ARC_OPCODE_NONE)
return (name && *name != '$' && strncmp (name, "__tagsym$$", 10));
}
-/* Parse the string of disassembler options. */
+/* Parse a disassembler option. */
-static void
-parse_arm_disassembler_options (const char *options)
+static bool
+arm_parse_option (const char *opt, void *data ATTRIBUTE_UNUSED)
{
- const char *opt;
-
- force_thumb = false;
- FOR_EACH_DISASSEMBLER_OPTION (opt, options)
+ if (startswith (opt, "reg-names-"))
{
- if (startswith (opt, "reg-names-"))
- {
- unsigned int i;
- for (i = 0; i < NUM_ARM_OPTIONS; i++)
- if (disassembler_options_cmp (opt, regnames[i].name) == 0)
- {
- regname_selected = i;
- break;
- }
+ unsigned int i;
+ for (i = 0; i < NUM_ARM_OPTIONS; i++)
+ if (strcmp (opt, regnames[i].name) == 0)
+ {
+ regname_selected = i;
+ break;
+ }
- if (i >= NUM_ARM_OPTIONS)
- /* xgettext: c-format */
- opcodes_error_handler (_("unrecognised register name set: %s"),
- opt);
- }
- else if (startswith (opt, "force-thumb"))
- force_thumb = 1;
- else if (startswith (opt, "no-force-thumb"))
- force_thumb = 0;
- else if (startswith (opt, "coproc"))
+ if (i >= NUM_ARM_OPTIONS)
+ /* xgettext: c-format */
+ opcodes_error_handler (_("unrecognised register name set: %s"),
+ opt);
+ }
+ else if (startswith (opt, "force-thumb"))
+ force_thumb = 1;
+ else if (startswith (opt, "no-force-thumb"))
+ force_thumb = 0;
+ else if (startswith (opt, "coproc"))
+ {
+ const char *procptr = opt + sizeof ("coproc") - 1;
+ char *endptr;
+ uint8_t coproc_number = strtol (procptr, &endptr, 10);
+ if (endptr != procptr + 1 || coproc_number > 7)
+ opcodes_error_handler (_("cde coprocessor not between 0-7: %s"),
+ opt);
+ else if (*endptr != '=')
+ opcodes_error_handler (_("coproc must have an argument: %s"),
+ opt);
+ else
{
- const char *procptr = opt + sizeof ("coproc") - 1;
- char *endptr;
- uint8_t coproc_number = strtol (procptr, &endptr, 10);
- if (endptr != procptr + 1 || coproc_number > 7)
- {
- opcodes_error_handler (_("cde coprocessor not between 0-7: %s"),
- opt);
- continue;
- }
- if (*endptr != '=')
- {
- opcodes_error_handler (_("coproc must have an argument: %s"),
- opt);
- continue;
- }
endptr += 1;
if (startswith (endptr, "generic"))
cde_coprocs &= ~(1 << coproc_number);
|| startswith (endptr, "CDE"))
cde_coprocs |= (1 << coproc_number);
else
- {
- opcodes_error_handler (
- _("coprocN argument takes options \"generic\","
- " \"cde\", or \"CDE\": %s"), opt);
- }
+ opcodes_error_handler
+ (_("coprocN argument takes options \"generic\","
+ " \"cde\", or \"CDE\": %s"), opt);
}
- else
- /* xgettext: c-format */
- opcodes_error_handler (_("unrecognised disassembler option: %s"), opt);
}
-
- return;
+ else
+ /* xgettext: c-format */
+ opcodes_error_handler (_("unrecognised disassembler option: %s"), opt);
+ return true;
}
static bool
if (info->disassembler_options)
{
- parse_arm_disassembler_options (info->disassembler_options);
+ force_thumb = false;
+ for_each_disassembler_option (info, arm_parse_option, NULL);
/* To avoid repeated parsing of these options, we remove them here. */
info->disassembler_options = NULL;
return print_insn_csky;
}
-/* Parse the string of disassembler options. */
-static void
-parse_csky_dis_options (const char *opts_in)
+/* Parse a disassembler option. */
+static bool
+parse_csky_option (const char *opt, void *data ATTRIBUTE_UNUSED)
{
- char *opts = xstrdup (opts_in);
- char *opt = opts;
- char *opt_end = opts;
-
- for (; opt_end != NULL; opt = opt_end + 1)
- {
- if ((opt_end = strchr (opt, ',')) != NULL)
- *opt_end = 0;
- if (strcmp (opt, "abi-names") == 0)
- using_abi = 1;
- else
- fprintf (stderr,
- "unrecognized disassembler option: %s", opt);
- }
- free (opts);
+ if (strcmp (opt, "abi-names") == 0)
+ using_abi = 1;
+ else
+ fprintf (stderr, "unrecognized disassembler option: %s", opt);
+ return true;
}
/* Get general register name. */
if (info->disassembler_options)
{
- parse_csky_dis_options (info->disassembler_options);
+ for_each_disassembler_option (info, parse_csky_option, NULL);
info->disassembler_options = NULL;
}
return (strlen (options) != 0) ? options : NULL;
}
-/* Like STRCMP, but treat ',' the same as '\0' so that we match
- strings like "foobar" against "foobar,xxyyzz,...". */
+/* Call FUNC for each comma separated option in INFO->disassembler_options,
+ passing a zero terminated option and DATA. The iteration terminates
+ should FUNC return false. */
-int
-disassembler_options_cmp (const char *s1, const char *s2)
+bool
+for_each_disassembler_option (struct disassemble_info *info,
+ bool (*func) (const char *, void *),
+ void *data)
{
- unsigned char c1, c2;
-
- do
- {
- c1 = (unsigned char) *s1++;
- if (c1 == ',')
- c1 = '\0';
- c2 = (unsigned char) *s2++;
- if (c2 == ',')
- c2 = '\0';
- if (c1 == '\0')
- return c1 - c2;
- }
- while (c1 == c2);
-
- return c1 - c2;
+ char *opt = (char *) info->disassembler_options;
+ bool ok = true;
+ if (opt != NULL)
+ while (ok)
+ {
+ char *opt_end = strchr (opt, ',');
+ if (opt_end != NULL)
+ *opt_end = 0;
+ ok = func (opt, data);
+ if (opt_end == NULL)
+ break;
+ *opt_end = ',';
+ opt = opt_end + 1;
+ }
+ return ok;
}
void
return true;
}
+static bool
+nfp_parse_option (const char *option, void *data)
+{
+ nfp_opts *opts = data;
+
+ if (strcmp (option, "no-pc") == 0)
+ opts->show_pc = 0;
+ else if (strcmp (option, "ctx4") == 0)
+ {
+ if (!opts->ctx_mode)
+ opts->ctx_mode = 4;
+ }
+ else if (strcmp (option, "ctx8") == 0)
+ opts->ctx_mode = 8;
+ else
+ {
+ opcodes_error_handler (_("invalid NFP option: %s"), option);
+ return false;
+ }
+ return true;
+}
+
static int
parse_disassembler_options (nfp_opts * opts, struct disassemble_info *dinfo)
{
- const char *option;
-
- if (dinfo->disassembler_options == NULL)
- return 0;
-
- FOR_EACH_DISASSEMBLER_OPTION (option, dinfo->disassembler_options)
- {
- if (disassembler_options_cmp (option, "no-pc") == 0)
- opts->show_pc = 0;
- else if (disassembler_options_cmp (option, "ctx4") == 0)
- {
- if (!opts->ctx_mode)
- opts->ctx_mode = 4;
- }
- else if (disassembler_options_cmp (option, "ctx8") == 0)
- opts->ctx_mode = 8;
- else
- {
- dinfo->fprintf_func (dinfo->stream, _("Invalid NFP option: %s"), option);
- return _NFP_ERR_STOP;
- }
- }
+ if (!for_each_disassembler_option (dinfo, nfp_parse_option, opts))
+ return _NFP_ERR_STOP;
return 0;
}
unsigned int i;
for (i = 0; i < ARRAY_SIZE (ppc_opts); i++)
- if (disassembler_options_cmp (ppc_opts[i].opt, arg) == 0)
+ if (strcmp (ppc_opts[i].opt, arg) == 0)
{
if (ppc_opts[i].sticky)
{
return ppc_cpu;
}
+struct ppc_parse_data
+{
+ ppc_cpu_t dialect;
+ ppc_cpu_t sticky;
+};
+
+static bool
+ppc_parse_option (const char *opt, void *data)
+{
+ struct ppc_parse_data *res = data;
+ ppc_cpu_t new_cpu;
+
+ if (strcmp (opt, "32") == 0)
+ res->dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
+ else if (strcmp (opt, "64") == 0)
+ res->dialect |= PPC_OPCODE_64;
+ else if ((new_cpu = ppc_parse_cpu (res->dialect, &res->sticky, opt)) != 0)
+ res->dialect = new_cpu;
+ else
+ /* xgettext: c-format */
+ opcodes_error_handler (_("warning: ignoring unknown -M%s option"), opt);
+ return true;
+}
+
/* Determine which set of machines to disassemble for. */
static void
powerpc_init_dialect (struct disassemble_info *info)
{
- ppc_cpu_t dialect = 0;
- ppc_cpu_t sticky = 0;
+ struct ppc_parse_data out = { 0, 0 };
struct dis_private *priv = calloc (1, sizeof (*priv));
if (priv == NULL)
{
case bfd_mach_ppc_403:
case bfd_mach_ppc_403gc:
- dialect = ppc_parse_cpu (dialect, &sticky, "403");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "403");
break;
case bfd_mach_ppc_405:
- dialect = ppc_parse_cpu (dialect, &sticky, "405");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "405");
break;
case bfd_mach_ppc_601:
- dialect = ppc_parse_cpu (dialect, &sticky, "601");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "601");
break;
case bfd_mach_ppc_750:
- dialect = ppc_parse_cpu (dialect, &sticky, "750cl");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "750cl");
break;
case bfd_mach_ppc_a35:
case bfd_mach_ppc_rs64ii:
case bfd_mach_ppc_rs64iii:
- dialect = ppc_parse_cpu (dialect, &sticky, "pwr2") | PPC_OPCODE_64;
+ out.dialect = (ppc_parse_cpu (out.dialect, &out.sticky, "pwr2")
+ | PPC_OPCODE_64);
break;
case bfd_mach_ppc_e500:
- dialect = ppc_parse_cpu (dialect, &sticky, "e500");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e500");
break;
case bfd_mach_ppc_e500mc:
- dialect = ppc_parse_cpu (dialect, &sticky, "e500mc");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e500mc");
break;
case bfd_mach_ppc_e500mc64:
- dialect = ppc_parse_cpu (dialect, &sticky, "e500mc64");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e500mc64");
break;
case bfd_mach_ppc_e5500:
- dialect = ppc_parse_cpu (dialect, &sticky, "e5500");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e5500");
break;
case bfd_mach_ppc_e6500:
- dialect = ppc_parse_cpu (dialect, &sticky, "e6500");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e6500");
break;
case bfd_mach_ppc_titan:
- dialect = ppc_parse_cpu (dialect, &sticky, "titan");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "titan");
break;
case bfd_mach_ppc_vle:
- dialect = ppc_parse_cpu (dialect, &sticky, "vle");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "vle");
break;
default:
if (info->arch == bfd_arch_powerpc)
- dialect = ppc_parse_cpu (dialect, &sticky, "power11") | PPC_OPCODE_ANY;
+ out.dialect = (ppc_parse_cpu (out.dialect, &out.sticky, "power11")
+ | PPC_OPCODE_ANY);
else
- dialect = ppc_parse_cpu (dialect, &sticky, "pwr");
+ out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "pwr");
break;
}
- const char *opt;
- FOR_EACH_DISASSEMBLER_OPTION (opt, info->disassembler_options)
- {
- ppc_cpu_t new_cpu = 0;
-
- if (disassembler_options_cmp (opt, "32") == 0)
- dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
- else if (disassembler_options_cmp (opt, "64") == 0)
- dialect |= PPC_OPCODE_64;
- else if ((new_cpu = ppc_parse_cpu (dialect, &sticky, opt)) != 0)
- dialect = new_cpu;
- else
- /* xgettext: c-format */
- opcodes_error_handler (_("warning: ignoring unknown -M%s option"), opt);
- }
+ for_each_disassembler_option (info, ppc_parse_option, &out);
info->private_data = priv;
- private_data (info)->dialect = dialect;
+ private_data (info)->dialect = out.dialect;
}
#define PPC_OPCD_SEGS (1 + PPC_OP (-1))