From: Jan Kratochvil Date: Wed, 13 May 2015 18:47:32 +0000 (+0200) Subject: infcall: stop_registers -> register_dummy_frame_dtor X-Git-Tag: gdb-7.10-release~514 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8a6c40311297f60ad13827650fdde13da301b505;p=external%2Fbinutils.git infcall: stop_registers -> register_dummy_frame_dtor 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 * 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c3d8e11..1d6cd4d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,33 @@ 2015-05-13 Jan Kratochvil + * 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 + * dummy-frame.c (struct dummy_frame_dtor_list): New. (struct dummy_frame): Replace dtor and dtor_data by dtor_list. (remove_dummy_frame): Process dtor_list. diff --git a/gdb/infcall.c b/gdb/infcall.c index cef6b91..d7515dd 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -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; diff --git a/gdb/infcall.h b/gdb/infcall.h index 77c5101..43b5f66 100644 --- a/gdb/infcall.h +++ b/gdb/infcall.h @@ -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 diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 11d5310..3d6c4c9 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -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) } /* 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); diff --git a/gdb/inferior.h b/gdb/inferior.h index 2530777..0d242fe 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -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 diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c index 34e9643..e3d4867 100644 --- a/gdb/python/py-finishbreakpoint.c +++ b/gdb/python/py-finishbreakpoint.c @@ -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) {