@@ -3444,6 +3444,104 @@ value_of_aarch64_user_reg (const frame_info_ptr &frame, const void *baton)
return value_of_register (*reg_p, get_next_frame_sentinel_okay (frame));
}
+/* Single step through MOPS instruction sequences on AArch64. */
+
+static std::vector<CORE_ADDR>
+aarch64_software_single_step_mops (struct regcache *regcache, CORE_ADDR loc,
+ uint32_t insn)
+{
+ const int insn_size = 4;
+ struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ uint8_t o0 = bit (insn, 21);
+ uint8_t op1 = bits (insn, 22, 23);
+ uint8_t op2 = bits (insn, 12, 15);
+
+ /* Look for the prologue instruction that begins the sequence. */
+
+ /* CPYFP* */
+ if (!((o0 == 0 && op1 == 0)
+ /* SETP* */
+ || (o0 == 0 && op1 == 3 && op2 < 4)
+ /* CPYP* */
+ || (o0 == 1 && op1 == 0)
+ /* SETGP* */
+ || (o0 == 1 && op1 == 3 && op2 < 4)))
+ /* Prologue instruction not found. */
+ return {};
+
+ /* Now look for the main instruction in the middle of the sequence. */
+
+ loc += insn_size;
+ ULONGEST insn_from_memory;
+ if (!safe_read_memory_unsigned_integer (loc, insn_size,
+ byte_order_for_code,
+ &insn_from_memory))
+ {
+ /* Assume we don't have a MOPS sequence, as we couldn't read the
+ instruction in this location. */
+ return {};
+ }
+
+ insn = insn_from_memory;
+ aarch64_inst inst;
+ if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0)
+ return {};
+ if (!AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
+ return {};
+
+ o0 = bit (insn, 21);
+ op1 = bits (insn, 22, 23);
+ op2 = bits (insn, 12, 15);
+
+ /* CPYFM* */
+ if (!((o0 == 0 && op1 == 1)
+ /* SETM* */
+ || (o0 == 0 && op1 == 3 && op2 >= 4 && op2 < 8)
+ /* CPYM* */
+ || (o0 == 1 && op1 == 1)
+ /* SETGM* */
+ || (o0 == 1 && op1 == 3 && op2 >= 4 && op2 < 8)))
+ /* Main instruction not found. */
+ return {};
+
+ /* Now look for the epilogue instruction that ends the sequence. */
+
+ loc += insn_size;
+ if (!safe_read_memory_unsigned_integer (loc, insn_size,
+ byte_order_for_code,
+ &insn_from_memory))
+ {
+ /* Assume we don't have a MOPS sequence, as we couldn't read the
+ instruction in this location. */
+ return {};
+ }
+
+ insn = insn_from_memory;
+ if (aarch64_decode_insn (insn, &inst, 1, nullptr) != 0)
+ return {};
+ if (!AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
+ return {};
+
+ o0 = bit (insn, 21);
+ op1 = bits (insn, 22, 23);
+ op2 = bits (insn, 12, 15);
+
+ /* CPYFE* */
+ if (!((o0 == 0 && op1 == 2)
+ /* SETE* (op2 >= 12 is unallocated space) */
+ || (o0 == 0 && op1 == 3 && op2 >= 8 && op2 < 12)
+ /* CPYE* */
+ || (o0 == 1 && op1 == 2)
+ /* SETGE* (op2 >= 12 is unallocated space) */
+ || (o0 == 1 && op1 == 3 && op2 >= 8 && op2 < 12)))
+ /* Epilogue instruction not found. */
+ return {};
+
+ /* Insert breakpoint after the end of the atomic sequence. */
+ return { loc + insn_size };
+}
+
/* Implement the "software_single_step" gdbarch method, needed to
single step through atomic sequences on AArch64. */
@@ -3479,6 +3577,9 @@ aarch64_software_single_step (struct regcache *regcache)
if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
return {};
+ if (AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
+ return aarch64_software_single_step_mops (regcache, loc, insn);
+
/* Look for a Load Exclusive instruction which begins the sequence. */
if (inst.opcode->iclass != ldstexcl || bit (insn, 22) == 0)
return {};
@@ -3808,8 +3909,10 @@ aarch64_displaced_step_copy_insn (struct gdbarch *gdbarch,
if (aarch64_decode_insn (insn, &inst, 1, NULL) != 0)
return NULL;
- /* Look for a Load Exclusive instruction which begins the sequence. */
- if (inst.opcode->iclass == ldstexcl && bit (insn, 22))
+ /* Look for a Load Exclusive instruction which begins the sequence,
+ or for a MOPS instruction. */
+ if ((inst.opcode->iclass == ldstexcl && bit (insn, 22))
+ || AARCH64_CPU_HAS_FEATURE (*inst.opcode->avariant, MOPS))
{
/* We can't displaced step atomic sequences. */
return NULL;