}
}
+/* With SRC being a buffer containing BIT_SIZE bits of data at BIT_OFFSET,
+ unpack that data into UNPACKED. UNPACKED_LEN is the size in bytes of
+ the unpacked buffer.
-/* Create a new value of type TYPE from the contents of OBJ starting
- at byte OFFSET, and bit offset BIT_OFFSET within that byte,
- proceeding for BIT_SIZE bits. If OBJ is an lval in memory, then
- assigning through the result will set the field fetched from.
- VALADDR is ignored unless OBJ is NULL, in which case,
- VALADDR+OFFSET must address the start of storage containing the
- packed value. The value returned in this case is never an lval.
- Assumes 0 <= BIT_OFFSET < HOST_CHAR_BIT. */
+ The size of the unpacked buffer (UNPACKED_LEN) is expected to be large
+ enough to contain at least BIT_OFFSET bits. If not, an error is raised.
-struct value *
-ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
- long offset, int bit_offset, int bit_size,
- struct type *type)
-{
- struct value *v;
- int src, /* Index into the source area */
- targ, /* Index into the target area */
- srcBitsLeft, /* Number of source bits left to move */
- nsrc, ntarg, /* Number of source and target bytes */
- unusedLS, /* Number of bits in next significant
+ IS_BIG_ENDIAN is nonzero if the data is stored in big endian mode,
+ zero otherwise.
+
+ IS_SIGNED_TYPE is nonzero if the data corresponds to a signed type.
+
+ IS_SCALAR is nonzero if the data corresponds to a signed type. */
+
+static void
+ada_unpack_from_contents (const gdb_byte *src, int bit_offset, int bit_size,
+ gdb_byte *unpacked, int unpacked_len,
+ int is_big_endian, int is_signed_type,
+ int is_scalar)
+{
+ int src_len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+ int src_idx; /* Index into the source area */
+ int src_bytes_left; /* Number of source bytes left to process. */
+ int srcBitsLeft; /* Number of source bits left to move */
+ int unusedLS; /* Number of bits in next significant
byte of source that are unused */
- accumSize; /* Number of meaningful bits in accum */
- unsigned char *bytes; /* First byte containing data to unpack */
- unsigned char *unpacked;
+
+ int unpacked_idx; /* Index into the unpacked buffer */
+ int unpacked_bytes_left; /* Number of bytes left to set in unpacked. */
+
unsigned long accum; /* Staging area for bits being transferred */
+ int accumSize; /* Number of meaningful bits in accum */
unsigned char sign;
- int len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+
/* Transmit bytes from least to most significant; delta is the direction
the indices move. */
- int delta = gdbarch_bits_big_endian (get_type_arch (type)) ? -1 : 1;
+ int delta = is_big_endian ? -1 : 1;
- type = ada_check_typedef (type);
-
- if (obj == NULL)
- {
- v = allocate_value (type);
- bytes = (unsigned char *) (valaddr + offset);
- }
- else if (VALUE_LVAL (obj) == lval_memory && value_lazy (obj))
- {
- v = value_at (type, value_address (obj) + offset);
- type = value_type (v);
- if (TYPE_LENGTH (type) * HOST_CHAR_BIT < bit_size)
- {
- /* This can happen in the case of an array of dynamic objects,
- where the size of each element changes from element to element.
- In that case, we're initially given the array stride, but
- after resolving the element type, we find that its size is
- less than this stride. In that case, adjust bit_size to
- match TYPE's length, and recompute LEN accordingly. */
- bit_size = TYPE_LENGTH (type) * HOST_CHAR_BIT;
- len = TYPE_LENGTH (type) + (bit_offset + HOST_CHAR_BIT - 1) / 8;
- }
- bytes = (unsigned char *) alloca (len);
- read_memory (value_address (v), bytes, len);
- }
- else
- {
- v = allocate_value (type);
- bytes = (unsigned char *) value_contents (obj) + offset;
- }
-
- if (obj != NULL)
- {
- long new_offset = offset;
-
- set_value_component_location (v, obj);
- set_value_bitpos (v, bit_offset + value_bitpos (obj));
- set_value_bitsize (v, bit_size);
- if (value_bitpos (v) >= HOST_CHAR_BIT)
- {
- ++new_offset;
- set_value_bitpos (v, value_bitpos (v) - HOST_CHAR_BIT);
- }
- set_value_offset (v, new_offset);
-
- /* Also set the parent value. This is needed when trying to
- assign a new value (in inferior memory). */
- set_value_parent (v, obj);
- }
- else
- set_value_bitsize (v, bit_size);
- unpacked = (unsigned char *) value_contents (v);
+ /* Make sure that unpacked is large enough to receive the BIT_SIZE
+ bits from SRC. .*/
+ if ((bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT > unpacked_len)
+ error (_("Cannot unpack %d bits into buffer of %d bytes"),
+ bit_size, unpacked_len);
srcBitsLeft = bit_size;
- nsrc = len;
- ntarg = TYPE_LENGTH (type);
+ src_bytes_left = src_len;
+ unpacked_bytes_left = unpacked_len;
sign = 0;
- if (bit_size == 0)
- {
- memset (unpacked, 0, TYPE_LENGTH (type));
- return v;
- }
- else if (gdbarch_bits_big_endian (get_type_arch (type)))
+
+ if (is_big_endian)
{
- src = len - 1;
- if (has_negatives (type)
- && ((bytes[0] << bit_offset) & (1 << (HOST_CHAR_BIT - 1))))
+ src_idx = src_len - 1;
+ if (is_signed_type
+ && ((src[0] << bit_offset) & (1 << (HOST_CHAR_BIT - 1))))
sign = ~0;
unusedLS =
(HOST_CHAR_BIT - (bit_size + bit_offset) % HOST_CHAR_BIT)
% HOST_CHAR_BIT;
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_ARRAY:
- case TYPE_CODE_UNION:
- case TYPE_CODE_STRUCT:
+ if (is_scalar)
+ {
+ accumSize = 0;
+ unpacked_idx = unpacked_len - 1;
+ }
+ else
+ {
/* Non-scalar values must be aligned at a byte boundary... */
accumSize =
(HOST_CHAR_BIT - bit_size % HOST_CHAR_BIT) % HOST_CHAR_BIT;
/* ... And are placed at the beginning (most-significant) bytes
of the target. */
- targ = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT - 1;
- ntarg = targ + 1;
- break;
- default:
- accumSize = 0;
- targ = TYPE_LENGTH (type) - 1;
- break;
- }
+ unpacked_idx = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT - 1;
+ unpacked_bytes_left = unpacked_idx + 1;
+ }
}
else
{
int sign_bit_offset = (bit_size + bit_offset - 1) % 8;
- src = targ = 0;
+ src_idx = unpacked_idx = 0;
unusedLS = bit_offset;
accumSize = 0;
- if (has_negatives (type) && (bytes[len - 1] & (1 << sign_bit_offset)))
+ if (is_signed_type && (src[src_len - 1] & (1 << sign_bit_offset)))
sign = ~0;
}
accum = 0;
- while (nsrc > 0)
+ while (src_bytes_left > 0)
{
/* Mask for removing bits of the next source byte that are not
part of the value. */
unsigned int signMask = sign & ~unusedMSMask;
accum |=
- (((bytes[src] >> unusedLS) & unusedMSMask) | signMask) << accumSize;
+ (((src[src_idx] >> unusedLS) & unusedMSMask) | signMask) << accumSize;
accumSize += HOST_CHAR_BIT - unusedLS;
if (accumSize >= HOST_CHAR_BIT)
{
- unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
+ unpacked[unpacked_idx] = accum & ~(~0L << HOST_CHAR_BIT);
accumSize -= HOST_CHAR_BIT;
accum >>= HOST_CHAR_BIT;
- ntarg -= 1;
- targ += delta;
+ unpacked_bytes_left -= 1;
+ unpacked_idx += delta;
}
srcBitsLeft -= HOST_CHAR_BIT - unusedLS;
unusedLS = 0;
- nsrc -= 1;
- src += delta;
+ src_bytes_left -= 1;
+ src_idx += delta;
}
- while (ntarg > 0)
+ while (unpacked_bytes_left > 0)
{
accum |= sign << accumSize;
- unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
+ unpacked[unpacked_idx] = accum & ~(~0L << HOST_CHAR_BIT);
accumSize -= HOST_CHAR_BIT;
if (accumSize < 0)
accumSize = 0;
accum >>= HOST_CHAR_BIT;
- ntarg -= 1;
- targ += delta;
+ unpacked_bytes_left -= 1;
+ unpacked_idx += delta;
}
+}
+
+/* Create a new value of type TYPE from the contents of OBJ starting
+ at byte OFFSET, and bit offset BIT_OFFSET within that byte,
+ proceeding for BIT_SIZE bits. If OBJ is an lval in memory, then
+ assigning through the result will set the field fetched from.
+ VALADDR is ignored unless OBJ is NULL, in which case,
+ VALADDR+OFFSET must address the start of storage containing the
+ packed value. The value returned in this case is never an lval.
+ Assumes 0 <= BIT_OFFSET < HOST_CHAR_BIT. */
- if (is_dynamic_type (value_type (v)))
- v = value_from_contents_and_address (value_type (v), value_contents (v),
- 0);
+struct value *
+ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
+ long offset, int bit_offset, int bit_size,
+ struct type *type)
+{
+ struct value *v;
+ const gdb_byte *src; /* First byte containing data to unpack */
+ gdb_byte *unpacked;
+ const int is_scalar = is_scalar_type (type);
+ const int is_big_endian = gdbarch_bits_big_endian (get_type_arch (type));
+ gdb_byte *staging = NULL;
+ int staging_len = 0;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
+ type = ada_check_typedef (type);
+
+ if (obj == NULL)
+ src = valaddr + offset;
+ else
+ src = value_contents (obj) + offset;
+
+ if (is_dynamic_type (type))
+ {
+ /* The length of TYPE might by dynamic, so we need to resolve
+ TYPE in order to know its actual size, which we then use
+ to create the contents buffer of the value we return.
+ The difficulty is that the data containing our object is
+ packed, and therefore maybe not at a byte boundary. So, what
+ we do, is unpack the data into a byte-aligned buffer, and then
+ use that buffer as our object's value for resolving the type. */
+ staging_len = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+ staging = (gdb_byte *) malloc (staging_len);
+ make_cleanup (xfree, staging);
+
+ ada_unpack_from_contents (src, bit_offset, bit_size,
+ staging, staging_len,
+ is_big_endian, has_negatives (type),
+ is_scalar);
+ type = resolve_dynamic_type (type, staging, 0);
+ if (TYPE_LENGTH (type) < (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT)
+ {
+ /* This happens when the length of the object is dynamic,
+ and is actually smaller than the space reserved for it.
+ For instance, in an array of variant records, the bit_size
+ we're given is the array stride, which is constant and
+ normally equal to the maximum size of its element.
+ But, in reality, each element only actually spans a portion
+ of that stride. */
+ bit_size = TYPE_LENGTH (type) * HOST_CHAR_BIT;
+ }
+ }
+
+ if (obj == NULL)
+ {
+ v = allocate_value (type);
+ src = valaddr + offset;
+ }
+ else if (VALUE_LVAL (obj) == lval_memory && value_lazy (obj))
+ {
+ int src_len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+ gdb_byte *buf;
+
+ v = value_at (type, value_address (obj) + offset);
+ buf = (gdb_byte *) alloca (src_len);
+ read_memory (value_address (v), buf, src_len);
+ src = buf;
+ }
+ else
+ {
+ v = allocate_value (type);
+ src = value_contents (obj) + offset;
+ }
+
+ if (obj != NULL)
+ {
+ long new_offset = offset;
+
+ set_value_component_location (v, obj);
+ set_value_bitpos (v, bit_offset + value_bitpos (obj));
+ set_value_bitsize (v, bit_size);
+ if (value_bitpos (v) >= HOST_CHAR_BIT)
+ {
+ ++new_offset;
+ set_value_bitpos (v, value_bitpos (v) - HOST_CHAR_BIT);
+ }
+ set_value_offset (v, new_offset);
+
+ /* Also set the parent value. This is needed when trying to
+ assign a new value (in inferior memory). */
+ set_value_parent (v, obj);
+ }
+ else
+ set_value_bitsize (v, bit_size);
+ unpacked = value_contents_writeable (v);
+
+ if (bit_size == 0)
+ {
+ memset (unpacked, 0, TYPE_LENGTH (type));
+ do_cleanups (old_chain);
+ return v;
+ }
+
+ if (staging != NULL && staging_len == TYPE_LENGTH (type))
+ {
+ /* Small short-cut: If we've unpacked the data into a buffer
+ of the same size as TYPE's length, then we can reuse that,
+ instead of doing the unpacking again. */
+ memcpy (unpacked, staging, staging_len);
+ }
+ else
+ ada_unpack_from_contents (src, bit_offset, bit_size,
+ unpacked, TYPE_LENGTH (type),
+ is_big_endian, has_negatives (type), is_scalar);
+
+ do_cleanups (old_chain);
return v;
}
{
static char *result;
static size_t result_len = 0;
- char *tmp;
+ const char *tmp;
/* First, unqualify the enumeration name:
1. Search for the last '.' character. If we find one, then skip