X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gdb%2Finfcall.c;h=b8b7ff5d328f2a44a9199c12753a49b27e832a99;hb=3dd5b83d5bd7977bb5b98c9ef9bd8345c0f26d80;hp=d42248ef5196a98128a0878d538234dc1bc66775;hpb=81b4675a00a6cef0e3e4e965dd70d41d178180e0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infcall.c b/gdb/infcall.c index d42248ef51..b8b7ff5d32 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -228,6 +228,21 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, return value_cast (type, arg); } +/* Return the return type of a function with its first instruction exactly at + the PC address. Return NULL otherwise. */ + +static struct type * +find_function_return_type (CORE_ADDR pc) +{ + struct symbol *sym = find_pc_function (pc); + + if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc + && SYMBOL_TYPE (sym) != NULL) + return TYPE_TARGET_TYPE (SYMBOL_TYPE (sym)); + + return NULL; +} + /* Determine a function's address and its return type from its value. Calls error() if the function is not valid for calling. */ @@ -236,32 +251,42 @@ find_function_addr (struct value *function, struct type **retval_type) { struct type *ftype = check_typedef (value_type (function)); struct gdbarch *gdbarch = get_type_arch (ftype); - enum type_code code = TYPE_CODE (ftype); struct type *value_type = NULL; - CORE_ADDR funaddr; + /* Initialize it just to avoid a GCC false warning. */ + CORE_ADDR funaddr = 0; /* If it's a member function, just look at the function part of it. */ /* Determine address to call. */ - if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) - { - funaddr = value_address (function); - value_type = TYPE_TARGET_TYPE (ftype); - } - else if (code == TYPE_CODE_PTR) + if (TYPE_CODE (ftype) == TYPE_CODE_FUNC + || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + funaddr = value_address (function); + else if (TYPE_CODE (ftype) == TYPE_CODE_PTR) { funaddr = value_as_address (function); ftype = check_typedef (TYPE_TARGET_TYPE (ftype)); if (TYPE_CODE (ftype) == TYPE_CODE_FUNC || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, + ¤t_target); + } + if (TYPE_CODE (ftype) == TYPE_CODE_FUNC + || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + { + value_type = TYPE_TARGET_TYPE (ftype); + + if (TYPE_GNU_IFUNC (ftype)) { - funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, - ¤t_target); - value_type = TYPE_TARGET_TYPE (ftype); + funaddr = gnu_ifunc_resolve_addr (gdbarch, funaddr); + + /* Skip querying the function symbol if no RETVAL_TYPE has been + asked for. */ + if (retval_type) + value_type = find_function_return_type (funaddr); } } - else if (code == TYPE_CODE_INT) + else if (TYPE_CODE (ftype) == TYPE_CODE_INT) { /* Handle the case of functions lacking debugging info. Their values are characters since their addresses are char. */ @@ -362,10 +387,8 @@ static struct gdb_exception run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) { volatile struct gdb_exception e; - int saved_async = 0; int saved_in_infcall = call_thread->control.in_infcall; ptid_t call_thread_ptid = call_thread->ptid; - char *saved_target_shortname = xstrdup (target_shortname); call_thread->control.in_infcall = 1; @@ -376,22 +399,24 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) /* We want stop_registers, please... */ call_thread->control.proceed_to_finish = 1; - if (target_can_async_p ()) - saved_async = target_async_mask (0); - TRY_CATCH (e, RETURN_MASK_ALL) - proceed (real_pc, TARGET_SIGNAL_0, 0); + { + proceed (real_pc, TARGET_SIGNAL_0, 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)) + { + wait_for_inferior (); + normal_stop (); + } + } /* 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); - /* Don't restore the async mask if the target has changed, - saved_async is for the original target. */ - if (saved_async - && strcmp (saved_target_shortname, target_shortname) == 0) - target_async_mask (saved_async); - enable_watchpoints_after_interactive_call_stop (); /* Call breakpoint_auto_delete on the current contents of the bpstat @@ -408,8 +433,6 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) if (call_thread != NULL) call_thread->control.in_infcall = saved_in_infcall; - xfree (saved_target_shortname); - return e; } @@ -470,6 +493,9 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) if (get_traceframe_number () >= 0) error (_("May not call functions while looking at trace frames.")); + if (execution_direction == EXEC_REVERSE) + error (_("Cannot call functions in reverse mode.")); + frame = get_current_frame (); gdbarch = get_frame_arch (frame);