diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 8d0553f3d7cd..e920cea49066 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -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;
