Share fork_inferior et al with gdbserver
[external/binutils.git] / gdb / gdbserver / linux-low.c
index d9f847d..7fbf744 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface to ptrace, for the remote server for GDB.
-   Copyright (C) 1995-2016 Free Software Foundation, Inc.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -22,7 +22,7 @@
 #include "agent.h"
 #include "tdesc.h"
 #include "rsp-low.h"
-
+#include "signals-state-save-restore.h"
 #include "nat/linux-nat.h"
 #include "nat/linux-waitpid.h"
 #include "gdb_wait.h"
@@ -47,6 +47,9 @@
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include "common-inferior.h"
+#include "nat/fork-inferior.h"
+#include "environ.h"
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -176,6 +179,14 @@ lwp_stop_reason (struct lwp_info *lwp)
   return lwp->stop_reason;
 }
 
+/* See nat/linux-nat.h.  */
+
+int
+lwp_is_stepping (struct lwp_info *lwp)
+{
+  return lwp->stepping;
+}
+
 /* A list of all unknown processes which receive stop signals.  Some
    other process will presumably claim each of these as forked
    children momentarily.  */
@@ -550,11 +561,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
              && can_software_single_step ()
              && event == PTRACE_EVENT_VFORK)
            {
-             /* If we leave reinsert breakpoints there, child will
-                hit it, so uninsert reinsert breakpoints from parent
+             /* If we leave single-step breakpoints there, child will
+                hit it, so uninsert single-step breakpoints from parent
                 (and child).  Once vfork child is done, reinsert
                 them back to parent.  */
-             uninsert_reinsert_breakpoints (event_thr);
+             uninsert_single_step_breakpoints (event_thr);
            }
 
          clone_all_breakpoints (child_thr, event_thr);
@@ -581,8 +592,13 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
          event_lwp->status_pending_p = 1;
          event_lwp->status_pending = wstat;
 
-         /* If the parent thread is doing step-over with reinsert
-            breakpoints, the list of reinsert breakpoints are cloned
+         /* Link the threads until the parent event is passed on to
+            higher layers.  */
+         event_lwp->fork_relative = child_lwp;
+         child_lwp->fork_relative = event_lwp;
+
+         /* If the parent thread is doing step-over with single-step
+            breakpoints, the list of single-step breakpoints are cloned
             from the parent's.  Remove them from the child process.
             In case of vfork, we'll reinsert them back once vforked
             child is done.  */
@@ -592,10 +608,10 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
              /* The child process is forked and stopped, so it is safe
                 to access its memory without stopping all other threads
                 from other processes.  */
-             delete_reinsert_breakpoints (child_thr);
+             delete_single_step_breakpoints (child_thr);
 
-             gdb_assert (has_reinsert_breakpoints (event_thr));
-             gdb_assert (!has_reinsert_breakpoints (child_thr));
+             gdb_assert (has_single_step_breakpoints (event_thr));
+             gdb_assert (!has_single_step_breakpoints (child_thr));
            }
 
          /* Report the event.  */
@@ -649,9 +665,9 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
 
       if (event_lwp->bp_reinsert != 0 && can_software_single_step ())
        {
-         reinsert_reinsert_breakpoints (event_thr);
+         reinsert_single_step_breakpoints (event_thr);
 
-         gdb_assert (has_reinsert_breakpoints (event_thr));
+         gdb_assert (has_single_step_breakpoints (event_thr));
        }
 
       /* Report the event.  */
@@ -933,57 +949,57 @@ add_lwp (ptid_t ptid)
   return lwp;
 }
 
+/* Callback to be used when calling fork_inferior, responsible for
+   actually initiating the tracing of the inferior.  */
+
+static void
+linux_ptrace_fun ()
+{
+  if (ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0,
+             (PTRACE_TYPE_ARG4) 0) < 0)
+    trace_start_error_with_name ("ptrace");
+
+  if (setpgid (0, 0) < 0)
+    trace_start_error_with_name ("setpgid");
+
+  /* If GDBserver is connected to gdb via stdio, redirect the inferior's
+     stdout to stderr so that inferior i/o doesn't corrupt the connection.
+     Also, redirect stdin to /dev/null.  */
+  if (remote_connection_is_stdio ())
+    {
+      if (close (0) < 0)
+       trace_start_error_with_name ("close");
+      if (open ("/dev/null", O_RDONLY) < 0)
+       trace_start_error_with_name ("open");
+      if (dup2 (2, 1) < 0)
+       trace_start_error_with_name ("dup2");
+      if (write (2, "stdin/stdout redirected\n",
+                sizeof ("stdin/stdout redirected\n") - 1) < 0)
+       {
+         /* Errors ignored.  */;
+       }
+    }
+}
+
 /* Start an inferior process and returns its pid.
-   ALLARGS is a vector of program-name and args. */
+   PROGRAM is the name of the program to be started, and PROGRAM_ARGS
+   are its arguments.  */
 
 static int
-linux_create_inferior (char *program, char **allargs)
+linux_create_inferior (const char *program,
+                      const std::vector<char *> &program_args)
 {
   struct lwp_info *new_lwp;
   int pid;
   ptid_t ptid;
   struct cleanup *restore_personality
     = maybe_disable_address_space_randomization (disable_randomization);
+  std::string str_program_args = stringify_argv (program_args);
 
-#if defined(__UCLIBC__) && defined(HAS_NOMMU)
-  pid = vfork ();
-#else
-  pid = fork ();
-#endif
-  if (pid < 0)
-    perror_with_name ("fork");
-
-  if (pid == 0)
-    {
-      close_most_fds ();
-      ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
-
-      setpgid (0, 0);
-
-      /* If gdbserver is connected to gdb via stdio, redirect the inferior's
-        stdout to stderr so that inferior i/o doesn't corrupt the connection.
-        Also, redirect stdin to /dev/null.  */
-      if (remote_connection_is_stdio ())
-       {
-         close (0);
-         open ("/dev/null", O_RDONLY);
-         dup2 (2, 1);
-         if (write (2, "stdin/stdout redirected\n",
-                    sizeof ("stdin/stdout redirected\n") - 1) < 0)
-           {
-             /* Errors ignored.  */;
-           }
-       }
-
-      execv (program, allargs);
-      if (errno == ENOENT)
-       execvp (program, allargs);
-
-      fprintf (stderr, "Cannot exec %s: %s.\n", program,
-              strerror (errno));
-      fflush (stderr);
-      _exit (0177);
-    }
+  pid = fork_inferior (program,
+                      str_program_args.c_str (),
+                      environ_vector (get_environ ()), linux_ptrace_fun,
+                      NULL, NULL, NULL, NULL);
 
   do_cleanups (restore_personality);
 
@@ -993,6 +1009,8 @@ linux_create_inferior (char *program, char **allargs)
   new_lwp = add_lwp (ptid);
   new_lwp->must_set_ptrace_flags = 1;
 
+  post_fork_inferior (pid, program);
+
   return pid;
 }
 
@@ -1966,10 +1984,9 @@ check_zombie_leaders (void)
             thread execs).  */
 
          if (debug_threads)
-           fprintf (stderr,
-                    "CZL: Thread group leader %d zombie "
-                    "(it exited, or another thread execd).\n",
-                    leader_pid);
+           debug_printf ("CZL: Thread group leader %d zombie "
+                         "(it exited, or another thread execd).\n",
+                         leader_pid);
 
          delete_lwp (leader_lp);
        }
@@ -2620,9 +2637,9 @@ maybe_hw_step (struct thread_info *thread)
     return 1;
   else
     {
-      /* GDBserver must insert reinsert breakpoint for software
+      /* GDBserver must insert single-step breakpoint for software
         single step.  */
-      gdb_assert (has_reinsert_breakpoints (thread));
+      gdb_assert (has_single_step_breakpoints (thread));
       return 0;
     }
 }
@@ -2641,7 +2658,10 @@ resume_stopped_resumed_lwps (struct inferior_list_entry *entry)
       && !lp->status_pending_p
       && thread->last_status.kind == TARGET_WAITKIND_IGNORE)
     {
-      int step = thread->last_resume_kind == resume_step;
+      int step = 0;
+
+      if (thread->last_resume_kind == resume_step)
+       step = maybe_hw_step (thread);
 
       if (debug_threads)
        debug_printf ("RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
@@ -2682,7 +2702,8 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
   if (ptid_equal (filter_ptid, minus_one_ptid) || ptid_is_pid (filter_ptid))
     {
       event_thread = (struct thread_info *)
-       find_inferior (&all_threads, status_pending_p_callback, &filter_ptid);
+       find_inferior_in_random (&all_threads, status_pending_p_callback,
+                                &filter_ptid);
       if (event_thread != NULL)
        event_child = get_thread_lwp (event_thread);
       if (debug_threads && event_thread)
@@ -2793,7 +2814,8 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
       /* ... and find an LWP with a status to report to the core, if
         any.  */
       event_thread = (struct thread_info *)
-       find_inferior (&all_threads, status_pending_p_callback, &filter_ptid);
+       find_inferior_in_random (&all_threads, status_pending_p_callback,
+                                &filter_ptid);
       if (event_thread != NULL)
        {
          event_child = get_thread_lwp (event_thread);
@@ -3325,13 +3347,13 @@ linux_wait_1 (ptid_t ptid,
      the breakpoint address.
      So in the case of the hardware single step advance the PC manually
      past the breakpoint and in the case of software single step advance only
-     if it's not the reinsert_breakpoint we are hitting.
+     if it's not the single_step_breakpoint we are hitting.
      This avoids that a program would keep trapping a permanent breakpoint
      forever.  */
   if (!ptid_equal (step_over_bkpt, null_ptid)
       && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
       && (event_child->stepping
-         || !reinsert_breakpoint_inserted_here (event_child->stop_pc)))
+         || !single_step_breakpoint_inserted_here (event_child->stop_pc)))
     {
       int increment_pc = 0;
       int breakpoint_kind = 0;
@@ -3385,8 +3407,8 @@ linux_wait_1 (ptid_t ptid,
 
       /* We have a SIGTRAP, possibly a step-over dance has just
         finished.  If so, tweak the state machine accordingly,
-        reinsert breakpoints and delete any reinsert (software
-        single-step) breakpoints.  */
+        reinsert breakpoints and delete any single-step
+        breakpoints.  */
       step_over_finished = finish_step_over (event_child);
 
       /* Now invoke the callbacks of any internal breakpoints there.  */
@@ -3439,6 +3461,8 @@ linux_wait_1 (ptid_t ptid,
 
          linux_resume_one_lwp (event_child, 0, 0, NULL);
 
+         if (debug_threads)
+           debug_exit ();
          return ignore_event (ourstatus);
        }
     }
@@ -3534,6 +3558,9 @@ linux_wait_1 (ptid_t ptid,
 
       linux_resume_one_lwp (event_child, event_child->stepping,
                            0, NULL);
+
+      if (debug_threads)
+       debug_exit ();
       return ignore_event (ourstatus);
     }
 
@@ -3589,6 +3616,10 @@ linux_wait_1 (ptid_t ptid,
          linux_resume_one_lwp (event_child, event_child->stepping,
                                WSTOPSIG (w), info_p);
        }
+
+      if (debug_threads)
+       debug_exit ();
+
       return ignore_event (ourstatus);
     }
 
@@ -3657,18 +3688,36 @@ linux_wait_1 (ptid_t ptid,
          (*the_low_target.set_pc) (regcache, event_child->stop_pc);
        }
 
-      /* We may have finished stepping over a breakpoint.  If so,
-        we've stopped and suspended all LWPs momentarily except the
-        stepping one.  This is where we resume them all again.  We're
-        going to keep waiting, so use proceed, which handles stepping
-        over the next breakpoint.  */
+      if (step_over_finished)
+       {
+         /* If we have finished stepping over a breakpoint, we've
+            stopped and suspended all LWPs momentarily except the
+            stepping one.  This is where we resume them all again.
+            We're going to keep waiting, so use proceed, which
+            handles stepping over the next breakpoint.  */
+         unsuspend_all_lwps (event_child);
+       }
+      else
+       {
+         /* Remove the single-step breakpoints if any.  Note that
+            there isn't single-step breakpoint if we finished stepping
+            over.  */
+         if (can_software_single_step ()
+             && has_single_step_breakpoints (current_thread))
+           {
+             stop_all_lwps (0, event_child);
+             delete_single_step_breakpoints (current_thread);
+             unstop_all_lwps (0, event_child);
+           }
+       }
+
       if (debug_threads)
        debug_printf ("proceeding all threads.\n");
+      proceed_all_lwps ();
 
-      if (step_over_finished)
-       unsuspend_all_lwps (event_child);
+      if (debug_threads)
+       debug_exit ();
 
-      proceed_all_lwps ();
       return ignore_event (ourstatus);
     }
 
@@ -3700,29 +3749,71 @@ linux_wait_1 (ptid_t ptid,
 
   /* Alright, we're going to report a stop.  */
 
-  if (!stabilizing_threads)
+  /* Remove single-step breakpoints.  */
+  if (can_software_single_step ())
     {
-      /* In all-stop, stop all threads.  */
-      if (!non_stop)
-       stop_all_lwps (0, NULL);
+      /* Remove single-step breakpoints or not.  It it is true, stop all
+        lwps, so that other threads won't hit the breakpoint in the
+        staled memory.  */
+      int remove_single_step_breakpoints_p = 0;
 
-      /* If we're not waiting for a specific LWP, choose an event LWP
-        from among those that have had events.  Giving equal priority
-        to all LWPs that have had events helps prevent
-        starvation.  */
-      if (ptid_equal (ptid, minus_one_ptid))
+      if (non_stop)
        {
-         event_child->status_pending_p = 1;
-         event_child->status_pending = w;
+         remove_single_step_breakpoints_p
+           = has_single_step_breakpoints (current_thread);
+       }
+      else
+       {
+         /* In all-stop, a stop reply cancels all previous resume
+            requests.  Delete all single-step breakpoints.  */
+         struct inferior_list_entry *inf, *tmp;
 
-         select_event_lwp (&event_child);
+         ALL_INFERIORS (&all_threads, inf, tmp)
+           {
+             struct thread_info *thread = (struct thread_info *) inf;
 
-         /* current_thread and event_child must stay in sync.  */
-         current_thread = get_lwp_thread (event_child);
+             if (has_single_step_breakpoints (thread))
+               {
+                 remove_single_step_breakpoints_p = 1;
+                 break;
+               }
+           }
+       }
 
-         event_child->status_pending_p = 0;
-         w = event_child->status_pending;
+      if (remove_single_step_breakpoints_p)
+       {
+         /* If we remove single-step breakpoints from memory, stop all lwps,
+            so that other threads won't hit the breakpoint in the staled
+            memory.  */
+         stop_all_lwps (0, event_child);
+
+         if (non_stop)
+           {
+             gdb_assert (has_single_step_breakpoints (current_thread));
+             delete_single_step_breakpoints (current_thread);
+           }
+         else
+           {
+             struct inferior_list_entry *inf, *tmp;
+
+             ALL_INFERIORS (&all_threads, inf, tmp)
+               {
+                 struct thread_info *thread = (struct thread_info *) inf;
+
+                 if (has_single_step_breakpoints (thread))
+                   delete_single_step_breakpoints (thread);
+               }
+           }
+
+         unstop_all_lwps (0, event_child);
        }
+    }
+
+  if (!stabilizing_threads)
+    {
+      /* In all-stop, stop all threads.  */
+      if (!non_stop)
+       stop_all_lwps (0, NULL);
 
       if (step_over_finished)
        {
@@ -3748,6 +3839,25 @@ linux_wait_1 (ptid_t ptid,
            }
        }
 
+      /* If we're not waiting for a specific LWP, choose an event LWP
+        from among those that have had events.  Giving equal priority
+        to all LWPs that have had events helps prevent
+        starvation.  */
+      if (ptid_equal (ptid, minus_one_ptid))
+       {
+         event_child->status_pending_p = 1;
+         event_child->status_pending = w;
+
+         select_event_lwp (&event_child);
+
+         /* current_thread and event_child must stay in sync.  */
+         current_thread = get_lwp_thread (event_child);
+
+         event_child->status_pending_p = 0;
+         w = event_child->status_pending;
+       }
+
+
       /* Stabilize threads (move out of jump pads).  */
       if (!non_stop)
        stabilize_threads ();
@@ -3766,6 +3876,15 @@ linux_wait_1 (ptid_t ptid,
     {
       /* If the reported event is an exit, fork, vfork or exec, let
         GDB know.  */
+
+      /* Break the unreported fork relationship chain.  */
+      if (event_child->waitstatus.kind == TARGET_WAITKIND_FORKED
+         || event_child->waitstatus.kind == TARGET_WAITKIND_VFORKED)
+       {
+         event_child->fork_relative->fork_relative = NULL;
+         event_child->fork_relative = NULL;
+       }
+
       *ourstatus = event_child->waitstatus;
       /* Clear the event lwp's waitstatus since we handled it already.  */
       event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE;
@@ -4201,20 +4320,15 @@ enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info)
 static void
 install_software_single_step_breakpoints (struct lwp_info *lwp)
 {
-  int i;
-  CORE_ADDR pc;
   struct thread_info *thread = get_lwp_thread (lwp);
   struct regcache *regcache = get_thread_regcache (thread, 1);
-  VEC (CORE_ADDR) *next_pcs = NULL;
   struct cleanup *old_chain = make_cleanup_restore_current_thread ();
 
-  make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs);
-
   current_thread = thread;
-  next_pcs = (*the_low_target.get_next_pcs) (regcache);
+  std::vector<CORE_ADDR> next_pcs = the_low_target.get_next_pcs (regcache);
 
-  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); ++i)
-    set_reinsert_breakpoint (pc, current_ptid);
+  for (CORE_ADDR pc : next_pcs)
+    set_single_step_breakpoint (pc, current_ptid);
 
   do_cleanups (old_chain);
 }
@@ -4344,21 +4458,15 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp,
          if (fast_tp_collecting == 0)
            {
              if (step == 0)
-               fprintf (stderr, "BAD - reinserting but not stepping.\n");
+               warning ("BAD - reinserting but not stepping.");
              if (lwp->suspended)
-               fprintf (stderr, "BAD - reinserting and suspended(%d).\n",
-                        lwp->suspended);
+               warning ("BAD - reinserting and suspended(%d).",
+                                lwp->suspended);
            }
        }
 
       step = maybe_hw_step (thread);
     }
-  else
-    {
-      /* If the thread isn't doing step-over, there shouldn't be any
-        reinsert breakpoints.  */
-      gdb_assert (!has_reinsert_breakpoints (thread));
-    }
 
   if (fast_tp_collecting == 1)
     {
@@ -4573,6 +4681,51 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
              continue;
            }
 
+         /* Ignore (wildcard) resume requests for already-resumed
+            threads.  */
+         if (r->resume[ndx].kind != resume_stop
+             && thread->last_resume_kind != resume_stop)
+           {
+             if (debug_threads)
+               debug_printf ("already %s LWP %ld at GDB's request\n",
+                             (thread->last_resume_kind
+                              == resume_step)
+                             ? "stepping"
+                             : "continuing",
+                             lwpid_of (thread));
+             continue;
+           }
+
+         /* Don't let wildcard resumes resume fork children that GDB
+            does not yet know are new fork children.  */
+         if (lwp->fork_relative != NULL)
+           {
+             struct inferior_list_entry *inf, *tmp;
+             struct lwp_info *rel = lwp->fork_relative;
+
+             if (rel->status_pending_p
+                 && (rel->waitstatus.kind == TARGET_WAITKIND_FORKED
+                     || rel->waitstatus.kind == TARGET_WAITKIND_VFORKED))
+               {
+                 if (debug_threads)
+                   debug_printf ("not resuming LWP %ld: has queued stop reply\n",
+                                 lwpid_of (thread));
+                 continue;
+               }
+           }
+
+         /* If the thread has a pending event that has already been
+            reported to GDBserver core, but GDB has not pulled the
+            event out of the vStopped queue yet, likewise, ignore the
+            (wildcard) resume request.  */
+         if (in_queued_stop_replies (entry->id))
+           {
+             if (debug_threads)
+               debug_printf ("not resuming LWP %ld: has queued stop reply\n",
+                             lwpid_of (thread));
+             continue;
+           }
+
          lwp->resume = &r->resume[ndx];
          thread->last_resume_kind = lwp->resume->kind;
 
@@ -4821,7 +4974,7 @@ start_step_over (struct lwp_info *lwp)
 }
 
 /* Finish a step-over.  Reinsert the breakpoint we had uninserted in
-   start_step_over, if still there, and delete any reinsert
+   start_step_over, if still there, and delete any single-step
    breakpoints we've set, on non hardware single-step targets.  */
 
 static int
@@ -4843,15 +4996,15 @@ finish_step_over (struct lwp_info *lwp)
 
       lwp->bp_reinsert = 0;
 
-      /* Delete any software-single-step reinsert breakpoints.  No
-        longer needed.  We don't have to worry about other threads
-        hitting this trap, and later not being able to explain it,
-        because we were stepping over a breakpoint, and we hold all
-        threads but LWP stopped while doing that.  */
+      /* Delete any single-step breakpoints.  No longer needed.  We
+        don't have to worry about other threads hitting this trap,
+        and later not being able to explain it, because we were
+        stepping over a breakpoint, and we hold all threads but
+        LWP stopped while doing that.  */
       if (!can_hardware_single_step ())
        {
-         gdb_assert (has_reinsert_breakpoints (current_thread));
-         delete_reinsert_breakpoints (current_thread);
+         gdb_assert (has_single_step_breakpoints (current_thread));
+         delete_single_step_breakpoints (current_thread);
        }
 
       step_over_bkpt = null_ptid;
@@ -5166,7 +5319,15 @@ proceed_one_lwp (struct inferior_list_entry *entry, void *except)
       if (debug_threads)
        debug_printf ("   stepping LWP %ld, client wants it stepping\n",
                      lwpid_of (thread));
-      step = 1;
+
+      /* If resume_step is requested by GDB, install single-step
+        breakpoints when the thread is about to be actually resumed if
+        the single-step breakpoints weren't removed.  */
+      if (can_software_single_step ()
+         && !has_single_step_breakpoints (thread))
+       install_software_single_step_breakpoints (lwp);
+
+      step = maybe_hw_step (thread);
     }
   else if (lwp->bp_reinsert != 0)
     {
@@ -5341,6 +5502,12 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
                 not "active".  This can happen in normal operation,
                 so suppress the warning in this case.  */
            }
+         else if (errno == ESRCH)
+           {
+             /* At this point, ESRCH should mean the process is
+                already gone, in which case we simply ignore attempts
+                to read its registers.  */
+           }
          else
            {
              char s[256];
@@ -5891,8 +6058,6 @@ linux_look_up_symbols (void)
 static void
 linux_request_interrupt (void)
 {
-  extern unsigned long signal_pid;
-
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  */
   kill (-signal_pid, SIGINT);
@@ -6349,6 +6514,8 @@ linux_supports_agent (void)
 static int
 linux_supports_range_stepping (void)
 {
+  if (can_software_single_step ())
+    return 1;
   if (*the_low_target.supports_range_stepping == NULL)
     return 0;