X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Farm-dis.c;h=60463d16e5211fe30b8a72d486278c77ff98fcca;hb=30bdf75259fabb1825e7244eed21551c024b725c;hp=74d78cb462162d94ebfd6887cce2fd978b3041d9;hpb=d908c8af5a1d7d9122decf3cab08018e9f925d27;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index 74d78cb462..60463d16e5 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -92,7 +92,8 @@ struct opcode16 %c print condition code (always bits 28-31 in ARM mode) %q print shifter argument - %u print condition code (unconditional in ARM mode) + %u print condition code (unconditional in ARM mode, + UNPREDICTABLE if not AL in Thumb) %A print address for ldc/stc/ldf/stf instruction %B print vstm/vldm register list %I print cirrus signed shift immediate: bits 0..3|4..6 @@ -101,6 +102,7 @@ struct opcode16 %Q print floating point precision in ldf/stf insn %R print floating point rounding mode + %c print as a condition code (for vsel) %r print as an ARM register %R as %<>r but r15 is UNPREDICTABLE %ru as %<>r but each u register must be unique. @@ -485,6 +487,20 @@ static const struct opcode32 coprocessor_opcodes[] = {FPU_VFP_EXT_FMA, 0x0e900a00, 0x0fb00f50, "vfnms%c.f32\t%y1, %y2, %y0"}, {FPU_VFP_EXT_FMA, 0x0e900b00, 0x0fb00f50, "vfnms%c.f64\t%z1, %z2, %z0"}, + /* FP v5. */ + {FPU_VFP_EXT_ARMV8, 0xfe000a00, 0xff800f00, "vsel%20-21c%u.f32\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_ARMV8, 0xfe000b00, 0xff800f00, "vsel%20-21c%u.f64\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_ARMV8, 0xfe800a00, 0xffb00f40, "vmaxnm%u.f32\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_ARMV8, 0xfe800b00, 0xffb00f40, "vmaxnm%u.f64\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_ARMV8, 0xfe800a40, 0xffb00f40, "vminnm%u.f32\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_ARMV8, 0xfe800b40, 0xffb00f40, "vminnm%u.f64\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_ARMV8, 0xfebc0a40, 0xffbc0f50, "vcvt%16-17?mpna%u.%7?su32.f32\t%y1, %y0"}, + {FPU_VFP_EXT_ARMV8, 0xfebc0b40, 0xffbc0f50, "vcvt%16-17?mpna%u.%7?su32.f64\t%y1, %z0"}, + {FPU_VFP_EXT_ARMV8, 0x0eb60a40, 0x0fbe0f50, "vrint%7,16??xzr%c.f32.f32\t%y1, %y0"}, + {FPU_VFP_EXT_ARMV8, 0x0eb60b40, 0x0fbe0f50, "vrint%7,16??xzr%c.f64.f64\t%z1, %z0"}, + {FPU_VFP_EXT_ARMV8, 0xfeb80a40, 0xffbc0f50, "vrint%16-17?mpna%u.f32.f32\t%y1, %y0"}, + {FPU_VFP_EXT_ARMV8, 0xfeb80b40, 0xffbc0f50, "vrint%16-17?mpna%u.f64.f64\t%z1, %z0"}, + /* Generic coprocessor instructions. */ { 0, SENTINEL_GENERIC_START, 0, "" }, {ARM_EXT_V5E, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15R, %16-19r, cr%0-3d"}, @@ -519,6 +535,8 @@ static const struct opcode32 coprocessor_opcodes[] = %% % %c print condition code + %u print condition code (unconditional in ARM mode, + UNPREDICTABLE if not AL in Thumb) %A print v{st,ld}[1234] operands %B print v{st,ld}[1234] any one operands %C print v{st,ld}[1234] single->all operands @@ -564,6 +582,8 @@ static const struct opcode32 neon_opcodes[] = {FPU_NEON_EXT_FMA, 0xf2200c10, 0xffa00f10, "vfms%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, /* Two registers, miscellaneous. */ + {FPU_NEON_EXT_ARMV8, 0xf3ba0400, 0xffbf0c10, "vrint%7-9?p?m?zaxn%u.f32.f32\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_ARMV8, 0xf3bb0000, 0xffbf0c10, "vcvt%8-9?mpna%u.%7?us32.f32\t%12-15,22R, %0-3,5R"}, {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"}, {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"}, {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"}, @@ -599,6 +619,8 @@ static const struct opcode32 neon_opcodes[] = {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"}, /* Three registers of the same length. */ + {FPU_NEON_EXT_ARMV8, 0xf3000f10, 0xffa00f10, "vmaxnm%u.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_ARMV8, 0xf3200f10, 0xffa00f10, "vminnm%u.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, @@ -818,6 +840,7 @@ static const struct opcode32 neon_opcodes[] = %P print address for pli instruction. %r print as an ARM register + %T print as an ARM register + 1 %R as %r but r15 is UNPREDICTABLE %{r|R}u as %{r|R} but if matches the other %u field then is UNPREDICTABLE %{r|R}U as %{r|R} but if matches the other %U field then is UNPREDICTABLE @@ -846,6 +869,24 @@ static const struct opcode32 arm_opcodes[] = {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"}, {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"}, + /* V8 instructions. */ + {ARM_EXT_V8, 0x0320f005, 0x0fffffff, "sevl"}, + {ARM_EXT_V8, 0xe1000070, 0xfff000f0, "hlt\t0x%16-19X%12-15X%8-11X%0-3X"}, + {ARM_EXT_V8, 0x01800e90, 0x0ff00ff0, "strlex%c\t%12-15r, %0-3r, [%16-19R]"}, + {ARM_EXT_V8, 0x01900e9f, 0x0ff00fff, "ldraex%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0x01a00e90, 0x0ff00ff0, "strlexd%c\t%12-15r, %0-3r, %0-3T, [%16-19R]"}, + {ARM_EXT_V8, 0x01b00e9f, 0x0ff00fff, "ldraexd%c\t%12-15r, %12-15T, [%16-19R]"}, + {ARM_EXT_V8, 0x01c00e90, 0x0ff00ff0, "strlexb%c\t%12-15r, %0-3r, [%16-19R]"}, + {ARM_EXT_V8, 0x01d00e9f, 0x0ff00fff, "ldraexb%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0x01e00e90, 0x0ff00ff0, "strlexh%c\t%12-15r, %0-3r, [%16-19R]"}, + {ARM_EXT_V8, 0x01f00e9f, 0x0ff00fff, "ldraexh%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0x0180fc90, 0x0ff0fff0, "strl%c\t%0-3r, [%16-19R]"}, + {ARM_EXT_V8, 0x01900c9f, 0x0ff00fff, "ldra%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0x01c0fc90, 0x0ff0fff0, "strlb%c\t%0-3r, [%16-19R]"}, + {ARM_EXT_V8, 0x01d00c9f, 0x0ff00fff, "ldrab%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0x01e0fc90, 0x0ff0fff0, "strlh%c\t%0-3r, [%16-19R]"}, + {ARM_EXT_V8, 0x01f00c9f, 0x0ff00fff, "ldraexh%c\t%12-15r, [%16-19R]"}, + /* Virtualization Extension instructions. */ {ARM_EXT_VIRT, 0x0160006e, 0x0fffffff, "eret%c"}, {ARM_EXT_VIRT, 0x01400070, 0x0ff000f0, "hvc%c\t%e"}, @@ -860,6 +901,8 @@ static const struct opcode32 arm_opcodes[] = /* V7 instructions. */ {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"}, {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V8, 0xf57ff051, 0xfffffff3, "dmb\t%U"}, + {ARM_EXT_V8, 0xf57ff041, 0xfffffff3, "dsb\t%U"}, {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"}, {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"}, {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"}, @@ -1239,6 +1282,10 @@ static const struct opcode16 thumb_opcodes[] = { /* Thumb instructions. */ + /* ARM V8 instructions. */ + {ARM_EXT_V8, 0xbf50, 0xffff, "sevl%c"}, + {ARM_EXT_V8, 0xba80, 0xffc0, "hlt\t%0-5x"}, + /* ARM V6K no-argument instructions. */ {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"}, {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"}, @@ -1408,9 +1455,29 @@ static const struct opcode16 thumb_opcodes[] = makes heavy use of special-case bit patterns. */ static const struct opcode32 thumb32_opcodes[] = { + /* V8 instructions. */ + {ARM_EXT_V8, 0xf3af8005, 0xffffffff, "sevl%c.w"}, + {ARM_EXT_V8, 0xf78f8000, 0xfffffffc, "dcps%0-1d"}, + {ARM_EXT_V8, 0xe8c00f8f, 0xfff00fff, "strlb%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8c00f9f, 0xfff00fff, "strlh%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8c00faf, 0xfff00fff, "strl%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8c00fc0, 0xfff00ff0, "strlexb%c\t%0-3r, %12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8c00fd0, 0xfff00ff0, "strlexh%c\t%0-3r, %12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8c00fe0, 0xfff00ff0, "strlex%c\t%0-3r, %12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8c000f0, 0xfff000f0, "strlexd%c\t%0-3r, %12-15r, %8-11r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d00f8f, 0xfff00fff, "ldrab%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d00f9f, 0xfff00fff, "ldrah%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d00faf, 0xfff00fff, "ldra%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d00fcf, 0xfff00fff, "ldraexb%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d00fdf, 0xfff00fff, "ldraexh%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d00fef, 0xfff00fff, "ldraex%c\t%12-15r, [%16-19R]"}, + {ARM_EXT_V8, 0xe8d000ff, 0xfff000ff, "ldraexd%c\t%12-15r, %8-11r, [%16-19R]"}, + /* V7 instructions. */ {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"}, {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V8, 0xf3bf8f51, 0xfffffff3, "dmb%c\t%U"}, + {ARM_EXT_V8, 0xf3bf8f41, 0xfffffff3, "dsb%c\t%U"}, {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"}, {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"}, {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"}, @@ -1692,6 +1759,9 @@ static unsigned int ifthen_next_state; /* The address of the insn for which the IT state is valid. */ static bfd_vma ifthen_address; #define IFTHEN_COND ((ifthen_state >> 4) & 0xf) +/* Indicates that the current Conditional state is unconditional or outside + an IT block. */ +#define COND_UNCOND 16 /* Functions. */ @@ -1870,7 +1940,7 @@ print_insn_coprocessor (bfd_vma pc, if (ifthen_state) cond = IFTHEN_COND; else - cond = 16; + cond = COND_UNCOND; } else { @@ -1879,13 +1949,13 @@ print_insn_coprocessor (bfd_vma pc, if ((given & 0xf0000000) == 0xf0000000) { mask |= 0xf0000000; - cond = 16; + cond = COND_UNCOND; } else { cond = (given >> 28) & 0xf; if (cond == 0xe) - cond = 16; + cond = COND_UNCOND; } } @@ -1979,6 +2049,11 @@ print_insn_coprocessor (bfd_vma pc, } break; + case 'u': + if (cond != COND_UNCOND) + is_unpredictable = TRUE; + + /* Fall through. */ case 'c': func (stream, "%s", arm_conditional[cond]); break; @@ -2142,6 +2217,31 @@ print_insn_coprocessor (bfd_vma pc, func (stream, "0x%lx", (value & 0xffffffffUL)); break; + case 'c': + switch (value) + { + case 0: + func (stream, "eq"); + break; + + case 1: + func (stream, "vs"); + break; + + case 2: + func (stream, "ge"); + break; + + case 3: + func (stream, "gt"); + break; + + default: + func (stream, "??"); + break; + } + break; + case '`': c++; if (value == 0) @@ -2488,6 +2588,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) if ((given & insn->mask) == insn->value) { signed long value_in_comment = 0; + bfd_boolean is_unpredictable = FALSE; const char *c; for (c = insn->assembler; *c; c++) @@ -2500,6 +2601,11 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) func (stream, "%%"); break; + case 'u': + if (thumb && ifthen_state) + is_unpredictable = TRUE; + + /* Fall through. */ case 'c': if (thumb && ifthen_state) func (stream, "%s", arm_conditional[IFTHEN_COND]); @@ -2819,7 +2925,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) func (stream, "{d%d-d%d}", regno, regno + num); } break; - + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': @@ -2913,6 +3019,9 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) if (value_in_comment > 32 || value_in_comment < -16) func (stream, "\t; 0x%lx", value_in_comment); + if (is_unpredictable) + func (stream, UNPREDICTABLE_INSTRUCTION); + return TRUE; } } @@ -2965,6 +3074,28 @@ banked_regname (unsigned reg) } } +/* Return the name of the DMB/DSB option. */ +static const char * +data_barrier_option (unsigned option) +{ + switch (option & 0xf) + { + case 0xf: return "sy"; + case 0xe: return "st"; + case 0xd: return "ld"; + case 0xb: return "ish"; + case 0xa: return "ishst"; + case 0x9: return "ishld"; + case 0x7: return "un"; + case 0x6: return "unst"; + case 0x5: return "nshld"; + case 0x3: return "osh"; + case 0x2: return "oshst"; + case 0x1: return "oshld"; + default: return NULL; + } +} + /* Print one ARM instruction from PC on INFO->STREAM. */ static void @@ -3315,20 +3446,11 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given) } else { - switch (given & 0xf) - { - case 0xf: func (stream, "sy"); break; - case 0x7: func (stream, "un"); break; - case 0xe: func (stream, "st"); break; - case 0x6: func (stream, "unst"); break; - case 0xb: func (stream, "ish"); break; - case 0xa: func (stream, "ishst"); break; - case 0x3: func (stream, "osh"); break; - case 0x2: func (stream, "oshst"); break; - default: + const char * opt = data_barrier_option (given & 0xf); + if (opt != NULL) + func (stream, "%s", opt); + else func (stream, "#%d", (int) given & 0xf); - break; - } } break; @@ -3347,6 +3469,11 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given) is_unpredictable = TRUE; /* Fall through. */ case 'r': + case 'T': + /* We want register + 1 when decoding T. */ + if (*c == 'T') + ++value; + if (c[1] == 'u') { /* Eat the 'u' character. */ @@ -4202,20 +4329,11 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) } else { - switch (given & 0xf) - { - case 0xf: func (stream, "sy"); break; - case 0x7: func (stream, "un"); break; - case 0xe: func (stream, "st"); break; - case 0x6: func (stream, "unst"); break; - case 0xb: func (stream, "ish"); break; - case 0xa: func (stream, "ishst"); break; - case 0x3: func (stream, "osh"); break; - case 0x2: func (stream, "oshst"); break; - default: - func (stream, "#%d", (int) given & 0xf); - break; - } + const char * opt = data_barrier_option (given & 0xf); + if (opt != NULL) + func (stream, "%s", opt); + else + func (stream, "#%d", (int) given & 0xf); } break;