diff options
Diffstat (limited to 'gdb/valarith.c')
-rw-r--r-- | gdb/valarith.c | 274 |
1 files changed, 141 insertions, 133 deletions
diff --git a/gdb/valarith.c b/gdb/valarith.c index e13db10ab55..6210267826e 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -252,7 +252,7 @@ int binop_types_user_defined_p (enum exp_opcode op, struct type *type1, struct type *type2) { - if (op == BINOP_ASSIGN || op == BINOP_CONCAT) + if (op == BINOP_ASSIGN) return 0; type1 = check_typedef (type1); @@ -651,153 +651,66 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside) } -/* Concatenate two values with the following conditions: - - (1) Both values must be either bitstring values or character string - values and the resulting value consists of the concatenation of - ARG1 followed by ARG2. - - or - - One value must be an integer value and the other value must be - either a bitstring value or character string value, which is - to be repeated by the number of times specified by the integer - value. - - - (2) Boolean values are also allowed and are treated as bit string - values of length 1. - - (3) Character values are also allowed and are treated as character - string values of length 1. */ +/* Concatenate two values. One value must be an array; and the other + value must either be an array with the same element type, or be of + the array's element type. */ struct value * value_concat (struct value *arg1, struct value *arg2) { - struct value *inval1; - struct value *inval2; - struct value *outval = NULL; - int inval1len, inval2len; - int count, idx; - char inchar; struct type *type1 = check_typedef (value_type (arg1)); struct type *type2 = check_typedef (value_type (arg2)); - struct type *char_type; - /* First figure out if we are dealing with two values to be concatenated - or a repeat count and a value to be repeated. INVAL1 is set to the - first of two concatenated values, or the repeat count. INVAL2 is set - to the second of the two concatenated values or the value to be - repeated. */ + if (type1->code () != TYPE_CODE_ARRAY && type2->code () != TYPE_CODE_ARRAY) + error ("no array provided to concatenation"); - if (type2->code () == TYPE_CODE_INT) + LONGEST low1, high1; + struct type *elttype1 = type1; + if (elttype1->code () == TYPE_CODE_ARRAY) { - struct type *tmp = type1; - - type1 = tmp; - tmp = type2; - inval1 = arg2; - inval2 = arg1; + elttype1 = TYPE_TARGET_TYPE (elttype1); + if (!get_array_bounds (type1, &low1, &high1)) + error (_("could not determine array bounds on left-hand-side of " + "array concatenation")); } else { - inval1 = arg1; - inval2 = arg2; + low1 = 0; + high1 = 0; } - /* Now process the input values. */ - - if (type1->code () == TYPE_CODE_INT) - { - /* We have a repeat count. Validate the second value and then - construct a value repeated that many times. */ - if (type2->code () == TYPE_CODE_STRING - || type2->code () == TYPE_CODE_CHAR) - { - count = longest_to_int (value_as_long (inval1)); - inval2len = TYPE_LENGTH (type2); - std::vector<char> ptr (count * inval2len); - if (type2->code () == TYPE_CODE_CHAR) - { - char_type = type2; - - inchar = (char) unpack_long (type2, - value_contents (inval2).data ()); - for (idx = 0; idx < count; idx++) - { - ptr[idx] = inchar; - } - } - else - { - char_type = TYPE_TARGET_TYPE (type2); - - for (idx = 0; idx < count; idx++) - memcpy (&ptr[idx * inval2len], value_contents (inval2).data (), - inval2len); - } - outval = value_string (ptr.data (), count * inval2len, char_type); - } - else if (type2->code () == TYPE_CODE_BOOL) - { - error (_("unimplemented support for boolean repeats")); - } - else - { - error (_("can't repeat values of that type")); - } - } - else if (type1->code () == TYPE_CODE_STRING - || type1->code () == TYPE_CODE_CHAR) - { - /* We have two character strings to concatenate. */ - if (type2->code () != TYPE_CODE_STRING - && type2->code () != TYPE_CODE_CHAR) - { - error (_("Strings can only be concatenated with other strings.")); - } - inval1len = TYPE_LENGTH (type1); - inval2len = TYPE_LENGTH (type2); - std::vector<char> ptr (inval1len + inval2len); - if (type1->code () == TYPE_CODE_CHAR) - { - char_type = type1; - - ptr[0] = (char) unpack_long (type1, value_contents (inval1).data ()); - } - else - { - char_type = TYPE_TARGET_TYPE (type1); - - memcpy (ptr.data (), value_contents (inval1).data (), inval1len); - } - if (type2->code () == TYPE_CODE_CHAR) - { - ptr[inval1len] = - (char) unpack_long (type2, value_contents (inval2).data ()); - } - else - { - memcpy (&ptr[inval1len], value_contents (inval2).data (), inval2len); - } - outval = value_string (ptr.data (), inval1len + inval2len, char_type); - } - else if (type1->code () == TYPE_CODE_BOOL) + LONGEST low2, high2; + struct type *elttype2 = type2; + if (elttype2->code () == TYPE_CODE_ARRAY) { - /* We have two bitstrings to concatenate. */ - if (type2->code () != TYPE_CODE_BOOL) - { - error (_("Booleans can only be concatenated " - "with other bitstrings or booleans.")); - } - error (_("unimplemented support for boolean concatenation.")); + elttype2 = TYPE_TARGET_TYPE (elttype2); + if (!get_array_bounds (type2, &low2, &high2)) + error (_("could not determine array bounds on right-hand-side of " + "array concatenation")); } else { - /* We don't know how to concatenate these operands. */ - error (_("illegal operands for concatenation.")); + low2 = 0; + high2 = 0; } - return (outval); + + if (!types_equal (elttype1, elttype2)) + error (_("concatenation with different element types")); + + LONGEST lowbound = current_language->c_style_arrays_p () ? 0 : 1; + LONGEST n_elts = (high1 - low1 + 1) + (high2 - low2 + 1); + struct type *atype = lookup_array_range_type (elttype1, + lowbound, + lowbound + n_elts - 1); + + struct value *result = allocate_value (atype); + gdb::array_view<gdb_byte> contents = value_contents_raw (result); + gdb::array_view<const gdb_byte> lhs_contents = value_contents (arg1); + gdb::array_view<const gdb_byte> rhs_contents = value_contents (arg2); + gdb::copy (lhs_contents, contents.slice (0, lhs_contents.size ())); + gdb::copy (rhs_contents, contents.slice (lhs_contents.size ())); + + return result; } /* Integer exponentiation: V1**V2, where both arguments are @@ -1157,6 +1070,66 @@ complex_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) return value_literal_complex (result_real, result_imag, result_type); } +/* Return the type's length in bits. */ + +static int +type_length_bits (type *type) +{ + int unit_size = gdbarch_addressable_memory_unit_size (type->arch ()); + return unit_size * 8 * TYPE_LENGTH (type); +} + +/* Check whether the RHS value of a shift is valid in C/C++ semantics. + SHIFT_COUNT is the shift amount, SHIFT_COUNT_TYPE is the type of + the shift count value, used to determine whether the type is + signed, and RESULT_TYPE is the result type. This is used to avoid + both negative and too-large shift amounts, which are undefined, and + would crash a GDB built with UBSan. Depending on the current + language, if the shift is not valid, this either warns and returns + false, or errors out. Returns true if valid. */ + +static bool +check_valid_shift_count (int op, type *result_type, + type *shift_count_type, ULONGEST shift_count) +{ + if (!shift_count_type->is_unsigned () && (LONGEST) shift_count < 0) + { + auto error_or_warning = [] (const char *msg) + { + /* Shifts by a negative amount are always an error in Go. Other + languages are more permissive and their compilers just warn or + have modes to disable the errors. */ + if (current_language->la_language == language_go) + error (("%s"), msg); + else + warning (("%s"), msg); + }; + + if (op == BINOP_RSH) + error_or_warning (_("right shift count is negative")); + else + error_or_warning (_("left shift count is negative")); + return false; + } + + if (shift_count >= type_length_bits (result_type)) + { + /* In Go, shifting by large amounts is defined. Be silent and + still return false, as the caller's error path does the right + thing for Go. */ + if (current_language->la_language != language_go) + { + if (op == BINOP_RSH) + warning (_("right shift count >= width of type")); + else + warning (_("left shift count >= width of type")); + } + return false; + } + + return true; +} + /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, characters, integers, or floats. @@ -1320,11 +1293,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) break; case BINOP_LSH: - v = v1 << v2; + if (!check_valid_shift_count (op, result_type, type2, v2)) + v = 0; + else + v = v1 << v2; break; case BINOP_RSH: - v = v1 >> v2; + if (!check_valid_shift_count (op, result_type, type2, v2)) + v = 0; + else + v = v1 >> v2; break; case BINOP_BITWISE_AND: @@ -1449,11 +1428,40 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) break; case BINOP_LSH: - v = v1 << v2; + if (!check_valid_shift_count (op, result_type, type2, v2)) + v = 0; + else + { + /* Cast to unsigned to avoid undefined behavior on + signed shift overflow (unless C++20 or later), + which would crash GDB when built with UBSan. + Note we don't warn on left signed shift overflow, + because starting with C++20, that is actually + defined behavior. Also, note GDB assumes 2's + complement throughout. */ + v = (ULONGEST) v1 << v2; + } break; case BINOP_RSH: - v = v1 >> v2; + if (!check_valid_shift_count (op, result_type, type2, v2)) + { + /* Pretend the too-large shift was decomposed in a + number of smaller shifts. An arithmetic signed + right shift of a negative number always yields -1 + with such semantics. This is the right thing to + do for Go, and we might as well do it for + languages where it is undefined. Also, pretend a + shift by a negative number was a shift by the + negative number cast to unsigned, which is the + same as shifting by a too-large number. */ + if (v1 < 0) + v = -1; + else + v = 0; + } + else + v = v1 >> v2; break; case BINOP_BITWISE_AND: |