gdb/
[binutils-gdb.git] / gdb / infrun.c
index eb2528ce7b9d771bf431f2b5f13185396645ddf0..6600bbb2ba3bc2ac0bfcf2ec4c345a6ac5a4abef 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
    1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008 Free Software Foundation, Inc.
+   2008, 2009 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -45,7 +45,6 @@
 #include "language.h"
 #include "solib.h"
 #include "main.h"
-
 #include "gdb_assert.h"
 #include "mi/mi-common.h"
 #include "event-top.h"
@@ -1231,7 +1230,8 @@ clear_proceed_status (void)
     }
 
   stop_after_trap = 0;
-  breakpoint_proceeded = 1;    /* We're about to proceed... */
+
+  observer_notify_about_to_proceed ();
 
   if (stop_registers)
     {
@@ -1661,7 +1661,7 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
    Cleanup local state that assumed the PTID was to be resumed, and
    report the stop to the frontend.  */
 
-void
+static void
 infrun_thread_stop_requested (ptid_t ptid)
 {
   struct displaced_step_request *it, *next, *prev = NULL;
@@ -1738,6 +1738,46 @@ delete_step_thread_step_resume_breakpoint_cleanup (void *arg)
   delete_step_thread_step_resume_breakpoint ();
 }
 
+/* Pretty print the results of target_wait, for debugging purposes.  */
+
+static void
+print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
+                          const struct target_waitstatus *ws)
+{
+  char *status_string = target_waitstatus_to_string (ws);
+  struct ui_file *tmp_stream = mem_fileopen ();
+  char *text;
+  long len;
+
+  /* The text is split over several lines because it was getting too long.
+     Call fprintf_unfiltered (gdb_stdlog) once so that the text is still
+     output as a unit; we want only one timestamp printed if debug_timestamp
+     is set.  */
+
+  fprintf_unfiltered (tmp_stream,
+                     "infrun: target_wait (%d", PIDGET (waiton_ptid));
+  if (PIDGET (waiton_ptid) != -1)
+    fprintf_unfiltered (tmp_stream,
+                       " [%s]", target_pid_to_str (waiton_ptid));
+  fprintf_unfiltered (tmp_stream, ", status) =\n");
+  fprintf_unfiltered (tmp_stream,
+                     "infrun:   %d [%s],\n",
+                     PIDGET (result_ptid), target_pid_to_str (result_ptid));
+  fprintf_unfiltered (tmp_stream,
+                     "infrun:   %s\n",
+                     status_string);
+
+  text = ui_file_xstrdup (tmp_stream, &len);
+
+  /* This uses %s in part to handle %'s in the text, but also to avoid
+     a gcc error: the format attribute requires a string literal.  */
+  fprintf_unfiltered (gdb_stdlog, "%s", text);
+
+  xfree (status_string);
+  xfree (text);
+  ui_file_delete (tmp_stream);
+}
+
 /* Wait for control to return from inferior to debugger.
 
    If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
@@ -1783,11 +1823,16 @@ wait_for_inferior (int treat_exec_as_sigtrap)
 
   while (1)
     {
+      struct cleanup *old_chain;
+
       if (deprecated_target_wait_hook)
        ecs->ptid = deprecated_target_wait_hook (waiton_ptid, &ecs->ws);
       else
        ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
 
+      if (debug_infrun)
+       print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
+
       if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
         {
           xfree (ecs->ws.value.execd_pathname);
@@ -1795,9 +1840,17 @@ wait_for_inferior (int treat_exec_as_sigtrap)
           ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
         }
 
+      /* If an error happens while handling the event, propagate GDB's
+        knowledge of the executing state to the frontend/user running
+        state.  */
+      old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+
       /* Now figure out what to do with the result of the result.  */
       handle_inferior_event (ecs);
 
+      /* No error, don't finish the state yet.  */
+      discard_cleanups (old_chain);
+
       if (!ecs->wait_some_more)
        break;
     }
@@ -1820,6 +1873,7 @@ fetch_inferior_event (void *client_data)
   struct execution_control_state ecss;
   struct execution_control_state *ecs = &ecss;
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+  struct cleanup *ts_old_chain;
   int was_sync = sync_execution;
 
   memset (ecs, 0, sizeof (*ecs));
@@ -1854,6 +1908,9 @@ fetch_inferior_event (void *client_data)
   else
     ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
 
+  if (debug_infrun)
+    print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
+
   if (non_stop
       && ecs->ws.kind != TARGET_WAITKIND_IGNORE
       && ecs->ws.kind != TARGET_WAITKIND_EXITED
@@ -1863,6 +1920,14 @@ fetch_inferior_event (void *client_data)
        thread.  */
     context_switch (ecs->ptid);
 
+  /* If an error happens while handling the event, propagate GDB's
+     knowledge of the executing state to the frontend/user running
+     state.  */
+  if (!non_stop)
+    ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+  else
+    ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid);
+
   /* Now figure out what to do with the result of the result.  */
   handle_inferior_event (ecs);
 
@@ -1886,6 +1951,9 @@ fetch_inferior_event (void *client_data)
        inferior_event_handler (INF_EXEC_COMPLETE, NULL);
     }
 
+  /* No error, don't finish the thread states yet.  */
+  discard_cleanups (ts_old_chain);
+
   /* Revert thread and frame.  */
   do_cleanups (old_chain);
 
@@ -4161,9 +4229,23 @@ normal_stop (void)
 {
   struct target_waitstatus last;
   ptid_t last_ptid;
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
 
   get_last_target_status (&last_ptid, &last);
 
+  /* If an exception is thrown from this point on, make sure to
+     propagate GDB's knowledge of the executing state to the
+     frontend/user running state.  A QUIT is an easy exception to see
+     here, so do this before any filtered output.  */
+  if (target_has_execution)
+    {
+      if (!non_stop)
+       make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+      else if (last.kind != TARGET_WAITKIND_SIGNALLED
+              && last.kind != TARGET_WAITKIND_EXITED)
+       make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
+    }
+
   /* In non-stop mode, we don't want GDB to switch threads behind the
      user's back, to avoid races where the user is typing a command to
      apply to thread x, but GDB switches to thread y before the user
@@ -4189,17 +4271,6 @@ normal_stop (void)
       previous_inferior_ptid = inferior_ptid;
     }
 
-  /* NOTE drow/2004-01-17: Is this still necessary?  */
-  /* Make sure that the current_frame's pc is correct.  This
-     is a correction for setting up the frame info before doing
-     gdbarch_decr_pc_after_break */
-  if (target_has_execution)
-    /* FIXME: cagney/2002-12-06: Has the PC changed?  Thanks to
-       gdbarch_decr_pc_after_break, the program counter can change.  Ask the
-       frame code to check for this and sort out any resultant mess.
-       gdbarch_decr_pc_after_break needs to just go away.  */
-    deprecated_update_frame_pc_hack (get_current_frame (), read_pc ());
-
   if (!breakpoints_always_inserted_mode () && target_has_execution)
     {
       if (remove_breakpoints ())
@@ -4207,7 +4278,6 @@ normal_stop (void)
          target_terminal_ours_for_output ();
          printf_filtered (_("\
 Cannot remove breakpoints because program is no longer writable.\n\
-It might be running in another process.\n\
 Further execution is probably impossible.\n"));
        }
     }
@@ -4235,6 +4305,15 @@ Further execution is probably impossible.\n"));
   if (target_has_stack && !stop_stack_dummy)
     set_current_sal_from_frame (get_current_frame (), 1);
 
+  /* Let the user/frontend see the threads as stopped.  */
+  do_cleanups (old_chain);
+
+  /* Look up the hook_stop and run it (CLI internally handles problem
+     of stop_command's pre-hook not existing).  */
+  if (stop_command)
+    catch_errors (hook_stop_stub, stop_command,
+                 "Error while running hook_stop:\n", RETURN_MASK_ALL);
+
   if (!target_has_stack)
     goto done;
 
@@ -4308,22 +4387,6 @@ Further execution is probably impossible.\n"));
              internal_error (__FILE__, __LINE__, _("Unknown value."));
            }
 
-         if (ui_out_is_mi_like_p (uiout))
-           {
-
-             ui_out_field_int (uiout, "thread-id",
-                               pid_to_thread_id (inferior_ptid));
-             if (non_stop)
-               {
-                 struct cleanup *back_to = make_cleanup_ui_out_list_begin_end 
-                   (uiout, "stopped-threads");
-                 ui_out_field_int (uiout, NULL,
-                                   pid_to_thread_id (inferior_ptid));                            
-                 do_cleanups (back_to);
-               }
-             else
-               ui_out_field_string (uiout, "stopped-threads", "all");
-           }
          /* The behavior of this routine with respect to the source
             flag is:
             SRC_LINE: Print only source line
@@ -4352,29 +4415,51 @@ Further execution is probably impossible.\n"));
 
   if (stop_stack_dummy)
     {
-      /* Pop the empty frame that contains the stack dummy.  POP_FRAME
-         ends with a setting of the current frame, so we can use that
-         next. */
-      frame_pop (get_current_frame ());
-      /* Set stop_pc to what it was before we called the function.
-         Can't rely on restore_inferior_status because that only gets
-         called if we don't stop in the called function.  */
-      stop_pc = read_pc ();
+      /* Pop the empty frame that contains the stack dummy.
+        This also restores inferior state prior to the call
+        (struct inferior_thread_state).  */
+      struct frame_info *frame = get_current_frame ();
+      gdb_assert (get_frame_type (frame) == DUMMY_FRAME);
+      frame_pop (frame);
+      /* frame_pop() calls reinit_frame_cache as the last thing it does
+        which means there's currently no selected frame.  We don't need
+        to re-establish a selected frame if the dummy call returns normally,
+        that will be done by restore_inferior_status.  However, we do have
+        to handle the case where the dummy call is returning after being
+        stopped (e.g. the dummy call previously hit a breakpoint).  We
+        can't know which case we have so just always re-establish a
+        selected frame here.  */
       select_frame (get_current_frame ());
     }
 
 done:
   annotate_stopped ();
-  if (!suppress_stop_observer
-      && !(target_has_execution
-          && last.kind != TARGET_WAITKIND_SIGNALLED
-          && last.kind != TARGET_WAITKIND_EXITED
-          && inferior_thread ()->step_multi))
+
+  /* Suppress the stop observer if we're in the middle of:
+
+     - a step n (n > 1), as there still more steps to be done.
+
+     - a "finish" command, as the observer will be called in
+       finish_command_continuation, so it can include the inferior
+       function's return value.
+
+     - calling an inferior function, as we pretend we inferior didn't
+       run at all.  The return value of the call is handled by the
+       expression evaluator, through call_function_by_hand.  */
+
+  if (!target_has_execution
+      || last.kind == TARGET_WAITKIND_SIGNALLED
+      || last.kind == TARGET_WAITKIND_EXITED
+      || (!inferior_thread ()->step_multi
+         && !(inferior_thread ()->stop_bpstat
+              && inferior_thread ()->proceed_to_finish)
+         && !inferior_thread ()->in_infcall))
     {
       if (!ptid_equal (inferior_ptid, null_ptid))
-       observer_notify_normal_stop (inferior_thread ()->stop_bpstat);
+       observer_notify_normal_stop (inferior_thread ()->stop_bpstat,
+                                    stop_print_frame);
       else
-       observer_notify_normal_stop (NULL);
+       observer_notify_normal_stop (NULL, stop_print_frame);
     }
 
   if (target_has_execution)
@@ -4384,26 +4469,7 @@ done:
        /* Delete the breakpoint we stopped at, if it wants to be deleted.
           Delete any breakpoint that is to be deleted at the next stop.  */
        breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
-
-      /* Mark the stopped threads accordingly.  In all-stop, all
-        threads of all processes are stopped when we get any event
-        reported.  In non-stop mode, only the event thread stops.  If
-        we're handling a process exit in non-stop mode, there's
-        nothing to do, as threads of the dead process are gone, and
-        threads of any other process were left running.  */
-      if (!non_stop)
-       set_running (minus_one_ptid, 0);
-      else if (last.kind != TARGET_WAITKIND_SIGNALLED
-              && last.kind != TARGET_WAITKIND_EXITED)
-       set_running (inferior_ptid, 0);
     }
-
-  /* Look up the hook_stop and run it (CLI internally handles problem
-     of stop_command's pre-hook not existing).  */
-  if (stop_command)
-    catch_errors (hook_stop_stub, stop_command,
-                 "Error while running hook_stop:\n", RETURN_MASK_ALL);
-
 }
 
 static int
@@ -4465,7 +4531,7 @@ Signal        Stop\tPrint\tPass to program\tDescription\n"));
 static void
 sig_print_info (enum target_signal oursig)
 {
-  char *name = target_signal_to_name (oursig);
+  const char *name = target_signal_to_name (oursig);
   int name_padding = 13 - strlen (name);
 
   if (name_padding <= 0)
@@ -4613,8 +4679,8 @@ handle_command (char *args, int from_tty)
            case TARGET_SIGNAL_INT:
              if (!allsigs && !sigs[signum])
                {
-                 if (query ("%s is used by the debugger.\n\
-Are you sure you want to change it? ", target_signal_to_name ((enum target_signal) signum)))
+                 if (query (_("%s is used by the debugger.\n\
+Are you sure you want to change it? "), target_signal_to_name ((enum target_signal) signum)))
                    {
                      sigs[signum] = 1;
                    }
@@ -4639,20 +4705,22 @@ Are you sure you want to change it? ", target_signal_to_name ((enum target_signa
       argv++;
     }
 
-  target_notice_signals (inferior_ptid);
+  for (signum = 0; signum < nsigs; signum++)
+    if (sigs[signum])
+      {
+       target_notice_signals (inferior_ptid);
 
-  if (from_tty)
-    {
-      /* Show the results.  */
-      sig_print_header ();
-      for (signum = 0; signum < nsigs; signum++)
-       {
-         if (sigs[signum])
-           {
-             sig_print_info (signum);
-           }
-       }
-    }
+       if (from_tty)
+         {
+           /* Show the results.  */
+           sig_print_header ();
+           for (; signum < nsigs; signum++)
+             if (sigs[signum])
+               sig_print_info (signum);
+         }
+
+       break;
+      }
 
   do_cleanups (old_chain);
 }
@@ -4763,11 +4831,167 @@ signals_info (char *signum_exp, int from_tty)
 
   printf_filtered (_("\nUse the \"handle\" command to change these tables.\n"));
 }
+
+/* The $_siginfo convenience variable is a bit special.  We don't know
+   for sure the type of the value until we actually have a chance to
+   fetch the data.  The type can change depending on gdbarch, so it it
+   also dependent on which thread you have selected.
+
+     1. making $_siginfo be an internalvar that creates a new value on
+     access.
+
+     2. making the value of $_siginfo be an lval_computed value.  */
+
+/* This function implements the lval_computed support for reading a
+   $_siginfo value.  */
+
+static void
+siginfo_value_read (struct value *v)
+{
+  LONGEST transferred;
+
+  transferred =
+    target_read (&current_target, TARGET_OBJECT_SIGNAL_INFO,
+                NULL,
+                value_contents_all_raw (v),
+                value_offset (v),
+                TYPE_LENGTH (value_type (v)));
+
+  if (transferred != TYPE_LENGTH (value_type (v)))
+    error (_("Unable to read siginfo"));
+}
+
+/* This function implements the lval_computed support for writing a
+   $_siginfo value.  */
+
+static void
+siginfo_value_write (struct value *v, struct value *fromval)
+{
+  LONGEST transferred;
+
+  transferred = target_write (&current_target,
+                             TARGET_OBJECT_SIGNAL_INFO,
+                             NULL,
+                             value_contents_all_raw (fromval),
+                             value_offset (v),
+                             TYPE_LENGTH (value_type (fromval)));
+
+  if (transferred != TYPE_LENGTH (value_type (fromval)))
+    error (_("Unable to write siginfo"));
+}
+
+static struct lval_funcs siginfo_value_funcs =
+  {
+    siginfo_value_read,
+    siginfo_value_write
+  };
+
+/* Return a new value with the correct type for the siginfo object of
+   the current thread.  Return a void value if there's no object
+   available.  */
+
+static struct value *
+siginfo_make_value (struct internalvar *var)
+{
+  struct type *type;
+  struct gdbarch *gdbarch;
+
+  if (target_has_stack
+      && !ptid_equal (inferior_ptid, null_ptid))
+    {
+      gdbarch = get_frame_arch (get_current_frame ());
+
+      if (gdbarch_get_siginfo_type_p (gdbarch))
+       {
+         type = gdbarch_get_siginfo_type (gdbarch);
+
+         return allocate_computed_value (type, &siginfo_value_funcs, NULL);
+       }
+    }
+
+  return allocate_value (builtin_type_void);
+}
+
 \f
-struct inferior_status
+/* Inferior thread state.
+   These are details related to the inferior itself, and don't include
+   things like what frame the user had selected or what gdb was doing
+   with the target at the time.
+   For inferior function calls these are things we want to restore
+   regardless of whether the function call successfully completes
+   or the dummy frame has to be manually popped.  */
+
+struct inferior_thread_state
 {
   enum target_signal stop_signal;
   CORE_ADDR stop_pc;
+  struct regcache *registers;
+};
+
+struct inferior_thread_state *
+save_inferior_thread_state (void)
+{
+  struct inferior_thread_state *inf_state = XMALLOC (struct inferior_thread_state);
+  struct thread_info *tp = inferior_thread ();
+
+  inf_state->stop_signal = tp->stop_signal;
+  inf_state->stop_pc = stop_pc;
+
+  inf_state->registers = regcache_dup (get_current_regcache ());
+
+  return inf_state;
+}
+
+/* Restore inferior session state to INF_STATE.  */
+
+void
+restore_inferior_thread_state (struct inferior_thread_state *inf_state)
+{
+  struct thread_info *tp = inferior_thread ();
+
+  tp->stop_signal = inf_state->stop_signal;
+  stop_pc = inf_state->stop_pc;
+
+  /* The inferior can be gone if the user types "print exit(0)"
+     (and perhaps other times).  */
+  if (target_has_execution)
+    /* NB: The register write goes through to the target.  */
+    regcache_cpy (get_current_regcache (), inf_state->registers);
+  regcache_xfree (inf_state->registers);
+  xfree (inf_state);
+}
+
+static void
+do_restore_inferior_thread_state_cleanup (void *state)
+{
+  restore_inferior_thread_state (state);
+}
+
+struct cleanup *
+make_cleanup_restore_inferior_thread_state (struct inferior_thread_state *inf_state)
+{
+  return make_cleanup (do_restore_inferior_thread_state_cleanup, inf_state);
+}
+
+void
+discard_inferior_thread_state (struct inferior_thread_state *inf_state)
+{
+  regcache_xfree (inf_state->registers);
+  xfree (inf_state);
+}
+
+struct regcache *
+get_inferior_thread_state_regcache (struct inferior_thread_state *inf_state)
+{
+  return inf_state->registers;
+}
+
+/* Session related state for inferior function calls.
+   These are the additional bits of state that need to be restored
+   when an inferior function call successfully completes.  */
+
+struct inferior_status
+{
   bpstat stop_bpstat;
   int stop_step;
   int stop_stack_dummy;
@@ -4781,32 +5005,23 @@ struct inferior_status
   int stop_after_trap;
   int stop_soon;
 
-  /* These are here because if call_function_by_hand has written some
-     registers and then decides to call error(), we better not have changed
-     any registers.  */
-  struct regcache *registers;
-
-  /* A frame unique identifier.  */
+  /* ID if the selected frame when the inferior function call was made.  */
   struct frame_id selected_frame_id;
 
-  int breakpoint_proceeded;
-  int restore_stack_info;
   int proceed_to_finish;
+  int in_infcall;
 };
 
 /* Save all of the information associated with the inferior<==>gdb
-   connection.  INF_STATUS is a pointer to a "struct inferior_status"
-   (defined in inferior.h).  */
+   connection.  */
 
 struct inferior_status *
-save_inferior_status (int restore_stack_info)
+save_inferior_status (void)
 {
   struct inferior_status *inf_status = XMALLOC (struct inferior_status);
   struct thread_info *tp = inferior_thread ();
   struct inferior *inf = current_inferior ();
 
-  inf_status->stop_signal = tp->stop_signal;
-  inf_status->stop_pc = stop_pc;
   inf_status->stop_step = tp->stop_step;
   inf_status->stop_stack_dummy = stop_stack_dummy;
   inf_status->stopped_by_random_signal = stopped_by_random_signal;
@@ -4823,13 +5038,11 @@ save_inferior_status (int restore_stack_info)
      called.  */
   inf_status->stop_bpstat = tp->stop_bpstat;
   tp->stop_bpstat = bpstat_copy (tp->stop_bpstat);
-  inf_status->breakpoint_proceeded = breakpoint_proceeded;
-  inf_status->restore_stack_info = restore_stack_info;
   inf_status->proceed_to_finish = tp->proceed_to_finish;
-
-  inf_status->registers = regcache_dup (get_current_regcache ());
+  inf_status->in_infcall = tp->in_infcall;
 
   inf_status->selected_frame_id = get_frame_id (get_selected_frame (NULL));
+
   return inf_status;
 }
 
@@ -4854,14 +5067,14 @@ restore_selected_frame (void *args)
   return (1);
 }
 
+/* Restore inferior session state to INF_STATUS.  */
+
 void
 restore_inferior_status (struct inferior_status *inf_status)
 {
   struct thread_info *tp = inferior_thread ();
   struct inferior *inf = current_inferior ();
 
-  tp->stop_signal = inf_status->stop_signal;
-  stop_pc = inf_status->stop_pc;
   tp->stop_step = inf_status->stop_step;
   stop_stack_dummy = inf_status->stop_stack_dummy;
   stopped_by_random_signal = inf_status->stopped_by_random_signal;
@@ -4874,24 +5087,11 @@ restore_inferior_status (struct inferior_status *inf_status)
   inf->stop_soon = inf_status->stop_soon;
   bpstat_clear (&tp->stop_bpstat);
   tp->stop_bpstat = inf_status->stop_bpstat;
-  breakpoint_proceeded = inf_status->breakpoint_proceeded;
+  inf_status->stop_bpstat = NULL;
   tp->proceed_to_finish = inf_status->proceed_to_finish;
+  tp->in_infcall = inf_status->in_infcall;
 
-  /* The inferior can be gone if the user types "print exit(0)"
-     (and perhaps other times).  */
-  if (target_has_execution)
-    /* NB: The register write goes through to the target.  */
-    regcache_cpy (get_current_regcache (), inf_status->registers);
-  regcache_xfree (inf_status->registers);
-
-  /* FIXME: If we are being called after stopping in a function which
-     is called from gdb, we should not be trying to restore the
-     selected frame; it just prints a spurious error message (The
-     message is useful, however, in detecting bugs in gdb (like if gdb
-     clobbers the stack)).  In fact, should we be restoring the
-     inferior status at all in that case?  .  */
-
-  if (target_has_stack && inf_status->restore_stack_info)
+  if (target_has_stack)
     {
       /* The point of catch_errors is that if the stack is clobbered,
          walking the stack might encounter a garbage pointer and
@@ -4903,7 +5103,6 @@ restore_inferior_status (struct inferior_status *inf_status)
        /* Error in restoring the selected frame.  Select the innermost
           frame.  */
        select_frame (get_current_frame ());
-
     }
 
   xfree (inf_status);
@@ -4926,10 +5125,9 @@ discard_inferior_status (struct inferior_status *inf_status)
 {
   /* See save_inferior_status for info on stop_bpstat. */
   bpstat_clear (&inf_status->stop_bpstat);
-  regcache_xfree (inf_status->registers);
   xfree (inf_status);
 }
-
+\f
 int
 inferior_has_forked (ptid_t pid, ptid_t *child_pid)
 {
@@ -5377,4 +5575,10 @@ Options are 'forward' or 'reverse'."),
 
   observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
   observer_attach_thread_stop_requested (infrun_thread_stop_requested);
+
+  /* Explicitly create without lookup, since that tries to create a
+     value with a void typed value, and when we get here, gdbarch
+     isn't initialized yet.  At this point, we're quite sure there
+     isn't another convenience variable of the same name.  */
+  create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
 }