Beispiel #1
0
/* When running a stand-alone SPE executable, we may need to skip one more
   exec event on startup, to get past the binfmt_misc loader.  */
static void
spu_skip_standalone_loader (void)
{
  if (target_has_execution && !current_inferior ()->attach_flag)
    {
      struct target_waitstatus ws;

      /* Only some kernels report an extra SIGTRAP with the binfmt_misc
	 loader; others do not.  In addition, if we have attached to an
	 already running inferior instead of starting a new one, we will
	 not see the extra SIGTRAP -- and we cannot readily distinguish
	 the two cases, in particular with the extended-remote target.

	 Thus we issue a single-step here.  If no extra SIGTRAP was pending,
	 this will step past the first instruction of the stand-alone SPE
	 executable loader, but we don't care about that.  */

      inferior_thread ()->control.in_infcall = 1; /* Suppress MI messages.  */

      target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
      target_wait (minus_one_ptid, &ws, 0);
      set_executing (minus_one_ptid, 0);

      inferior_thread ()->control.in_infcall = 0;
    }
}
Beispiel #2
0
static void
osf_solib_create_inferior_hook (int from_tty)
{
    struct inferior *inf;
    struct thread_info *tp;

    inf = current_inferior ();

    /* If we are attaching to the inferior, the shared libraries
       have already been mapped, so nothing more to do.  */
    if (inf->attach_flag)
        return;

    /* Nothing to do for statically bound executables.  */

    if (symfile_objfile == NULL
            || symfile_objfile->obfd == NULL
            || ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0))
        return;

    /* Now run the target.  It will eventually get a SIGTRAP, at
       which point all of the libraries will have been mapped in and we
       can go groveling around in the rld structures to find
       out what we need to know about them.

       If debugging from a core file, we cannot resume the execution
       of the inferior.  But this is actually not an issue, because
       shared libraries have already been mapped anyways, which means
       we have nothing more to do.  */
    if (!target_can_run (&current_target))
        return;

    tp = inferior_thread ();
    clear_proceed_status ();
    inf->stop_soon = STOP_QUIETLY;
    tp->stop_signal = TARGET_SIGNAL_0;
    do
    {
        target_resume (minus_one_ptid, 0, tp->stop_signal);
        wait_for_inferior (0);
    }
    while (tp->stop_signal != TARGET_SIGNAL_TRAP);

    /*  solib_add will call reinit_frame_cache.
       But we are stopped in the runtime loader and we do not have symbols
       for the runtime loader. So heuristic_proc_start will be called
       and will put out an annoying warning.
       Delaying the resetting of stop_soon until after symbol loading
       suppresses the warning.  */
    solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
    inf->stop_soon = NO_STOP_QUIETLY;
}
Beispiel #3
0
static void
mi_about_to_proceed (void)
{
  /* Suppress output while calling an inferior function.  */

  if (!ptid_equal (inferior_ptid, null_ptid))
    {
      struct thread_info *tp = inferior_thread ();

      if (tp->control.in_infcall)
	return;
    }

  mi_proceeded = 1;
}
Beispiel #4
0
int
inf_ptrace_target::follow_fork (int follow_child, int detach_fork)
{
  if (!follow_child)
    {
      struct thread_info *tp = inferior_thread ();
      pid_t child_pid = tp->pending_follow.value.related_pid.pid ();

      /* Breakpoints have already been detached from the child by
	 infrun.c.  */

      if (ptrace (PT_DETACH, child_pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
	perror_with_name (("ptrace"));
    }

  return 0;
}
static PyObject *
get_event_thread (void)
{
  PyObject *thread;

  if (non_stop)
    thread = (PyObject *) thread_to_thread_object (inferior_thread ());
  else
    thread = Py_None;

  if (!thread)
    {
      PyErr_SetString (PyExc_RuntimeError, "Could not find event thread");
      return NULL;
    }

  return thread;
}
Beispiel #6
0
static void
cli_on_normal_stop (struct bpstats *bs, int print_frame)
{
  if (!print_frame)
    return;

  SWITCH_THRU_ALL_UIS ()
    {
      struct interp *interp = top_level_interpreter ();
      struct cli_interp *cli = as_cli_interp (interp);
      struct thread_info *thread;

      if (cli == NULL)
	continue;

      thread = inferior_thread ();
      if (should_print_stop_to_console (interp, thread))
	print_stop_event (cli->cli_uiout);
    }
}
Beispiel #7
0
static void
python_on_normal_stop (struct bpstats *bs, int print_frame)
{
  struct cleanup *cleanup;
  enum gdb_signal stop_signal;

  if (!gdb_python_initialized)
    return;

  if (!find_thread_ptid (inferior_ptid))
      return;

  stop_signal = inferior_thread ()->suspend.stop_signal;

  cleanup = ensure_python_env (get_current_arch (), current_language);

  if (emit_stop_event (bs, stop_signal) < 0)
    gdbpy_print_stack ();

  do_cleanups (cleanup);
}
Beispiel #8
0
/* General function to handle events in the inferior.  So far it just
   takes care of detecting errors reported by select() or poll(),
   otherwise it assumes that all is OK, and goes on reading data from
   the fd.  This however may not always be what we want to do.  */
void
inferior_event_handler (enum inferior_event_type event_type, 
			gdb_client_data client_data)
{
  struct cleanup *cleanup_if_error = make_bpstat_clear_actions_cleanup ();

  switch (event_type)
    {
    case INF_REG_EVENT:
      /* Use catch errors for now, until the inner layers of
	 fetch_inferior_event (i.e. readchar) can return meaningful
	 error status.  If an error occurs while getting an event from
	 the target, just cancel the current command.  */
      if (!catch_errors (fetch_inferior_event_wrapper, 
			 client_data, "", RETURN_MASK_ALL))
	{
	  bpstat_clear_actions ();
	  do_all_intermediate_continuations (1);
	  do_all_continuations (1);
	  async_enable_stdin ();
	  display_gdb_prompt (0);
	}
      break;

    case INF_EXEC_COMPLETE:
      if (!non_stop)
	{
	  /* Unregister the inferior from the event loop.  This is done
	     so that when the inferior is not running we don't get
	     distracted by spurious inferior output.  */
	  if (target_has_execution)
	    target_async (NULL, 0);
	}

      /* Do all continuations associated with the whole inferior (not
	 a particular thread).  */
      if (!ptid_equal (inferior_ptid, null_ptid))
	do_all_inferior_continuations (0);

      /* If we were doing a multi-step (eg: step n, next n), but it
	 got interrupted by a breakpoint, still do the pending
	 continuations.  The continuation itself is responsible for
	 distinguishing the cases.  The continuations are allowed to
	 touch the inferior memory, e.g. to remove breakpoints, so run
	 them before running breakpoint commands, which may resume the
	 target.  */
      if (non_stop
	  && target_has_execution
	  && !ptid_equal (inferior_ptid, null_ptid))
	do_all_intermediate_continuations_thread (inferior_thread (), 0);
      else
	do_all_intermediate_continuations (0);

      /* Always finish the previous command before running any
	 breakpoint commands.  Any stop cancels the previous command.
	 E.g. a "finish" or "step-n" command interrupted by an
	 unrelated breakpoint is canceled.  */
      if (non_stop
	  && target_has_execution
	  && !ptid_equal (inferior_ptid, null_ptid))
	do_all_continuations_thread (inferior_thread (), 0);
      else
	do_all_continuations (0);

      /* When running a command list (from a user command, say), these
	 are only run when the command list is all done.  */
      if (interpreter_async)
	{
	  volatile struct gdb_exception e;

	  check_frame_language_change ();

	  /* Don't propagate breakpoint commands errors.  Either we're
	     stopping or some command resumes the inferior.  The user will
	     be informed.  */
	  TRY_CATCH (e, RETURN_MASK_ALL)
	    {
	      bpstat_do_actions ();
	    }
	  exception_print (gdb_stderr, e);
	}
      break;

    case INF_EXEC_CONTINUE:
      /* Is there anything left to do for the command issued to
         complete?  */

      if (non_stop)
	do_all_intermediate_continuations_thread (inferior_thread (), 0);
      else
	do_all_intermediate_continuations (0);
      break;

    case INF_TIMER:
    default:
      printf_unfiltered (_("Event type not recognized.\n"));
      break;
    }

  discard_cleanups (cleanup_if_error);
}
Beispiel #9
0
static void
mi_on_resume (ptid_t ptid)
{
  struct thread_info *tp = NULL;

  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
    tp = inferior_thread ();
  else
    tp = find_thread_ptid (ptid);

  /* Suppress output while calling an inferior function.  */
  if (tp->control.in_infcall)
    return;

  /* To cater for older frontends, emit ^running, but do it only once
     per each command.  We do it here, since at this point we know
     that the target was successfully resumed, and in non-async mode,
     we won't return back to MI interpreter code until the target
     is done running, so delaying the output of "^running" until then
     will make it impossible for frontend to know what's going on.

     In future (MI3), we'll be outputting "^done" here.  */
  if (!running_result_record_printed && mi_proceeded)
    {
      fprintf_unfiltered (raw_stdout, "%s^running\n",
			  current_token ? current_token : "");
    }

  if (ptid_get_pid (ptid) == -1)
    fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
  else if (ptid_is_pid (ptid))
    {
      int count = 0;

      /* Backwards compatibility.  If there's only one inferior,
	 output "all", otherwise, output each resumed thread
	 individually.  */
      iterate_over_inferiors (mi_inferior_count, &count);

      if (count == 1)
	fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
      else
	iterate_over_threads (mi_output_running_pid, &ptid);
    }
  else
    {
      struct thread_info *ti = find_thread_ptid (ptid);

      gdb_assert (ti);
      fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n", ti->num);
    }

  if (!running_result_record_printed && mi_proceeded)
    {
      running_result_record_printed = 1;
      /* This is what gdb used to do historically -- printing prompt even if
	 it cannot actually accept any input.  This will be surely removed
	 for MI3, and may be removed even earlier.  SYNC_EXECUTION is
	 checked here because we only need to emit a prompt if a
	 synchronous command was issued when the target is async.  */
      if (!target_is_async_p () || sync_execution)
	fputs_unfiltered ("(gdb) \n", raw_stdout);
    }
  gdb_flush (raw_stdout);
}
Beispiel #10
0
static void
mi_on_normal_stop (struct bpstats *bs, int print_frame)
{
  /* Since this can be called when CLI command is executing,
     using cli interpreter, be sure to use MI uiout for output,
     not the current one.  */
  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());

  if (print_frame)
    {
      int core;

      if (current_uiout != mi_uiout)
	{
	  /* The normal_stop function has printed frame information
	     into CLI uiout, or some other non-MI uiout.  There's no
	     way we can extract proper fields from random uiout
	     object, so we print the frame again.  In practice, this
	     can only happen when running a CLI command in MI.  */
	  struct ui_out *saved_uiout = current_uiout;
	  struct target_waitstatus last;
	  ptid_t last_ptid;

	  current_uiout = mi_uiout;

	  get_last_target_status (&last_ptid, &last);
	  print_stop_event (&last);

	  current_uiout = saved_uiout;
	}
      /* Otherwise, frame information has already been printed by
	 normal_stop.  */
      else
	{
	  /* Breakpoint hits should always be mirrored to the console.
	     Deciding what to mirror to the console wrt to breakpoints
	     and random stops gets messy real fast.  E.g., say "s"
	     trips on a breakpoint.  We'd clearly want to mirror the
	     event to the console in this case.  But what about more
	     complicated cases like "s&; thread n; s&", and one of
	     those steps spawning a new thread, and that thread
	     hitting a breakpoint?  It's impossible in general to
	     track whether the thread had any relation to the commands
	     that had been executed.  So we just simplify and always
	     mirror breakpoints and random events to the console.

	     Also, CLI execution commands (-interpreter-exec console
	     "next", for example) in async mode have the opposite
	     issue as described in the "then" branch above --
	     normal_stop has already printed frame information to MI
	     uiout, but nothing has printed the same information to
	     the CLI channel.  We should print the source line to the
	     console when stepping or other similar commands, iff the
	     step was started by a console command (but not if it was
	     started with -exec-step or similar).  */
	  struct thread_info *tp = inferior_thread ();

	  if ((!tp->control.stop_step
		  && !tp->control.proceed_to_finish)
	      || (tp->control.command_interp != NULL
		  && tp->control.command_interp != top_level_interpreter ()))
	    {
	      struct mi_interp *mi = top_level_interpreter_data ();
	      struct target_waitstatus last;
	      ptid_t last_ptid;
	      struct cleanup *old_chain;

	      /* Set the current uiout to CLI uiout temporarily.  */
	      old_chain = make_cleanup (restore_current_uiout_cleanup,
					current_uiout);
	      current_uiout = mi->cli_uiout;

	      get_last_target_status (&last_ptid, &last);
	      print_stop_event (&last);

	      do_cleanups (old_chain);
	    }
	}

      ui_out_field_int (mi_uiout, "thread-id",
			pid_to_thread_id (inferior_ptid));
      if (non_stop)
	{
	  struct cleanup *back_to = make_cleanup_ui_out_list_begin_end 
	    (mi_uiout, "stopped-threads");

	  ui_out_field_int (mi_uiout, NULL,
			    pid_to_thread_id (inferior_ptid));
	  do_cleanups (back_to);
	}
      else
	ui_out_field_string (mi_uiout, "stopped-threads", "all");

      core = target_core_of_thread (inferior_ptid);
      if (core != -1)
	ui_out_field_int (mi_uiout, "core", core);
    }
  
  fputs_unfiltered ("*stopped", raw_stdout);
  mi_out_put (mi_uiout, raw_stdout);
  mi_out_rewind (mi_uiout);
  mi_print_timing_maybe ();
  fputs_unfiltered ("\n", raw_stdout);
  gdb_flush (raw_stdout);
}
/* General function to handle events in the inferior. So far it just
   takes care of detecting errors reported by select() or poll(),
   otherwise it assumes that all is OK, and goes on reading data from
   the fd. This however may not always be what we want to do. */
void
inferior_event_handler (enum inferior_event_type event_type, 
			gdb_client_data client_data)
{
  struct gdb_exception e;
  int was_sync = 0;

  switch (event_type)
    {
    case INF_ERROR:
      printf_unfiltered (_("error detected from target.\n"));
      pop_all_targets_above (file_stratum, 0);
      discard_all_intermediate_continuations ();
      discard_all_continuations ();
      async_enable_stdin ();
      break;

    case INF_REG_EVENT:
      /* Use catch errors for now, until the inner layers of
	 fetch_inferior_event (i.e. readchar) can return meaningful
	 error status.  If an error occurs while getting an event from
	 the target, just get rid of the target. */
      if (!catch_errors (fetch_inferior_event_wrapper, 
			 client_data, "", RETURN_MASK_ALL))
	{
	  pop_all_targets_above (file_stratum, 0);
	  discard_all_intermediate_continuations ();
	  discard_all_continuations ();
	  async_enable_stdin ();
	  display_gdb_prompt (0);
	}
      break;

    case INF_EXEC_COMPLETE:

      if (!non_stop)
	{
	  /* Unregister the inferior from the event loop. This is done
	     so that when the inferior is not running we don't get
	     distracted by spurious inferior output.  */
	  if (target_has_execution)
	    target_async (NULL, 0);
	}

      /* The call to async_enable_stdin below resets 'sync_execution'.
	 However, if sync_execution is 1 now, we also need to show the
	 prompt below, so save the current value.  */
      was_sync = sync_execution;
      async_enable_stdin ();

      /* Do all continuations associated with the whole inferior (not
	 a particular thread).  */
      if (!ptid_equal (inferior_ptid, null_ptid))
	do_all_inferior_continuations ();

      /* If we were doing a multi-step (eg: step n, next n), but it
	 got interrupted by a breakpoint, still do the pending
	 continuations.  The continuation itself is responsible for
	 distinguishing the cases.  The continuations are allowed to
	 touch the inferior memory, e.g. to remove breakpoints, so run
	 them before running breakpoint commands, which may resume the
	 target.  */
      if (non_stop
	  && target_has_execution
	  && !ptid_equal (inferior_ptid, null_ptid))
	do_all_intermediate_continuations_thread (inferior_thread ());
      else
	do_all_intermediate_continuations ();

      /* Always finish the previous command before running any
	 breakpoint commands.  Any stop cancels the previous command.
	 E.g. a "finish" or "step-n" command interrupted by an
	 unrelated breakpoint is canceled.  */
      if (non_stop
	  && target_has_execution
	  && !ptid_equal (inferior_ptid, null_ptid))
	do_all_continuations_thread (inferior_thread ());
      else
	do_all_continuations ();

      if (current_language != expected_language
	  && language_mode == language_mode_auto)
	language_info (1);	/* Print what changed.  */

      /* Don't propagate breakpoint commands errors.  Either we're
	 stopping or some command resumes the inferior.  The user will
	 be informed.  */
      TRY_CATCH (e, RETURN_MASK_ALL)
	{
	  bpstat_do_actions ();
	}

      if (!was_sync
	  && exec_done_display_p
	  && (ptid_equal (inferior_ptid, null_ptid)
	      || !is_running (inferior_ptid)))
	printf_unfiltered (_("completed.\n"));
      break;

    case INF_EXEC_CONTINUE:
      /* Is there anything left to do for the command issued to
         complete? */

      if (non_stop)
	do_all_intermediate_continuations_thread (inferior_thread ());
      else
	do_all_intermediate_continuations ();
      break;

    case INF_QUIT_REQ: 
      /* FIXME: ezannoni 1999-10-04. This call should really be a
	 target vector entry, so that it can be used for any kind of
	 targets. */
      async_remote_interrupt_twice (NULL);
      break;

    case INF_TIMER:
    default:
      printf_unfiltered (_("Event type not recognized.\n"));
      break;
    }
}
Beispiel #12
0
static int
arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs,
		    struct displaced_step_closure *dsc)
{
  CORE_ADDR return_to = 0;

  struct frame_info *frame;
  unsigned int svc_number = displaced_read_reg (regs, dsc, 7);
  int is_sigreturn = 0;
  int is_thumb;

  frame = get_current_frame ();

  is_sigreturn = arm_linux_sigreturn_return_addr(frame, svc_number,
						 &return_to, &is_thumb);
  if (is_sigreturn)
    {
	  struct symtab_and_line sal;

	  if (debug_displaced)
	    fprintf_unfiltered (gdb_stdlog, "displaced: found "
	      "sigreturn/rt_sigreturn SVC call.  PC in frame = %lx\n",
	      (unsigned long) get_frame_pc (frame));

	  if (debug_displaced)
	    fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx.  "
	      "Setting momentary breakpoint.\n", (unsigned long) return_to);

	  gdb_assert (inferior_thread ()->control.step_resume_breakpoint
		      == NULL);

	  sal = find_pc_line (return_to, 0);
	  sal.pc = return_to;
	  sal.section = find_pc_overlay (return_to);
	  sal.explicit_pc = 1;

	  frame = get_prev_frame (frame);

	  if (frame)
	    {
	      inferior_thread ()->control.step_resume_breakpoint
        	= set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame),
					    bp_step_resume);

	      /* set_momentary_breakpoint invalidates FRAME.  */
	      frame = NULL;

	      /* We need to make sure we actually insert the momentary
	         breakpoint set above.  */
	      insert_breakpoints ();
	    }
	  else if (debug_displaced)
	    fprintf_unfiltered (gdb_stderr, "displaced: couldn't find previous "
				"frame to set momentary breakpoint for "
				"sigreturn/rt_sigreturn\n");
	}
      else if (debug_displaced)
	fprintf_unfiltered (gdb_stdlog, "displaced: sigreturn/rt_sigreturn "
			    "SVC call not in signal trampoline frame\n");
    

  /* Preparation: If we detect sigreturn, set momentary breakpoint at resume
		  location, else nothing.
     Insn: unmodified svc.
     Cleanup: if pc lands in scratch space, pc <- insn_addr + 4
              else leave pc alone.  */


  dsc->cleanup = &arm_linux_cleanup_svc;
  /* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
     instruction.  */
  dsc->wrote_to_pc = 1;

  return 0;
}
Beispiel #13
0
static void
mi_on_normal_stop (struct bpstats *bs, int print_frame)
{
  /* Since this can be called when CLI command is executing,
     using cli interpreter, be sure to use MI uiout for output,
     not the current one.  */
  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());

  if (print_frame)
    {
      struct thread_info *tp;
      int core;

      tp = inferior_thread ();

      if (tp->thread_fsm != NULL
	  && thread_fsm_finished_p (tp->thread_fsm))
	{
	  enum async_reply_reason reason;

	  reason = thread_fsm_async_reply_reason (tp->thread_fsm);
	  ui_out_field_string (mi_uiout, "reason",
			       async_reason_lookup (reason));
	}
      print_stop_event (mi_uiout);

      /* Breakpoint hits should always be mirrored to the console.
	 Deciding what to mirror to the console wrt to breakpoints and
	 random stops gets messy real fast.  E.g., say "s" trips on a
	 breakpoint.  We'd clearly want to mirror the event to the
	 console in this case.  But what about more complicated cases
	 like "s&; thread n; s&", and one of those steps spawning a
	 new thread, and that thread hitting a breakpoint?  It's
	 impossible in general to track whether the thread had any
	 relation to the commands that had been executed.  So we just
	 simplify and always mirror breakpoints and random events to
	 the console.

	 OTOH, we should print the source line to the console when
	 stepping or other similar commands, iff the step was started
	 by a console command, but not if it was started with
	 -exec-step or similar.  */
      if ((bpstat_what (tp->control.stop_bpstat).main_action
	   == BPSTAT_WHAT_STOP_NOISY)
	  || !(tp->thread_fsm != NULL
	       && thread_fsm_finished_p (tp->thread_fsm))
	  || (tp->control.command_interp != NULL
	      && tp->control.command_interp != top_level_interpreter ()))
	{
	  struct mi_interp *mi
	    = (struct mi_interp *) top_level_interpreter_data ();

	  print_stop_event (mi->cli_uiout);
	}

      ui_out_field_int (mi_uiout, "thread-id",
			pid_to_thread_id (inferior_ptid));
      if (non_stop)
	{
	  struct cleanup *back_to = make_cleanup_ui_out_list_begin_end 
	    (mi_uiout, "stopped-threads");

	  ui_out_field_int (mi_uiout, NULL,
			    pid_to_thread_id (inferior_ptid));
	  do_cleanups (back_to);
	}
      else
	ui_out_field_string (mi_uiout, "stopped-threads", "all");

      core = target_core_of_thread (inferior_ptid);
      if (core != -1)
	ui_out_field_int (mi_uiout, "core", core);
    }
  
  fputs_unfiltered ("*stopped", raw_stdout);
  mi_out_put (mi_uiout, raw_stdout);
  mi_out_rewind (mi_uiout);
  mi_print_timing_maybe ();
  fputs_unfiltered ("\n", raw_stdout);
  gdb_flush (raw_stdout);
}
Beispiel #14
0
static int
arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
		    struct regcache *regs, struct displaced_step_closure *dsc)
{
  CORE_ADDR from = dsc->insn_addr;
  struct frame_info *frame;
  unsigned int svc_number = displaced_read_reg (regs, from, 7);

  if (debug_displaced)
    fprintf_unfiltered (gdb_stdlog, "displaced: copying Linux svc insn %.8lx\n",
			(unsigned long) insn);

  frame = get_current_frame ();

  /* Is this a sigreturn or rt_sigreturn syscall?  Note: these are only useful
     for EABI.  */
  if (svc_number == 119 || svc_number == 173)
    {
      if (get_frame_type (frame) == SIGTRAMP_FRAME)
	{
	  CORE_ADDR return_to;
	  struct symtab_and_line sal;

	  if (debug_displaced)
	    fprintf_unfiltered (gdb_stdlog, "displaced: found "
	      "sigreturn/rt_sigreturn SVC call. PC in frame = %lx\n",
	      (unsigned long) get_frame_pc (frame));

	  return_to = frame_unwind_caller_pc (frame);
	  if (debug_displaced)
	    fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx. "
	      "Setting momentary breakpoint.\n", (unsigned long) return_to);

	  gdb_assert (inferior_thread ()->step_resume_breakpoint == NULL);

	  sal = find_pc_line (return_to, 0);
	  sal.pc = return_to;
	  sal.section = find_pc_overlay (return_to);
	  sal.explicit_pc = 1;

	  frame = get_prev_frame (frame);

	  if (frame)
	    {
	      inferior_thread ()->step_resume_breakpoint
        	= set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame),
					    bp_step_resume);

	      /* We need to make sure we actually insert the momentary
	         breakpoint set above.  */
	      insert_breakpoints ();
	    }
	  else if (debug_displaced)
	    fprintf_unfiltered (gdb_stderr, "displaced: couldn't find previous "
				"frame to set momentary breakpoint for "
				"sigreturn/rt_sigreturn\n");
	}
      else if (debug_displaced)
	fprintf_unfiltered (gdb_stdlog, "displaced: sigreturn/rt_sigreturn "
			    "SVC call not in signal trampoline frame\n");
    }

  /* Preparation: If we detect sigreturn, set momentary breakpoint at resume
		  location, else nothing.
     Insn: unmodified svc.
     Cleanup: if pc lands in scratch space, pc <- insn_addr + 4
              else leave pc alone.  */

  dsc->modinsn[0] = insn;

  dsc->cleanup = &arm_linux_cleanup_svc;
  /* Pretend we wrote to the PC, so cleanup doesn't set PC to the next
     instruction.  */
  dsc->wrote_to_pc = 1;

  return 0;
}