diff --git a/gdb/inferior.h b/gdb/inferior.h
index 3cec101..d831c90 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -414,6 +414,10 @@ struct inferior
      operation to get past e.g., a breakpoint.  */
   struct thread_info *step_over_queue_head;
 
+  /* True if preparing a displaced step ever failed.  If so, we won't
+     try displaced stepping for this inferior again.  */
+  int displaced_stepping_failed;
+
   /* Per inferior data-pointers required by other GDB modules.  */
   REGISTRY_FIELDS;
 };
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 8da97fc..2f288a0 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1617,7 +1617,7 @@ can_use_displaced_stepping_p (struct gdbarch *gdbarch)
    over a breakpoint in the current thread.  */
 
 static int
-use_displaced_stepping_now_p (struct gdbarch *gdbarch,
+use_displaced_stepping_now_p (struct inferior *inf, struct gdbarch *gdbarch,
 			      enum gdb_signal sig)
 {
   CORE_ADDR retval;
@@ -1626,7 +1626,8 @@ use_displaced_stepping_now_p (struct gdbarch *gdbarch,
      the comments for displaced_step_prepare explain why.  The
      comments in the handle_inferior event for dealing with 'random
      signals' explain what we do instead.  */
-  return  (sig == GDB_SIGNAL_0
+  return  (!inf->displaced_stepping_failed
+	   && sig == GDB_SIGNAL_0
 	   && can_use_displaced_stepping_p (gdbarch)
 	   && entry_point_address_query (&retval));
 }
@@ -1926,6 +1927,7 @@ static void keep_going_pass (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static int keep_going_stepped_thread (struct thread_info *tp);
 static int thread_still_needs_step_over (struct thread_info *tp);
+static void stop_all_threads (void);
 
 /* Are there any pending step-over requests for INF?  If so, run one
    now and return true.  Otherwise, return false.  */
@@ -2373,11 +2375,40 @@ resume (enum gdb_signal sig)
      instruction at a different address.  */
   if (tp->control.trap_expected
       && !step_over_info_valid_p ()
-      && use_displaced_stepping_now_p (gdbarch, sig))
+      && use_displaced_stepping_now_p (current_inferior (), gdbarch, sig))
     {
-      struct displaced_step_inferior_state *displaced;
+      int prepared = -1;
 
-      if (!displaced_step_prepare (inferior_ptid))
+      TRY
+	{
+	  prepared = displaced_step_prepare (inferior_ptid);
+	}
+      CATCH (ex, RETURN_MASK_ERROR)
+	{
+	  if (ex.error != MEMORY_ERROR)
+	    throw_exception (ex);
+
+	  if (debug_infrun)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "infrun: disabling displaced stepping: %s\n",
+				  ex.message);
+	    }
+
+	  /* Be verbose if "set displaced-stepping" is "on", silent if
+	     "auto".  */
+	  if (can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
+	    {
+	      warning (_("disabling displaced stepping: %s\n"),
+		       ex.message);
+	    }
+
+	  /* Disable further displaced stepping attempts.  */
+	  current_inferior ()->displaced_stepping_failed = 1;
+	}
+      END_CATCH
+
+      if (prepared == 0)
 	{
 	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog,
@@ -2388,14 +2419,32 @@ resume (enum gdb_signal sig)
 	  discard_cleanups (old_cleanups);
 	  return;
 	}
+      else if (prepared < 0)
+	{
+	  /* Fallback to stepping over the breakpoint in-line.  */
 
-      /* Update pc to reflect the new address from which we will execute
-	 instructions due to displaced stepping.  */
-      pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
+	  if (target_is_non_stop_p ())
+	    stop_all_threads ();
 
-      displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
-      step = gdbarch_displaced_step_hw_singlestep (gdbarch,
-						   displaced->step_closure);
+	  set_step_over_info (get_regcache_aspace (regcache),
+			      regcache_read_pc (regcache), 0);
+
+	  step = maybe_software_singlestep (gdbarch, pc);
+
+	  insert_breakpoints ();
+	}
+      else if (prepared > 0)
+	{
+	  struct displaced_step_inferior_state *displaced;
+
+	  /* Update pc to reflect the new address from which we will
+	     execute instructions due to displaced stepping.  */
+	  pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
+
+	  displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
+	  step = gdbarch_displaced_step_hw_singlestep (gdbarch,
+						       displaced->step_closure);
+	}
     }
 
   /* Do we need to do it the hard way, w/temp breakpoints?  */
@@ -2525,7 +2574,7 @@ resume (enum gdb_signal sig)
   if (debug_displaced
       && tp->control.trap_expected
       && !step_over_info_valid_p ()
-      && use_displaced_stepping_now_p (gdbarch, sig))
+      && use_displaced_stepping_now_p (current_inferior (), gdbarch, sig))
     {
       struct regcache *resume_regcache = get_thread_regcache (tp->ptid);
       struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache);
@@ -7179,7 +7228,8 @@ keep_going_pass (struct execution_control_state *ecs)
       else if (remove_wps)
 	set_step_over_info (NULL, 0, remove_wps);
       else if (remove_bp
-	       && !use_displaced_stepping_now_p (get_regcache_arch (regcache),
+	       && !use_displaced_stepping_now_p (current_inferior (),
+						 get_regcache_arch (regcache),
 						 signo))
 	{
 	  set_step_over_info (get_regcache_aspace (regcache),
diff --git a/gdb/testsuite/gdb.base/valgrind-disp-step.c b/gdb/testsuite/gdb.base/valgrind-disp-step.c
new file mode 100644
index 0000000..baba74e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/valgrind-disp-step.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+static int
+foo (void)
+{
+}
+
+int
+main (void)
+{
+  foo (); /* stop 0 */
+  foo (); /* stop 1 */
+  foo (); /* stop 2 */
+  foo (); /* stop 3 */
+  foo (); /* stop 4 */
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/valgrind-disp-step.exp b/gdb/testsuite/gdb.base/valgrind-disp-step.exp
new file mode 100644
index 0000000..ded1ff7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/valgrind-disp-step.exp
@@ -0,0 +1,131 @@
+# Copyright 2012-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Step over breakpoints with displaced stepping off/on.  We can't
+# really use displaced stepping with Valgrind, so what this really
+# tests is that GDB falls back to in-line stepping automatically
+# instead of getting stuck or crashing.
+
+if [is_remote target] {
+    # The test always runs locally.
+    return 0
+}
+
+standard_testfile .c
+if {[build_executable "failed to build" $testfile $srcfile {debug}] == -1} {
+    return -1
+}
+
+set test "spawn valgrind"
+set cmd "valgrind --vgdb-error=0 $binfile"
+set res [remote_spawn host $cmd]
+if { $res < 0 || $res == "" } {
+    verbose -log "Spawning $cmd failed."
+    unsupported $test
+    return -1
+}
+pass $test
+# Declare GDB now as running.
+set gdb_spawn_id $res
+
+# GDB started by vgdb stops already after the startup is executed, like with
+# non-extended gdbserver.  It is also not correct to run/attach the inferior.
+set use_gdb_stub 1
+
+set test "valgrind started"
+# The trailing '.' differs for different memcheck versions.
+gdb_test_multiple "" $test {
+    -re "Memcheck, a memory error detector\\.?\r\n" {
+	pass $test
+    }
+    -re "valgrind: failed to start tool 'memcheck' for platform '.*': No such file or directory" {
+	unsupported $test
+	return -1
+    }
+    -re "valgrind: wrong ELF executable class" {
+	unsupported $test
+	return -1
+    }
+    -re "command not found" {
+	# The spawn succeeded, but then valgrind was not found - e.g. if
+	# we spawned SSH to a remote system.
+	unsupported $test
+	return -1
+    }
+    -re "valgrind: Bad option.*--vgdb-error=0" {
+	# valgrind is not >= 3.7.0.
+	unsupported $test
+	return -1
+    }
+}
+
+set test "vgdb prompt"
+# The trailing '.' differs for different memcheck versions.
+gdb_test_multiple "" $test {
+    -re "  (target remote | \[^\r\n\]*/vgdb \[^\r\n\]*)\r\n" {
+	set vgdbcmd $expect_out(1,string)
+	pass $test
+    }
+}
+
+# Do not kill valgrind.
+set valgrind_pid [exp_pid -i [board_info host fileid]]
+unset gdb_spawn_id
+set board [host_info name]
+unset_board_info fileid
+
+clean_restart $testfile
+
+gdb_test "$vgdbcmd" " in \\.?_start .*" "target remote for vgdb"
+
+gdb_test "monitor v.set gdb_output" "valgrind output will go to gdb.*"
+
+gdb_test_no_output "set displaced-stepping off"
+gdb_breakpoint "main" "breakpoint at main"
+gdb_test "continue" " stop 0 .*" "continue to main"
+delete_breakpoints
+
+set curr_stop 0
+foreach displaced { "off" "on" } {
+    with_test_prefix "displaced $displaced" {
+
+	gdb_test_no_output "set displaced-stepping $displaced"
+
+	foreach go { "once" "twice" } {
+	    with_test_prefix $go {
+		gdb_test "break" "Breakpoint .* at .*" "set breakpoint"
+
+		# Whether we should see a warning.
+		set should_warn [expr {$go == "once" && $displaced == "on"}]
+
+		incr curr_stop
+
+		set msg "step over breakpoint"
+		set pattern " stop $curr_stop .*$gdb_prompt $"
+		gdb_test_multiple "next" $msg {
+		    -re "warning: disabling displaced stepping.*$pattern" {
+			gdb_assert $should_warn $msg
+		    }
+		    -re "$pattern" {
+			gdb_assert !$should_warn $msg
+		    }
+		}
+	    }
+	}
+    }
+}
+
+# Only if valgrind got stuck.
+remote_exec host "kill -9 ${valgrind_pid}"
