From patchwork Tue Oct 21 12:45:39 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siva Chandra Reddy X-Patchwork-Id: 3309 Received: (qmail 10259 invoked by alias); 21 Oct 2014 12:45:48 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 10236 invoked by uid 89); 21 Oct 2014 12:45:47 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.8 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-oi0-f45.google.com Received: from mail-oi0-f45.google.com (HELO mail-oi0-f45.google.com) (209.85.218.45) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 21 Oct 2014 12:45:44 +0000 Received: by mail-oi0-f45.google.com with SMTP id i138so864490oig.4 for ; Tue, 21 Oct 2014 05:45:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type; bh=QpzaTlGhmQnmXLlcXGuyy28XJK0ql33VBJa/YMXLapE=; b=Ybvy8tIFJySdBWo8vvBmAeO78rVEc+pewvF+9A1aWrp6h43sZKtTY/zeVyp5RRfr44 COwGP7f2/MHi1eitnyVdt134D8d4D8FLj9dpNarz24vk5iscJRjNphxB817OxI9gf2am JFgnG63QQzDrMVSFfprWVPL2NO8ApqBEm0eSOUFGin2vgFh/lUfLte+HP+MqWlsy/a/M 5CGZQssxouzv+Yq49IpP6P77qccEPVdLtLHFOKRV+zUea84wGgO26ePz+DzPBE9hA5cR zfTHg0fHUmUge89Rsc69E6F/GiQceBdpEhjl9G9tllD3ne8u4a0B0vrA7kt0QeZAtzlD SXkQ== X-Gm-Message-State: ALoCoQm+Fygunz5AZ+axDU9ZGBgiEPNWLSZVNxkTlUrOcsrMBgD6d1ngBV2rl1nJJMRVpcu1sGi1 MIME-Version: 1.0 X-Received: by 10.182.234.35 with SMTP id ub3mr13529852obc.37.1413895539464; Tue, 21 Oct 2014 05:45:39 -0700 (PDT) Received: by 10.202.197.13 with HTTP; Tue, 21 Oct 2014 05:45:39 -0700 (PDT) In-Reply-To: References: Date: Tue, 21 Oct 2014 05:45:39 -0700 Message-ID: Subject: Re: [PATCH 2/2 v3] Enable having chained function calls in expressions From: Siva Chandra To: gdb-patches X-IsSubscribed: yes The patch was missing. Attached now. On Mon, Oct 20, 2014 at 1:03 PM, Siva Chandra wrote: > Enable having chained function calls in expressions. > > Link to description: https://sourceware.org/ml/gdb-patches/2014-09/msg00788.html > > gdb/ChangeLog: > > 2014-10-20 Siva Chandra Reddy > > * eval.c (evaluate_expression): Cleanup stack mirrors that might > have been created. > (add_value_to_expression_stack, skip_current_expression_stack): New > functions. > * infcall.c (call_function_by_hand): New argument EXP of type > struct expression *. Setup stack mirrors for return values. > (get_return_value_from_memory): New function. > * infcall.h (call_function_by_hand): Update signature and all callers. > * valarith.c (value_x_binop): New argument EXP of type > struct expression *. > (value_x_unop): Likewise. > * value.c (add_value_to_expression_stack) > (skip_current_expression_stack): New functions. > * value.h (add_value_to_expression_stack) > (skip_current_expression_stack): Declare. > (value_x_binop, value_x_unop): Update signature and all callers. > > gdb/testsuite/ChangeLog: > > 2014-10-20 Siva Chandra Reddy > > * gdb.cp/chained-calls.cc: New file. > * gdb.cp/chained-calls.exp: New file. > * gdb.cp/smartp.exp: Remove KFAIL from c2->inta. diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 5793cd2..32da705 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -10297,7 +10297,7 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp, return allocate_value (TYPE_TARGET_TYPE (rtype)); return allocate_value (rtype); } - return call_function_by_hand (argvec[0], nargs, argvec + 1); + return call_function_by_hand (argvec[0], nargs, argvec + 1, exp); case TYPE_CODE_INTERNAL_FUNCTION: if (noside == EVAL_AVOID_SIDE_EFFECTS) /* We don't know anything about what the internal diff --git a/gdb/elfread.c b/gdb/elfread.c index 19aaed3..dee4ab9 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -955,7 +955,7 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc) /* STT_GNU_IFUNC resolver functions have no parameters. FUNCTION is the function entry address. ADDRESS may be a function descriptor. */ - address_val = call_function_by_hand (function, 0, NULL); + address_val = call_function_by_hand (function, 0, NULL, NULL); address = value_as_address (address_val); address = gdbarch_convert_from_func_ptr_addr (gdbarch, address, ¤t_target); diff --git a/gdb/eval.c b/gdb/eval.c index 5906744..a8844a6 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -38,6 +38,7 @@ #include "valprint.h" #include "gdb_obstack.h" #include "objfiles.h" +#include "common/vec.h" #include /* This is defined in valops.c */ @@ -137,8 +138,59 @@ struct value * evaluate_expression (struct expression *exp) { int pc = 0; + struct value *res; + struct cleanup *cleanups; - return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); + cleanups = make_cleanup (VEC_cleanup (value_ptr), &exp->stack_mirror_vec); + res = evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); + do_cleanups (cleanups); + delink_stack_mirror (res); + + return res; + +} + +/* Add value V to the expression stack of expression EXP. */ + +void +add_value_to_expression_stack (struct expression *exp, struct value *v) +{ + gdb_assert (exp != NULL); + VEC_safe_push (value_ptr, exp->stack_mirror_vec, v); +} + +/* Return an address after skipping over the current values on the expression + stack of EXP. SP is the current stack frame pointer. Non-zero DOWNWARD + indicates that the stack grows downwards/backwards. */ + +CORE_ADDR +skip_current_expression_stack (struct expression *exp, CORE_ADDR sp, + int downward) +{ + CORE_ADDR addr = sp; + + gdb_assert (exp != NULL); + if (!VEC_empty (value_ptr, exp->stack_mirror_vec)) + { + struct value *v = VEC_last (value_ptr, exp->stack_mirror_vec); + CORE_ADDR val_addr = value_address (v); + + if (downward) + { + gdb_assert (sp >= val_addr); + addr = val_addr; + } + else + { + struct type *type; + + gdb_assert (sp <= val_addr); + type = value_type (v); + addr = val_addr + TYPE_LENGTH (type); + } + } + + return addr; } /* Evaluate an expression, avoiding all memory references @@ -1143,12 +1195,12 @@ evaluate_subexp_standard (struct type *expect_type, argvec[3] = value_from_longest (long_type, selector); argvec[4] = 0; - ret = call_function_by_hand (argvec[0], 3, argvec + 1); + ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp); if (gnu_runtime) { /* Function objc_msg_lookup returns a pointer. */ argvec[0] = ret; - ret = call_function_by_hand (argvec[0], 3, argvec + 1); + ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp); } if (value_as_long (ret) == 0) error (_("Target does not respond to this message selector.")); @@ -1165,11 +1217,11 @@ evaluate_subexp_standard (struct type *expect_type, argvec[3] = value_from_longest (long_type, selector); argvec[4] = 0; - ret = call_function_by_hand (argvec[0], 3, argvec + 1); + ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp); if (gnu_runtime) { argvec[0] = ret; - ret = call_function_by_hand (argvec[0], 3, argvec + 1); + ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp); } /* ret should now be the selector. */ @@ -1311,10 +1363,10 @@ evaluate_subexp_standard (struct type *expect_type, deprecated_set_value_type (argvec[0], lookup_pointer_type (lookup_function_type (value_type (argvec[0])))); argvec[0] - = call_function_by_hand (argvec[0], nargs + 2, argvec + 1); + = call_function_by_hand (argvec[0], nargs + 2, argvec + 1, exp); } - ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1); + ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1, exp); return ret; } break; @@ -1431,7 +1483,7 @@ evaluate_subexp_standard (struct type *expect_type, struct value *value = NULL; TRY_CATCH (except, RETURN_MASK_ERROR) { - value = value_x_unop (arg2, op, noside); + value = value_x_unop (arg2, op, noside, exp); } if (except.reason < 0) @@ -1734,7 +1786,7 @@ evaluate_subexp_standard (struct type *expect_type, case TYPE_CODE_XMETHOD: return call_xmethod (argvec[0], nargs, argvec + 1); default: - return call_function_by_hand (argvec[0], nargs, argvec + 1); + return call_function_by_hand (argvec[0], nargs, argvec + 1, exp); } /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve. */ @@ -1845,7 +1897,7 @@ evaluate_subexp_standard (struct type *expect_type, struct value *value = NULL; TRY_CATCH (except, RETURN_MASK_ERROR) { - value = value_x_unop (arg1, op, noside); + value = value_x_unop (arg1, op, noside, exp); } if (except.reason < 0) @@ -1945,7 +1997,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); else return value_concat (arg1, arg2); @@ -1956,7 +2008,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) return arg1; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); else return value_assign (arg1, arg2); @@ -1968,7 +2020,8 @@ evaluate_subexp_standard (struct type *expect_type, return arg1; op = exp->elts[pc + 1].opcode; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside); + return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside, + exp); else if (op == BINOP_ADD && ptrmath_type_p (exp->language_defn, value_type (arg1)) && is_integral_type (value_type (arg2))) @@ -1999,7 +2052,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); else if (ptrmath_type_p (exp->language_defn, value_type (arg1)) && is_integral_type (value_type (arg2))) return value_ptradd (arg1, value_as_long (arg2)); @@ -2018,7 +2071,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); else if (ptrmath_type_p (exp->language_defn, value_type (arg1)) && ptrmath_type_p (exp->language_defn, value_type (arg2))) { @@ -2051,7 +2104,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); else { /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero, @@ -2094,7 +2147,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); else { /* If the user attempts to subscript something that is not an @@ -2160,7 +2213,7 @@ evaluate_subexp_standard (struct type *expect_type, if (binop_user_defined_p (op, arg1, arg2)) { - arg1 = value_x_binop (arg1, arg2, op, OP_NULL, noside); + arg1 = value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2244,7 +2297,7 @@ evaluate_subexp_standard (struct type *expect_type, if (binop_user_defined_p (op, arg1, arg2)) { arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2271,7 +2324,7 @@ evaluate_subexp_standard (struct type *expect_type, if (binop_user_defined_p (op, arg1, arg2)) { arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2290,7 +2343,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) { - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2307,7 +2360,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) { - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2324,7 +2377,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) { - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2341,7 +2394,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) { - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2358,7 +2411,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) { - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2375,7 +2428,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; if (binop_user_defined_p (op, arg1, arg2)) { - return value_x_binop (arg1, arg2, op, OP_NULL, noside); + return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp); } else { @@ -2410,7 +2463,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (unop_user_defined_p (op, arg1)) - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); else { unop_promote (exp->language_defn, exp->gdbarch, &arg1); @@ -2422,7 +2475,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (unop_user_defined_p (op, arg1)) - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); else { unop_promote (exp->language_defn, exp->gdbarch, &arg1); @@ -2437,7 +2490,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (unop_user_defined_p (UNOP_COMPLEMENT, arg1)) - return value_x_unop (arg1, UNOP_COMPLEMENT, noside); + return value_x_unop (arg1, UNOP_COMPLEMENT, noside, exp); else { unop_promote (exp->language_defn, exp->gdbarch, &arg1); @@ -2449,7 +2502,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (unop_user_defined_p (op, arg1)) - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); else { type = language_bool_type (exp->language_defn, exp->gdbarch); @@ -2468,7 +2521,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; if (unop_user_defined_p (op, arg1)) - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); else if (noside == EVAL_AVOID_SIDE_EFFECTS) { type = check_typedef (value_type (arg1)); @@ -2602,7 +2655,7 @@ evaluate_subexp_standard (struct type *expect_type, return arg1; else if (unop_user_defined_p (op, arg1)) { - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); } else { @@ -2626,7 +2679,7 @@ evaluate_subexp_standard (struct type *expect_type, return arg1; else if (unop_user_defined_p (op, arg1)) { - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); } else { @@ -2650,7 +2703,7 @@ evaluate_subexp_standard (struct type *expect_type, return arg1; else if (unop_user_defined_p (op, arg1)) { - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); } else { @@ -2677,7 +2730,7 @@ evaluate_subexp_standard (struct type *expect_type, return arg1; else if (unop_user_defined_p (op, arg1)) { - return value_x_unop (arg1, op, noside); + return value_x_unop (arg1, op, noside, exp); } else { @@ -2827,7 +2880,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, /* We can't optimize out "&*" if there's a user-defined operator*. */ if (unop_user_defined_p (op, x)) { - x = value_x_unop (x, op, noside); + x = value_x_unop (x, op, noside, exp); goto default_case_after_eval; } diff --git a/gdb/expression.h b/gdb/expression.h index 4081a60..96b33c2 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -76,11 +76,17 @@ union exp_element struct objfile *objfile; }; +struct value; +typedef struct value *value_ptr; +DEF_VEC_P (value_ptr); +typedef VEC (value_ptr) value_vec; + struct expression { const struct language_defn *language_defn; /* language it was entered in. */ struct gdbarch *gdbarch; /* architecture it was parsed in. */ + value_vec *stack_mirror_vec; int nelts; union exp_element elts[1]; }; diff --git a/gdb/gcore.c b/gdb/gcore.c index d2adfc8..c4ba961 100644 --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -308,7 +308,7 @@ call_target_sbrk (int sbrk_arg) target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int, sbrk_arg); gdb_assert (target_sbrk_arg); - ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg); + ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg, NULL); if (ret == NULL) return (bfd_vma) 0; diff --git a/gdb/infcall.c b/gdb/infcall.c index bbac693..61b5573 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -455,6 +455,35 @@ cleanup_delete_std_terminate_breakpoint (void *ignore) delete_std_terminate_breakpoint (); } +/* Reads a value returned by an inferior function for those return + values whose address is passed as the hidden first argument. + TYPE is the type of value. ADDR is the address from where to read it. + EXP is the expression whose evaluation lead to calling the inferior + function. It is NULL if the inferior function call was not made while + evaluating an expression. */ + +static struct value * +get_return_value_from_memory (struct type *type, CORE_ADDR addr, + struct expression *exp) +{ + struct value *retval; + if (exp != NULL) + { + struct value *mirror; + + mirror = value_from_contents_and_address (type, NULL, addr); + add_value_to_expression_stack (exp, mirror); + retval = allocate_value_mirrored_on_stack (mirror); + } + else + retval = allocate_value (type); + + read_value_memory (retval, 0, 1, addr, value_contents_raw (retval), + TYPE_LENGTH (type)); + + return retval; +} + /* 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 @@ -471,10 +500,14 @@ cleanup_delete_std_terminate_breakpoint (void *ignore) May fail to return, if a breakpoint or signal is hit during the execution of the function. - ARGS is modified to contain coerced values. */ + ARGS is modified to contain coerced values. + EXP is the expression whose evaluation lead to calling the inferior + function. It is NULL if the inferior function call was not made while + evaluating an expression. */ struct value * -call_function_by_hand (struct value *function, int nargs, struct value **args) +call_function_by_hand (struct value *function, int nargs, struct value **args, + struct expression *exp) { CORE_ADDR sp; struct type *values_type, *target_values_type; @@ -532,6 +565,16 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) { CORE_ADDR old_sp = get_frame_sp (frame); + /* Skip over the stack mirrors that might have been generated during the + evaluation of the current expression. */ + if (exp != NULL) + { + if (gdbarch_inner_than (gdbarch, 1, 2)) + old_sp = skip_current_expression_stack (exp, old_sp, 1); + else + old_sp = skip_current_expression_stack (exp, old_sp, 0); + } + if (gdbarch_frame_align_p (gdbarch)) { sp = gdbarch_frame_align (gdbarch, old_sp); @@ -718,10 +761,17 @@ 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. */ + stack if necessary. Make certain that the value is correctly + aligned. - if (struct_return || hidden_first_param_p) + While evaluating expressions, we reserve space on the stack for the + return value even if the language ABI and the target ABI do not require + that the return value be passed as an hidden first argument. This is + because we want to store the return value as an on-stack mirror of the + actual value returned by this function. This enables us to have chained + function calls in expressions. */ + + if (struct_return || hidden_first_param_p || exp != NULL) { if (gdbarch_inner_than (gdbarch, 1, 2)) { @@ -1059,33 +1109,39 @@ When the function is done executing, GDB will silently stop."), 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)); + retval = get_return_value_from_memory (values_type, struct_addr, exp); else if (TYPE_CODE (target_values_type) != TYPE_CODE_VOID) { /* If the function returns void, don't bother fetching the return value. */ + struct value *mirror; + switch (gdbarch_return_value (gdbarch, function, target_values_type, NULL, NULL, NULL)) { case RETURN_VALUE_REGISTER_CONVENTION: case RETURN_VALUE_ABI_RETURNS_ADDRESS: case RETURN_VALUE_ABI_PRESERVES_ADDRESS: + retval = allocate_value (values_type); gdbarch_return_value (gdbarch, function, values_type, retbuf, value_contents_raw (retval), NULL); + if (exp != NULL) + { + struct value *mirror; + + mirror = setup_stack_mirror (retval, struct_addr); + add_value_to_expression_stack (exp, mirror); + } break; case RETURN_VALUE_STRUCT_CONVENTION: - read_value_memory (retval, 0, 1, struct_addr, - value_contents_raw (retval), - TYPE_LENGTH (values_type)); + retval = get_return_value_from_memory (values_type, struct_addr, + exp); break; } } + else + retval = allocate_value (values_type); do_cleanups (retbuf_cleanup); diff --git a/gdb/infcall.h b/gdb/infcall.h index c6dcdc3..4de931b 100644 --- a/gdb/infcall.h +++ b/gdb/infcall.h @@ -22,6 +22,7 @@ struct value; struct type; +struct expression; extern CORE_ADDR find_function_addr (struct value *function, struct type **retval_type); @@ -36,6 +37,7 @@ extern CORE_ADDR find_function_addr (struct value *function, ARGS is modified to contain coerced values. */ extern struct value *call_function_by_hand (struct value *function, int nargs, - struct value **args); + struct value **args, + struct expression *exp); #endif diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c index 835e612..8ba4741 100644 --- a/gdb/linux-fork.c +++ b/gdb/linux-fork.c @@ -468,7 +468,7 @@ inferior_call_waitpid (ptid_t pptid, int pid) argv[2] = value_from_longest (builtin_type (gdbarch)->builtin_int, 0); argv[3] = 0; - retv = call_function_by_hand (waitpid_fn, 3, argv); + retv = call_function_by_hand (waitpid_fn, 3, argv, NULL); if (value_as_long (retv) < 0) goto out; @@ -683,7 +683,7 @@ checkpoint_command (char *args, int from_tty) old_chain = make_cleanup_restore_integer (&checkpointing_pid); checkpointing_pid = ptid_get_pid (inferior_ptid); - ret = call_function_by_hand (fork_fn, 0, &ret); + ret = call_function_by_hand (fork_fn, 0, &ret, NULL); do_cleanups (old_chain); if (!ret) /* Probably can't happen. */ error (_("checkpoint: call_function_by_hand returned null.")); diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c index 8a3d21e..10194f0 100644 --- a/gdb/objc-lang.c +++ b/gdb/objc-lang.c @@ -131,7 +131,7 @@ lookup_objc_class (struct gdbarch *gdbarch, char *classname) classval = value_string (classname, strlen (classname) + 1, char_type); classval = value_coerce_array (classval); return (CORE_ADDR) value_as_long (call_function_by_hand (function, - 1, &classval)); + 1, &classval, NULL)); } CORE_ADDR @@ -160,7 +160,7 @@ lookup_child_selector (struct gdbarch *gdbarch, char *selname) selstring = value_coerce_array (value_string (selname, strlen (selname) + 1, char_type)); - return value_as_long (call_function_by_hand (function, 1, &selstring)); + return value_as_long (call_function_by_hand (function, 1, &selstring, NULL)); } struct value * @@ -181,12 +181,12 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len) if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0).minsym) { function = find_function_in_inferior("_NSNewStringFromCString", NULL); - nsstringValue = call_function_by_hand(function, 1, &stringValue[2]); + nsstringValue = call_function_by_hand(function, 1, &stringValue[2], NULL); } else if (lookup_minimal_symbol("istr", 0, 0).minsym) { function = find_function_in_inferior("istr", NULL); - nsstringValue = call_function_by_hand(function, 1, &stringValue[2]); + nsstringValue = call_function_by_hand(function, 1, &stringValue[2], NULL); } else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0).minsym) { @@ -198,7 +198,7 @@ value_nsstring (struct gdbarch *gdbarch, char *ptr, int len) (type, lookup_objc_class (gdbarch, "NSString")); stringValue[1] = value_from_longest (type, lookup_child_selector (gdbarch, "stringWithCString:")); - nsstringValue = call_function_by_hand(function, 3, &stringValue[0]); + nsstringValue = call_function_by_hand(function, 3, &stringValue[0], NULL); } else error (_("NSString: internal error -- no way to create new NSString")); @@ -1194,7 +1194,7 @@ print_object_command (char *args, int from_tty) if (function == NULL) error (_("Unable to locate _NSPrintForDebugger in child process")); - description = call_function_by_hand (function, 1, &object); + description = call_function_by_hand (function, 1, &object, NULL); string_addr = value_as_long (description); if (string_addr == 0) diff --git a/gdb/parse.c b/gdb/parse.c index 27947e7..4e93815 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -193,6 +193,7 @@ initialize_expout (struct parser_state *ps, size_t initial_size, + EXP_ELEM_TO_BYTES (ps->expout_size)); ps->expout->language_defn = lang; ps->expout->gdbarch = gdbarch; + ps->expout->stack_mirror_vec = NULL; } /* See definition in parser-defs.h. */ diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 4313170..0d65b48 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -795,7 +795,7 @@ valpy_call (PyObject *self, PyObject *args, PyObject *keywords) struct cleanup *cleanup = make_cleanup_value_free_to_mark (mark); struct value *return_value; - return_value = call_function_by_hand (function, args_count, vargs); + return_value = call_function_by_hand (function, args_count, vargs, NULL); result = value_to_value_object (return_value); do_cleanups (cleanup); } @@ -1039,7 +1039,10 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) if (!handled) { if (binop_user_defined_p (op, arg1, arg2)) - res_val = value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); + { + res_val = value_x_binop (arg1, arg2, op, OP_NULL, + EVAL_NORMAL, NULL); + } else res_val = value_binop (arg1, arg2, op); } diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c index 032f5de..f3bd6c7 100644 --- a/gdb/spu-tdep.c +++ b/gdb/spu-tdep.c @@ -2058,7 +2058,7 @@ flush_ea_cache (void) type = lookup_pointer_type (type); addr = BMSYMBOL_VALUE_ADDRESS (msymbol); - call_function_by_hand (value_from_pointer (type, addr), 0, NULL); + call_function_by_hand (value_from_pointer (type, addr), 0, NULL, NULL); } } diff --git a/gdb/testsuite/gdb.cp/chained-calls.cc b/gdb/testsuite/gdb.cp/chained-calls.cc new file mode 100644 index 0000000..e8f4c17 --- /dev/null +++ b/gdb/testsuite/gdb.cp/chained-calls.cc @@ -0,0 +1,132 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +class S +{ +public: + S () { } + S (S &obj); + + S operator+ (const S &s); + + int a; +}; + +S::S (S &obj) +{ + a = obj.a; +} + +S +S::operator+ (const S &s) +{ + S res; + + res.a = a + s.a; + + return res; +} + +S +f (int i) +{ + S s; + + s.a = i; + + return s; +} + +int +g (const S &s) +{ + return s.a; +} + +class A +{ +public: + A operator+ (const A &); + int a; +}; + +A +A::operator+ (const A &obj) +{ + A n; + + n.a = a + obj.a; + + return n; +} + +A +p () +{ + A a; + a.a = 12345678; + return a; +} + +A +r () +{ + A a; + a.a = 10000000; + return a; +} + +A +q (const A &a) +{ + return a; +} + +class B +{ +public: + int b[1024]; +}; + +B +makeb () +{ + B b; + int i; + + for (i = 0; i < 1024; i++) + b.b[i] = i; + + return b; +} + +int +getb (const B &b, int i) +{ + return b.b[i]; +} + +int +main () +{ + int i = g(f(0)); + A a = q(p() + r()); + + B b = makeb (); + + return i + getb(b, 0); /* Break here */ +} diff --git a/gdb/testsuite/gdb.cp/chained-calls.exp b/gdb/testsuite/gdb.cp/chained-calls.exp new file mode 100644 index 0000000..b8ca775 --- /dev/null +++ b/gdb/testsuite/gdb.cp/chained-calls.exp @@ -0,0 +1,39 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the gdb testsuite + +if {[skip_cplus_tests]} { continue } + +standard_testfile .cc + +if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} { + return -1 +} + +if {![runto_main]} { + return -1 +} + +gdb_breakpoint [gdb_get_line_number "Break here"] +gdb_continue_to_breakpoint "Break here" + +gdb_test "p g(f(12345))" ".* = 12345" "g(f())" +gdb_test "p q(p())" ".* = {a = 12345678}" "q(p())" +gdb_test "p p() + r()" ".* = {a = 22345678}" "p() + r()" +gdb_test "p g(f(6700) + f(89))" ".* = 6789" "g(f() + f())" +gdb_test "p g(f(g(f(300) + f(40))) + f(5))" ".* = 345" \ + "g(f(g(f() + f())) + f())" +gdb_test "p getb(makeb(), 789)" ".* = 789" "getb(makeb(), ...)" diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp index 2a1028a..e3d271f 100644 --- a/gdb/testsuite/gdb.cp/smartp.exp +++ b/gdb/testsuite/gdb.cp/smartp.exp @@ -72,6 +72,5 @@ gdb_test "p b->foo()" "= 66" gdb_test "p c->foo()" "= 66" gdb_test "p c->inta" "= 77" -setup_kfail "gdb/11606" "*-*-*" gdb_test "p c2->inta" "= 77" diff --git a/gdb/valarith.c b/gdb/valarith.c index 154629b..e7e69fe 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -339,11 +339,16 @@ value_user_defined_op (struct value **argp, struct value **args, char *name, OP is the operatore, and if it is BINOP_ASSIGN_MODIFY, then OTHEROP is the opcode saying how to modify it. Otherwise, OTHEROP is - unused. */ + unused. + + EXP is the expression whose evaluation requires performing the binary + operation. It is NULL if the operation is not being performed as part + of an expression evaluation. */ struct value * value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op, - enum exp_opcode otherop, enum noside noside) + enum exp_opcode otherop, enum noside noside, + struct expression *exp) { struct value **argvec; char *ptr; @@ -499,12 +504,13 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op, } else return call_function_by_hand (argvec[0], 2 - static_memfuncp, - argvec + 1); + argvec + 1, exp); } throw_error (NOT_FOUND_ERROR, _("member function %s not found"), tstr); #ifdef lint - return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1); + return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1, + exp); #endif } @@ -512,10 +518,15 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op, defined operator that matches the operator in question. Create an argument vector that calls arg1.operator @ (arg1) and return that value (where '@' is (almost) any unary operator which - is legal for GNU C++). */ + is legal for GNU C++). + + EXP is the expression whose evaluation requires performing the unary + operation. It is NULL if the operation is not being performed as part + of an expression evaluation. */ struct value * -value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside) +value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside, + struct expression *exp) { struct gdbarch *gdbarch = get_type_arch (value_type (arg1)); struct value **argvec; @@ -609,7 +620,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside) return call_xmethod (argvec[0], 1, argvec + 1); } else - return call_function_by_hand (argvec[0], nargs, argvec + 1); + return call_function_by_hand (argvec[0], nargs, argvec + 1, exp); } throw_error (NOT_FOUND_ERROR, _("member function %s not found"), tstr); diff --git a/gdb/valops.c b/gdb/valops.c index 21b24f4..c5be9d7 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -191,7 +191,7 @@ value_allocate_space_in_inferior (int len) struct value *blocklen; blocklen = value_from_longest (builtin_type (gdbarch)->builtin_int, len); - val = call_function_by_hand (val, 1, &blocklen); + val = call_function_by_hand (val, 1, &blocklen, NULL); if (value_logical_not (val)) { if (!target_has_execution) diff --git a/gdb/value.h b/gdb/value.h index 55d5ed6..8d4d79e 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -824,6 +824,12 @@ extern struct value *evaluate_subexp (struct type *expect_type, extern struct value *evaluate_subexpression_type (struct expression *exp, int subexp); +extern void add_value_to_expression_stack (struct expression *exp, + struct value *v); + +extern CORE_ADDR skip_current_expression_stack (struct expression *exp, + CORE_ADDR sp, int downward); + extern void fetch_subexp_value (struct expression *exp, int *pc, struct value **valp, struct value **resultp, struct value **val_chain, @@ -944,10 +950,11 @@ extern struct value *value_of_this_silent (const struct language_defn *lang); extern struct value *value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op, enum exp_opcode otherop, - enum noside noside); + enum noside noside, + struct expression *exp); extern struct value *value_x_unop (struct value *arg1, enum exp_opcode op, - enum noside noside); + enum noside noside, struct expression *exp); extern struct value *value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *type, int offset);