#include "objfiles.h"
#include "valprint.h"
#include "cli/cli-decode.h"
-
+#include "exceptions.h"
#include "python/python.h"
-
+#include <ctype.h>
#include "tracepoint.h"
-/* Prototypes for exported functions. */
+/* Prototypes for exported functions. */
void _initialize_values (void);
void *cookie;
};
+/* Defines an [OFFSET, OFFSET + LENGTH) range. */
+
+struct range
+{
+ /* Lowest offset in the range. */
+ int offset;
+
+ /* Length of the range. */
+ int length;
+};
+
+typedef struct range range_s;
+
+DEF_VEC_O(range_s);
+
+/* Returns true if the ranges defined by [offset1, offset1+len1) and
+ [offset2, offset2+len2) overlap. */
+
+static int
+ranges_overlap (int offset1, int len1,
+ int offset2, int len2)
+{
+ ULONGEST h, l;
+
+ l = max (offset1, offset2);
+ h = min (offset1 + len1, offset2 + len2);
+ return (l < h);
+}
+
+/* Returns true if the first argument is strictly less than the
+ second, useful for VEC_lower_bound. We keep ranges sorted by
+ offset and coalesce overlapping and contiguous ranges, so this just
+ compares the starting offset. */
+
+static int
+range_lessthan (const range_s *r1, const range_s *r2)
+{
+ return r1->offset < r2->offset;
+}
+
+/* Returns true if RANGES contains any range that overlaps [OFFSET,
+ OFFSET+LENGTH). */
+
+static int
+ranges_contain (VEC(range_s) *ranges, int offset, int length)
+{
+ range_s what;
+ int i;
+
+ what.offset = offset;
+ what.length = length;
+
+ /* We keep ranges sorted by offset and coalesce overlapping and
+ contiguous ranges, so to check if a range list contains a given
+ range, we can do a binary search for the position the given range
+ would be inserted if we only considered the starting OFFSET of
+ ranges. We call that position I. Since we also have LENGTH to
+ care for (this is a range afterall), we need to check if the
+ _previous_ range overlaps the I range. E.g.,
+
+ R
+ |---|
+ |---| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=1
+
+ In the case above, the binary search would return `I=1', meaning,
+ this OFFSET should be inserted at position 1, and the current
+ position 1 should be pushed further (and before 2). But, `0'
+ overlaps with R.
+
+ Then we need to check if the I range overlaps the I range itself.
+ E.g.,
+
+ R
+ |---|
+ |---| |---| |-------| ... |--|
+ 0 1 2 N
+
+ I=1
+ */
+
+ i = VEC_lower_bound (range_s, ranges, &what, range_lessthan);
+
+ if (i > 0)
+ {
+ struct range *bef = VEC_index (range_s, ranges, i - 1);
+
+ if (ranges_overlap (bef->offset, bef->length, offset, length))
+ return 1;
+ }
+
+ if (i < VEC_length (range_s, ranges))
+ {
+ struct range *r = VEC_index (range_s, ranges, i);
+
+ if (ranges_overlap (r->offset, r->length, offset, length))
+ return 1;
+ }
+
+ return 0;
+}
+
static struct cmd_list_element *functionlist;
struct value
/* Only used for bitfields; position of start of field. For
gdbarch_bits_big_endian=0 targets, it is the position of the LSB. For
- gdbarch_bits_big_endian=1 targets, it is the position of the MSB. */
+ gdbarch_bits_big_endian=1 targets, it is the position of the MSB. */
int bitpos;
/* Only used for bitfields; the containing value. This allows a
valid if lazy is nonzero. */
gdb_byte *contents;
+ /* Unavailable ranges in CONTENTS. We mark unavailable ranges,
+ rather than available, since the common and default case is for a
+ value to be available. This is filled in at value read time. */
+ VEC(range_s) *unavailable;
+
/* The number of references to this value. When a value is created,
the value chain holds a reference, so REFERENCE_COUNT is 1. If
release_value is called, this value is removed from the chain but
int reference_count;
};
-/* Prototypes for local functions. */
+int
+value_bytes_available (const struct value *value, int offset, int length)
+{
+ gdb_assert (!value->lazy);
+
+ return !ranges_contain (value->unavailable, offset, length);
+}
+
+int
+value_entirely_available (struct value *value)
+{
+ /* We can only tell whether the whole value is available when we try
+ to read it. */
+ if (value->lazy)
+ value_fetch_lazy (value);
+
+ if (VEC_empty (range_s, value->unavailable))
+ return 1;
+ return 0;
+}
+
+void
+mark_value_bytes_unavailable (struct value *value, int offset, int length)
+{
+ range_s newr;
+ int i;
+
+ /* Insert the range sorted. If there's overlap or the new range
+ would be contiguous with an existing range, merge. */
+
+ newr.offset = offset;
+ newr.length = length;
+
+ /* Do a binary search for the position the given range would be
+ inserted if we only considered the starting OFFSET of ranges.
+ Call that position I. Since we also have LENGTH to care for
+ (this is a range afterall), we need to check if the _previous_
+ range overlaps the I range. E.g., calling R the new range:
+
+ #1 - overlaps with previous
+
+ R
+ |-...-|
+ |---| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=1
+
+ In the case #1 above, the binary search would return `I=1',
+ meaning, this OFFSET should be inserted at position 1, and the
+ current position 1 should be pushed further (and become 2). But,
+ note that `0' overlaps with R, so we want to merge them.
+
+ A similar consideration needs to be taken if the new range would
+ be contiguous with the previous range:
+
+ #2 - contiguous with previous
+
+ R
+ |-...-|
+ |--| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=1
+
+ If there's no overlap with the previous range, as in:
+
+ #3 - not overlapping and not contiguous
+
+ R
+ |-...-|
+ |--| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=1
+
+ or if I is 0:
+
+ #4 - R is the range with lowest offset
+
+ R
+ |-...-|
+ |--| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=0
+
+ ... we just push the new range to I.
+
+ All the 4 cases above need to consider that the new range may
+ also overlap several of the ranges that follow, or that R may be
+ contiguous with the following range, and merge. E.g.,
+
+ #5 - overlapping following ranges
+
+ R
+ |------------------------|
+ |--| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=0
+
+ or:
+
+ R
+ |-------|
+ |--| |---| |------| ... |--|
+ 0 1 2 N
+
+ I=1
+
+ */
+
+ i = VEC_lower_bound (range_s, value->unavailable, &newr, range_lessthan);
+ if (i > 0)
+ {
+ struct range *bef = VEC_index (range_s, value->unavailable, i - 1);
+
+ if (ranges_overlap (bef->offset, bef->length, offset, length))
+ {
+ /* #1 */
+ ULONGEST l = min (bef->offset, offset);
+ ULONGEST h = max (bef->offset + bef->length, offset + length);
+
+ bef->offset = l;
+ bef->length = h - l;
+ i--;
+ }
+ else if (offset == bef->offset + bef->length)
+ {
+ /* #2 */
+ bef->length += length;
+ i--;
+ }
+ else
+ {
+ /* #3 */
+ VEC_safe_insert (range_s, value->unavailable, i, &newr);
+ }
+ }
+ else
+ {
+ /* #4 */
+ VEC_safe_insert (range_s, value->unavailable, i, &newr);
+ }
+
+ /* Check whether the ranges following the one we've just added or
+ touched can be folded in (#5 above). */
+ if (i + 1 < VEC_length (range_s, value->unavailable))
+ {
+ struct range *t;
+ struct range *r;
+ int removed = 0;
+ int next = i + 1;
+
+ /* Get the range we just touched. */
+ t = VEC_index (range_s, value->unavailable, i);
+ removed = 0;
+
+ i = next;
+ for (; VEC_iterate (range_s, value->unavailable, i, r); i++)
+ if (r->offset <= t->offset + t->length)
+ {
+ ULONGEST l, h;
+
+ l = min (t->offset, r->offset);
+ h = max (t->offset + t->length, r->offset + r->length);
+
+ t->offset = l;
+ t->length = h - l;
+
+ removed++;
+ }
+ else
+ {
+ /* If we couldn't merge this one, we won't be able to
+ merge following ones either, since the ranges are
+ always sorted by OFFSET. */
+ break;
+ }
+
+ if (removed != 0)
+ VEC_block_remove (range_s, value->unavailable, next, removed);
+ }
+}
+
+/* Find the first range in RANGES that overlaps the range defined by
+ OFFSET and LENGTH, starting at element POS in the RANGES vector,
+ Returns the index into RANGES where such overlapping range was
+ found, or -1 if none was found. */
+
+static int
+find_first_range_overlap (VEC(range_s) *ranges, int pos,
+ int offset, int length)
+{
+ range_s *r;
+ int i;
+
+ for (i = pos; VEC_iterate (range_s, ranges, i, r); i++)
+ if (ranges_overlap (r->offset, r->length, offset, length))
+ return i;
+
+ return -1;
+}
+
+int
+value_available_contents_eq (const struct value *val1, int offset1,
+ const struct value *val2, int offset2,
+ int length)
+{
+ int idx1 = 0, idx2 = 0;
+
+ /* This routine is used by printing routines, where we should
+ already have read the value. Note that we only know whether a
+ value chunk is available if we've tried to read it. */
+ gdb_assert (!val1->lazy && !val2->lazy);
+
+ while (length > 0)
+ {
+ range_s *r1, *r2;
+ ULONGEST l1, h1;
+ ULONGEST l2, h2;
+
+ idx1 = find_first_range_overlap (val1->unavailable, idx1,
+ offset1, length);
+ idx2 = find_first_range_overlap (val2->unavailable, idx2,
+ offset2, length);
+
+ /* The usual case is for both values to be completely available. */
+ if (idx1 == -1 && idx2 == -1)
+ return (memcmp (val1->contents + offset1,
+ val2->contents + offset2,
+ length) == 0);
+ /* The contents only match equal if the available set matches as
+ well. */
+ else if (idx1 == -1 || idx2 == -1)
+ return 0;
+
+ gdb_assert (idx1 != -1 && idx2 != -1);
+
+ r1 = VEC_index (range_s, val1->unavailable, idx1);
+ r2 = VEC_index (range_s, val2->unavailable, idx2);
+
+ /* Get the unavailable windows intersected by the incoming
+ ranges. The first and last ranges that overlap the argument
+ range may be wider than said incoming arguments ranges. */
+ l1 = max (offset1, r1->offset);
+ h1 = min (offset1 + length, r1->offset + r1->length);
+
+ l2 = max (offset2, r2->offset);
+ h2 = min (offset2 + length, r2->offset + r2->length);
+
+ /* Make them relative to the respective start offsets, so we can
+ compare them for equality. */
+ l1 -= offset1;
+ h1 -= offset1;
+
+ l2 -= offset2;
+ h2 -= offset2;
+
+ /* Different availability, no match. */
+ if (l1 != l2 || h1 != h2)
+ return 0;
+
+ /* Compare the _available_ contents. */
+ if (memcmp (val1->contents + offset1,
+ val2->contents + offset2,
+ l1) != 0)
+ return 0;
+
+ length -= h1;
+ offset1 += h1;
+ offset2 += h1;
+ }
+
+ return 1;
+}
+
+/* Prototypes for local functions. */
static void show_values (char *, int);
static struct value_history_chunk *value_history_chain;
-static int value_history_count; /* Abs number of last entry stored */
+static int value_history_count; /* Abs number of last entry stored. */
\f
/* List of all value objects currently allocated
struct lval_funcs *funcs,
void *closure)
{
- struct value *v = allocate_value (type);
+ struct value *v = allocate_value_lazy (type);
VALUE_LVAL (v) = lval_computed;
v->location.computed.funcs = funcs;
v->location.computed.closure = closure;
- set_value_lazy (v, 1);
return v;
}
}
static void
-require_not_optimized_out (struct value *value)
+require_not_optimized_out (const struct value *value)
{
if (value->optimized_out)
error (_("value has been optimized out"));
}
+static void
+require_available (const struct value *value)
+{
+ if (!VEC_empty (range_s, value->unavailable))
+ throw_error (NOT_AVAILABLE_ERROR, _("value is not available"));
+}
+
const gdb_byte *
value_contents_for_printing (struct value *value)
{
return value->contents;
}
+const gdb_byte *
+value_contents_for_printing_const (const struct value *value)
+{
+ gdb_assert (!value->lazy);
+ return value->contents;
+}
+
const gdb_byte *
value_contents_all (struct value *value)
{
const gdb_byte *result = value_contents_for_printing (value);
require_not_optimized_out (value);
+ require_available (value);
return result;
}
+/* Copy LENGTH bytes of SRC value's (all) contents
+ (value_contents_all) starting at SRC_OFFSET, into DST value's (all)
+ contents, starting at DST_OFFSET. If unavailable contents are
+ being copied from SRC, the corresponding DST contents are marked
+ unavailable accordingly. Neither DST nor SRC may be lazy
+ values.
+
+ It is assumed the contents of DST in the [DST_OFFSET,
+ DST_OFFSET+LENGTH) range are wholly available. */
+
+void
+value_contents_copy_raw (struct value *dst, int dst_offset,
+ struct value *src, int src_offset, int length)
+{
+ range_s *r;
+ int i;
+
+ /* A lazy DST would make that this copy operation useless, since as
+ soon as DST's contents were un-lazied (by a later value_contents
+ call, say), the contents would be overwritten. A lazy SRC would
+ mean we'd be copying garbage. */
+ gdb_assert (!dst->lazy && !src->lazy);
+
+ /* The overwritten DST range gets unavailability ORed in, not
+ replaced. Make sure to remember to implement replacing if it
+ turns out actually necessary. */
+ gdb_assert (value_bytes_available (dst, dst_offset, length));
+
+ /* Copy the data. */
+ memcpy (value_contents_all_raw (dst) + dst_offset,
+ value_contents_all_raw (src) + src_offset,
+ length);
+
+ /* Copy the meta-data, adjusted. */
+ for (i = 0; VEC_iterate (range_s, src->unavailable, i, r); i++)
+ {
+ ULONGEST h, l;
+
+ l = max (r->offset, src_offset);
+ h = min (r->offset + r->length, src_offset + length);
+
+ if (l < h)
+ mark_value_bytes_unavailable (dst,
+ dst_offset + (l - src_offset),
+ h - l);
+ }
+}
+
+/* Copy LENGTH bytes of SRC value's (all) contents
+ (value_contents_all) starting at SRC_OFFSET byte, into DST value's
+ (all) contents, starting at DST_OFFSET. If unavailable contents
+ are being copied from SRC, the corresponding DST contents are
+ marked unavailable accordingly. DST must not be lazy. If SRC is
+ lazy, it will be fetched now. If SRC is not valid (is optimized
+ out), an error is thrown.
+
+ It is assumed the contents of DST in the [DST_OFFSET,
+ DST_OFFSET+LENGTH) range are wholly available. */
+
+void
+value_contents_copy (struct value *dst, int dst_offset,
+ struct value *src, int src_offset, int length)
+{
+ require_not_optimized_out (src);
+
+ if (src->lazy)
+ value_fetch_lazy (src);
+
+ value_contents_copy_raw (dst, dst_offset, src, src_offset, length);
+}
+
int
value_lazy (struct value *value)
{
{
const gdb_byte *result = value_contents_writeable (value);
require_not_optimized_out (value);
+ require_available (value);
return result;
}
int
value_bits_valid (const struct value *value, int offset, int length)
{
- if (value == NULL || !value->optimized_out)
+ if (!value->optimized_out)
return 1;
if (value->lval != lval_computed
|| !value->location.computed.funcs->check_validity)
value_bits_synthetic_pointer (const struct value *value,
int offset, int length)
{
- if (value == NULL || value->lval != lval_computed
+ if (value->lval != lval_computed
|| !value->location.computed.funcs->check_synthetic_pointer)
return 0;
return value->location.computed.funcs->check_synthetic_pointer (value,
}
CORE_ADDR
-value_address (struct value *value)
+value_address (const struct value *value)
{
if (value->lval == lval_internalvar
|| value->lval == lval_internalvar_component)
}
xfree (val->contents);
+ VEC_free (range_s, val->unavailable);
}
xfree (val);
}
TYPE_LENGTH (value_enclosing_type (arg)));
}
+ val->unavailable = VEC_copy (range_s, arg->unavailable);
val->parent = arg->parent;
if (val->parent)
value_incref (val->parent);
/* The variable holds an integer value. */
INTERNALVAR_INTEGER,
- /* The variable holds a pointer value. */
- INTERNALVAR_POINTER,
-
/* The variable holds a GDB-provided string. */
INTERNALVAR_STRING,
LONGEST val;
} integer;
- /* A pointer value used with INTERNALVAR_POINTER. */
- struct
- {
- struct type *type;
- CORE_ADDR val;
- } pointer;
-
/* A string value used with INTERNALVAR_STRING. */
char *string;
} u;
val = value_from_longest (var->u.integer.type, var->u.integer.val);
break;
- case INTERNALVAR_POINTER:
- val = value_from_pointer (var->u.pointer.type, var->u.pointer.val);
- break;
-
case INTERNALVAR_STRING:
val = value_cstring (var->u.string, strlen (var->u.string),
builtin_type (gdbarch)->builtin_char);
int
get_internalvar_integer (struct internalvar *var, LONGEST *result)
{
- switch (var->kind)
+ if (var->kind == INTERNALVAR_INTEGER)
{
- case INTERNALVAR_INTEGER:
*result = var->u.integer.val;
return 1;
+ }
- default:
- return 0;
+ if (var->kind == INTERNALVAR_VALUE)
+ {
+ struct type *type = check_typedef (value_type (var->u.value));
+
+ if (TYPE_CODE (type) == TYPE_CODE_INT)
+ {
+ *result = value_as_long (var->u.value);
+ return 1;
+ }
}
+
+ return 0;
}
static int
/* Copies created here are never canonical. */
break;
- case TYPE_CODE_INT:
- new_kind = INTERNALVAR_INTEGER;
- new_data.integer.type = value_type (val);
- new_data.integer.val = value_as_long (val);
- break;
-
- case TYPE_CODE_PTR:
- new_kind = INTERNALVAR_POINTER;
- new_data.pointer.type = value_type (val);
- new_data.pointer.val = value_as_address (val);
- break;
-
default:
new_kind = INTERNALVAR_VALUE;
new_data.value = value_copy (val);
= copy_type_recursive (objfile, var->u.integer.type, copied_types);
break;
- case INTERNALVAR_POINTER:
- if (TYPE_OBJFILE (var->u.pointer.type) == objfile)
- var->u.pointer.type
- = copy_type_recursive (objfile, var->u.pointer.type, copied_types);
- break;
-
case INTERNALVAR_VALUE:
preserve_one_value (var->u.value, objfile, copied_types);
break;
return foo;
}
-/* Extract a value as a C pointer. Does not deallocate the value.
+/* Extract a value as a C pointer. Does not deallocate the value.
Note that val's type may not actually be a pointer; value_as_long
handles all the cases. */
CORE_ADDR
int len;
int nosign;
- *invp = 0; /* Assume valid. */
+ *invp = 0; /* Assume valid. */
CHECK_TYPEDEF (type);
code = TYPE_CODE (type);
len = TYPE_LENGTH (type);
\f
/* Get the value of the FIELDNO'th field (which must be static) of
TYPE. Return NULL if the field doesn't exist or has been
- optimized out. */
+ optimized out. */
struct value *
value_static_field (struct type *type, int fieldno)
case FIELD_LOC_KIND_PHYSNAME:
{
char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
- /*TYPE_FIELD_NAME (type, fieldno);*/
+ /* TYPE_FIELD_NAME (type, fieldno); */
struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0);
if (sym == NULL)
{
/* With some compilers, e.g. HP aCC, static data members are
- reported as non-debuggable symbols */
+ reported as non-debuggable symbols. */
struct minimal_symbol *msym = lookup_minimal_symbol (phys_name,
NULL, NULL);
/* Given a value ARG1 (offset by OFFSET bytes)
of a struct or union type ARG_TYPE,
extract and return the value of one of its (non-static) fields.
- FIELDNO says which field. */
+ FIELDNO says which field. */
struct value *
value_primitive_field (struct value *arg1, int offset,
else if (fieldno < TYPE_N_BASECLASSES (arg_type))
{
/* This field is actually a base subobject, so preserve the
- entire object's contents for later references to virtual
- bases, etc. */
+ entire object's contents for later references to virtual
+ bases, etc. */
/* Lazy register values with offsets are not supported. */
if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1))
else
{
v = allocate_value (value_enclosing_type (arg1));
- memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1),
- TYPE_LENGTH (value_enclosing_type (arg1)));
+ value_contents_copy_raw (v, 0, arg1, 0,
+ TYPE_LENGTH (value_enclosing_type (arg1)));
}
v->type = type;
v->offset = value_offset (arg1);
else
{
v = allocate_value (type);
- memcpy (value_contents_raw (v),
- value_contents_raw (arg1) + offset,
- TYPE_LENGTH (type));
+ value_contents_copy_raw (v, value_embedded_offset (v),
+ arg1, value_embedded_offset (arg1) + offset,
+ TYPE_LENGTH (type));
}
v->offset = (value_offset (arg1) + offset
+ value_embedded_offset (arg1));
/* Given a value ARG1 of a struct or union type,
extract and return the value of one of its (non-static) fields.
- FIELDNO says which field. */
+ FIELDNO says which field. */
struct value *
value_field (struct value *arg1, int fieldno)
J is an index into F which provides the desired method.
We only use the symbol for its address, so be happy with either a
- full symbol or a minimal symbol.
- */
+ full symbol or a minimal symbol. */
struct value *
value_fn_field (struct value **arg1p, struct fn_field *f,
value_addr (*arg1p)));
/* Move the `this' pointer according to the offset.
- VALUE_OFFSET (*arg1p) += offset;
- */
+ VALUE_OFFSET (*arg1p) += offset; */
}
return v;
}
\f
-/* Unpack a bitfield of the specified FIELD_TYPE, from the anonymous
- object at VALADDR. The bitfield starts at BITPOS bits and contains
- BITSIZE bits.
-
- Extracting bits depends on endianness of the machine. Compute the
- number of least significant bits to discard. For big endian machines,
- we compute the total number of bits in the anonymous object, subtract
- off the bit count from the MSB of the object to the MSB of the
- bitfield, then the size of the bitfield, which leaves the LSB discard
- count. For little endian machines, the discard count is simply the
- number of bits from the LSB of the anonymous object to the LSB of the
- bitfield.
- If the field is signed, we also do sign extension. */
+/* Helper function for both unpack_value_bits_as_long and
+ unpack_bits_as_long. See those functions for more details on the
+ interface; the only difference is that this function accepts either
+ a NULL or a non-NULL ORIGINAL_VALUE. */
-LONGEST
-unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr,
- int bitpos, int bitsize)
+static int
+unpack_value_bits_as_long_1 (struct type *field_type, const gdb_byte *valaddr,
+ int embedded_offset, int bitpos, int bitsize,
+ const struct value *original_value,
+ LONGEST *result)
{
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (field_type));
ULONGEST val;
ULONGEST valmask;
int lsbcount;
int bytes_read;
+ int read_offset;
/* Read the minimum number of bytes required; there may not be
enough bytes to read an entire ULONGEST. */
else
bytes_read = TYPE_LENGTH (field_type);
- val = extract_unsigned_integer (valaddr + bitpos / 8,
+ read_offset = bitpos / 8;
+
+ if (original_value != NULL
+ && !value_bytes_available (original_value, embedded_offset + read_offset,
+ bytes_read))
+ return 0;
+
+ val = extract_unsigned_integer (valaddr + embedded_offset + read_offset,
bytes_read, byte_order);
- /* Extract bits. See comment above. */
+ /* Extract bits. See comment above. */
if (gdbarch_bits_big_endian (get_type_arch (field_type)))
lsbcount = (bytes_read * 8 - bitpos % 8 - bitsize);
val >>= lsbcount;
/* If the field does not entirely fill a LONGEST, then zero the sign bits.
- If the field is signed, and is negative, then sign extend. */
+ If the field is signed, and is negative, then sign extend. */
if ((bitsize > 0) && (bitsize < 8 * (int) sizeof (val)))
{
}
}
}
- return (val);
+
+ *result = val;
+ return 1;
}
-/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at
- VALADDR. See unpack_bits_as_long for more details. */
+/* Unpack a bitfield of the specified FIELD_TYPE, from the object at
+ VALADDR + EMBEDDED_OFFSET, and store the result in *RESULT.
+ VALADDR points to the contents of ORIGINAL_VALUE, which must not be
+ NULL. The bitfield starts at BITPOS bits and contains BITSIZE
+ bits.
-LONGEST
-unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno)
+ Returns false if the value contents are unavailable, otherwise
+ returns true, indicating a valid value has been stored in *RESULT.
+
+ Extracting bits depends on endianness of the machine. Compute the
+ number of least significant bits to discard. For big endian machines,
+ we compute the total number of bits in the anonymous object, subtract
+ off the bit count from the MSB of the object to the MSB of the
+ bitfield, then the size of the bitfield, which leaves the LSB discard
+ count. For little endian machines, the discard count is simply the
+ number of bits from the LSB of the anonymous object to the LSB of the
+ bitfield.
+
+ If the field is signed, we also do sign extension. */
+
+int
+unpack_value_bits_as_long (struct type *field_type, const gdb_byte *valaddr,
+ int embedded_offset, int bitpos, int bitsize,
+ const struct value *original_value,
+ LONGEST *result)
+{
+ gdb_assert (original_value != NULL);
+
+ return unpack_value_bits_as_long_1 (field_type, valaddr, embedded_offset,
+ bitpos, bitsize, original_value, result);
+
+}
+
+/* Unpack a field FIELDNO of the specified TYPE, from the object at
+ VALADDR + EMBEDDED_OFFSET. VALADDR points to the contents of
+ ORIGINAL_VALUE. See unpack_value_bits_as_long for more
+ details. */
+
+static int
+unpack_value_field_as_long_1 (struct type *type, const gdb_byte *valaddr,
+ int embedded_offset, int fieldno,
+ const struct value *val, LONGEST *result)
{
int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
struct type *field_type = TYPE_FIELD_TYPE (type, fieldno);
- return unpack_bits_as_long (field_type, valaddr, bitpos, bitsize);
+ return unpack_value_bits_as_long_1 (field_type, valaddr, embedded_offset,
+ bitpos, bitsize, val,
+ result);
+}
+
+/* Unpack a field FIELDNO of the specified TYPE, from the object at
+ VALADDR + EMBEDDED_OFFSET. VALADDR points to the contents of
+ ORIGINAL_VALUE, which must not be NULL. See
+ unpack_value_bits_as_long for more details. */
+
+int
+unpack_value_field_as_long (struct type *type, const gdb_byte *valaddr,
+ int embedded_offset, int fieldno,
+ const struct value *val, LONGEST *result)
+{
+ gdb_assert (val != NULL);
+
+ return unpack_value_field_as_long_1 (type, valaddr, embedded_offset,
+ fieldno, val, result);
+}
+
+/* Unpack a field FIELDNO of the specified TYPE, from the anonymous
+ object at VALADDR. See unpack_value_bits_as_long for more details.
+ This function differs from unpack_value_field_as_long in that it
+ operates without a struct value object. */
+
+LONGEST
+unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno)
+{
+ LONGEST result;
+
+ unpack_value_field_as_long_1 (type, valaddr, 0, fieldno, NULL, &result);
+ return result;
+}
+
+/* Return a new value with type TYPE, which is FIELDNO field of the
+ object at VALADDR + EMBEDDEDOFFSET. VALADDR points to the contents
+ of VAL. If the VAL's contents required to extract the bitfield
+ from are unavailable, the new value is correspondingly marked as
+ unavailable. */
+
+struct value *
+value_field_bitfield (struct type *type, int fieldno,
+ const gdb_byte *valaddr,
+ int embedded_offset, const struct value *val)
+{
+ LONGEST l;
+
+ if (!unpack_value_field_as_long (type, valaddr, embedded_offset, fieldno,
+ val, &l))
+ {
+ struct type *field_type = TYPE_FIELD_TYPE (type, fieldno);
+ struct value *retval = allocate_value (field_type);
+ mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (field_type));
+ return retval;
+ }
+ else
+ {
+ return value_from_longest (TYPE_FIELD_TYPE (type, fieldno), l);
+ }
}
/* Modify the value of a bitfield. ADDR points to a block of memory in
target byte order; the bitfield starts in the byte pointed to. FIELDVAL
is the desired value of the field, in host byte order. BITPOS and BITSIZE
- indicate which bits (in target bit order) comprise the bitfield.
+ indicate which bits (in target bit order) comprise the bitfield.
Requires 0 < BITSIZE <= lbits, 0 <= BITPOS % 8 + BITSIZE <= lbits, and
0 <= BITPOS, where lbits is the size of a LONGEST in bits. */
const gdb_byte *valaddr,
CORE_ADDR address)
{
- struct value *v = allocate_value (type);
+ struct value *v;
if (valaddr == NULL)
- set_value_lazy (v, 1);
+ v = allocate_value_lazy (type);
else
- memcpy (value_contents_raw (v), valaddr, TYPE_LENGTH (type));
+ {
+ v = allocate_value (type);
+ memcpy (value_contents_raw (v), valaddr, TYPE_LENGTH (type));
+ }
set_value_address (v, address);
VALUE_LVAL (v) = lval_memory;
return v;
return val;
}
+/* Extract a value from the history file. Input will be of the form
+ $digits or $$digits. See block comment above 'write_dollar_variable'
+ for details. */
+
+struct value *
+value_from_history_ref (char *h, char **endp)
+{
+ int index, len;
+
+ if (h[0] == '$')
+ len = 1;
+ else
+ return NULL;
+
+ if (h[1] == '$')
+ len = 2;
+
+ /* Find length of numeral string. */
+ for (; isdigit (h[len]); len++)
+ ;
+
+ /* Make sure numeral string is not part of an identifier. */
+ if (h[len] == '_' || isalpha (h[len]))
+ return NULL;
+
+ /* Now collect the index value. */
+ if (h[1] == '$')
+ {
+ if (len == 2)
+ {
+ /* For some bizarre reason, "$$" is equivalent to "$$1",
+ rather than to "$$0" as it ought to be! */
+ index = -1;
+ *endp += len;
+ }
+ else
+ index = -strtol (&h[2], endp, 10);
+ }
+ else
+ {
+ if (len == 1)
+ {
+ /* "$" is equivalent to "$0". */
+ index = 0;
+ *endp += len;
+ }
+ else
+ index = strtol (&h[1], endp, 10);
+ }
+
+ return access_value_history (index);
+}
+
struct value *
coerce_ref (struct value *arg)
{
\"$__\" holds the contents of the last address examined with \"x\"."),
&showlist);
- add_cmd ("values", no_class, show_values, _("\
+ add_cmd ("values", no_set_class, show_values, _("\
Elements of value history around item number IDX (or last ten)."),
&showlist);