[PATCH 141/203] Introduce array_operation

Tom Tromey
2021-01-01T21:49:12Z

This adds class array_operation, which implements OP_ARRAY.

gdb/ChangeLog
2021-01-01 Tom Tromey <tom@tromey.com>

* expop.h (class array_operation): New.
* eval.c (array_operation::evaluate_struct_tuple)
(array_operation::evaluate): New methods.
---
gdb/ChangeLog | 6 ++
gdb/eval.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/expop.h | 22 ++++++
3 files changed, 228 insertions(+)

diff --git a/gdb/eval.c b/gdb/eval.c
index 62b3f219ca4..2589e35ae30 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -2547,6 +2547,206 @@ adl_func_operation::evaluate (struct type *expect_type,

}

+/* This function evaluates brace-initializers (in C/C++) for
+ structure types. */
+
+struct value *
+array_operation::evaluate_struct_tuple (struct value *struct_val,
+ struct expression *exp,
+ enum noside noside, int nargs)
+{
+ const std::vector<operation_up> &in_args = std::get<2> (m_storage);
+ struct type *struct_type = check_typedef (value_type (struct_val));
+ struct type *field_type;
+ int fieldno = -1;
+
+ int idx = 0;
+ while (--nargs >= 0)
+ {
+ struct value *val = NULL;
+ int bitpos, bitsize;
+ bfd_byte *addr;
+
+ fieldno++;
+ /* Skip static fields. */
+ while (fieldno < struct_type->num_fields ()
+ && field_is_static (&struct_type->field (fieldno)))
+ fieldno++;
+ if (fieldno >= struct_type->num_fields ())
+ error (_("too many initializers"));
+ field_type = struct_type->field (fieldno).type ();
+ if (field_type->code () == TYPE_CODE_UNION
+ && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0')
+ error (_("don't know which variant you want to set"));
+
+ /* Here, struct_type is the type of the inner struct,
+ while substruct_type is the type of the inner struct.
+ These are the same for normal structures, but a variant struct
+ contains anonymous union fields that contain substruct fields.
+ The value fieldno is the index of the top-level (normal or
+ anonymous union) field in struct_field, while the value
+ subfieldno is the index of the actual real (named inner) field
+ in substruct_type. */
+
+ field_type = struct_type->field (fieldno).type ();
+ if (val == 0)
+ val = in_args[idx++]->evaluate (field_type, exp, noside);
+
+ /* Now actually set the field in struct_val. */
+
+ /* Assign val to field fieldno. */
+ if (value_type (val) != field_type)
+ val = value_cast (field_type, val);
+
+ bitsize = TYPE_FIELD_BITSIZE (struct_type, fieldno);
+ bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno);
+ addr = value_contents_writeable (struct_val) + bitpos / 8;
+ if (bitsize)
+ modify_field (struct_type, addr,
+ value_as_long (val), bitpos % 8, bitsize);
+ else
+ memcpy (addr, value_contents (val),
+ TYPE_LENGTH (value_type (val)));
+
+ }
+ return struct_val;
+}
+
+value *
+array_operation::evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside)
+{
+ int tem;
+ int tem2 = std::get<0> (m_storage);
+ int tem3 = std::get<1> (m_storage);
+ const std::vector<operation_up> &in_args = std::get<2> (m_storage);
+ int nargs = tem3 - tem2 + 1;
+ struct type *type = expect_type ? check_typedef (expect_type) : nullptr;
+
+ if (expect_type != nullptr && noside != EVAL_SKIP
+ && type->code () == TYPE_CODE_STRUCT)
+ {
+ struct value *rec = allocate_value (expect_type);
+
+ memset (value_contents_raw (rec), '\0', TYPE_LENGTH (type));
+ return evaluate_struct_tuple (rec, exp, noside, nargs);
+ }
+
+ if (expect_type != nullptr && noside != EVAL_SKIP
+ && type->code () == TYPE_CODE_ARRAY)
+ {
+ struct type *range_type = type->index_type ();
+ struct type *element_type = TYPE_TARGET_TYPE (type);
+ struct value *array = allocate_value (expect_type);
+ int element_size = TYPE_LENGTH (check_typedef (element_type));
+ LONGEST low_bound, high_bound, index;
+
+ if (!get_discrete_bounds (range_type, &low_bound, &high_bound))
+ {
+ low_bound = 0;
+ high_bound = (TYPE_LENGTH (type) / element_size) - 1;
+ }
+ index = low_bound;
+ memset (value_contents_raw (array), 0, TYPE_LENGTH (expect_type));
+ for (tem = nargs; --nargs >= 0;)
+ {
+ struct value *element;
+
+ element = in_args[index - low_bound]->evaluate (element_type,
+ exp, noside);
+ if (value_type (element) != element_type)
+ element = value_cast (element_type, element);
+ if (index > high_bound)
+ /* To avoid memory corruption. */
+ error (_("Too many array elements"));
+ memcpy (value_contents_raw (array)
+ + (index - low_bound) * element_size,
+ value_contents (element),
+ element_size);
+ index++;
+ }
+ return array;
+ }
+
+ if (expect_type != nullptr && noside != EVAL_SKIP
+ && type->code () == TYPE_CODE_SET)
+ {
+ struct value *set = allocate_value (expect_type);
+ gdb_byte *valaddr = value_contents_raw (set);
+ struct type *element_type = type->index_type ();
+ struct type *check_type = element_type;
+ LONGEST low_bound, high_bound;
+
+ /* Get targettype of elementtype. */
+ while (check_type->code () == TYPE_CODE_RANGE
+ || check_type->code () == TYPE_CODE_TYPEDEF)
+ check_type = TYPE_TARGET_TYPE (check_type);
+
+ if (!get_discrete_bounds (element_type, &low_bound, &high_bound))
+ error (_("(power)set type with unknown size"));
+ memset (valaddr, '\0', TYPE_LENGTH (type));
+ int idx = 0;
+ for (tem = 0; tem < nargs; tem++)
+ {
+ LONGEST range_low, range_high;
+ struct type *range_low_type, *range_high_type;
+ struct value *elem_val;
+
+ elem_val = in_args[idx++]->evaluate (element_type, exp, noside);
+ range_low_type = range_high_type = value_type (elem_val);
+ range_low = range_high = value_as_long (elem_val);
+
+ /* Check types of elements to avoid mixture of elements from
+ different types. Also check if type of element is "compatible"
+ with element type of powerset. */
+ if (range_low_type->code () == TYPE_CODE_RANGE)
+ range_low_type = TYPE_TARGET_TYPE (range_low_type);
+ if (range_high_type->code () == TYPE_CODE_RANGE)
+ range_high_type = TYPE_TARGET_TYPE (range_high_type);
+ if ((range_low_type->code () != range_high_type->code ())
+ || (range_low_type->code () == TYPE_CODE_ENUM
+ && (range_low_type != range_high_type)))
+ /* different element modes. */
+ error (_("POWERSET tuple elements of different mode"));
+ if ((check_type->code () != range_low_type->code ())
+ || (check_type->code () == TYPE_CODE_ENUM
+ && range_low_type != check_type))
+ error (_("incompatible POWERSET tuple elements"));
+ if (range_low > range_high)
+ {
+ warning (_("empty POWERSET tuple range"));
+ continue;
+ }
+ if (range_low < low_bound || range_high > high_bound)
+ error (_("POWERSET tuple element out of range"));
+ range_low -= low_bound;
+ range_high -= low_bound;
+ for (; range_low <= range_high; range_low++)
+ {
+ int bit_index = (unsigned) range_low % TARGET_CHAR_BIT;
+
+ if (gdbarch_byte_order (exp->gdbarch) == BFD_ENDIAN_BIG)
+ bit_index = TARGET_CHAR_BIT - 1 - bit_index;
+ valaddr[(unsigned) range_low / TARGET_CHAR_BIT]
+ |= 1 << bit_index;
+ }
+ }
+ return set;
+ }
+
+ value **argvec = XALLOCAVEC (struct value *, nargs);
+ for (tem = 0; tem < nargs; tem++)
+ {
+ /* Ensure that array expressions are coerced into pointer
+ objects. */
+ argvec[tem] = in_args[tem]->evaluate_with_coercion (exp, noside);
+ }
+ if (noside == EVAL_SKIP)
+ return eval_skip_value (exp);
+ return value_array (tem2, tem3, argvec);
+}
+
}

struct value *
diff --git a/gdb/expop.h b/gdb/expop.h
index a8aa0f43acc..08e40345e76 100644
--- a/gdb/expop.h
+++ b/gdb/expop.h
@@ -2046,6 +2046,28 @@ class adl_func_operation
{ return OP_ADL_FUNC; }
};

+/* The OP_ARRAY operation. */
+class array_operation
+ : public tuple_holding_operation<int, int, std::vector<operation_up>>
+{
+public:
+
+ using tuple_holding_operation::tuple_holding_operation;
+
+ value *evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside) override;
+
+ enum exp_opcode opcode () const override
+ { return OP_ARRAY; }
+
+private:
+
+ struct value *evaluate_struct_tuple (struct value *struct_val,
+ struct expression *exp,
+ enum noside noside, int nargs);
+};
+
} /* namespace expr */

#endif /* EXPOP_H */
--
2.26.2