aboutsummaryrefslogtreecommitdiff
path: root/gdb/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/eval.c')
-rw-r--r--gdb/eval.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/gdb/eval.c b/gdb/eval.c
new file mode 100644
index 0000000..97f39c3
--- /dev/null
+++ b/gdb/eval.c
@@ -0,0 +1,556 @@
+/* Evaluate expressions for GDB.
+ Copyright (C) 1986, 1987 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "defs.h"
+#include "initialize.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+START_FILE
+
+/* 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_c_expression (exp);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_long (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_c_1 (expptr, 0);
+ register CORE_ADDR addr;
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+
+ addr = value_as_long (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ return addr;
+}
+
+value
+parse_and_eval (exp)
+ char *exp;
+{
+ struct expression *expr = parse_c_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;
+}
+
+/* Evaluate an expression in internal prefix form
+ such as is constructed by expread.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 ();
+
+/* Values of NOSIDE argument to eval_subexp. */
+enum noside
+{ EVAL_NORMAL,
+ EVAL_SKIP,
+ EVAL_AVOID_SIDE_EFFECTS,
+};
+
+value
+evaluate_expression (exp)
+ struct expression *exp;
+{
+ int pc = 0;
+ return evaluate_subexp (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 (exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+static value
+evaluate_subexp (exp, pos, noside)
+ register struct expression *exp;
+ register int *pos;
+ enum noside noside;
+{
+ enum exp_opcode op;
+ int tem;
+ register int pc;
+ register value arg1, arg2;
+ int nargs;
+ value *argvec;
+
+ pc = (*pos)++;
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_LONG:
+ (*pos) += 3;
+ return value_from_long (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) += 2;
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_of_variable (exp->elts[pc + 1].symbol);
+
+ case OP_LAST:
+ (*pos) += 2;
+ return access_value_history (exp->elts[pc + 1].longconst);
+
+ case OP_REGISTER:
+ (*pos) += 2;
+ return value_of_register (exp->elts[pc + 1].longconst);
+
+ case OP_INTERNALVAR:
+ (*pos) += 2;
+ return value_of_internalvar (exp->elts[pc + 1].internalvar);
+
+ case OP_FUNCALL:
+ (*pos) += 2;
+ nargs = exp->elts[pc + 1].longconst;
+ argvec = (value *) alloca (sizeof (value) * (nargs + 1));
+ 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;
+ if (noside == EVAL_AVOID_SIDE_EFFECTS)
+ return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
+ return call_function (argvec[0], nargs, argvec + 1);
+
+ case OP_STRING:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_string (&exp->elts[pc + 1].string, tem);
+
+ case TERNOP_COND:
+ /* Skip third and second args to evaluate the first one. */
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (value_zerop (arg1))
+ {
+ evaluate_subexp (exp, pos, EVAL_SKIP);
+ return evaluate_subexp (exp, pos, noside);
+ }
+ else
+ {
+ arg2 = evaluate_subexp (exp, pos, noside);
+ evaluate_subexp (exp, pos, EVAL_SKIP);
+ return arg2;
+ }
+
+ case STRUCTOP_STRUCT:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_struct_elt (arg1, &exp->elts[pc + 1].string,
+ "structure");
+
+ case STRUCTOP_PTR:
+ tem = strlen (&exp->elts[pc + 1].string);
+ (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_struct_elt (arg1, &exp->elts[pc + 1].string,
+ "structure pointer");
+
+ case BINOP_ASSIGN:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ return value_assign (arg1, arg2);
+
+ case BINOP_ASSIGN_MODIFY:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ op = exp->elts[pc + 1].opcode;
+ 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;
+ 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;
+ return value_sub (arg1, arg2);
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ case BINOP_LOGAND:
+ case BINOP_LOGIOR:
+ case BINOP_LOGXOR:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ 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;
+ return value_subscript (arg1, arg2, op);
+
+ case BINOP_AND:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ tem = value_zerop (arg1);
+ arg2 = evaluate_subexp (exp, pos,
+ (tem ? EVAL_SKIP : noside));
+ return value_from_long (builtin_type_int,
+ !tem && !value_zerop (arg2));
+
+ case BINOP_OR:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ tem = value_zerop (arg1);
+ arg2 = evaluate_subexp (exp, pos,
+ (!tem ? EVAL_SKIP : noside));
+ return value_from_long (builtin_type_int,
+ !tem || !value_zerop (arg2));
+
+ case BINOP_EQUAL:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ tem = value_equal (arg1, arg2);
+ return value_from_long (builtin_type_int, tem);
+
+ case BINOP_NOTEQUAL:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ tem = value_equal (arg1, arg2);
+ return value_from_long (builtin_type_int, ! tem);
+
+ case BINOP_LESS:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ tem = value_less (arg1, arg2);
+ return value_from_long (builtin_type_int, tem);
+
+ case BINOP_GTR:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ tem = value_less (arg2, arg1);
+ return value_from_long (builtin_type_int, tem);
+
+ case BINOP_GEQ:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ tem = value_less (arg1, arg2);
+ return value_from_long (builtin_type_int, ! tem);
+
+ case BINOP_LEQ:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ tem = value_less (arg2, arg1);
+ return value_from_long (builtin_type_int, ! tem);
+
+ case BINOP_REPEAT:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_repeat (arg1, value_as_long (arg2));
+
+ case BINOP_COMMA:
+ evaluate_subexp (exp, pos, noside);
+ return evaluate_subexp (exp, pos, noside);
+
+ case UNOP_NEG:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_neg (arg1);
+
+ case UNOP_LOGNOT:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_lognot (arg1);
+
+ case UNOP_ZEROP:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_from_long (builtin_type_int, value_zerop (arg1));
+
+ case UNOP_IND:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_ind (arg1);
+
+ case UNOP_ADDR:
+ if (noside == EVAL_SKIP)
+ {
+ evaluate_subexp (exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+ return evaluate_subexp_for_address (exp, pos, noside);
+
+ case UNOP_SIZEOF:
+ if (noside == EVAL_SKIP)
+ {
+ evaluate_subexp (exp, pos, EVAL_SKIP);
+ goto nosideret;
+ }
+ return evaluate_subexp_for_sizeof (exp, pos);
+
+ case UNOP_CAST:
+ (*pos) += 2;
+ arg1 = evaluate_subexp (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 (exp, pos, noside);
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_at (exp->elts[pc + 1].type, value_as_long (arg1));
+
+ case UNOP_PREINCREMENT:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = value_add (arg1, value_from_long (builtin_type_char, 1));
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ return value_assign (arg1, arg2);
+
+ case UNOP_PREDECREMENT:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1));
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ return value_assign (arg1, arg2);
+
+ case UNOP_POSTINCREMENT:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = value_add (arg1, value_from_long (builtin_type_char, 1));
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ value_assign (arg1, arg2);
+ return arg1;
+
+ case UNOP_POSTDECREMENT:
+ arg1 = evaluate_subexp (exp, pos, noside);
+ arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1));
+ if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+ return arg1;
+ value_assign (arg1, arg2);
+ return arg1;
+ }
+
+ nosideret:
+ return value_from_long (builtin_type_long, 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;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case UNOP_IND:
+ (*pos)++;
+ return evaluate_subexp (exp, pos, noside);
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
+ evaluate_subexp (exp, pos, noside));
+
+ case OP_VAR_VALUE:
+ (*pos) += 3;
+ return locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0);
+
+ default:
+ return value_addr (evaluate_subexp (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. */
+
+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;
+
+ pc = (*pos);
+ op = exp->elts[pc].opcode;
+
+ switch (op)
+ {
+ case OP_VAR_VALUE:
+ if (TYPE_CODE (SYMBOL_TYPE (exp->elts[pc + 1].symbol)) == TYPE_CODE_ARRAY)
+ {
+ (*pos) += 3;
+ val = locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0);
+ return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (exp->elts[pc + 1].symbol))),
+ val);
+ }
+ }
+
+ return evaluate_subexp (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 (exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_long (builtin_type_int,
+ TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
+
+ case UNOP_MEMVAL:
+ (*pos) += 3;
+ return value_from_long (builtin_type_int,
+ TYPE_LENGTH (exp->elts[pc + 1].type));
+
+ case OP_VAR_VALUE:
+ (*pos) += 3;
+ return value_from_long (builtin_type_int,
+ TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol)));
+
+ default:
+ val = evaluate_subexp (exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+ return value_from_long (builtin_type_int,
+ TYPE_LENGTH (VALUE_TYPE (val)));
+ }
+}
+
+static
+initialize ()
+{ }
+
+END_FILE