Automatic date update in version.in
[external/binutils.git] / opcodes / aarch64-dis.c
index 373ddae..4c31f57 100644 (file)
@@ -1,5 +1,5 @@
 /* aarch64-dis.c -- AArch64 disassembler.
-   Copyright (C) 2009-2018 Free Software Foundation, Inc.
+   Copyright (C) 2009-2019 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of the GNU opcodes library.
@@ -45,7 +45,7 @@ static int no_aliases = 0;    /* If set disassemble as most general inst.  */
                                  output as comments.  */
 
 /* Currently active instruction sequence.  */
-static aarch64_instr_sequence insn_sequence ATTRIBUTE_UNUSED;
+static aarch64_instr_sequence insn_sequence;
 
 static void
 set_default_aarch64_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED)
@@ -665,6 +665,8 @@ aarch64_ext_imm (const aarch64_operand *self, aarch64_opnd_info *info,
 
   if (operand_need_shift_by_two (self))
     imm <<= 2;
+  else if (operand_need_shift_by_four (self))
+    imm <<= 4;
 
   if (info->type == AARCH64_OPND_ADDR_ADRP)
     imm <<= 12;
@@ -1065,7 +1067,8 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info,
   /* simm (imm9 or imm7)  */
   imm = extract_field (self->fields[0], code, 0);
   info->addr.offset.imm = sign_extend (imm, fields[self->fields[0]].width - 1);
-  if (self->fields[0] == FLD_imm7)
+  if (self->fields[0] == FLD_imm7
+      || info->qualifier == AARCH64_OPND_QLF_imm_tag)
     /* scaled immediate in ld/st pair instructions.  */
     info->addr.offset.imm *= aarch64_get_qualifier_esize (info->qualifier);
   /* qualifier */
@@ -1243,6 +1246,12 @@ aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED,
     case AARCH64_OPND_SYSREG_DC: sysins_ops = aarch64_sys_regs_dc; break;
     case AARCH64_OPND_SYSREG_IC: sysins_ops = aarch64_sys_regs_ic; break;
     case AARCH64_OPND_SYSREG_TLBI: sysins_ops = aarch64_sys_regs_tlbi; break;
+    case AARCH64_OPND_SYSREG_SR:
+       sysins_ops = aarch64_sys_regs_sr;
+        /* Let's remove op2 for rctx.  Refer to comments in the definition of
+           aarch64_sys_regs_sr[].  */
+       value = value & ~(0x7);
+       break;
     default: assert (0); return FALSE;
     }
 
@@ -1306,7 +1315,7 @@ aarch64_ext_hint (const aarch64_operand *self ATTRIBUTE_UNUSED,
 
   for (i = 0; aarch64_hint_options[i].name != NULL; i++)
     {
-      if (hint_number == aarch64_hint_options[i].value)
+      if (hint_number == HINT_VAL (aarch64_hint_options[i].value))
        {
          info->hint_option = &(aarch64_hint_options[i]);
          return TRUE;
@@ -2983,10 +2992,11 @@ aarch64_decode_insn (aarch64_insn insn, aarch64_inst *inst,
 
 static void
 print_operands (bfd_vma pc, const aarch64_opcode *opcode,
-               const aarch64_opnd_info *opnds, struct disassemble_info *info)
+               const aarch64_opnd_info *opnds, struct disassemble_info *info,
+               bfd_boolean *has_notes)
 {
-  int i, pcrel_p, num_printed;
   char *notes = NULL;
+  int i, pcrel_p, num_printed;
   for (i = 0, num_printed = 0; i < AARCH64_MAX_OPND_NUM; ++i)
     {
       char str[128];
@@ -3016,7 +3026,10 @@ print_operands (bfd_vma pc, const aarch64_opcode *opcode,
     }
 
     if (notes && !no_notes)
-      (*info->fprintf_func) (info->stream, "\t; note: %s", notes);
+      {
+       *has_notes = TRUE;
+       (*info->fprintf_func) (info->stream, "  // note: %s", notes);
+      }
 }
 
 /* Set NAME to a copy of INST's mnemonic with the "." suffix removed.  */
@@ -3074,15 +3087,63 @@ print_comment (const aarch64_inst *inst, struct disassemble_info *info)
     }
 }
 
+/* Build notes from verifiers into a string for printing.  */
+
+static void
+print_verifier_notes (aarch64_operand_error *detail,
+                     struct disassemble_info *info)
+{
+  if (no_notes)
+    return;
+
+  /* The output of the verifier cannot be a fatal error, otherwise the assembly
+     would not have succeeded.  We can safely ignore these.  */
+  assert (detail->non_fatal);
+  assert (detail->error);
+
+  /* If there are multiple verifier messages, concat them up to 1k.  */
+  (*info->fprintf_func) (info->stream, "  // note: %s", detail->error);
+  if (detail->index >= 0)
+     (*info->fprintf_func) (info->stream, " at operand %d", detail->index + 1);
+}
+
 /* Print the instruction according to *INST.  */
 
 static void
 print_aarch64_insn (bfd_vma pc, const aarch64_inst *inst,
-                   struct disassemble_info *info)
+                   const aarch64_insn code,
+                   struct disassemble_info *info,
+                   aarch64_operand_error *mismatch_details)
 {
+  bfd_boolean has_notes = FALSE;
+
   print_mnemonic_name (inst, info);
-  print_operands (pc, inst->opcode, inst->operands, info);
+  print_operands (pc, inst->opcode, inst->operands, info, &has_notes);
   print_comment (inst, info);
+
+  /* We've already printed a note, not enough space to print more so exit.
+     Usually notes shouldn't overlap so it shouldn't happen that we have a note
+     from a register and instruction at the same time.  */
+  if (has_notes)
+    return;
+
+  /* Always run constraint verifiers, this is needed because constraints need to
+     maintain a global state regardless of whether the instruction has the flag
+     set or not.  */
+  enum err_type result = verify_constraints (inst, code, pc, FALSE,
+                                            mismatch_details, &insn_sequence);
+  switch (result)
+    {
+    case ERR_UND:
+    case ERR_UNP:
+    case ERR_NYI:
+      assert (0);
+    case ERR_VFI:
+      print_verifier_notes (mismatch_details, info);
+      break;
+    default:
+      break;
+    }
 }
 
 /* Entry-point of the instruction disassembler and printer.  */
@@ -3139,7 +3200,7 @@ print_insn_aarch64_word (bfd_vma pc,
       break;
     case ERR_OK:
       user_friendly_fixup (&inst);
-      print_aarch64_insn (pc, &inst, info);
+      print_aarch64_insn (pc, &inst, word, info, errors);
       break;
     default:
       abort ();