diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 1d5fb2001d..c69361d4ea 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -1201,6 +1201,28 @@ aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
   return false;
 }
 
+#define BRK_INSN_MASK 0xd4200000
+
+/* Implementation of gdbarch_insn_is_breakpoint for aarch64.  */
+
+static bool
+aarch64_insn_is_breakpoint (gdbarch *gdbarch,
+			    const gdb_byte *insn,
+			    unsigned int insn_size)
+{
+  gdb_assert (insn != nullptr);
+
+  uint32_t i;
+
+  i = (uint32_t) extract_unsigned_integer (insn, insn_size,
+					   gdbarch_byte_order (gdbarch));
+
+  /* Check if INSN is a BRK instruction pattern.  There are multiple choices
+     of such instructions with different immediate values.  Different OS' may
+     use a different variation, but they have the same outcome.  */
+  return (i & BRK_INSN_MASK) == BRK_INSN_MASK;
+}
+
 /* When arguments must be pushed onto the stack, they go on in reverse
    order.  The code below implements a FILO (stack) to do this.  */
 
@@ -3357,6 +3379,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch,
 					   aarch64_execute_dwarf_cfa_vendor_op);
 
+  /* Permanent/Program breakpoint handling.  */
+  set_gdbarch_insn_is_breakpoint (gdbarch, aarch64_insn_is_breakpoint);
+
   /* Add some default predicates.  */
   frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);
   dwarf2_append_unwinders (gdbarch);
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index a1a003f91f..99c9f281be 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -876,6 +876,13 @@ int default_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
   return 0;
 }
 
+bool default_insn_is_breakpoint (struct gdbarch *gdbarch,
+				 const gdb_byte  *insn,
+				 unsigned int insn_size)
+{
+  return false;
+}
+
 void
 default_skip_permanent_breakpoint (struct regcache *regcache)
 {
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 48ff3bb9a1..77ffe8190c 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -227,6 +227,9 @@ extern int default_return_in_first_hidden_param_p (struct gdbarch *,
 extern int default_insn_is_call (struct gdbarch *, CORE_ADDR);
 extern int default_insn_is_ret (struct gdbarch *, CORE_ADDR);
 extern int default_insn_is_jump (struct gdbarch *, CORE_ADDR);
+extern bool default_insn_is_breakpoint (struct gdbarch *gdbarch,
+					const gdb_byte *insn,
+					unsigned int insn_size);
 
 /* Do-nothing version of vsyscall_range.  Returns false.  */
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 904abda8db..ffb7f7f8be 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -8599,14 +8599,23 @@ program_breakpoint_here_p (struct gdbarch *gdbarch, CORE_ADDR address)
   target_mem = (gdb_byte *) alloca (len);
 
   /* Enable the automatic memory restoration from breakpoints while
-     we read the memory.  Otherwise we could say about our temporary
-     breakpoints they are permanent.  */
+     we read the memory.  Otherwise we may find temporary breakpoints, ones
+     inserted by GDB, and flag them as permanent breakpoints.  */
   scoped_restore restore_memory
     = make_scoped_restore_show_memory_breakpoints (0);
 
-  if (target_read_memory (address, target_mem, len) == 0
-      && memcmp (target_mem, bpoint, len) == 0)
-    return 1;
+  if (target_read_memory (address, target_mem, len) == 0)
+    {
+      /* Check if this is a breakpoint instruction for this architecture,
+	 including ones used by GDB. 
+
+	 Some architectures have more than one possible breakpoint
+	 instruction, but GDB does not use all of them.  We should detect those
+	 as well.  */
+      if (gdbarch_insn_is_breakpoint (gdbarch, target_mem, len)
+	  ||  memcmp (target_mem, bpoint, len) == 0)
+	return 1;
+    }
 
   return 0;
 }
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 59c97da985..9e21ba7eca 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -345,6 +345,7 @@ struct gdbarch
   gdbarch_insn_is_call_ftype *insn_is_call;
   gdbarch_insn_is_ret_ftype *insn_is_ret;
   gdbarch_insn_is_jump_ftype *insn_is_jump;
+  gdbarch_insn_is_breakpoint_ftype *insn_is_breakpoint;
   gdbarch_auxv_parse_ftype *auxv_parse;
   gdbarch_print_auxv_entry_ftype *print_auxv_entry;
   gdbarch_vsyscall_range_ftype *vsyscall_range;
@@ -464,6 +465,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->insn_is_call = default_insn_is_call;
   gdbarch->insn_is_ret = default_insn_is_ret;
   gdbarch->insn_is_jump = default_insn_is_jump;
+  gdbarch->insn_is_breakpoint = default_insn_is_breakpoint;
   gdbarch->print_auxv_entry = default_print_auxv_entry;
   gdbarch->vsyscall_range = default_vsyscall_range;
   gdbarch->infcall_mmap = default_infcall_mmap;
@@ -708,6 +710,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of insn_is_call, invalid_p == 0 */
   /* Skip verify of insn_is_ret, invalid_p == 0 */
   /* Skip verify of insn_is_jump, invalid_p == 0 */
+  /* Skip verify of insn_is_breakpoint, invalid_p == 0 */
   /* Skip verify of auxv_parse, has predicate.  */
   /* Skip verify of print_auxv_entry, invalid_p == 0 */
   /* Skip verify of vsyscall_range, invalid_p == 0 */
@@ -1137,6 +1140,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: inner_than = <%s>\n",
                       host_address_to_string (gdbarch->inner_than));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: insn_is_breakpoint = <%s>\n",
+                      host_address_to_string (gdbarch->insn_is_breakpoint));
   fprintf_unfiltered (file,
                       "gdbarch_dump: insn_is_call = <%s>\n",
                       host_address_to_string (gdbarch->insn_is_call));
@@ -4928,6 +4934,23 @@ set_gdbarch_insn_is_jump (struct gdbarch *gdbarch,
   gdbarch->insn_is_jump = insn_is_jump;
 }
 
+bool
+gdbarch_insn_is_breakpoint (struct gdbarch *gdbarch, const gdb_byte *insn, unsigned int insn_size)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->insn_is_breakpoint != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_insn_is_breakpoint called\n");
+  return gdbarch->insn_is_breakpoint (gdbarch, insn, insn_size);
+}
+
+void
+set_gdbarch_insn_is_breakpoint (struct gdbarch *gdbarch,
+                                gdbarch_insn_is_breakpoint_ftype insn_is_breakpoint)
+{
+  gdbarch->insn_is_breakpoint = insn_is_breakpoint;
+}
+
 int
 gdbarch_auxv_parse_p (struct gdbarch *gdbarch)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 78e05ecdcb..d94950b8f2 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -1545,6 +1545,13 @@ typedef int (gdbarch_insn_is_jump_ftype) (struct gdbarch *gdbarch, CORE_ADDR add
 extern int gdbarch_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr);
 extern void set_gdbarch_insn_is_jump (struct gdbarch *gdbarch, gdbarch_insn_is_jump_ftype *insn_is_jump);
 
+/* Return true if INSN of size INSN_SIZE acts like a permanent breakpoint and
+   false otherwise. */
+
+typedef bool (gdbarch_insn_is_breakpoint_ftype) (struct gdbarch *gdbarch, const gdb_byte *insn, unsigned int insn_size);
+extern bool gdbarch_insn_is_breakpoint (struct gdbarch *gdbarch, const gdb_byte *insn, unsigned int insn_size);
+extern void set_gdbarch_insn_is_breakpoint (struct gdbarch *gdbarch, gdbarch_insn_is_breakpoint_ftype *insn_is_breakpoint);
+
 /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
    Return 0 if *READPTR is already at the end of the buffer.
    Return -1 if there is insufficient buffer for a whole entry.
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 331eb39278..dbf31ee8ae 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1152,6 +1152,10 @@ m;int;insn_is_ret;CORE_ADDR addr;addr;;default_insn_is_ret;;0
 # Return non-zero if the instruction at ADDR is a jump; zero otherwise.
 m;int;insn_is_jump;CORE_ADDR addr;addr;;default_insn_is_jump;;0
 
+# Return true if INSN of size INSN_SIZE acts like a permanent breakpoint and
+# false otherwise.
+m;bool;insn_is_breakpoint;const gdb_byte *insn, unsigned int insn_size;insn, insn_size;;default_insn_is_breakpoint;;0
+
 # Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
 # Return 0 if *READPTR is already at the end of the buffer.
 # Return -1 if there is insufficient buffer for a whole entry.
