diff options
Diffstat (limited to 'gnu/usr.bin/gdb/gdb/eval.c')
-rw-r--r-- | gnu/usr.bin/gdb/gdb/eval.c | 1213 |
1 files changed, 1213 insertions, 0 deletions
diff --git a/gnu/usr.bin/gdb/gdb/eval.c b/gnu/usr.bin/gdb/gdb/eval.c new file mode 100644 index 000000000000..f641a65f95a4 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/eval.c @@ -0,0 +1,1213 @@ +/* Evaluate expressions for GDB. + Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "value.h" +#include "expression.h" +#include "target.h" +#include "frame.h" +#include "language.h" /* For CAST_IS_CONVERSION */ + +/* Values of NOSIDE argument to eval_subexp. */ +enum noside +{ EVAL_NORMAL, + EVAL_SKIP, /* Only effect is to increment pos. */ + EVAL_AVOID_SIDE_EFFECTS /* Don't modify any variables or + call any functions. The value + returned will have the correct + type, and will have an + approximately correct lvalue + type (inaccuracy: anything that is + listed as being in a register in + the function in which it was + declared will be lval_register). */ +}; + +/* Prototypes for local functions. */ + +static value +evaluate_subexp_for_sizeof PARAMS ((struct expression *, int *)); + +static value +evaluate_subexp_with_coercion PARAMS ((struct expression *, int *, + enum noside)); + +static value +evaluate_subexp_for_address PARAMS ((struct expression *, int *, + enum noside)); + +static value +evaluate_subexp PARAMS ((struct type *, struct expression *, int *, + enum noside)); + + +/* Parse the string EXP as a C expression, evaluate it, + and return the result as a number. */ + +CORE_ADDR +parse_and_eval_address (exp) + char *exp; +{ + struct expression *expr = parse_expression (exp); + register CORE_ADDR addr; + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + addr = value_as_pointer (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +/* Like parse_and_eval_address but takes a pointer to a char * variable + and advanced that variable across the characters parsed. */ + +CORE_ADDR +parse_and_eval_address_1 (expptr) + char **expptr; +{ + struct expression *expr = parse_exp_1 (expptr, (struct block *)0, 0); + register CORE_ADDR addr; + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + addr = value_as_pointer (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +value +parse_and_eval (exp) + char *exp; +{ + struct expression *expr = parse_expression (exp); + register value val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Parse up to a comma (or to a closeparen) + in the string EXPP as an expression, evaluate it, and return the value. + EXPP is advanced to point to the comma. */ + +value +parse_to_comma_and_eval (expp) + char **expp; +{ + struct expression *expr = parse_exp_1 (expp, (struct block *) 0, 1); + register value val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Evaluate an expression in internal prefix form + such as is constructed by parse.y. + + See expression.h for info on the format of an expression. */ + +static value evaluate_subexp (); +static value evaluate_subexp_for_address (); +static value evaluate_subexp_for_sizeof (); +static value evaluate_subexp_with_coercion (); + +value +evaluate_expression (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL); +} + +/* Evaluate an expression, avoiding all memory references + and getting a value whose type alone is correct. */ + +value +evaluate_type (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS); +} + +static value +evaluate_subexp (expect_type, exp, pos, noside) + struct type *expect_type; + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + int tem, tem2, tem3; + register int pc, pc2 = 0, oldpos; + register value arg1 = NULL, arg2 = NULL, arg3; + struct type *type; + int nargs; + value *argvec; + + pc = (*pos)++; + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_SCOPE: + tem = longest_to_int (exp->elts[pc + 2].longconst); + (*pos) += 4 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = value_struct_elt_for_reference (exp->elts[pc + 1].type, + 0, + exp->elts[pc + 1].type, + &exp->elts[pc + 3].string, + expect_type); + if (arg1 == NULL) + error ("There is no field named %s", &exp->elts[pc + 3].string); + return arg1; + + case OP_LONG: + (*pos) += 3; + return value_from_longest (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst); + + case OP_DOUBLE: + (*pos) += 3; + return value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst); + + case OP_VAR_VALUE: + (*pos) += 3; + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct symbol * sym = exp->elts[pc + 2].symbol; + enum lval_type lv; + + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_LABEL: + case LOC_CONST_BYTES: + lv = not_lval; + break; + + case LOC_REGISTER: + case LOC_REGPARM: + lv = lval_register; + break; + + default: + lv = lval_memory; + break; + } + + return value_zero (SYMBOL_TYPE (sym), lv); + } + else + return value_of_variable (exp->elts[pc + 2].symbol, + exp->elts[pc + 1].block); + + case OP_LAST: + (*pos) += 2; + return + access_value_history (longest_to_int (exp->elts[pc + 1].longconst)); + + case OP_REGISTER: + (*pos) += 2; + return value_of_register (longest_to_int (exp->elts[pc + 1].longconst)); + + case OP_BOOL: + (*pos) += 2; + return value_from_longest (builtin_type_chill_bool, + exp->elts[pc + 1].longconst); + + case OP_INTERNALVAR: + (*pos) += 2; + return value_of_internalvar (exp->elts[pc + 1].internalvar); + + case OP_STRING: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + if (noside == EVAL_SKIP) + goto nosideret; + return value_string (&exp->elts[pc + 2].string, tem); + + case OP_BITSTRING: + error ("support for OP_BITSTRING unimplemented"); + break; + + case OP_ARRAY: + (*pos) += 3; + tem2 = longest_to_int (exp->elts[pc + 1].longconst); + tem3 = longest_to_int (exp->elts[pc + 2].longconst); + nargs = tem3 - tem2 + 1; + argvec = (value *) alloca (sizeof (value) * nargs); + for (tem = 0; tem < nargs; tem++) + { + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + } + if (noside == EVAL_SKIP) + goto nosideret; + return (value_array (tem2, tem3, argvec)); + break; + + case TERNOP_COND: + /* Skip third and second args to evaluate the first one. */ + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (value_logical_not (arg1)) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + return arg2; + } + + case OP_FUNCALL: + (*pos) += 2; + op = exp->elts[*pos].opcode; + if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { + int fnptr; + + nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + + if (noside == EVAL_SKIP) + goto nosideret; + + if (op == STRUCTOP_MEMBER) + { + arg2 = evaluate_subexp_for_address (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + + /* If the function is a virtual function, then the + aggregate value (providing the structure) plays + its part by providing the vtable. Otherwise, + it is just along for the ride: call the function + directly. */ + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + + fnptr = longest_to_int (value_as_long (arg1)); + + if (METHOD_PTR_IS_VIRTUAL(fnptr)) + { + int fnoffset = METHOD_PTR_TO_VOFFSET(fnptr); + struct type *basetype; + struct type *domain_type = + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); + int i, j; + basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); + if (domain_type != basetype) + arg2 = value_cast(lookup_pointer_type (domain_type), arg2); + basetype = TYPE_VPTR_BASETYPE (domain_type); + for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--) + { + struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i); + /* If one is virtual, then all are virtual. */ + if (TYPE_FN_FIELD_VIRTUAL_P (f, 0)) + for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j) + if (TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset) + { + value temp = value_ind (arg2); + arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0); + arg2 = value_addr (temp); + goto got_it; + } + } + if (i < 0) + error ("virtual function at index %d not found", fnoffset); + } + else + { + VALUE_TYPE (arg1) = lookup_pointer_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); + } + got_it: + + /* Now, say which argument to start evaluating from */ + tem = 2; + } + else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { + /* Hair for method invocations */ + int tem2; + + nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; + /* First, evaluate the structure into arg2 */ + pc2 = (*pos)++; + tem2 = longest_to_int (exp->elts[pc2 + 1].longconst); + *pos += 3 + BYTES_TO_EXP_ELEM (tem2 + 1); + if (noside == EVAL_SKIP) + goto nosideret; + + if (op == STRUCTOP_STRUCT) + { + /* If v is a variable in a register, and the user types + v.method (), this will produce an error, because v has + no address. + + A possible way around this would be to allocate a + copy of the variable on the stack, copy in the + contents, call the function, and copy out the + contents. I.e. convert this from call by reference + to call by copy-return (or whatever it's called). + However, this does not work because it is not the + same: the method being called could stash a copy of + the address, and then future uses through that address + (after the method returns) would be expected to + use the variable itself, not some copy of it. */ + arg2 = evaluate_subexp_for_address (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + } + /* Now, say which argument to start evaluating from */ + tem = 2; + } + else + { + nargs = longest_to_int (exp->elts[pc + 1].longconst); + tem = 0; + } + /* Allocate arg vector, including space for the function to be + called in argvec[0] and a terminating NULL */ + argvec = (value *) alloca (sizeof (value) * (nargs + 2)); + for (; tem <= nargs; tem++) + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + + /* signal end of arglist */ + argvec[tem] = 0; + + if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) + { + int static_memfuncp; + value temp = arg2; + + argvec[1] = arg2; + argvec[0] = + value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 2].string, + &static_memfuncp, + op == STRUCTOP_STRUCT + ? "structure" : "structure pointer"); + arg2 = value_from_longest (lookup_pointer_type (VALUE_TYPE (temp)), + VALUE_ADDRESS (temp)+VALUE_OFFSET (temp)); + argvec[1] = arg2; + if (static_memfuncp) + { + argvec[1] = argvec[0]; + nargs--; + argvec++; + } + } + else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) + { + argvec[1] = arg2; + argvec[0] = arg1; + } + + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the return type doesn't look like a function type, call an + error. This can happen if somebody tries to turn a variable into + a function call. This is here because people often want to + call, eg, strcmp, which gdb doesn't know is a function. If + gdb isn't asked for it's opinion (ie. through "whatis"), + it won't offer it. */ + + struct type *ftype = + TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])); + + if (ftype) + return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]))); + else + error ("Expression of type other than \"Function returning ...\" used as function"); + } + return call_function_by_hand (argvec[0], nargs, argvec + 1); + + case STRUCTOP_STRUCT: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0), + lval_memory); + else + { + value temp = arg1; + return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string, + (int *) 0, "structure"); + } + + case STRUCTOP_PTR: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0), + lval_memory); + else + { + value temp = arg1; + return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string, + (int *) 0, "structure pointer"); + } + + case STRUCTOP_MEMBER: + arg1 = evaluate_subexp_for_address (exp, pos, noside); + goto handle_pointer_to_member; + case STRUCTOP_MPTR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + handle_pointer_to_member: + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR) + goto bad_pointer_to_member; + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); + if (TYPE_CODE (type) == TYPE_CODE_METHOD) + error ("not implemented: pointer-to-method in pointer-to-member construct"); + if (TYPE_CODE (type) != TYPE_CODE_MEMBER) + goto bad_pointer_to_member; + /* Now, convert these values to an address. */ + arg1 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg1); + arg3 = value_from_longest (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + value_as_long (arg1) + value_as_long (arg2)); + return value_ind (arg3); + bad_pointer_to_member: + error("non-pointer-to-member value used in pointer-to-member construct"); + + case BINOP_CONCAT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_concat (arg1, arg2); + + case BINOP_ASSIGN: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + 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); + else + return value_assign (arg1, arg2); + + case BINOP_ASSIGN_MODIFY: + (*pos) += 2; + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + 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); + else if (op == BINOP_ADD) + arg2 = value_add (arg1, arg2); + else if (op == BINOP_SUB) + arg2 = value_sub (arg1, arg2); + else + arg2 = value_binop (arg1, arg2, op); + return value_assign (arg1, arg2); + + case BINOP_ADD: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_add (arg1, arg2); + + case BINOP_SUB: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_sub (arg1, arg2); + + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_MOD: + case BINOP_LSH: + case BINOP_RSH: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + if (noside == EVAL_AVOID_SIDE_EFFECTS + && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD)) + return value_zero (VALUE_TYPE (arg1), not_lval); + else + return value_binop (arg1, arg2, op); + + case BINOP_SUBSCRIPT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + if (type) + return value_zero (type, VALUE_LVAL (arg1)); + else + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } + + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL); + else + return value_subscript (arg1, arg2); + + case MULTI_SUBSCRIPT: + (*pos) += 2; + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + while (nargs-- > 0) + { + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + /* FIXME: EVAL_SKIP handling may not be correct. */ + if (noside == EVAL_SKIP) + { + if (nargs > 0) + { + continue; + } + else + { + goto nosideret; + } + } + /* FIXME: EVAL_AVOID_SIDE_EFFECTS handling may not be correct. */ + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + if (type != NULL) + { + arg1 = value_zero (type, VALUE_LVAL (arg1)); + noside = EVAL_SKIP; + continue; + } + else + { + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } + } + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg1 = value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + arg1 = value_subscript (arg1, arg2); + } + } + return (arg1); + + case BINOP_LOGICAL_AND: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + 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); + } + else + { + tem = value_logical_not (arg1); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, + (tem ? EVAL_SKIP : noside)); + return value_from_longest (builtin_type_int, + (LONGEST) (!tem && !value_logical_not (arg2))); + } + + case BINOP_LOGICAL_OR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + 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); + } + else + { + tem = value_logical_not (arg1); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, + (!tem ? EVAL_SKIP : noside)); + return value_from_longest (builtin_type_int, + (LONGEST) (!tem || !value_logical_not (arg2))); + } + + case BINOP_EQUAL: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_NOTEQUAL: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) ! tem); + } + + case BINOP_LESS: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_GTR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg2, arg1); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_GEQ: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg2, arg1) || value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_LEQ: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + { + return value_x_binop (arg1, arg2, op, OP_NULL); + } + else + { + tem = value_less (arg1, arg2) || value_equal (arg1, arg2); + return value_from_longest (builtin_type_int, (LONGEST) tem); + } + + case BINOP_REPEAT: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT) + error ("Non-integral right operand for \"@\" operator."); + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return allocate_repeat_value (VALUE_TYPE (arg1), + longest_to_int (value_as_long (arg2))); + else + return value_repeat (arg1, longest_to_int (value_as_long (arg2))); + + case BINOP_COMMA: + evaluate_subexp (NULL_TYPE, exp, pos, noside); + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_NEG: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op); + else + return value_neg (arg1); + + case UNOP_COMPLEMENT: + /* C++: check for and handle destructor names. */ + op = exp->elts[*pos].opcode; + + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (UNOP_COMPLEMENT, arg1)) + return value_x_unop (arg1, UNOP_COMPLEMENT); + else + return value_complement (arg1); + + case UNOP_LOGICAL_NOT: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op); + else + return value_from_longest (builtin_type_int, + (LONGEST) value_logical_not (arg1)); + + case UNOP_IND: + if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR) + expect_type = TYPE_TARGET_TYPE (expect_type); + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF + /* In C you can dereference an array to get the 1st elt. */ + || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY + ) + return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + lval_memory); + else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT) + /* GDB allows dereferencing an int. */ + return value_zero (builtin_type_int, lval_memory); + else + error ("Attempt to take contents of a non-pointer value."); + } + return value_ind (arg1); + + case UNOP_ADDR: + /* C++: check for and handle pointer to members. */ + + op = exp->elts[*pos].opcode; + + if (noside == EVAL_SKIP) + { + if (op == OP_SCOPE) + { + int temm = longest_to_int (exp->elts[pc+3].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (temm + 1); + } + else + evaluate_subexp (expect_type, exp, pos, EVAL_SKIP); + goto nosideret; + } + + return evaluate_subexp_for_address (exp, pos, noside); + + case UNOP_SIZEOF: + if (noside == EVAL_SKIP) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_sizeof (exp, pos); + + case UNOP_CAST: + (*pos) += 2; + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_cast (exp->elts[pc + 1].type, arg1); + + case UNOP_MEMVAL: + (*pos) += 2; + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (exp->elts[pc + 1].type, lval_memory); + else + return value_at_lazy (exp->elts[pc + 1].type, + value_as_pointer (arg1)); + + case UNOP_PREINCREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_add (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + return value_assign (arg1, arg2); + } + + case UNOP_PREDECREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_sub (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + return value_assign (arg1, arg2); + } + + case UNOP_POSTINCREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_add (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + value_assign (arg1, arg2); + return arg1; + } + + case UNOP_POSTDECREMENT: + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + else if (unop_user_defined_p (op, arg1)) + { + return value_x_unop (arg1, op); + } + else + { + arg2 = value_sub (arg1, value_from_longest (builtin_type_char, + (LONGEST) 1)); + value_assign (arg1, arg2); + return arg1; + } + + case OP_THIS: + (*pos) += 1; + return value_of_this (1); + + case OP_TYPE: + error ("Attempt to use a type name as an expression"); + + default: + /* Removing this case and compiling with gcc -Wall reveals that + a lot of cases are hitting this case. Some of these should + probably be removed from expression.h (e.g. do we need a BINOP_SCOPE + and an OP_SCOPE?); others are legitimate expressions which are + (apparently) not fully implemented. + + If there are any cases landing here which mean a user error, + then they should be separate cases, with more descriptive + error messages. */ + + error ("\ +GDB does not (yet) know how to evaluated that kind of expression"); + } + + nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return the address of that subexpression. + Advance *POS over the subexpression. + If the subexpression isn't an lvalue, get an error. + NOSIDE may be EVAL_AVOID_SIDE_EFFECTS; + then only the type of the result need be correct. */ + +static value +evaluate_subexp_for_address (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + register int pc; + struct symbol *var; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case UNOP_IND: + (*pos)++; + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), + evaluate_subexp (NULL_TYPE, exp, pos, noside)); + + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; + + /* C++: The "address" of a reference should yield the address + * of the object pointed to. Let value_addr() deal with it. */ + if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_REF) + goto default_case; + + (*pos) += 4; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct type *type = + lookup_pointer_type (SYMBOL_TYPE (var)); + enum address_class sym_class = SYMBOL_CLASS (var); + + if (sym_class == LOC_CONST + || sym_class == LOC_CONST_BYTES + || sym_class == LOC_REGISTER + || sym_class == LOC_REGPARM) + error ("Attempt to take address of register or constant."); + + return + value_zero (type, not_lval); + } + else + return + locate_var_value + (var, + block_innermost_frame (exp->elts[pc + 1].block)); + + default: + default_case: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + value x = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (VALUE_LVAL (x) == lval_memory) + return value_zero (lookup_pointer_type (VALUE_TYPE (x)), + not_lval); + else + error ("Attempt to take address of non-lval"); + } + return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + } +} + +/* Evaluate like `evaluate_subexp' except coercing arrays to pointers. + When used in contexts where arrays will be coerced anyway, this is + equivalent to `evaluate_subexp' but much faster because it avoids + actually fetching array contents (perhaps obsolete now that we have + VALUE_LAZY). + + Note that we currently only do the coercion for C expressions, where + arrays are zero based and the coercion is correct. For other languages, + with nonzero based arrays, coercion loses. Use CAST_IS_CONVERSION + to decide if coercion is appropriate. + + */ + +static value +evaluate_subexp_with_coercion (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + register enum exp_opcode op; + register int pc; + register value val; + struct symbol *var; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_VAR_VALUE: + var = exp->elts[pc + 2].symbol; + if (TYPE_CODE (SYMBOL_TYPE (var)) == TYPE_CODE_ARRAY + && CAST_IS_CONVERSION) + { + (*pos) += 4; + val = + locate_var_value + (var, block_innermost_frame (exp->elts[pc + 1].block)); + return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (var))), + val); + } + /* FALLTHROUGH */ + + default: + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return a value for the size of that subexpression. + Advance *POS over the subexpression. */ + +static value +evaluate_subexp_for_sizeof (exp, pos) + register struct expression *exp; + register int *pos; +{ + enum exp_opcode op; + register int pc; + value val; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + /* This case is handled specially + so that we avoid creating a value for the result type. + If the result type is very big, it's desirable not to + create a value unnecessarily. */ + case UNOP_IND: + (*pos)++; + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_longest (builtin_type_int, (LONGEST) + TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val)))); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_from_longest (builtin_type_int, + (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type)); + + case OP_VAR_VALUE: + (*pos) += 4; + return + value_from_longest + (builtin_type_int, + (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 2].symbol))); + + default: + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_longest (builtin_type_int, + (LONGEST) TYPE_LENGTH (VALUE_TYPE (val))); + } +} + +/* Parse a type expression in the string [P..P+LENGTH). */ + +struct type * +parse_and_eval_type (p, length) + char *p; + int length; +{ + char *tmp = (char *)alloca (length + 4); + struct expression *expr; + tmp[0] = '('; + memcpy (tmp+1, p, length); + tmp[length+1] = ')'; + tmp[length+2] = '0'; + tmp[length+3] = '\0'; + expr = parse_expression (tmp); + if (expr->elts[0].opcode != UNOP_CAST) + error ("Internal error in eval_type."); + return expr->elts[1].type; +} |