From 8b8464d228b46a2abd677a0a440e0d08da75df0b Mon Sep 17 00:00:00 2001 From: Shahab Vahedi Date: Wed, 2 Jun 2021 15:30:16 +0300 Subject: [PATCH 16/20] arc: Construct disassembler options dynamically The idea of this change is simple: Populate a data structure, namely "disasm_option_and_arg_t" from "include/dis-asm.h", to encompass the disassembly options and their possible arguments. This will make it easier to manage or extend those options by adapting entries in a data structure, "arc_options". There will be lesser need to hard-code the options in the code itself. Moreover, ARC GDB will use this population function, "disassembler_options_arc ()", to enable the "set disassembler-option" for ARC targets. The gdb change will be in a separate patch though. The changes in this patch can be divided into: 1) Introduction of "disassembler_options_arc ()" that will return a "disasm_option_and_arg_t" structure representing the disassembly options and their likely arguments. 2) New data type "arc_options_arg_t" and new data "arc_options". These are the internals for keeping track of options and arguments entries that can easily be extended. 3) To print the options, the "print_arc_disassembler_options ()" has been adjusted to use this dynamically built structure instead of having them hard-coded inside. To see this in effect, one can look into the output of: $ ./binutils/objdump --help ... The following ARC specific disassembler options are... ... include/ChangeLog: * dis-asm.h (disassembler_options_arc): New prototype. opcodes/ChangeLog: * arc-dis.c (arc_option_arg_t): New enumeration. (arc_options): New variable. (disassembler_options_arc): New function. (print_arc_disassembler_options): Reimplement in terms of "disassembler_options_arc". Will be a part of GDB 11: https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=8f467114435286e4f78b16fc1f5864acf6488fc0 --- include/ChangeLog | 4 + include/dis-asm.h | 1 opcodes/ChangeLog | 8 ++ opcodes/arc-dis.c | 180 +++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 166 insertions(+), 27 deletions(-) --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2021-06-02 Shahab Vahedi + + * dis-asm.h (disassembler_options_arc): New prototype. + 2020-09-12 H.J. Lu PR ld/26391 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -311,6 +311,7 @@ extern void disassemble_init_s390 (struct disassemble_info *); extern void disassemble_init_wasm32 (struct disassemble_info *); extern void disassemble_init_nds32 (struct disassemble_info *); +extern const disasm_options_and_args_t *disassembler_options_arc (void); extern const disasm_options_and_args_t *disassembler_options_arm (void); extern const disasm_options_and_args_t *disassembler_options_mips (void); extern const disasm_options_and_args_t *disassembler_options_powerpc (void); --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,11 @@ +2021-06-02 Shahab Vahedi + + * arc-dis.c (arc_option_arg_t): New enumeration. + (arc_options): New variable. + (disassembler_options_arc): New function. + (print_arc_disassembler_options): Reimplement in terms of + "disassembler_options_arc". + 2020-10-22 Andrew Burgess * csky-dis.c (csky_get_disassembler): Don't return NULL when there --- a/opcodes/arc-dis.c +++ b/opcodes/arc-dis.c @@ -1412,41 +1412,167 @@ return print_insn_arc; } +/* Indices into option argument vector for options that do require + an argument. Use ARC_OPTION_ARG_NONE for options that don't + expect an argument. */ +typedef enum +{ + ARC_OPTION_ARG_NONE = -1, + ARC_OPTION_ARG_ARCH, + ARC_OPTION_ARG_SIZE +} arc_option_arg_t; + +/* Valid ARC disassembler options. */ +static struct +{ + const char *name; + const char *description; + arc_option_arg_t arg; +} arc_options[] = +{ + { "cpu=", N_("Enforce the designated architecture while decoding."), + ARC_OPTION_ARG_ARCH }, + { "dsp", N_("Recognize DSP instructions."), + ARC_OPTION_ARG_NONE }, + { "spfp", N_("Recognize FPX SP instructions."), + ARC_OPTION_ARG_NONE }, + { "dpfp", N_("Recognize FPX DP instructions."), + ARC_OPTION_ARG_NONE }, + { "quarkse_em", N_("Recognize FPU QuarkSE-EM instructions."), + ARC_OPTION_ARG_NONE }, + { "fpuda", N_("Recognize double assist FPU instructions."), + ARC_OPTION_ARG_NONE }, + { "fpus", N_("Recognize single precision FPU instructions."), + ARC_OPTION_ARG_NONE }, + { "fpud", N_("Recognize double precision FPU instructions."), + ARC_OPTION_ARG_NONE }, + { "nps400", N_("Recognize NPS400 instructions."), + ARC_OPTION_ARG_NONE }, + { "hex", N_("Use only hexadecimal number to print immediates."), + ARC_OPTION_ARG_NONE } +}; + +/* Populate the structure for representing ARC's disassembly options. + Such a dynamic initialization is desired, because it makes the maintenance + easier and also gdb uses this to enable the "disassembler-option". */ + +const disasm_options_and_args_t * +disassembler_options_arc (void) +{ + static disasm_options_and_args_t *opts_and_args; + + if (opts_and_args == NULL) + { + disasm_option_arg_t *args; + disasm_options_t *opts; + size_t i; + const size_t nr_of_options = ARRAY_SIZE (arc_options); + /* There is a null element at the end of CPU_TYPES, therefore + NR_OF_CPUS is actually 1 more and that is desired here too. */ + const size_t nr_of_cpus = ARRAY_SIZE (cpu_types); + + opts_and_args = XNEW (disasm_options_and_args_t); + opts_and_args->args + = XNEWVEC (disasm_option_arg_t, ARC_OPTION_ARG_SIZE + 1); + opts_and_args->options.name + = XNEWVEC (const char *, nr_of_options + 1); + opts_and_args->options.description + = XNEWVEC (const char *, nr_of_options + 1); + opts_and_args->options.arg + = XNEWVEC (const disasm_option_arg_t *, nr_of_options + 1); + + /* Populate the arguments for "cpu=" option. */ + args = opts_and_args->args; + args[ARC_OPTION_ARG_ARCH].name = "ARCH"; + args[ARC_OPTION_ARG_ARCH].values = XNEWVEC (const char *, nr_of_cpus); + for (i = 0; i < nr_of_cpus; ++i) + args[ARC_OPTION_ARG_ARCH].values[i] = cpu_types[i].name; + args[ARC_OPTION_ARG_SIZE].name = NULL; + args[ARC_OPTION_ARG_SIZE].values = NULL; + + /* Populate the options. */ + opts = &opts_and_args->options; + for (i = 0; i < nr_of_options; ++i) + { + opts->name[i] = arc_options[i].name; + opts->description[i] = arc_options[i].description; + if (arc_options[i].arg != ARC_OPTION_ARG_NONE) + opts->arg[i] = &args[arc_options[i].arg]; + else + opts->arg[i] = NULL; + } + opts->name[nr_of_options] = NULL; + opts->description[nr_of_options] = NULL; + opts->arg[nr_of_options] = NULL; + } + + return opts_and_args; +} + + void print_arc_disassembler_options (FILE *stream) { - int i; + const disasm_options_and_args_t *opts_and_args; + const disasm_option_arg_t *args; + const disasm_options_t *opts; + size_t i, j; + size_t max_len = 0; + + opts_and_args = disassembler_options_arc (); + opts = &opts_and_args->options; + args = opts_and_args->args; - fprintf (stream, _("\n\ -The following ARC specific disassembler options are supported for use \n\ -with -M switch (multiple options should be separated by commas):\n")); + fprintf (stream, _("\nThe following ARC specific disassembler options are" + " supported for use \nwith the -M switch (multiple" + " options should be separated by commas):\n")); + + /* Find the maximum length for printing options (and their arg name). */ + for (i = 0; opts->name[i] != NULL; ++i) + { + size_t len = strlen (opts->name[i]); + len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0; + max_len = (len > max_len) ? len : max_len; + } + + /* Print the options, their arg and description, if any. */ + for (i = 0, ++max_len; opts->name[i] != NULL; ++i) + { + fprintf (stream, " %s", opts->name[i]); + if (opts->arg[i] != NULL) + fprintf (stream, "%s", opts->arg[i]->name); + if (opts->description[i] != NULL) + { + size_t len = strlen (opts->name[i]); + len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0; + fprintf (stream, + "%*c %s", (int) (max_len - len), ' ', opts->description[i]); + } + fprintf (stream, _("\n")); + } - /* cpu=... options. */ - for (i = 0; cpu_types[i].name; ++i) + /* Print the possible values of an argument. */ + for (i = 0; args[i].name != NULL; ++i) { - /* As of now all value CPU values are less than 16 characters. */ - fprintf (stream, " cpu=%-16s\tEnforce %s ISA.\n", - cpu_types[i].name, cpu_types[i].isa); + size_t len = 3; + fprintf (stream, _("\n\ + For the options above, the following values are supported for \"%s\":\n "), + args[i].name); + for (j = 0; args[i].values[j] != NULL; ++j) + { + fprintf (stream, " %s", args[i].values[j]); + len += strlen (args[i].values[j]) + 1; + /* reset line if printed too long. */ + if (len >= 78) + { + fprintf (stream, _("\n ")); + len = 3; + } + } + fprintf (stream, _("\n")); } - fprintf (stream, _("\ - dsp Recognize DSP instructions.\n")); - fprintf (stream, _("\ - spfp Recognize FPX SP instructions.\n")); - fprintf (stream, _("\ - dpfp Recognize FPX DP instructions.\n")); - fprintf (stream, _("\ - quarkse_em Recognize FPU QuarkSE-EM instructions.\n")); - fprintf (stream, _("\ - fpuda Recognize double assist FPU instructions.\n")); - fprintf (stream, _("\ - fpus Recognize single precision FPU instructions.\n")); - fprintf (stream, _("\ - fpud Recognize double precision FPU instructions.\n")); - fprintf (stream, _("\ - nps400 Recognize NPS400 instructions.\n")); - fprintf (stream, _("\ - hex Use only hexadecimal number to print immediates.\n")); + fprintf (stream, _("\n")); } void arc_insn_decode (bfd_vma addr,