infcall: stop_registers -> register_dummy_frame_dtor
authorJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 13 May 2015 18:47:32 +0000 (20:47 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 13 May 2015 18:49:08 +0000 (20:49 +0200)
With dummy_frame destructors GDB no longer has to use global stop_registers.
dummy_frame's registers can be now stored associated with their specific
dummy_frame.

gdb/ChangeLog
2015-05-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

* infcall.c (struct dummy_frame_context_saver)
(dummy_frame_context_saver_data_free, dummy_frame_context_saver_dtor)
(dummy_frame_context_saver_drop, dummy_frame_context_saver_cleanup)
(dummy_frame_context_saver_get_regs, dummy_frame_context_saver_setup):
New.
(call_function_by_hand_dummy): Move discard_cleanups of
inf_status_cleanup before dummy_frame_push.  Call
dummy_frame_context_saver_setup and prepare context_saver_cleanup.
Use dummy_frame_context_saver_get_regs instead of stop_registers.
* infcall.h (struct dummy_frame_context_saver)
(dummy_frame_context_saver_drop, dummy_frame_context_saver_cleanup)
(dummy_frame_context_saver_get_regs, dummy_frame_context_saver_setup):
New declarations.
* infcmd.c: Include infcall.h.
(get_return_value): Add parameter ctx_saver, use it instead of
stop_registers.
(print_return_value): Add parameter ctx_saver, pass it.
(struct finish_command_continuation_args): Add field ctx_saver.
(finish_command_continuation): Update print_return_value caller.
(finish_command_continuation_free_arg): Free also ctx_saver.
(finish_forward): Call dummy_frame_context_saver_setup.
* inferior.h (struct dummy_frame_context_saver): New declaration.
(get_return_value): Add parameter ctx_saver.
* python/py-finishbreakpoint.c (bpfinishpy_pre_stop_hook): Update
get_return_value caller.

gdb/ChangeLog
gdb/infcall.c
gdb/infcall.h
gdb/infcmd.c
gdb/inferior.h
gdb/python/py-finishbreakpoint.c

index c3d8e113bed27716a33dbb8acc2dfca1b3034015..1d6cd4d6017e03e3f91b5133424f41857c5aa8c1 100644 (file)
@@ -1,3 +1,31 @@
+2015-05-13  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       * infcall.c (struct dummy_frame_context_saver)
+       (dummy_frame_context_saver_data_free, dummy_frame_context_saver_dtor)
+       (dummy_frame_context_saver_drop, dummy_frame_context_saver_cleanup)
+       (dummy_frame_context_saver_get_regs, dummy_frame_context_saver_setup):
+       New.
+       (call_function_by_hand_dummy): Move discard_cleanups of
+       inf_status_cleanup before dummy_frame_push.  Call
+       dummy_frame_context_saver_setup and prepare context_saver_cleanup.
+       Use dummy_frame_context_saver_get_regs instead of stop_registers.
+       * infcall.h (struct dummy_frame_context_saver)
+       (dummy_frame_context_saver_drop, dummy_frame_context_saver_cleanup)
+       (dummy_frame_context_saver_get_regs, dummy_frame_context_saver_setup):
+       New declarations.
+       * infcmd.c: Include infcall.h.
+       (get_return_value): Add parameter ctx_saver, use it instead of
+       stop_registers.
+       (print_return_value): Add parameter ctx_saver, pass it.
+       (struct finish_command_continuation_args): Add field ctx_saver.
+       (finish_command_continuation): Update print_return_value caller.
+       (finish_command_continuation_free_arg): Free also ctx_saver.
+       (finish_forward): Call dummy_frame_context_saver_setup.
+       * inferior.h (struct dummy_frame_context_saver): New declaration.
+       (get_return_value): Add parameter ctx_saver.
+       * python/py-finishbreakpoint.c (bpfinishpy_pre_stop_hook): Update
+       get_return_value caller.
+
 2015-05-13  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * dummy-frame.c (struct dummy_frame_dtor_list): New.
index cef6b915d635406169fb54aa75f6c2065c794a0a..d7515dd5f49b2614454c7ea32d0f95d3ab4a3533 100644 (file)
@@ -469,6 +469,96 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
   return call_function_by_hand_dummy (function, nargs, args, NULL, NULL);
 }
 
+/* Data for dummy_frame_context_saver.  Structure can be freed only
+   after both dummy_frame_context_saver_dtor and
+   dummy_frame_context_saver_drop have been called for it.  */
+
+struct dummy_frame_context_saver
+{
+  /* Inferior registers fetched before associated dummy_frame got freed
+     and before any other destructors of associated dummy_frame got called.
+     It is initialized to NULL.  */
+  struct regcache *retbuf;
+
+  /* It is 1 if this dummy_frame_context_saver_drop has been already
+     called.  */
+  int drop_done;
+};
+
+/* Free struct dummy_frame_context_saver.  */
+
+static void
+dummy_frame_context_saver_free (struct dummy_frame_context_saver *saver)
+{
+  regcache_xfree (saver->retbuf);
+  xfree (saver);
+}
+
+/* Destructor for associated dummy_frame.  */
+
+static void
+dummy_frame_context_saver_dtor (void *data_voidp, int registers_valid)
+{
+  struct dummy_frame_context_saver *data = data_voidp;
+
+  gdb_assert (data->retbuf == NULL);
+
+  if (data->drop_done)
+    dummy_frame_context_saver_free (data);
+  else if (registers_valid)
+    data->retbuf = regcache_dup (get_current_regcache ());
+}
+
+/* Caller is no longer interested in this
+   struct dummy_frame_context_saver.  After its associated dummy_frame
+   gets freed struct dummy_frame_context_saver can be also freed.  */
+
+void
+dummy_frame_context_saver_drop (struct dummy_frame_context_saver *saver)
+{
+  saver->drop_done = 1;
+
+  if (!find_dummy_frame_dtor (dummy_frame_context_saver_dtor, saver))
+    dummy_frame_context_saver_free (saver);
+}
+
+/* Stub dummy_frame_context_saver_drop compatible with make_cleanup.  */
+
+void
+dummy_frame_context_saver_cleanup (void *data)
+{
+  struct dummy_frame_context_saver *saver = data;
+
+  dummy_frame_context_saver_drop (saver);
+}
+
+/* Fetch RETBUF field of possibly opaque DTOR_DATA.
+   RETBUF must not be NULL.  */
+
+struct regcache *
+dummy_frame_context_saver_get_regs (struct dummy_frame_context_saver *saver)
+{
+  gdb_assert (saver->retbuf != NULL);
+  return saver->retbuf;
+}
+
+/* Register provider of inferior registers at the time DUMMY_ID frame of
+   PTID gets freed (before inferior registers get restored to those
+   before dummy_frame).  */
+
+struct dummy_frame_context_saver *
+dummy_frame_context_saver_setup (struct frame_id dummy_id, ptid_t ptid)
+{
+  struct dummy_frame_context_saver *saver;
+
+  saver = xmalloc (sizeof (*saver));
+  saver->retbuf = NULL;
+  saver->drop_done = 0;
+  register_dummy_frame_dtor (dummy_id, inferior_ptid,
+                            dummy_frame_context_saver_dtor, saver);
+  return saver;
+}
+
 /* All this stuff with a dummy frame may seem unnecessarily complicated
    (why not just save registers in GDB?).  The purpose of pushing a dummy
    frame which looks just like a real frame is so that if you call a
@@ -513,6 +603,8 @@ call_function_by_hand_dummy (struct value *function,
   struct gdb_exception e;
   char name_buf[RAW_FUNCTION_ADDRESS_SIZE];
   int stack_temporaries = thread_stack_temporaries_enabled_p (inferior_ptid);
+  struct dummy_frame_context_saver *context_saver;
+  struct cleanup *context_saver_cleanup;
 
   if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
     ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
@@ -886,6 +978,11 @@ call_function_by_hand_dummy (struct value *function,
   if (unwind_on_terminating_exception_p)
     set_std_terminate_breakpoint ();
 
+  /* Discard both inf_status and caller_state cleanups.
+     From this point on we explicitly restore the associated state
+     or discard it.  */
+  discard_cleanups (inf_status_cleanup);
+
   /* Everything's ready, push all the info needed to restore the
      caller (and identify the dummy-frame) onto the dummy-frame
      stack.  */
@@ -894,10 +991,12 @@ call_function_by_hand_dummy (struct value *function,
     register_dummy_frame_dtor (dummy_id, inferior_ptid,
                               dummy_dtor, dummy_dtor_data);
 
-  /* Discard both inf_status and caller_state cleanups.
-     From this point on we explicitly restore the associated state
-     or discard it.  */
-  discard_cleanups (inf_status_cleanup);
+  /* dummy_frame_context_saver_setup must be called last so that its
+     saving of inferior registers gets called first (before possible
+     DUMMY_DTOR destructor).  */
+  context_saver = dummy_frame_context_saver_setup (dummy_id, inferior_ptid);
+  context_saver_cleanup = make_cleanup (dummy_frame_context_saver_cleanup,
+                                       context_saver);
 
   /* Register a clean-up for unwind_on_terminating_exception_breakpoint.  */
   terminate_bp_cleanup = make_cleanup (cleanup_delete_std_terminate_breakpoint,
@@ -1112,13 +1211,8 @@ When the function is done executing, GDB will silently stop."),
      and the dummy frame has already been popped.  */
 
   {
-    struct address_space *aspace = get_regcache_aspace (stop_registers);
-    struct regcache *retbuf = regcache_xmalloc (gdbarch, aspace);
-    struct cleanup *retbuf_cleanup = make_cleanup_regcache_xfree (retbuf);
     struct value *retval = NULL;
 
-    regcache_cpy_no_passthrough (retbuf, stop_registers);
-
     /* Inferior call is successful.  Restore the inferior status.
        At this stage, leave the RETBUF alone.  */
     restore_infcall_control_state (inf_status);
@@ -1145,7 +1239,8 @@ When the function is done executing, GDB will silently stop."),
       {
        retval = allocate_value (values_type);
        gdbarch_return_value (gdbarch, function, values_type,
-                             retbuf, value_contents_raw (retval), NULL);
+                             dummy_frame_context_saver_get_regs (context_saver),
+                             value_contents_raw (retval), NULL);
        if (stack_temporaries && class_or_union_p (values_type))
          {
            /* Values of class type returned in registers are copied onto
@@ -1160,7 +1255,7 @@ When the function is done executing, GDB will silently stop."),
          }
       }
 
-    do_cleanups (retbuf_cleanup);
+    do_cleanups (context_saver_cleanup);
 
     gdb_assert (retval);
     return retval;
index 77c510179ae82a3d3d735723a17ccede354a64db..43b5f66a736f9cfa12a585f3ed74aa731cc8121c 100644 (file)
@@ -50,4 +50,13 @@ extern struct value *
                               dummy_frame_dtor_ftype *dummy_dtor,
                               void *dummy_dtor_data);
 
+struct dummy_frame_context_saver;
+extern void dummy_frame_context_saver_drop
+  (struct dummy_frame_context_saver *data);
+extern void dummy_frame_context_saver_cleanup (void *data_voidp);
+extern struct regcache *dummy_frame_context_saver_get_regs
+  (struct dummy_frame_context_saver *saver);
+extern struct dummy_frame_context_saver *dummy_frame_context_saver_setup
+  (struct frame_id dummy_id, ptid_t ptid);
+
 #endif
index 11d5310766ce077755669461685f5875786e417b..3d6c4c9a6169d24ddb92fb7aa43a771b63cf790b 100644 (file)
@@ -54,6 +54,7 @@
 #include "continuations.h"
 #include "linespec.h"
 #include "cli/cli-utils.h"
+#include "infcall.h"
 
 /* Local functions: */
 
@@ -1506,18 +1507,22 @@ advance_command (char *arg, int from_tty)
 }
 \f
 /* Return the value of the result of a function at the end of a 'finish'
-   command/BP.  */
+   command/BP.  DTOR_DATA (if not NULL) can represent inferior registers
+   right after an inferior call has finished.  */
 
 struct value *
-get_return_value (struct value *function, struct type *value_type)
+get_return_value (struct value *function, struct type *value_type,
+                 struct dummy_frame_context_saver *ctx_saver)
 {
-  struct regcache *stop_regs = stop_registers;
+  struct regcache *stop_regs = NULL;
   struct gdbarch *gdbarch;
   struct value *value;
   struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
 
   /* If stop_registers were not saved, use the current registers.  */
-  if (!stop_regs)
+  if (ctx_saver != NULL)
+    stop_regs = dummy_frame_context_saver_get_regs (ctx_saver);
+  else
     {
       stop_regs = regcache_dup (get_current_regcache ());
       make_cleanup_regcache_xfree (stop_regs);
@@ -1557,12 +1562,15 @@ get_return_value (struct value *function, struct type *value_type)
   return value;
 }
 
-/* Print the result of a function at the end of a 'finish' command.  */
+/* Print the result of a function at the end of a 'finish' command.
+   DTOR_DATA (if not NULL) can represent inferior registers right after
+   an inferior call has finished.  */
 
 static void
-print_return_value (struct value *function, struct type *value_type)
+print_return_value (struct value *function, struct type *value_type,
+                   struct dummy_frame_context_saver *ctx_saver)
 {
-  struct value *value = get_return_value (function, value_type);
+  struct value *value = get_return_value (function, value_type, ctx_saver);
   struct ui_out *uiout = current_uiout;
 
   if (value)
@@ -1613,6 +1621,11 @@ struct finish_command_continuation_args
   int thread;
   struct breakpoint *breakpoint;
   struct symbol *function;
+
+  /* Inferior registers stored right before dummy_frame has been freed
+     after an inferior call.  It can be NULL if no inferior call was
+     involved, GDB will then use current inferior registers.  */
+  struct dummy_frame_context_saver *ctx_saver;
 };
 
 static void
@@ -1653,7 +1666,7 @@ finish_command_continuation (void *arg, int err)
                  /* print_return_value can throw an exception in some
                     circumstances.  We need to catch this so that we still
                     delete the breakpoint.  */
-                 print_return_value (func, value_type);
+                 print_return_value (func, value_type, a->ctx_saver);
                }
              CATCH (ex, RETURN_MASK_ALL)
                {
@@ -1677,7 +1690,11 @@ finish_command_continuation (void *arg, int err)
 static void
 finish_command_continuation_free_arg (void *arg)
 {
-  xfree (arg);
+  struct finish_command_continuation_args *cargs = arg;
+
+  if (cargs->ctx_saver != NULL)
+    dummy_frame_context_saver_drop (cargs->ctx_saver);
+  xfree (cargs);
 }
 
 /* finish_backward -- helper function for finish_command.  */
@@ -1742,13 +1759,21 @@ finish_forward (struct symbol *function, struct frame_info *frame)
   struct symtab_and_line sal;
   struct thread_info *tp = inferior_thread ();
   struct breakpoint *breakpoint;
-  struct cleanup *old_chain;
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
   struct finish_command_continuation_args *cargs;
   int thread = tp->num;
+  struct dummy_frame_context_saver *saver = NULL;
 
   sal = find_pc_line (get_frame_pc (frame), 0);
   sal.pc = get_frame_pc (frame);
 
+  if (get_frame_type (frame) == DUMMY_FRAME)
+    {
+      saver = dummy_frame_context_saver_setup (get_stack_frame_id (frame),
+                                              inferior_ptid);
+      make_cleanup (dummy_frame_context_saver_cleanup, saver);
+    }
+
   breakpoint = set_momentary_breakpoint (gdbarch, sal,
                                         get_stack_frame_id (frame),
                                          bp_finish);
@@ -1756,7 +1781,7 @@ finish_forward (struct symbol *function, struct frame_info *frame)
   /* set_momentary_breakpoint invalidates FRAME.  */
   frame = NULL;
 
-  old_chain = make_cleanup_delete_breakpoint (breakpoint);
+  make_cleanup_delete_breakpoint (breakpoint);
 
   set_longjmp_breakpoint (tp, frame_id);
   make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
@@ -1768,6 +1793,7 @@ finish_forward (struct symbol *function, struct frame_info *frame)
   cargs->thread = thread;
   cargs->breakpoint = breakpoint;
   cargs->function = function;
+  cargs->ctx_saver = saver;
   add_continuation (tp, finish_command_continuation, cargs,
                     finish_command_continuation_free_arg);
   proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
index 253077733a8e1455207da5947eab220d30841c92..0d242fe790f3a4fe56230eea35e626eb9029fbff 100644 (file)
@@ -165,8 +165,10 @@ extern void detach_command (char *, int);
 
 extern void notice_new_inferior (ptid_t, int, int);
 
-extern struct value *get_return_value (struct value *function,
-                                       struct type *value_type);
+struct dummy_frame_context_saver;
+extern struct value *get_return_value
+  (struct value *function, struct type *value_type,
+   struct dummy_frame_context_saver *ctx_saver);
 
 /* Prepare for execution command.  TARGET is the target that will run
    the command.  BACKGROUND determines whether this is a foreground
index 34e964347003a36a3facc4f06bada6b4004ec7dc..e3d48671a43114ab29eae444050bc8ec8e84d51c 100644 (file)
@@ -106,7 +106,10 @@ bpfinishpy_pre_stop_hook (struct gdbpy_breakpoint_object *bp_obj)
         value_object_to_value (self_finishbp->function_value);
       struct type *value_type =
         type_object_to_type (self_finishbp->return_type);
-      struct value *ret = get_return_value (function, value_type);
+
+      /* bpfinishpy_init cannot finish into DUMMY_FRAME (throws an error
+         in such case) so it is OK to always pass CTX_SAVER as NULL.  */
+      struct value *ret = get_return_value (function, value_type, NULL);
 
       if (ret)
         {