From patchwork Sat Oct 25 14:24:10 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: 3373 Received: (qmail 8836 invoked by alias); 25 Oct 2014 14:24:17 -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 8824 invoked by uid 89); 25 Oct 2014 14:24:16 -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-f42.google.com Received: from mail-oi0-f42.google.com (HELO mail-oi0-f42.google.com) (209.85.218.42) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Sat, 25 Oct 2014 14:24:12 +0000 Received: by mail-oi0-f42.google.com with SMTP id a141so1556873oig.29 for ; Sat, 25 Oct 2014 07:24:10 -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:date:message-id:subject:from:to :content-type; bh=IYx5xGgPVpMSPS8Su9CR1ErD3BNLDnIhkMngXO1SXqs=; b=mO7Crr7ivI7199UufakJyoRF2/aEMXDYpBkb+yD1mF8nN0xurGRBeFxbxIF0hEjXOn YjuRreGBRsVTNcCIa6Su5b8Ew+dzKbT0vxiS1+LBwOn4DsEGd53PuxLD3XHLJoFrNRiY rcF+wG4U4VBU9uYFb3NUWV7zcf9Y30i0y2xzLqX0WSL7PXXOjGsRiQ0XPXkkg/IrMA79 L+XmTL9iQKxDO/ozcy1C8DB99nU0Wc0RwvsrVSew7so8lowrYivxGcy1zmlumD1w1Vyk zu24wTOfQduX7KV3iGgD4ij2RJHzUbmFDIMBjcke5vn1ZLSR79gz58MJ3SkgObWWQ5nq BAzA== X-Gm-Message-State: ALoCoQk/MOz7imb9C5epiTrczWxrVFKnY8EdWy54pqv4C88lY8WGYNpDIKrOmiadpE6LMcKpePeP MIME-Version: 1.0 X-Received: by 10.60.47.40 with SMTP id a8mr9769528oen.18.1414247050302; Sat, 25 Oct 2014 07:24:10 -0700 (PDT) Received: by 10.202.197.13 with HTTP; Sat, 25 Oct 2014 07:24:10 -0700 (PDT) Date: Sat, 25 Oct 2014 07:24:10 -0700 Message-ID: Subject: [PATCH v4] Make chained function calls in expressions work From: Siva Chandra To: gdb-patches , Ulrich Weigand X-IsSubscribed: yes This is a follow up to the thread here: https://sourceware.org/ml/gdb-patches/2014-10/msg00000.html I have made all the suggested changes which now eliminates the need for two patches in this set. The single patch is attached. gdb/ChangeLog: 2014-10-25 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. * expression.h (struct expression): New field 'on_stack_temporaries_vec'. * gdbtypes.c (class_or_union_p): New function. * gdbtypes.h (class_or_union_p): Declare. * infcall.c (call_function_by_hand): New argument EXP of type struct expression *. Setup stack temporaries for return values of class type. (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 (write_value_to_memory): New function. (value_fetch_lazy): Fix its description comment. * value.h (add_value_to_expression_stack) (skip_current_expression_stack, write_value_to_memory): Declare. (value_x_binop, value_x_unop): Update signature and all callers. gdb/testsuite/ChangeLog: 2014-10-25 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..d1cc309 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 */ @@ -136,9 +137,72 @@ parse_to_comma_and_eval (const char **expp) struct value * evaluate_expression (struct expression *exp) { - int pc = 0; + int i, pc = 0; + struct value *res, *val; + struct cleanup *cleanups; + value_vec *vec = exp->on_stack_temporaries_vec; + + cleanups = make_cleanup (VEC_cleanup (value_ptr), + &exp->on_stack_temporaries_vec); + res = evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); + /* If the result is on the expression stack, fetch it and mark it as + not_lval. */ + for (i = 0; VEC_iterate (value_ptr, vec, 1, val); i++) + { + if (res == val) + { + if (value_lazy (res)) + value_fetch_lazy (res); + VALUE_LVAL (res) = not_lval; + break; + } + } + do_cleanups (cleanups); + + 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->on_stack_temporaries_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. */ - return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); +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->on_stack_temporaries_vec)) + { + struct value *v = VEC_last (value_ptr, exp->on_stack_temporaries_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 +1207,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 +1229,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 +1375,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 +1495,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 +1798,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 +1909,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 +2009,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 +2020,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 +2032,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 +2064,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 +2083,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 +2116,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 +2159,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 +2225,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 +2309,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 +2336,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 +2355,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 +2372,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 +2389,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 +2406,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 +2423,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 +2440,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 +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); @@ -2422,7 +2487,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 +2502,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 +2514,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 +2533,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 +2667,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 +2691,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 +2715,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 +2742,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 +2892,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..05242b6 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 *on_stack_temporaries_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/gdbtypes.c b/gdb/gdbtypes.c index ee33d77..5388612 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -2501,6 +2501,15 @@ is_scalar_type_recursive (struct type *t) return 0; } +/* Return true is T is a class or a union. False otherwise. */ + +int +class_or_union_p (const struct type *t) +{ + return (TYPE_CODE (t) == TYPE_CODE_STRUCT + || TYPE_CODE (t) == TYPE_CODE_UNION); +} + /* A helper function which returns true if types A and B represent the "same" class type. This is true if the types have the same main type, or the same name. */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index bd1a0ab..f9d2986 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -1751,6 +1751,8 @@ extern int get_array_bounds (struct type *type, LONGEST *low_bound, extern int class_types_same_p (const struct type *, const struct type *); +extern int class_or_union_p (const struct type *); + extern int is_ancestor (struct type *, struct type *); extern int is_public_ancestor (struct type *, struct type *); diff --git a/gdb/infcall.c b/gdb/infcall.c index bbac693..241ec2e 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -455,6 +455,33 @@ 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) + { + retval = value_from_contents_and_address (type, NULL, addr); + add_value_to_expression_stack (exp, retval); + } + 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 +498,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 +563,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); @@ -719,9 +760,21 @@ 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. + + 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) + if (struct_return || hidden_first_param_p + || (exp != NULL && class_or_union_p (values_type))) { if (gdbarch_inner_than (gdbarch, 1, 2)) { @@ -1059,13 +1112,8 @@ 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 @@ -1076,16 +1124,30 @@ When the function is done executing, GDB will silently stop."), 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 && 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. */ + write_value_to_memory (retval, struct_addr); + add_value_to_expression_stack (exp, retval); + } 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..a03c266 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->on_stack_temporaries_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..a30ec3b --- /dev/null +++ b/gdb/testsuite/gdb.cp/chained-calls.cc @@ -0,0 +1,203 @@ +/* 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]; +} + +class C +{ +public: + C (); + ~C (); + + A operator* (); + + A *a_ptr; +}; + +C::C () +{ + a_ptr = new A; + a_ptr->a = 5678; +} + +C::~C () +{ + delete a_ptr; +} + +A +C::operator* () +{ + return *a_ptr; +} + +#define TYPE_INDEX 1 + +enum type +{ + INT, + CHAR +}; + +union U +{ +public: + U (type t); + type get_type (); + + int a; + char c; + type tp[2]; +}; + +U::U (type t) +{ + tp[TYPE_INDEX] = t; +} + +U +make_int () +{ + return U (INT); +} + +U +make_char () +{ + return U (CHAR); +} + +type +U::get_type () +{ + return tp[TYPE_INDEX]; +} + +int +main () +{ + int i = g(f(0)); + A a = q(p() + r()); + + B b = makeb (); + C c; + + 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..c903bea --- /dev/null +++ b/gdb/testsuite/gdb.cp/chained-calls.exp @@ -0,0 +1,44 @@ +# 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 q(p() + r())" ".* = {a = 22345678}" "q(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(), ...)" +gdb_test "p *c" ".* = {a = 5678}" "*c" +gdb_test "p *c + *c" ".* = {a = 11356}" "*c + *c" +gdb_test "P q(*c + *c)" ".* = {a = 11356}" "q(*c + *c)" +gdb_test "p make_int().get_type ()" ".* = INT" "make_int().get_type ()" 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..d80cf62 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 7f3e4f5..5fcefc2 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.c b/gdb/value.c index ecfb154..058d04f 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -1080,6 +1080,20 @@ set_value_parent (struct value *value, struct value *parent) value_free (old); } +/* Write contents of V at ADDR. Also, set lval_type of V to lval_memory. + It is as error if V's lval_type is anything other than not_lval. */ + +void +write_value_to_memory (struct value *v, CORE_ADDR addr) +{ + gdb_assert (VALUE_LVAL (v) == not_lval); + + write_memory (addr, value_contents_raw (v), TYPE_LENGTH (value_type (v))); + VALUE_LVAL (v) = lval_memory; + v->location.address = addr; + v->lazy = 0; +} + gdb_byte * value_contents_raw (struct value *value) { @@ -3730,11 +3744,8 @@ value_initialized (struct value *val) return val->initialized; } -/* Called only from the value_contents and value_contents_all() - macros, if the current data for a variable needs to be loaded into - value_contents(VAL). Fetches the data from the user's process, and - clears the lazy flag to indicate that the data in the buffer is - valid. +/* Fetches the data from the user's process, and clears the lazy flag + to indicate that the data in the buffer is valid. If the value is zero-length, we avoid calling read_memory, which would abort. We mark the value as fetched anyway -- all 0 bytes of diff --git a/gdb/value.h b/gdb/value.h index e3603c3..1e0efee 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -363,6 +363,8 @@ extern const gdb_byte * extern int value_fetch_lazy (struct value *val); +extern void write_value_to_memory (struct value *v, CORE_ADDR addr); + /* If nonzero, this is the value of a variable which does not actually exist in the program, at least partially. If the value is lazy, this may fetch it now. */ @@ -819,6 +821,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, @@ -939,10 +947,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);