X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Farc-dis.c;h=ac8d6aa750018eae1de5db9c6b4a4b6f35d8f7bd;hb=1dadb1dd718f93801bcca669a0fb38e3da6177b8;hp=0cf4bff1817bda0b325e8c77b2f50f0b224bfef6;hpb=53a346d8236aec06f1d3c767716d3340fb0aa013;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index 0cf4bff181..ac8d6aa750 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-2020 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 @@ -129,8 +137,7 @@ static linkclass decodelist = NULL; (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf)) \ : bfd_getb32 (buf)) -#define BITS(word,s,e) (((word) << (sizeof (word) * 8 - 1 - e)) >> \ - (s + (sizeof (word) * 8 - 1 - e))) +#define BITS(word,s,e) (((word) >> (s)) & ((1ull << ((e) - (s)) << 1) - 1)) #define OPCODE_32BIT_INSN(word) (BITS ((word), 27, 31)) /* Functions implementation. */ @@ -173,7 +180,9 @@ skip_this_opcode (const struct arc_opcode *opcode) /* Check opcode for major 0x06, return if it is not in. */ if (arc_opcode_len (opcode) == 4 - && OPCODE_32BIT_INSN (opcode->opcode) != 0x06) + && (OPCODE_32BIT_INSN (opcode->opcode) != 0x06 + /* Can be an APEX extensions. */ + && OPCODE_32BIT_INSN (opcode->opcode) != 0x07)) return FALSE; /* or not a known truble class. */ @@ -181,6 +190,8 @@ skip_this_opcode (const struct arc_opcode *opcode) { case FLOAT: case DSP: + case ARITH: + case MPY: break; default: return FALSE; @@ -283,7 +294,7 @@ find_format_from_table (struct disassemble_info *info, if (operand->extract) value = (*operand->extract) (insn, &invalid); else - value = (insn >> operand->shift) & ((1 << operand->bits) - 1); + value = (insn >> operand->shift) & ((1ull << operand->bits) - 1); /* Check for LIMM indicator. If it is there, then make sure we pick the right format. */ @@ -660,7 +671,7 @@ arc_insn_length (bfd_byte msb, bfd_byte lsb, struct disassemble_info *info) break; default: - abort (); + return 0; } } @@ -735,16 +746,16 @@ operand_iterator_next (struct arc_operand_iterator *iter, static void 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); @@ -752,22 +763,86 @@ parse_option (const char *option) 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, "nps400") == 0) + { + add_to_decodelist (ACL, NPS400); + add_to_decodelist (ARITH, NPS400); + add_to_decodelist (BITOP, NPS400); + add_to_decodelist (BMU, NPS400); + add_to_decodelist (CONTROL, NPS400); + add_to_decodelist (DMA, NPS400); + add_to_decodelist (DPI, NPS400); + add_to_decodelist (MEMORY, NPS400); + add_to_decodelist (MISC, NPS400); + add_to_decodelist (NET, NPS400); + add_to_decodelist (PMU, NPS400); + add_to_decodelist (PROTOCOL_DECODE, NPS400); + add_to_decodelist (ULTRAIP, NPS400); + } + + 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); +} + +#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" +}; + +/* 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) +{ + int i; + + for (i = 0; cpu_types[i].name; ++i) + { + if (!disassembler_options_cmp (cpu_types[i].name, option)) + { + 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. */ @@ -775,22 +850,26 @@ parse_option (const char *option) static void parse_disassembler_options (const char *options) { + const char *option; + if (options == NULL) return; - while (*options) - { - /* Skip empty options. */ - if (*options == ',') - { - ++ options; - continue; - } - - parse_option (options); + /* 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; - while (*options != ',' && *options != '\0') - ++ options; + 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); } } @@ -859,16 +938,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) { @@ -885,41 +964,50 @@ 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 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. */ - info->bytes_per_line = 8; /* In the next lines, we set two info variables control the way @@ -927,7 +1015,6 @@ print_insn_arc (bfd_vma memaddr, 8 and bytes_per_chunk is 4, the output will look like this: 00: 00000000 00000000 with the chunks displayed according to "display_endian". */ - if (info->section && !(info->section->flags & SEC_CODE)) { @@ -955,6 +1042,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); @@ -981,13 +1069,16 @@ print_insn_arc (bfd_vma memaddr, (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data); break; default: - abort (); + return -1; } return size; } insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info); pr_debug ("instruction length = %d bytes\n", insn_len); + if (insn_len == 0) + return -1; + arc_infop = info->private_data; arc_infop->insn_len = insn_len; @@ -1040,7 +1131,7 @@ print_insn_arc (bfd_vma memaddr, default: /* There is no instruction whose length is not 2, 4, 6, or 8. */ - abort (); + return -1; } pr_debug ("instruction value = %llx\n", insn); @@ -1065,27 +1156,31 @@ 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: - abort (); + return -1; } info->insn_type = dis_noninsn; @@ -1111,6 +1206,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)) @@ -1148,6 +1244,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) { @@ -1165,6 +1275,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) { @@ -1180,22 +1294,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) { @@ -1211,6 +1321,7 @@ print_insn_arc (bfd_vma memaddr, && !(operand->flags & ARC_OPERAND_ALIGNED16) && value >= 0 && value <= 14) { + /* Leave/Enter mnemonics. */ switch (value) { case 0: @@ -1224,6 +1335,8 @@ print_insn_arc (bfd_vma memaddr, regnames[13 + value - 1]); break; } + rpcl = FALSE; + rset = FALSE; } else { @@ -1254,6 +1367,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; } @@ -1278,10 +1406,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, _("\ @@ -1296,6 +1434,10 @@ 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, _("\ + nps400 Recognize NPS400 instructions.\n")); + fprintf (stream, _("\ + hex Use only hexadecimal number to print immediates.\n")); } void arc_insn_decode (bfd_vma addr,