diff options
Diffstat (limited to 'gdb/valarith.c')
-rw-r--r-- | gdb/valarith.c | 277 |
1 files changed, 162 insertions, 115 deletions
diff --git a/gdb/valarith.c b/gdb/valarith.c index 3848029..79c0943 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -1,5 +1,6 @@ /* Perform arithmetic and other operations on values, for GDB. - Copyright 1986, 1989, 1991, 1992 Free Software Foundation, Inc. + Copyright 1986, 1989, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. This file is part of GDB. @@ -34,15 +35,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define TRUNCATION_TOWARDS_ZERO ((-5 / 2) == -2) #endif -static value -value_subscripted_rvalue PARAMS ((value, value)); +static value_ptr value_subscripted_rvalue PARAMS ((value_ptr, value_ptr)); -value +value_ptr value_add (arg1, arg2) - value arg1, arg2; + value_ptr arg1, arg2; { - register value valint, valptr; + register value_ptr valint, valptr; register int len; COERCE_ARRAY (arg1); @@ -75,9 +75,9 @@ value_add (arg1, arg2) return value_binop (arg1, arg2, BINOP_ADD); } -value +value_ptr value_sub (arg1, arg2) - value arg1, arg2; + value_ptr arg1, arg2; { COERCE_ARRAY (arg1); @@ -94,13 +94,15 @@ value_sub (arg1, arg2) - (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) * value_as_long (arg2))); } - else if (VALUE_TYPE (arg1) == VALUE_TYPE (arg2)) + else if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR + && TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) + == TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg2)))) { /* pointer to <type x> - pointer to <type x>. */ return value_from_longest (builtin_type_long, /* FIXME -- should be ptrdiff_t */ (value_as_long (arg1) - value_as_long (arg2)) - / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))); + / (LONGEST) (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))))); } else { @@ -119,12 +121,12 @@ an integer nor a pointer of the same type."); FIXME: Perhaps we should validate that the index is valid and if verbosity is set, warn about invalid indices (but still use them). */ -value +value_ptr value_subscript (array, idx) - value array, idx; + value_ptr array, idx; { int lowerbound; - value bound; + value_ptr bound; struct type *range_type; COERCE_REF (array); @@ -152,14 +154,14 @@ value_subscript (array, idx) (eg, a vector register). This routine used to promote floats to doubles, but no longer does. */ -static value +static value_ptr value_subscripted_rvalue (array, idx) - value array, idx; + value_ptr array, idx; { struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array)); int elt_size = TYPE_LENGTH (elt_type); int elt_offs = elt_size * longest_to_int (value_as_long (idx)); - value v; + value_ptr v; if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array))) error ("no such vector element"); @@ -186,7 +188,7 @@ value_subscripted_rvalue (array, idx) int binop_user_defined_p (op, arg1, arg2) enum exp_opcode op; - value arg1, arg2; + value_ptr arg1, arg2; { if (op == BINOP_ASSIGN) return 0; @@ -206,7 +208,7 @@ binop_user_defined_p (op, arg1, arg2) int unop_user_defined_p (op, arg1) enum exp_opcode op; - value arg1; + value_ptr arg1; { if (op == UNOP_ADDR) return 0; @@ -224,14 +226,14 @@ int unop_user_defined_p (op, arg1) is the opcode saying how to modify it. Otherwise, OTHEROP is unused. */ -value +value_ptr value_x_binop (arg1, arg2, op, otherop) - value arg1, arg2; + value_ptr arg1, arg2; enum exp_opcode op, otherop; { - value * argvec; - char *ptr, *mangle_ptr; - char tstr[13], mangle_tstr[13]; + value_ptr * argvec; + char *ptr; + char tstr[13]; int static_memfuncp; COERCE_REF (arg1); @@ -245,7 +247,7 @@ value_x_binop (arg1, arg2, op, otherop) if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT) error ("Can't do that binary op on that type"); /* FIXME be explicit */ - argvec = (value *) alloca (sizeof (value) * 4); + argvec = (value_ptr *) alloca (sizeof (value_ptr) * 4); argvec[1] = value_addr (arg1); argvec[2] = arg2; argvec[3] = 0; @@ -321,12 +323,12 @@ value_x_binop (arg1, arg2, op, otherop) and return that value (where '@' is (almost) any unary operator which is legal for GNU C++). */ -value +value_ptr value_x_unop (arg1, op) - value arg1; + value_ptr arg1; enum exp_opcode op; { - value * argvec; + value_ptr * argvec; char *ptr, *mangle_ptr; char tstr[13], mangle_tstr[13]; int static_memfuncp; @@ -339,7 +341,7 @@ value_x_unop (arg1, op) if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT) error ("Can't do that unary op on that type"); /* FIXME be explicit */ - argvec = (value *) alloca (sizeof (value) * 3); + argvec = (value_ptr *) alloca (sizeof (value_ptr) * 3); argvec[1] = value_addr (arg1); argvec[2] = 0; @@ -398,11 +400,11 @@ value_x_unop (arg1, op) string values of length 1. */ -value +value_ptr value_concat (arg1, arg2) - value arg1, arg2; + value_ptr arg1, arg2; { - register value inval1, inval2, outval; + register value_ptr inval1, inval2, outval; int inval1len, inval2len; int count, idx; char *ptr; @@ -517,14 +519,6 @@ value_concat (arg1, arg2) } -/* The type we give to value_binop results. This is a kludge to get around - the fact that we don't know how to determine the result type from - the types of the operands. (I'm not really sure how much we feel - the need to duplicate the exact rules of the current language. - They can get really hairy. But not to do so makes it hard to document - just what we *do* do). */ -static struct type *signed_operation_result; -static struct type *unsigned_operation_result; /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, @@ -532,31 +526,27 @@ static struct type *unsigned_operation_result; Does not support addition and subtraction on pointers; use value_add or value_sub if you want to handle those possibilities. */ -value +value_ptr value_binop (arg1, arg2, op) - value arg1, arg2; + value_ptr arg1, arg2; enum exp_opcode op; { - register value val; + register value_ptr val; COERCE_ENUM (arg1); COERCE_ENUM (arg2); if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT - && - TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_CHAR - && - TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT - && - TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_BOOL) + && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_CHAR + && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT + && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_BOOL + && TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_RANGE) || (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT - && - TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_CHAR - && - TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT - && - TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_BOOL)) + && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_CHAR + && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT + && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_BOOL + && TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_RANGE)) error ("Argument to arithmetic operation not a number or boolean."); if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT @@ -629,16 +619,64 @@ value_binop (arg1, arg2, op) else /* Integral operations here. */ /* FIXME: Also mixed integral/booleans, with result an integer. */ + /* FIXME: This implements ANSI C rules (also correct for C++). + What about FORTRAN and chill? */ { - /* Should we promote to unsigned longest? */ - if ((TYPE_UNSIGNED (VALUE_TYPE (arg1)) - || TYPE_UNSIGNED (VALUE_TYPE (arg2))) - && (TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST) - || TYPE_LENGTH (VALUE_TYPE (arg2)) >= sizeof (unsigned LONGEST))) + struct type *type1 = VALUE_TYPE (arg1); + struct type *type2 = VALUE_TYPE (arg2); + int promoted_len1 = TYPE_LENGTH (type1); + int promoted_len2 = TYPE_LENGTH (type2); + int is_unsigned1 = TYPE_UNSIGNED (type1); + int is_unsigned2 = TYPE_UNSIGNED (type2); + int result_len; + int unsigned_operation; + + /* Determine type length and signedness after promotion for + both operands. */ + if (promoted_len1 < TYPE_LENGTH (builtin_type_int)) + { + is_unsigned1 = 0; + promoted_len1 = TYPE_LENGTH (builtin_type_int); + } + if (promoted_len2 < TYPE_LENGTH (builtin_type_int)) + { + is_unsigned2 = 0; + promoted_len2 = TYPE_LENGTH (builtin_type_int); + } + + /* Determine type length of the result, and if the operation should + be done unsigned. + Use the signedness of the operand with the greater length. + If both operands are of equal length, use unsigned operation + if one of the operands is unsigned. */ + if (promoted_len1 > promoted_len2) + { + unsigned_operation = is_unsigned1; + result_len = promoted_len1; + } + else if (promoted_len2 > promoted_len1) + { + unsigned_operation = is_unsigned2; + result_len = promoted_len2; + } + else + { + unsigned_operation = is_unsigned1 || is_unsigned2; + result_len = promoted_len1; + } + + if (unsigned_operation) { unsigned LONGEST v1, v2, v; v1 = (unsigned LONGEST) value_as_long (arg1); v2 = (unsigned LONGEST) value_as_long (arg2); + + /* Truncate values to the type length of the result. */ + if (result_len < sizeof (unsigned LONGEST)) + { + v1 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1; + v2 &= ((LONGEST) 1 << HOST_CHAR_BIT * result_len) - 1; + } switch (op) { @@ -718,12 +756,32 @@ value_binop (arg1, arg2, op) case BINOP_MAX: v = v1 > v2 ? v1 : v2; break; + + case BINOP_EQUAL: + v = v1 == v2; + break; + + case BINOP_LESS: + v = v1 < v2; + break; default: error ("Invalid binary operation on numbers."); } - val = allocate_value (unsigned_operation_result); + /* This is a kludge to get around the fact that we don't + know how to determine the result type from the types of + the operands. (I'm not really sure how much we feel the + need to duplicate the exact rules of the current + language. They can get really hairy. But not to do so + makes it hard to document just what we *do* do). */ + + /* Can't just call init_type because we wouldn't know what + name to give the type. */ + val = allocate_value + (result_len > TARGET_LONG_BIT / HOST_CHAR_BIT + ? builtin_type_unsigned_long_long + : builtin_type_unsigned_long); store_unsigned_integer (VALUE_CONTENTS_RAW (val), TYPE_LENGTH (VALUE_TYPE (val)), v); @@ -816,12 +874,32 @@ value_binop (arg1, arg2, op) case BINOP_MAX: v = v1 > v2 ? v1 : v2; break; + + case BINOP_EQUAL: + v = v1 == v2; + break; + + case BINOP_LESS: + v = v1 < v2; + break; default: error ("Invalid binary operation on numbers."); } - - val = allocate_value (signed_operation_result); + + /* This is a kludge to get around the fact that we don't + know how to determine the result type from the types of + the operands. (I'm not really sure how much we feel the + need to duplicate the exact rules of the current + language. They can get really hairy. But not to do so + makes it hard to document just what we *do* do). */ + + /* Can't just call init_type because we wouldn't know what + name to give the type. */ + val = allocate_value + (result_len > TARGET_LONG_BIT / HOST_CHAR_BIT + ? builtin_type_long_long + : builtin_type_long); store_signed_integer (VALUE_CONTENTS_RAW (val), TYPE_LENGTH (VALUE_TYPE (val)), v); @@ -835,7 +913,7 @@ value_binop (arg1, arg2, op) int value_logical_not (arg1) - value arg1; + value_ptr arg1; { register int len; register char *p; @@ -862,7 +940,7 @@ value_logical_not (arg1) int value_equal (arg1, arg2) - register value arg1, arg2; + register value_ptr arg1, arg2; { register int len; @@ -877,7 +955,8 @@ value_equal (arg1, arg2) code2 = TYPE_CODE (VALUE_TYPE (arg2)); if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) - return value_as_long (arg1) == value_as_long (arg2); + return longest_to_int (value_as_long (value_binop (arg1, arg2, + BINOP_EQUAL))); else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) return value_as_double (arg1) == value_as_double (arg2); @@ -914,7 +993,7 @@ value_equal (arg1, arg2) int value_less (arg1, arg2) - register value arg1, arg2; + register value_ptr arg1, arg2; { register enum type_code code1; register enum type_code code2; @@ -926,14 +1005,8 @@ value_less (arg1, arg2) code2 = TYPE_CODE (VALUE_TYPE (arg2)); if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) - { - if (TYPE_UNSIGNED (VALUE_TYPE (arg1)) - || TYPE_UNSIGNED (VALUE_TYPE (arg2))) - return ((unsigned LONGEST) value_as_long (arg1) - < (unsigned LONGEST) value_as_long (arg2)); - else - return value_as_long (arg1) < value_as_long (arg2); - } + return longest_to_int (value_as_long (value_binop (arg1, arg2, + BINOP_LESS))); else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) return value_as_double (arg1) < value_as_double (arg2); @@ -956,9 +1029,9 @@ value_less (arg1, arg2) /* The unary operators - and ~. Both free the argument ARG1. */ -value +value_ptr value_neg (arg1) - register value arg1; + register value_ptr arg1; { register struct type *type; @@ -976,9 +1049,9 @@ value_neg (arg1) } } -value +value_ptr value_complement (arg1) - register value arg1; + register value_ptr arg1; { COERCE_ENUM (arg1); @@ -999,8 +1072,9 @@ value_bit_index (type, valaddr, index) int index; { struct type *range; - int low_bound, high_bound, bit_length; + int low_bound, high_bound; LONGEST word; + unsigned rel_index; range = TYPE_FIELD_TYPE (type, 0); if (TYPE_CODE (range) != TYPE_CODE_RANGE) return -2; @@ -1008,33 +1082,18 @@ value_bit_index (type, valaddr, index) high_bound = TYPE_HIGH_BOUND (range); if (index < low_bound || index > high_bound) return -1; - bit_length = high_bound - low_bound + 1; - index -= low_bound; - if (bit_length <= TARGET_CHAR_BIT) - word = unpack_long (builtin_type_unsigned_char, valaddr); - else if (bit_length <= TARGET_SHORT_BIT) - word = unpack_long (builtin_type_unsigned_short, valaddr); - else - { - int word_start_index = (index / TARGET_INT_BIT) * TARGET_INT_BIT; - index -= word_start_index; - word = unpack_long (builtin_type_unsigned_int, - valaddr + (word_start_index / HOST_CHAR_BIT)); - } -#if BITS_BIG_ENDIAN - if (bit_length <= TARGET_CHAR_BIT) - index = TARGET_CHAR_BIT - 1 - index; - else if (bit_length <= TARGET_SHORT_BIT) - index = TARGET_SHORT_BIT - 1 - index; - else - index = TARGET_INT_BIT - 1 - index; -#endif - return (word >> index) & 1; + rel_index = index - low_bound; + word = unpack_long (builtin_type_unsigned_char, + valaddr + (rel_index / TARGET_CHAR_BIT)); + rel_index %= TARGET_CHAR_BIT; + if (BITS_BIG_ENDIAN) + rel_index = TARGET_CHAR_BIT - 1 - rel_index; + return (word >> rel_index) & 1; } -value +value_ptr value_in (element, set) - value element, set; + value_ptr element, set; { int member; if (TYPE_CODE (VALUE_TYPE (set)) != TYPE_CODE_SET) @@ -1054,16 +1113,4 @@ value_in (element, set) void _initialize_valarith () { - /* Can't just call init_type because we wouldn't know what names to give - them. */ - if (sizeof (LONGEST) > TARGET_LONG_BIT / HOST_CHAR_BIT) - { - unsigned_operation_result = builtin_type_unsigned_long_long; - signed_operation_result = builtin_type_long_long; - } - else - { - unsigned_operation_result = builtin_type_unsigned_long; - signed_operation_result = builtin_type_long; - } } |