X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Finfcall.c;h=139c361aa403fb59b16886d13e2b03fa0228f1f4;hb=0e1862bb401f47716446aef143b2bf7a4563f541;hp=1b2c3d6eb4c63e1e17bbaccc87500bc30dd20499;hpb=a14dd77ea7e057d2bd7af3d23c65ecef2a1f41a1;p=binutils-gdb.git diff --git a/gdb/infcall.c b/gdb/infcall.c index 1b2c3d6eb4c..139c361aa40 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -1,6 +1,6 @@ /* Perform an inferior function call, for GDB, the GNU debugger. - Copyright (C) 1986-2012 Free Software Foundation, Inc. + Copyright (C) 1986-2015 Free Software Foundation, Inc. This file is part of GDB. @@ -23,19 +23,19 @@ #include "target.h" #include "regcache.h" #include "inferior.h" -#include "gdb_assert.h" +#include "infrun.h" #include "block.h" #include "gdbcore.h" #include "language.h" #include "objfiles.h" #include "gdbcmd.h" #include "command.h" -#include "gdb_string.h" #include "infcall.h" #include "dummy-frame.h" #include "ada-lang.h" #include "gdbthread.h" -#include "exceptions.h" +#include "event-top.h" +#include "observer.h" /* If we can't find a function's name from its address, we print this instead. */ @@ -213,7 +213,6 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, case TYPE_CODE_SET: case TYPE_CODE_RANGE: case TYPE_CODE_STRING: - case TYPE_CODE_BITSTRING: case TYPE_CODE_ERROR: case TYPE_CODE_MEMBERPTR: case TYPE_CODE_METHODPTR: @@ -356,10 +355,10 @@ get_function_name (CORE_ADDR funaddr, char *buf, int buf_size) { /* Try the minimal symbols. */ - struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr); + struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (funaddr); - if (msymbol) - return SYMBOL_PRINT_NAME (msymbol); + if (msymbol.minsym) + return MSYMBOL_PRINT_NAME (msymbol.minsym); } { @@ -384,37 +383,77 @@ get_function_name (CORE_ADDR funaddr, char *buf, int buf_size) static struct gdb_exception run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) { - volatile struct gdb_exception e; + struct gdb_exception caught_error = exception_none; int saved_in_infcall = call_thread->control.in_infcall; ptid_t call_thread_ptid = call_thread->ptid; + int saved_sync_execution = sync_execution; + int was_running = call_thread->state == THREAD_RUNNING; + + /* Infcalls run synchronously, in the foreground. */ + if (target_can_async_p ()) + sync_execution = 1; call_thread->control.in_infcall = 1; - clear_proceed_status (); + clear_proceed_status (0); disable_watchpoints_before_interactive_call_start (); - /* We want stop_registers, please... */ + /* We want to print return value, please... */ call_thread->control.proceed_to_finish = 1; - TRY_CATCH (e, RETURN_MASK_ALL) + TRY { - proceed (real_pc, GDB_SIGNAL_0, 0); + int was_sync = sync_execution; + + proceed (real_pc, GDB_SIGNAL_0); /* Inferior function calls are always synchronous, even if the target supports asynchronous execution. Do here what `proceed' itself does in sync mode. */ - if (target_can_async_p () && is_running (inferior_ptid)) + if (target_can_async_p ()) { wait_for_inferior (); normal_stop (); + /* If GDB was previously in sync execution mode, then ensure + that it remains so. normal_stop calls + async_enable_stdin, so reset it again here. In other + cases, stdin will be re-enabled by + inferior_event_handler, when an exception is thrown. */ + if (was_sync) + async_disable_stdin (); } } + CATCH (e, RETURN_MASK_ALL) + { + caught_error = e; + } + END_CATCH /* At this point the current thread may have changed. Refresh CALL_THREAD as it could be invalid if its thread has exited. */ call_thread = find_thread_ptid (call_thread_ptid); + /* If the infcall does NOT succeed, normal_stop will have already + finished the thread states. However, on success, normal_stop + defers here, so that we can set back the thread states to what + they were before the call. Note that we must also finish the + state of new threads that might have spawned while the call was + running. The main cases to handle are: + + - "(gdb) print foo ()", or any other command that evaluates an + expression at the prompt. (The thread was marked stopped before.) + + - "(gdb) break foo if return_false()" or similar cases where we + do an infcall while handling an event (while the thread is still + marked running). In this example, whether the condition + evaluates true and thus we'll present a user-visible stop is + decided elsewhere. */ + if (!was_running + && ptid_equal (call_thread_ptid, inferior_ptid) + && stop_stack_dummy == STOP_STACK_DUMMY) + finish_thread_state (user_visible_resume_ptid (0)); + enable_watchpoints_after_interactive_call_stop (); /* Call breakpoint_auto_delete on the current contents of the bpstat @@ -422,7 +461,7 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) If all error()s out of proceed ended up calling normal_stop (and perhaps they should; it already does in the special case of error out of resume()), then we wouldn't need this. */ - if (e.reason < 0) + if (caught_error.reason < 0) { if (call_thread != NULL) breakpoint_auto_delete (call_thread->control.stop_bpstat); @@ -431,7 +470,9 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) if (call_thread != NULL) call_thread->control.in_infcall = saved_in_infcall; - return e; + sync_execution = saved_sync_execution; + + return caught_error; } /* A cleanup function that calls delete_std_terminate_breakpoint. */ @@ -441,6 +482,104 @@ cleanup_delete_std_terminate_breakpoint (void *ignore) delete_std_terminate_breakpoint (); } +/* See infcall.h. */ + +struct value * +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 @@ -460,7 +599,10 @@ cleanup_delete_std_terminate_breakpoint (void *ignore) ARGS is modified to contain coerced values. */ struct value * -call_function_by_hand (struct value *function, int nargs, struct value **args) +call_function_by_hand_dummy (struct value *function, + int nargs, struct value **args, + dummy_frame_dtor_ftype *dummy_dtor, + void *dummy_dtor_data) { CORE_ADDR sp; struct type *values_type, *target_values_type; @@ -481,6 +623,9 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) ptid_t call_thread_ptid; 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)); @@ -579,13 +724,40 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) If the ABI specifies a "Red Zone" (see the doco) the code below will quietly trash it. */ sp = old_sp; + + /* Skip over the stack temporaries that might have been generated during + the evaluation of an expression. */ + if (stack_temporaries) + { + struct value *lastval; + + lastval = get_last_thread_stack_temporary (inferior_ptid); + if (lastval != NULL) + { + CORE_ADDR lastval_addr = value_address (lastval); + + if (gdbarch_inner_than (gdbarch, 1, 2)) + { + gdb_assert (sp >= lastval_addr); + sp = lastval_addr; + } + else + { + gdb_assert (sp <= lastval_addr); + sp = lastval_addr + TYPE_LENGTH (value_type (lastval)); + } + + if (gdbarch_frame_align_p (gdbarch)) + sp = gdbarch_frame_align (gdbarch, sp); + } + } } funaddr = find_function_addr (function, &values_type); if (!values_type) values_type = builtin_type (gdbarch)->builtin_int; - CHECK_TYPEDEF (values_type); + values_type = check_typedef (values_type); /* Are we returning a value using a structure return (passing a hidden argument pointing to storage) or a normal value return? @@ -612,6 +784,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) target_values_type = values_type; } + observer_notify_inferior_call_pre (inferior_ptid, funaddr); + /* Determine the location of the breakpoint (and possibly other stuff) that the called function will return to. The SPARC, for a function returning a structure or union, needs to make space for @@ -705,17 +879,27 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) /* Reserve space for the return structure to be written on the stack, if necessary. Make certain that the value is correctly - aligned. */ + aligned. - if (struct_return || hidden_first_param_p) - { - int len = TYPE_LENGTH (values_type); + While evaluating expressions, we reserve space on the stack for + return values of class type even if the language ABI and the target + ABI do not require that the return value be passed as a hidden first + argument. This is because we want to store the return value as an + on-stack temporary while the expression is being evaluated. This + enables us to have chained function calls in expressions. + + Keeping the return values as on-stack temporaries while the expression + is being evaluated is OK because the thread is stopped until the + expression is completely evaluated. */ + if (struct_return || hidden_first_param_p + || (stack_temporaries && class_or_union_p (values_type))) + { if (gdbarch_inner_than (gdbarch, 1, 2)) { /* Stack grows downward. Align STRUCT_ADDR and SP after making space for the return value. */ - sp -= len; + sp -= TYPE_LENGTH (values_type); if (gdbarch_frame_align_p (gdbarch)) sp = gdbarch_frame_align (gdbarch, sp); struct_addr = sp; @@ -727,7 +911,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) if (gdbarch_frame_align_p (gdbarch)) sp = gdbarch_frame_align (gdbarch, sp); struct_addr = sp; - sp += len; + sp += TYPE_LENGTH (values_type); if (gdbarch_frame_align_p (gdbarch)) sp = gdbarch_frame_align (gdbarch, sp); } @@ -815,16 +999,26 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) if (unwind_on_terminating_exception_p) set_std_terminate_breakpoint (); - /* Everything's ready, push all the info needed to restore the - caller (and identify the dummy-frame) onto the dummy-frame - stack. */ - dummy_frame_push (caller_state, &dummy_id); - /* 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. */ + dummy_frame_push (caller_state, &dummy_id, inferior_ptid); + if (dummy_dtor != NULL) + register_dummy_frame_dtor (dummy_id, inferior_ptid, + dummy_dtor, dummy_dtor_data); + + /* 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, NULL); @@ -847,6 +1041,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) e = run_inferior_call (tp, real_pc); } + observer_notify_inferior_call_post (call_thread_ptid, funaddr); + /* Rethrow an error if we got one trying to run the inferior. */ if (e.reason < 0) @@ -929,8 +1125,11 @@ When the function is done executing, GDB will silently stop."), if (stopped_by_random_signal || stop_stack_dummy != STOP_STACK_DUMMY) { - const char *name = get_function_name (funaddr, - name_buf, sizeof (name_buf)); + /* Make a copy as NAME may be in an objfile freed by dummy_frame_pop. */ + char *name = xstrdup (get_function_name (funaddr, + name_buf, sizeof (name_buf))); + make_cleanup (xfree, name); + if (stopped_by_random_signal) { @@ -944,7 +1143,7 @@ When the function is done executing, GDB will silently stop."), /* We must get back to the frame we were before the dummy call. */ - dummy_frame_pop (dummy_id); + dummy_frame_pop (dummy_id, call_thread_ptid); /* We also need to restore inferior status to that before the dummy call. */ @@ -985,7 +1184,7 @@ When the function is done executing, GDB will silently stop."), { /* We must get back to the frame we were before the dummy call. */ - dummy_frame_pop (dummy_id); + dummy_frame_pop (dummy_id, call_thread_ptid); /* We also need to restore inferior status to that before the dummy call. */ @@ -1036,46 +1235,51 @@ 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); - /* Figure out the value returned by the function. */ - retval = allocate_value (values_type); - - if (hidden_first_param_p) - read_value_memory (retval, 0, 1, struct_addr, - value_contents_raw (retval), - TYPE_LENGTH (values_type)); - else if (TYPE_CODE (target_values_type) != TYPE_CODE_VOID) + if (TYPE_CODE (values_type) == TYPE_CODE_VOID) + retval = allocate_value (values_type); + else if (struct_return || hidden_first_param_p) { - /* If the function returns void, don't bother fetching the - return value. */ - switch (gdbarch_return_value (gdbarch, function, target_values_type, - NULL, NULL, NULL)) + if (stack_temporaries) + { + retval = value_from_contents_and_address (values_type, NULL, + struct_addr); + push_thread_stack_temporary (inferior_ptid, retval); + } + else { - case RETURN_VALUE_REGISTER_CONVENTION: - case RETURN_VALUE_ABI_RETURNS_ADDRESS: - case RETURN_VALUE_ABI_PRESERVES_ADDRESS: - gdbarch_return_value (gdbarch, function, values_type, - retbuf, value_contents_raw (retval), NULL); - break; - case RETURN_VALUE_STRUCT_CONVENTION: + retval = allocate_value (values_type); read_value_memory (retval, 0, 1, struct_addr, value_contents_raw (retval), TYPE_LENGTH (values_type)); - break; + } + } + else + { + retval = allocate_value (values_type); + gdbarch_return_value (gdbarch, function, values_type, + 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 + the stack and their lval_type set to lval_memory. This is + required because further evaluation of the expression + could potentially invoke methods on the return value + requiring GDB to evaluate the "this" pointer. To evaluate + the this pointer, GDB needs the memory address of the + value. */ + value_force_lval (retval, struct_addr); + push_thread_stack_temporary (inferior_ptid, retval); } } - do_cleanups (retbuf_cleanup); + do_cleanups (context_saver_cleanup); gdb_assert (retval); return retval;