X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Farc-dis.c;h=ee598918c51ff7506d50d364dcdf962769af69dd;hb=2daf894ed0baf72dd3f422b7a71630145568db30;hp=3afd2533c860b62027e808770b237e50ae455092;hpb=6ec7c1ae19e9e1bf2edad5125941a2fd5fdfde0b;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index 3afd2533c8..ee598918c5 100644 --- a/opcodes/arc-dis.c +++ b/opcodes/arc-dis.c @@ -1,5 +1,5 @@ /* Instruction printing code for the ARC. - Copyright (C) 1994-2017 Free Software Foundation, Inc. + Copyright (C) 1994-2019 Free Software Foundation, Inc. Contributed by Claudiu Zissulescu (claziss@synopsys.com) @@ -117,6 +117,14 @@ typedef struct skipclass disassembling. */ static linkclass decodelist = NULL; +/* ISA mask value enforced via disassembler info options. ARC_OPCODE_NONE + value means that no CPU is enforced. */ + +static unsigned enforced_isa_mask = ARC_OPCODE_NONE; + +/* True if we want to print using only hex numbers. */ +static bfd_boolean print_hex = FALSE; + /* Macros section. */ #ifdef DEBUG @@ -181,6 +189,7 @@ skip_this_opcode (const struct arc_opcode *opcode) { case FLOAT: case DSP: + case ARITH: break; default: return FALSE; @@ -733,63 +742,115 @@ operand_iterator_next (struct arc_operand_iterator *iter, /* Helper for parsing the options. */ static void -parse_option (char *option) +parse_option (const char *option) { - if (CONST_STRNEQ (option, "dsp")) + if (disassembler_options_cmp (option, "dsp") == 0) add_to_decodelist (DSP, NONE); - else if (CONST_STRNEQ (option, "spfp")) + else if (disassembler_options_cmp (option, "spfp") == 0) add_to_decodelist (FLOAT, SPX); - else if (CONST_STRNEQ (option, "dpfp")) + else if (disassembler_options_cmp (option, "dpfp") == 0) add_to_decodelist (FLOAT, DPX); - else if (CONST_STRNEQ (option, "quarkse_em")) + else if (disassembler_options_cmp (option, "quarkse_em") == 0) { add_to_decodelist (FLOAT, DPX); add_to_decodelist (FLOAT, SPX); - add_to_decodelist (FLOAT, QUARKSE); + add_to_decodelist (FLOAT, QUARKSE1); + add_to_decodelist (FLOAT, QUARKSE2); } - else if (CONST_STRNEQ (option, "fpuda")) + else if (disassembler_options_cmp (option, "fpuda") == 0) add_to_decodelist (FLOAT, DPA); - else if (CONST_STRNEQ (option, "fpus")) + else if (disassembler_options_cmp (option, "fpus") == 0) { add_to_decodelist (FLOAT, SP); add_to_decodelist (FLOAT, CVT); } - else if (CONST_STRNEQ (option, "fpud")) + else if (disassembler_options_cmp (option, "fpud") == 0) { add_to_decodelist (FLOAT, DP); add_to_decodelist (FLOAT, CVT); } + else if (CONST_STRNEQ (option, "hex")) + print_hex = TRUE; else - fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); + /* xgettext:c-format */ + opcodes_error_handler (_("unrecognised disassembler option: %s"), option); } -/* Go over the options list and parse it. */ +#define ARC_CPU_TYPE_A6xx(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARC600, "ARC600" } +#define ARC_CPU_TYPE_A7xx(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARC700, "ARC700" } +#define ARC_CPU_TYPE_AV2EM(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARCv2EM, "ARC EM" } +#define ARC_CPU_TYPE_AV2HS(NAME,EXTRA) \ + { #NAME, ARC_OPCODE_ARCv2HS, "ARC HS" } +#define ARC_CPU_TYPE_NONE \ + { 0, 0, 0 } + +/* A table of CPU names and opcode sets. */ +static const struct cpu_type +{ + const char *name; + unsigned flags; + const char *isa; +} + cpu_types[] = +{ + #include "elf/arc-cpu.def" +}; -static void -parse_disassembler_options (char *options) +/* Helper for parsing the CPU options. Accept any of the ARC architectures + values. OPTION should be a value passed to cpu=. */ + +static unsigned +parse_cpu_option (const char *option) { - if (options == NULL) - return; + int i; - while (*options) + for (i = 0; cpu_types[i].name; ++i) { - /* Skip empty options. */ - if (*options == ',') + if (!disassembler_options_cmp (cpu_types[i].name, option)) { - ++ options; - continue; + return cpu_types[i].flags; } + } + + /* xgettext:c-format */ + opcodes_error_handler (_("unrecognised disassembler CPU option: %s"), option); + return ARC_OPCODE_NONE; +} + +/* Go over the options list and parse it. */ - parse_option (options); +static void +parse_disassembler_options (const char *options) +{ + const char *option; - while (*options != ',' && *options != '\0') - ++ options; + if (options == NULL) + return; + + /* Disassembler might be reused for difference CPU's, and cpu option set for + the first one shouldn't be applied to second (which might not have + explicit cpu in its options. Therefore it is required to reset enforced + CPU when new options are being parsed. */ + enforced_isa_mask = ARC_OPCODE_NONE; + + FOR_EACH_DISASSEMBLER_OPTION (option, 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=`. */ + enforced_isa_mask = parse_cpu_option (option + 4); + else + parse_option (option); } } @@ -858,16 +919,16 @@ print_insn_arc (bfd_vma memaddr, int status; unsigned int insn_len; unsigned long long insn = 0; - unsigned isa_mask; + unsigned isa_mask = ARC_OPCODE_NONE; const struct arc_opcode *opcode; bfd_boolean need_comma; bfd_boolean open_braket; int size; const struct arc_operand *operand; - int value; + int value, vpcl; struct arc_operand_iterator iter; - Elf_Internal_Ehdr *header = NULL; struct arc_disassemble_info *arc_infop; + bfd_boolean rpcl = FALSE, rset = FALSE; if (info->disassembler_options) { @@ -884,34 +945,44 @@ print_insn_arc (bfd_vma memaddr, highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0); lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1); - if (info->section && info->section->owner) - header = elf_elfheader (info->section->owner); - - switch (info->mach) + /* Figure out CPU type, unless it was enforced via disassembler options. */ + if (enforced_isa_mask == ARC_OPCODE_NONE) { - case bfd_mach_arc_arc700: - isa_mask = ARC_OPCODE_ARC700; - break; + Elf_Internal_Ehdr *header = NULL; - case bfd_mach_arc_arc600: - isa_mask = ARC_OPCODE_ARC600; - break; + if (info->section && info->section->owner) + header = elf_elfheader (info->section->owner); - case bfd_mach_arc_arcv2: - default: - isa_mask = ARC_OPCODE_ARCv2EM; - /* TODO: Perhaps remove defitinion of header since it is only used at - this location. */ - if (header != NULL - && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS) + switch (info->mach) { - isa_mask = ARC_OPCODE_ARCv2HS; - /* FPU instructions are not extensions for HS. */ - add_to_decodelist (FLOAT, SP); - add_to_decodelist (FLOAT, DP); - add_to_decodelist (FLOAT, CVT); + case bfd_mach_arc_arc700: + isa_mask = ARC_OPCODE_ARC700; + break; + + case bfd_mach_arc_arc600: + isa_mask = ARC_OPCODE_ARC600; + break; + + case bfd_mach_arc_arcv2: + default: + isa_mask = ARC_OPCODE_ARCv2EM; + /* TODO: Perhaps remove definition of header since it is only used at + this location. */ + if (header != NULL + && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS) + isa_mask = ARC_OPCODE_ARCv2HS; + break; } - break; + } + else + isa_mask = enforced_isa_mask; + + if (isa_mask == ARC_OPCODE_ARCv2HS) + { + /* FPU instructions are not extensions for HS. */ + add_to_decodelist (FLOAT, SP); + add_to_decodelist (FLOAT, DP); + add_to_decodelist (FLOAT, CVT); } /* This variable may be set by the instruction decoder. It suggests @@ -954,6 +1025,7 @@ print_insn_arc (bfd_vma memaddr, /* Read the insn into a host word. */ status = (*info->read_memory_func) (memaddr, buffer, size, info); + if (status != 0) { (*info->memory_error_func) (status, memaddr, info); @@ -1064,23 +1136,23 @@ print_insn_arc (bfd_vma memaddr, switch (insn_len) { case 2: - (*info->fprintf_func) (info->stream, ".long %#04llx", + (*info->fprintf_func) (info->stream, ".shor\t%#04llx", insn & 0xffff); break; case 4: - (*info->fprintf_func) (info->stream, ".long %#08llx", + (*info->fprintf_func) (info->stream, ".word\t%#08llx", insn & 0xffffffff); break; case 6: - (*info->fprintf_func) (info->stream, ".long %#08llx", + (*info->fprintf_func) (info->stream, ".long\t%#08llx", insn & 0xffffffff); - (*info->fprintf_func) (info->stream, ".long %#04llx", + (*info->fprintf_func) (info->stream, ".long\t%#04llx", (insn >> 32) & 0xffff); break; case 8: - (*info->fprintf_func) (info->stream, ".long %#08llx", + (*info->fprintf_func) (info->stream, ".long\t%#08llx", insn & 0xffffffff); - (*info->fprintf_func) (info->stream, ".long %#08llx", + (*info->fprintf_func) (info->stream, ".long\t%#08llx", insn >> 32); break; default: @@ -1110,6 +1182,7 @@ print_insn_arc (bfd_vma memaddr, /* Now extract and print the operands. */ operand = NULL; + vpcl = 0; while (operand_iterator_next (&iter, &operand, &value)) { if (open_braket && (operand->flags & ARC_OPERAND_BRAKET)) @@ -1147,6 +1220,20 @@ print_insn_arc (bfd_vma memaddr, need_comma = TRUE; + if (operand->flags & ARC_OPERAND_PCREL) + { + rpcl = TRUE; + vpcl = value; + rset = TRUE; + + info->target = (bfd_vma) (memaddr & ~3) + value; + } + else if (!(operand->flags & ARC_OPERAND_IR)) + { + vpcl = value; + rset = TRUE; + } + /* Print the operand as directed by the flags. */ if (operand->flags & ARC_OPERAND_IR) { @@ -1164,6 +1251,10 @@ print_insn_arc (bfd_vma memaddr, rname = regnames[value + 1]; (*info->fprintf_func) (info->stream, "%s", rname); } + if (value == 63) + rpcl = TRUE; + else + rpcl = FALSE; } else if (operand->flags & ARC_OPERAND_LIMM) { @@ -1179,22 +1270,18 @@ print_insn_arc (bfd_vma memaddr, info->target = (bfd_vma) value; } } - else if (operand->flags & ARC_OPERAND_PCREL) - { - /* PCL relative. */ - if (info->flags & INSN_HAS_RELOC) - memaddr = 0; - (*info->print_address_func) ((memaddr & ~3) + value, info); - - info->target = (bfd_vma) (memaddr & ~3) + value; - } else if (operand->flags & ARC_OPERAND_SIGNED) { const char *rname = get_auxreg (opcode, value, isa_mask); if (rname && open_braket) (*info->fprintf_func) (info->stream, "%s", rname); else - (*info->fprintf_func) (info->stream, "%d", value); + { + if (print_hex) + (*info->fprintf_func) (info->stream, "%#x", value); + else + (*info->fprintf_func) (info->stream, "%d", value); + } } else if (operand->flags & ARC_OPERAND_ADDRTYPE) { @@ -1208,9 +1295,25 @@ print_insn_arc (bfd_vma memaddr, if (operand->flags & ARC_OPERAND_TRUNCATE && !(operand->flags & ARC_OPERAND_ALIGNED32) && !(operand->flags & ARC_OPERAND_ALIGNED16) - && value > 0 && value <= 14) - (*info->fprintf_func) (info->stream, "r13-%s", - regnames[13 + value - 1]); + && value >= 0 && value <= 14) + { + /* Leave/Enter mnemonics. */ + switch (value) + { + case 0: + need_comma = FALSE; + break; + case 1: + (*info->fprintf_func) (info->stream, "r13"); + break; + default: + (*info->fprintf_func) (info->stream, "r13-%s", + regnames[13 + value - 1]); + break; + } + rpcl = FALSE; + rset = FALSE; + } else { const char *rname = get_auxreg (opcode, value, isa_mask); @@ -1240,6 +1343,21 @@ print_insn_arc (bfd_vma memaddr, arc_infop->operands_count ++; } + /* Pretty print extra info for pc-relative operands. */ + if (rpcl && rset) + { + if (info->flags & INSN_HAS_RELOC) + /* If the instruction has a reloc associated with it, then the + offset field in the instruction will actually be the addend + for the reloc. (We are using REL type relocs). In such + cases, we can ignore the pc when computing addresses, since + the addend is not currently pc-relative. */ + memaddr = 0; + + (*info->fprintf_func) (info->stream, "\t;"); + (*info->print_address_func) ((memaddr & ~3) + vpcl, info); + } + return insn_len; } @@ -1264,10 +1382,20 @@ arc_get_disassembler (bfd *abfd) void print_arc_disassembler_options (FILE *stream) { + int i; + 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")); + /* cpu=... options. */ + for (i = 0; cpu_types[i].name; ++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); + } + fprintf (stream, _("\ dsp Recognize DSP instructions.\n")); fprintf (stream, _("\ @@ -1282,6 +1410,8 @@ with -M switch (multiple options should be separated by commas):\n")); fpus Recognize single precision FPU instructions.\n")); fprintf (stream, _("\ fpud Recognize double precision FPU instructions.\n")); + fprintf (stream, _("\ + hex Use only hexadecimal number to print immediates.\n")); } void arc_insn_decode (bfd_vma addr,