/* Low level packing and unpacking of values for GDB, the GNU Debugger.
- Copyright (C) 1986-2016 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "target.h"
#include "language.h"
#include "demangle.h"
-#include "doublest.h"
#include "regcache.h"
#include "block.h"
-#include "dfp.h"
+#include "target-float.h"
#include "objfiles.h"
#include "valprint.h"
#include "cli/cli-decode.h"
#include "tracepoint.h"
#include "cp-abi.h"
#include "user-regs.h"
-
-/* Prototypes for exported functions. */
-
-void _initialize_values (void);
+#include <algorithm>
+#include "completer.h"
+#include "gdbsupport/selftest.h"
+#include "gdbsupport/array-view.h"
+#include "cli/cli-style.h"
/* Definition of a user function. */
struct internal_function
struct range
{
/* Lowest offset in the range. */
- int offset;
+ LONGEST offset;
/* Length of the range. */
- int length;
-};
+ LONGEST length;
-typedef struct range range_s;
+ /* Returns true if THIS is strictly less than OTHER, useful for
+ searching. We keep ranges sorted by offset and coalesce
+ overlapping and contiguous ranges, so this just compares the
+ starting offset. */
-DEF_VEC_O(range_s);
+ bool operator< (const range &other) const
+ {
+ return offset < other.offset;
+ }
+
+ /* Returns true if THIS is equal to OTHER. */
+ bool operator== (const range &other) const
+ {
+ return offset == other.offset && length == other.length;
+ }
+};
/* 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)
+ranges_overlap (LONGEST offset1, LONGEST len1,
+ LONGEST offset2, LONGEST len2)
{
ULONGEST h, l;
- l = max (offset1, offset2);
- h = min (offset1 + len1, offset2 + len2);
+ l = std::max (offset1, offset2);
+ h = std::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)
+ranges_contain (const std::vector<range> &ranges, LONGEST offset,
+ LONGEST length)
{
- range_s what;
- int i;
+ range what;
what.offset = offset;
what.length = length;
I=1
*/
- i = VEC_lower_bound (range_s, ranges, &what, range_lessthan);
- if (i > 0)
+ auto i = std::lower_bound (ranges.begin (), ranges.end (), what);
+
+ if (i > ranges.begin ())
{
- struct range *bef = VEC_index (range_s, ranges, i - 1);
+ const struct range &bef = *(i - 1);
- if (ranges_overlap (bef->offset, bef->length, offset, length))
+ if (ranges_overlap (bef.offset, bef.length, offset, length))
return 1;
}
- if (i < VEC_length (range_s, ranges))
+ if (i < ranges.end ())
{
- struct range *r = VEC_index (range_s, ranges, i);
+ const struct range &r = *i;
- if (ranges_overlap (r->offset, r->length, offset, length))
+ if (ranges_overlap (r.offset, r.length, offset, length))
return 1;
}
struct value
{
+ explicit value (struct type *type_)
+ : modifiable (1),
+ lazy (1),
+ initialized (1),
+ stack (0),
+ type (type_),
+ enclosing_type (type_)
+ {
+ }
+
+ ~value ()
+ {
+ if (VALUE_LVAL (this) == lval_computed)
+ {
+ const struct lval_funcs *funcs = location.computed.funcs;
+
+ if (funcs->free_closure)
+ funcs->free_closure (this);
+ }
+ else if (VALUE_LVAL (this) == lval_xcallable)
+ delete location.xm_worker;
+ }
+
+ DISABLE_COPY_AND_ASSIGN (value);
+
/* Type of value; either not an lval, or one of the various
different possible kinds of lval. */
- enum lval_type lval;
+ enum lval_type lval = not_lval;
/* Is it modifiable? Only relevant if lval != not_lval. */
unsigned int modifiable : 1;
used instead of read_memory to enable extra caching. */
unsigned int stack : 1;
- /* If the value has been released. */
- unsigned int released : 1;
-
- /* Register number if the value is from a register. */
- short regnum;
-
/* Location of value (if lval). */
union
{
- /* If lval == lval_memory, this is the address in the inferior.
- If lval == lval_register, this is the byte offset into the
- registers structure. */
+ /* If lval == lval_memory, this is the address in the inferior */
CORE_ADDR address;
+ /*If lval == lval_register, the value is from a register. */
+ struct
+ {
+ /* Register number. */
+ int regnum;
+ /* Frame ID of "next" frame to which a register value is relative.
+ If the register value is found relative to frame F, then the
+ frame id of F->next will be stored in next_frame_id. */
+ struct frame_id next_frame_id;
+ } reg;
+
/* Pointer to internal variable. */
struct internalvar *internalvar;
/* Closure for those functions to use. */
void *closure;
} computed;
- } location;
+ } location {};
/* Describes offset of a value within lval of a structure in target
- addressable memory units. If lval == lval_memory, this is an offset to
- the address. If lval == lval_register, this is a further offset from
- location.address within the registers structure. Note also the member
- embedded_offset below. */
- int offset;
+ addressable memory units. Note also the member embedded_offset
+ below. */
+ LONGEST offset = 0;
/* Only used for bitfields; number of bits contained in them. */
- int bitsize;
+ LONGEST bitsize = 0;
/* 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. */
- int bitpos;
+ little-endian targets, it is the position of the LSB. For
+ big-endian targets, it is the position of the MSB. */
+ LONGEST bitpos = 0;
/* 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
the caller of release_value now has a reference to this value.
The caller must arrange for a call to value_free later. */
- int reference_count;
+ int reference_count = 1;
/* Only used for bitfields; the containing value. This allows a
single read from the target when displaying multiple
bitfields. */
- struct value *parent;
-
- /* Frame register value is relative to. This will be described in
- the lval enum above as "lval_register". */
- struct frame_id frame_id;
+ value_ref_ptr parent;
/* Type of the value. */
struct type *type;
`type', and `embedded_offset' is zero, so everything works
normally. */
struct type *enclosing_type;
- int embedded_offset;
- int pointed_to_offset;
-
- /* Values are stored in a chain, so that they can be deleted easily
- over calls to the inferior. Values assigned to internal
- variables, put into the value history or exposed to Python are
- taken off this list. */
- struct value *next;
+ LONGEST embedded_offset = 0;
+ LONGEST pointed_to_offset = 0;
/* Actual contents of the value. Target byte-order. NULL or not
valid if lazy is nonzero. */
- gdb_byte *contents;
+ gdb::unique_xmalloc_ptr<gdb_byte> contents;
/* Unavailable ranges in CONTENTS. We mark unavailable ranges,
rather than available, since the common and default case is for a
The unavailable ranges are tracked in bits. Note that a contents
bit that has been optimized out doesn't really exist in the
program, so it can't be marked unavailable either. */
- VEC(range_s) *unavailable;
+ std::vector<range> unavailable;
/* Likewise, but for optimized out contents (a chunk of the value of
a variable that does not actually exist in the program). If LVAL
saved registers and optimized-out program variables values are
treated pretty much the same, except not-saved registers have a
different string representation and related error strings. */
- VEC(range_s) *optimized_out;
+ std::vector<range> optimized_out;
};
/* See value.h. */
}
int
-value_bits_available (const struct value *value, int offset, int length)
+value_bits_available (const struct value *value, LONGEST offset, LONGEST length)
{
gdb_assert (!value->lazy);
}
int
-value_bytes_available (const struct value *value, int offset, int length)
+value_bytes_available (const struct value *value,
+ LONGEST offset, LONGEST length)
{
return value_bits_available (value,
offset * TARGET_CHAR_BIT,
if (value->lazy)
value_fetch_lazy (value);
- if (VEC_empty (range_s, value->unavailable))
+ if (value->unavailable.empty ())
return 1;
return 0;
}
static int
value_entirely_covered_by_range_vector (struct value *value,
- VEC(range_s) **ranges)
+ const std::vector<range> &ranges)
{
/* We can only tell whether the whole value is optimized out /
unavailable when we try to read it. */
if (value->lazy)
value_fetch_lazy (value);
- if (VEC_length (range_s, *ranges) == 1)
+ if (ranges.size () == 1)
{
- struct range *t = VEC_index (range_s, *ranges, 0);
+ const struct range &t = ranges[0];
- if (t->offset == 0
- && t->length == (TARGET_CHAR_BIT
- * TYPE_LENGTH (value_enclosing_type (value))))
+ if (t.offset == 0
+ && t.length == (TARGET_CHAR_BIT
+ * TYPE_LENGTH (value_enclosing_type (value))))
return 1;
}
int
value_entirely_unavailable (struct value *value)
{
- return value_entirely_covered_by_range_vector (value, &value->unavailable);
+ return value_entirely_covered_by_range_vector (value, value->unavailable);
}
int
value_entirely_optimized_out (struct value *value)
{
- return value_entirely_covered_by_range_vector (value, &value->optimized_out);
+ return value_entirely_covered_by_range_vector (value, value->optimized_out);
}
/* Insert into the vector pointed to by VECTORP the bit range starting of
OFFSET bits, and extending for the next LENGTH bits. */
static void
-insert_into_bit_range_vector (VEC(range_s) **vectorp, int offset, int length)
+insert_into_bit_range_vector (std::vector<range> *vectorp,
+ LONGEST offset, LONGEST length)
{
- range_s newr;
- int i;
+ range newr;
/* Insert the range sorted. If there's overlap or the new range
would be contiguous with an existing range, merge. */
*/
- i = VEC_lower_bound (range_s, *vectorp, &newr, range_lessthan);
- if (i > 0)
+ auto i = std::lower_bound (vectorp->begin (), vectorp->end (), newr);
+ if (i > vectorp->begin ())
{
- struct range *bef = VEC_index (range_s, *vectorp, i - 1);
+ struct range &bef = *(i - 1);
- if (ranges_overlap (bef->offset, bef->length, offset, length))
+ 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);
+ ULONGEST l = std::min (bef.offset, offset);
+ ULONGEST h = std::max (bef.offset + bef.length, offset + length);
- bef->offset = l;
- bef->length = h - l;
+ bef.offset = l;
+ bef.length = h - l;
i--;
}
- else if (offset == bef->offset + bef->length)
+ else if (offset == bef.offset + bef.length)
{
/* #2 */
- bef->length += length;
+ bef.length += length;
i--;
}
else
{
/* #3 */
- VEC_safe_insert (range_s, *vectorp, i, &newr);
+ i = vectorp->insert (i, newr);
}
}
else
{
/* #4 */
- VEC_safe_insert (range_s, *vectorp, i, &newr);
+ i = vectorp->insert (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, *vectorp))
+ if (i != vectorp->end () && i + 1 < vectorp->end ())
{
- struct range *t;
- struct range *r;
int removed = 0;
- int next = i + 1;
+ auto next = i + 1;
/* Get the range we just touched. */
- t = VEC_index (range_s, *vectorp, i);
+ struct range &t = *i;
removed = 0;
i = next;
- for (; VEC_iterate (range_s, *vectorp, i, r); i++)
- if (r->offset <= t->offset + t->length)
- {
- ULONGEST l, h;
+ for (; i < vectorp->end (); i++)
+ {
+ struct range &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);
+ l = std::min (t.offset, r.offset);
+ h = std::max (t.offset + t.length, r.offset + r.length);
- t->offset = l;
- t->length = h - l;
+ 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;
- }
+ 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, *vectorp, next, removed);
+ vectorp->erase (next, next + removed);
}
}
void
-mark_value_bits_unavailable (struct value *value, int offset, int length)
+mark_value_bits_unavailable (struct value *value,
+ LONGEST offset, LONGEST length)
{
insert_into_bit_range_vector (&value->unavailable, offset, length);
}
void
-mark_value_bytes_unavailable (struct value *value, int offset, int length)
+mark_value_bytes_unavailable (struct value *value,
+ LONGEST offset, LONGEST length)
{
mark_value_bits_unavailable (value,
offset * TARGET_CHAR_BIT,
found, or -1 if none was found. */
static int
-find_first_range_overlap (VEC(range_s) *ranges, int pos,
- int offset, int length)
+find_first_range_overlap (const std::vector<range> *ranges, int pos,
+ LONGEST offset, LONGEST 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;
+ for (i = pos; i < ranges->size (); i++)
+ {
+ const range &r = (*ranges)[i];
+ if (ranges_overlap (r.offset, r.length, offset, length))
+ return i;
+ }
return -1;
}
struct ranges_and_idx
{
/* The ranges. */
- VEC(range_s) *ranges;
+ const std::vector<range> *ranges;
/* The range we've last found in RANGES. Given ranges are sorted,
we can start the next lookup here. */
static int
find_first_range_overlap_and_match (struct ranges_and_idx *rp1,
struct ranges_and_idx *rp2,
- int offset1, int offset2,
- int length, ULONGEST *l, ULONGEST *h)
+ LONGEST offset1, LONGEST offset2,
+ LONGEST length, ULONGEST *l, ULONGEST *h)
{
rp1->idx = find_first_range_overlap (rp1->ranges, rp1->idx,
offset1, length);
return 0;
else
{
- range_s *r1, *r2;
+ const range *r1, *r2;
ULONGEST l1, h1;
ULONGEST l2, h2;
- r1 = VEC_index (range_s, rp1->ranges, rp1->idx);
- r2 = VEC_index (range_s, rp2->ranges, rp2->idx);
+ r1 = &(*rp1->ranges)[rp1->idx];
+ r2 = &(*rp2->ranges)[rp2->idx];
/* 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);
+ l1 = std::max (offset1, r1->offset);
+ h1 = std::min (offset1 + length, r1->offset + r1->length);
- l2 = max (offset2, r2->offset);
- h2 = min (offset2 + length, offset2 + r2->length);
+ l2 = std::max (offset2, r2->offset);
+ h2 = std::min (offset2 + length, offset2 + r2->length);
/* Make them relative to the respective start offsets, so we can
compare them for equality. */
with LENGTH bits of VAL2's contents starting at OFFSET2 bits.
Return true if the available bits match. */
-static int
+static bool
value_contents_bits_eq (const struct value *val1, int offset1,
const struct value *val2, int offset2,
int length)
memset (&rp1, 0, sizeof (rp1));
memset (&rp2, 0, sizeof (rp2));
- rp1[0].ranges = val1->unavailable;
- rp2[0].ranges = val2->unavailable;
- rp1[1].ranges = val1->optimized_out;
- rp2[1].ranges = val2->optimized_out;
+ rp1[0].ranges = &val1->unavailable;
+ rp2[0].ranges = &val2->unavailable;
+ rp1[1].ranges = &val1->optimized_out;
+ rp2[1].ranges = &val2->optimized_out;
while (length > 0)
{
if (!find_first_range_overlap_and_match (&rp1[i], &rp2[i],
offset1, offset2, length,
&l_tmp, &h_tmp))
- return 0;
+ return false;
/* We're interested in the lowest/first range found. */
if (i == 0 || l_tmp < l)
}
/* Compare the available/valid contents. */
- if (memcmp_with_bit_offsets (val1->contents, offset1,
- val2->contents, offset2, l) != 0)
- return 0;
+ if (memcmp_with_bit_offsets (val1->contents.get (), offset1,
+ val2->contents.get (), offset2, l) != 0)
+ return false;
length -= h;
offset1 += h;
offset2 += h;
}
- return 1;
+ return true;
}
-int
-value_contents_eq (const struct value *val1, int offset1,
- const struct value *val2, int offset2,
- int length)
+bool
+value_contents_eq (const struct value *val1, LONGEST offset1,
+ const struct value *val2, LONGEST offset2,
+ LONGEST length)
{
return value_contents_bits_eq (val1, offset1 * TARGET_CHAR_BIT,
val2, offset2 * TARGET_CHAR_BIT,
length * TARGET_CHAR_BIT);
}
-/* Prototypes for local functions. */
-
-static void show_values (char *, int);
-
-static void show_convenience (char *, int);
+/* The value-history records all the values printed by print commands
+ during this session. */
-/* The value-history records all the values printed
- by print commands during this session. Each chunk
- records 60 consecutive values. The first chunk on
- the chain records the most recent values.
- The total number of values is in value_history_count. */
-
-#define VALUE_HISTORY_CHUNK 60
-
-struct value_history_chunk
- {
- struct value_history_chunk *next;
- struct value *values[VALUE_HISTORY_CHUNK];
- };
-
-/* Chain of chunks now in use. */
-
-static struct value_history_chunk *value_history_chain;
-
-static int value_history_count; /* Abs number of last entry stored. */
+static std::vector<value_ref_ptr> value_history;
\f
/* List of all value objects currently allocated
(except for those released by calls to release_value)
This is so they can be freed after each command. */
-static struct value *all_values;
+static std::vector<value_ref_ptr> all_values;
/* Allocate a lazy value for type TYPE. Its actual content is
"lazily" allocated too: the content field of the return value is
description correctly. */
check_typedef (type);
- val = XCNEW (struct value);
- val->contents = NULL;
- val->next = all_values;
- all_values = val;
- val->type = type;
- val->enclosing_type = type;
- VALUE_LVAL (val) = not_lval;
- val->location.address = 0;
- VALUE_FRAME_ID (val) = null_frame_id;
- val->offset = 0;
- val->bitpos = 0;
- val->bitsize = 0;
- VALUE_REGNUM (val) = -1;
- val->lazy = 1;
- val->embedded_offset = 0;
- val->pointed_to_offset = 0;
- val->modifiable = 1;
- val->initialized = 1; /* Default to initialized. */
+ val = new struct value (type);
/* Values start out on the all_values chain. */
- val->reference_count = 1;
+ all_values.emplace_back (val);
return val;
}
/* Implement the "set max-value-size" command. */
static void
-set_max_value_size (char *args, int from_tty,
+set_max_value_size (const char *args, int from_tty,
struct cmd_list_element *c)
{
gdb_assert (max_value_size == -1 || max_value_size >= 0);
if (!val->contents)
{
check_type_length_before_alloc (val->enclosing_type);
- val->contents
- = (gdb_byte *) xzalloc (TYPE_LENGTH (val->enclosing_type));
+ val->contents.reset
+ ((gdb_byte *) xzalloc (TYPE_LENGTH (val->enclosing_type)));
}
}
/* Accessor methods. */
-struct value *
-value_next (const struct value *value)
-{
- return value->next;
-}
-
struct type *
value_type (const struct value *value)
{
value->type = type;
}
-int
+LONGEST
value_offset (const struct value *value)
{
return value->offset;
}
void
-set_value_offset (struct value *value, int offset)
+set_value_offset (struct value *value, LONGEST offset)
{
value->offset = offset;
}
-int
+LONGEST
value_bitpos (const struct value *value)
{
return value->bitpos;
}
void
-set_value_bitpos (struct value *value, int bit)
+set_value_bitpos (struct value *value, LONGEST bit)
{
value->bitpos = bit;
}
-int
+LONGEST
value_bitsize (const struct value *value)
{
return value->bitsize;
}
void
-set_value_bitsize (struct value *value, int bit)
+set_value_bitsize (struct value *value, LONGEST bit)
{
value->bitsize = bit;
}
struct value *
value_parent (const struct value *value)
{
- return value->parent;
+ return value->parent.get ();
}
/* See value.h. */
void
set_value_parent (struct value *value, struct value *parent)
{
- struct value *old = value->parent;
-
- value->parent = parent;
- if (parent != NULL)
- value_incref (parent);
- value_free (old);
+ value->parent = value_ref_ptr::new_reference (parent);
}
gdb_byte *
int unit_size = gdbarch_addressable_memory_unit_size (arch);
allocate_value_contents (value);
- return value->contents + value->embedded_offset * unit_size;
+ return value->contents.get () + value->embedded_offset * unit_size;
}
gdb_byte *
value_contents_all_raw (struct value *value)
{
allocate_value_contents (value);
- return value->contents;
+ return value->contents.get ();
}
struct type *
{
/* If result's target type is TYPE_CODE_STRUCT, proceed to
fetch its rtti type. */
- if ((TYPE_CODE (result) == TYPE_CODE_PTR
- || TYPE_CODE (result) == TYPE_CODE_REF)
+ if ((TYPE_CODE (result) == TYPE_CODE_PTR || TYPE_IS_REFERENCE (result))
&& TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (result)))
== TYPE_CODE_STRUCT
&& !value_optimized_out (value))
static void
require_not_optimized_out (const struct value *value)
{
- if (!VEC_empty (range_s, value->optimized_out))
+ if (!value->optimized_out.empty ())
{
if (value->lval == lval_register)
error (_("register has not been saved in frame"));
static void
require_available (const struct value *value)
{
- if (!VEC_empty (range_s, value->unavailable))
+ if (!value->unavailable.empty ())
throw_error (NOT_AVAILABLE_ERROR, _("value is not available"));
}
{
if (value->lazy)
value_fetch_lazy (value);
- return value->contents;
+ return value->contents.get ();
}
const gdb_byte *
value_contents_for_printing_const (const struct value *value)
{
gdb_assert (!value->lazy);
- return value->contents;
+ return value->contents.get ();
}
const gdb_byte *
SRC_BIT_OFFSET+BIT_LENGTH) ranges into *DST_RANGE, adjusted. */
static void
-ranges_copy_adjusted (VEC (range_s) **dst_range, int dst_bit_offset,
- VEC (range_s) *src_range, int src_bit_offset,
+ranges_copy_adjusted (std::vector<range> *dst_range, int dst_bit_offset,
+ const std::vector<range> &src_range, int src_bit_offset,
int bit_length)
{
- range_s *r;
- int i;
-
- for (i = 0; VEC_iterate (range_s, src_range, i, r); i++)
+ for (const range &r : src_range)
{
ULONGEST h, l;
- l = max (r->offset, src_bit_offset);
- h = min (r->offset + r->length, src_bit_offset + bit_length);
+ l = std::max (r.offset, (LONGEST) src_bit_offset);
+ h = std::min (r.offset + r.length,
+ (LONGEST) src_bit_offset + bit_length);
if (l < h)
insert_into_bit_range_vector (dst_range,
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)
+value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
+ struct value *src, LONGEST src_offset, LONGEST length)
{
- int src_bit_offset, dst_bit_offset, bit_length;
+ LONGEST src_bit_offset, dst_bit_offset, bit_length;
struct gdbarch *arch = get_value_arch (src);
int unit_size = gdbarch_addressable_memory_unit_size (arch);
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)
+value_contents_copy (struct value *dst, LONGEST dst_offset,
+ struct value *src, LONGEST src_offset, LONGEST length)
{
if (src->lazy)
value_fetch_lazy (src);
{
/* We can only know if a value is optimized out once we have tried to
fetch it. */
- if (VEC_empty (range_s, value->optimized_out) && value->lazy)
+ if (value->optimized_out.empty () && value->lazy)
{
- TRY
+ try
{
value_fetch_lazy (value);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
/* Fall back to checking value->optimized_out. */
}
- END_CATCH
}
- return !VEC_empty (range_s, value->optimized_out);
+ return !value->optimized_out.empty ();
}
/* Mark contents of VALUE as optimized out, starting at OFFSET bytes, and
/* See value.h. */
void
-mark_value_bits_optimized_out (struct value *value, int offset, int length)
+mark_value_bits_optimized_out (struct value *value,
+ LONGEST offset, LONGEST length)
{
insert_into_bit_range_vector (&value->optimized_out, offset, length);
}
int
value_bits_synthetic_pointer (const struct value *value,
- int offset, int length)
+ LONGEST offset, LONGEST length)
{
if (value->lval != lval_computed
|| !value->location.computed.funcs->check_synthetic_pointer)
length);
}
-int
+LONGEST
value_embedded_offset (const struct value *value)
{
return value->embedded_offset;
}
void
-set_value_embedded_offset (struct value *value, int val)
+set_value_embedded_offset (struct value *value, LONGEST val)
{
value->embedded_offset = val;
}
-int
+LONGEST
value_pointed_to_offset (const struct value *value)
{
return value->pointed_to_offset;
}
void
-set_value_pointed_to_offset (struct value *value, int val)
+set_value_pointed_to_offset (struct value *value, LONGEST val)
{
value->pointed_to_offset = val;
}
CORE_ADDR
value_address (const struct value *value)
{
- if (value->lval == lval_internalvar
- || value->lval == lval_internalvar_component
- || value->lval == lval_xcallable)
+ if (value->lval != lval_memory)
return 0;
if (value->parent != NULL)
- return value_address (value->parent) + value->offset;
+ return value_address (value->parent.get ()) + value->offset;
if (NULL != TYPE_DATA_LOCATION (value_type (value)))
{
gdb_assert (PROP_CONST == TYPE_DATA_LOCATION_KIND (value_type (value)));
CORE_ADDR
value_raw_address (const struct value *value)
{
- if (value->lval == lval_internalvar
- || value->lval == lval_internalvar_component
- || value->lval == lval_xcallable)
+ if (value->lval != lval_memory)
return 0;
return value->location.address;
}
void
set_value_address (struct value *value, CORE_ADDR addr)
{
- gdb_assert (value->lval != lval_internalvar
- && value->lval != lval_internalvar_component
- && value->lval != lval_xcallable);
+ gdb_assert (value->lval == lval_memory);
value->location.address = addr;
}
}
struct frame_id *
-deprecated_value_frame_id_hack (struct value *value)
+deprecated_value_next_frame_id_hack (struct value *value)
{
- return &value->frame_id;
+ gdb_assert (value->lval == lval_register);
+ return &value->location.reg.next_frame_id;
}
-short *
+int *
deprecated_value_regnum_hack (struct value *value)
{
- return &value->regnum;
+ gdb_assert (value->lval == lval_register);
+ return &value->location.reg.regnum;
}
int
struct value *
value_mark (void)
{
- return all_values;
+ if (all_values.empty ())
+ return nullptr;
+ return all_values.back ().get ();
}
-/* Take a reference to VAL. VAL will not be deallocated until all
- references are released. */
+/* See value.h. */
void
value_incref (struct value *val)
chain. */
void
-value_free (struct value *val)
+value_decref (struct value *val)
{
- if (val)
+ if (val != nullptr)
{
gdb_assert (val->reference_count > 0);
val->reference_count--;
- if (val->reference_count > 0)
- return;
-
- /* If there's an associated parent value, drop our reference to
- it. */
- if (val->parent != NULL)
- value_free (val->parent);
-
- if (VALUE_LVAL (val) == lval_computed)
- {
- const struct lval_funcs *funcs = val->location.computed.funcs;
-
- if (funcs->free_closure)
- funcs->free_closure (val);
- }
- else if (VALUE_LVAL (val) == lval_xcallable)
- free_xmethod_worker (val->location.xm_worker);
-
- xfree (val->contents);
- VEC_free (range_s, val->unavailable);
+ if (val->reference_count == 0)
+ delete val;
}
- xfree (val);
}
/* Free all values allocated since MARK was obtained by value_mark
void
value_free_to_mark (const struct value *mark)
{
- struct value *val;
- struct value *next;
-
- for (val = all_values; val && val != mark; val = next)
- {
- next = val->next;
- val->released = 1;
- value_free (val);
- }
- all_values = val;
-}
-
-/* Free all the values that have been allocated (except for those released).
- Call after each command, successful or not.
- In practice this is called before each command, which is sufficient. */
-
-void
-free_all_values (void)
-{
- struct value *val;
- struct value *next;
-
- for (val = all_values; val; val = next)
- {
- next = val->next;
- val->released = 1;
- value_free (val);
- }
-
- all_values = 0;
-}
-
-/* Frees all the elements in a chain of values. */
-
-void
-free_value_chain (struct value *v)
-{
- struct value *next;
-
- for (; v; v = next)
- {
- next = value_next (v);
- value_free (v);
- }
+ auto iter = std::find (all_values.begin (), all_values.end (), mark);
+ if (iter == all_values.end ())
+ all_values.clear ();
+ else
+ all_values.erase (iter + 1, all_values.end ());
}
/* Remove VAL from the chain all_values
so it will not be freed automatically. */
-void
+value_ref_ptr
release_value (struct value *val)
{
- struct value *v;
-
- if (all_values == val)
- {
- all_values = val->next;
- val->next = NULL;
- val->released = 1;
- return;
- }
+ if (val == nullptr)
+ return value_ref_ptr ();
- for (v = all_values; v; v = v->next)
+ std::vector<value_ref_ptr>::reverse_iterator iter;
+ for (iter = all_values.rbegin (); iter != all_values.rend (); ++iter)
{
- if (v->next == val)
+ if (*iter == val)
{
- v->next = val->next;
- val->next = NULL;
- val->released = 1;
- break;
+ value_ref_ptr result = *iter;
+ all_values.erase (iter.base () - 1);
+ return result;
}
}
-}
-
-/* If the value is not already released, release it.
- If the value is already released, increment its reference count.
- That is, this function ensures that the value is released from the
- value chain and that the caller owns a reference to it. */
-void
-release_value_or_incref (struct value *val)
-{
- if (val->released)
- value_incref (val);
- else
- release_value (val);
+ /* We must always return an owned reference. Normally this happens
+ because we transfer the reference from the value chain, but in
+ this case the value was not on the chain. */
+ return value_ref_ptr::new_reference (val);
}
-/* Release all values up to mark */
-struct value *
+/* See value.h. */
+
+std::vector<value_ref_ptr>
value_release_to_mark (const struct value *mark)
{
- struct value *val;
- struct value *next;
+ std::vector<value_ref_ptr> result;
- for (val = next = all_values; next; next = next->next)
+ auto iter = std::find (all_values.begin (), all_values.end (), mark);
+ if (iter == all_values.end ())
+ std::swap (result, all_values);
+ else
{
- if (next->next == mark)
- {
- all_values = next->next;
- next->next = NULL;
- return val;
- }
- next->released = 1;
+ std::move (iter + 1, all_values.end (), std::back_inserter (result));
+ all_values.erase (iter + 1, all_values.end ());
}
- all_values = 0;
- return val;
+ std::reverse (result.begin (), result.end ());
+ return result;
}
/* Return a copy of the value ARG.
val->offset = arg->offset;
val->bitpos = arg->bitpos;
val->bitsize = arg->bitsize;
- VALUE_FRAME_ID (val) = VALUE_FRAME_ID (arg);
- VALUE_REGNUM (val) = VALUE_REGNUM (arg);
val->lazy = arg->lazy;
val->embedded_offset = value_embedded_offset (arg);
val->pointed_to_offset = arg->pointed_to_offset;
TYPE_LENGTH (value_enclosing_type (arg)));
}
- val->unavailable = VEC_copy (range_s, arg->unavailable);
- val->optimized_out = VEC_copy (range_s, arg->optimized_out);
- set_value_parent (val, arg->parent);
+ val->unavailable = arg->unavailable;
+ val->optimized_out = arg->optimized_out;
+ val->parent = arg->parent;
if (VALUE_LVAL (val) == lval_computed)
{
const struct lval_funcs *funcs = val->location.computed.funcs;
int
record_latest_value (struct value *val)
{
- int i;
-
/* We don't want this value to have anything to do with the inferior anymore.
In particular, "set $1 = 50" should not affect the variable from which
the value was taken, and fast watchpoints should be able to assume that
but the current contents of that location. c'est la vie... */
val->modifiable = 0;
- /* The value may have already been released, in which case we're adding a
- new reference for its entry in the history. That is why we call
- release_value_or_incref here instead of release_value. */
- release_value_or_incref (val);
-
- /* Here we treat value_history_count as origin-zero
- and applying to the value being stored now. */
-
- i = value_history_count % VALUE_HISTORY_CHUNK;
- if (i == 0)
- {
- struct value_history_chunk *newobj = XCNEW (struct value_history_chunk);
-
- newobj->next = value_history_chain;
- value_history_chain = newobj;
- }
+ value_history.push_back (release_value (val));
- value_history_chain->values[i] = val;
-
- /* Now we regard value_history_count as origin-one
- and applying to the value just stored. */
-
- return ++value_history_count;
+ return value_history.size ();
}
/* Return a copy of the value in the history with sequence number NUM. */
struct value *
access_value_history (int num)
{
- struct value_history_chunk *chunk;
- int i;
int absnum = num;
if (absnum <= 0)
- absnum += value_history_count;
+ absnum += value_history.size ();
if (absnum <= 0)
{
else
error (_("History does not go back to $$%d."), -num);
}
- if (absnum > value_history_count)
+ if (absnum > value_history.size ())
error (_("History has not yet reached $%d."), absnum);
absnum--;
- /* Now absnum is always absolute and origin zero. */
-
- chunk = value_history_chain;
- for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK
- - absnum / VALUE_HISTORY_CHUNK;
- i > 0; i--)
- chunk = chunk->next;
-
- return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]);
+ return value_copy (value_history[absnum].get ());
}
static void
-show_values (char *num_exp, int from_tty)
+show_values (const char *num_exp, int from_tty)
{
int i;
struct value *val;
else
{
/* "show values" means print the last 10 values. */
- num = value_history_count - 9;
+ num = value_history.size () - 9;
}
if (num <= 0)
num = 1;
- for (i = num; i < num + 10 && i <= value_history_count; i++)
+ for (i = num; i < num + 10 && i <= value_history.size (); i++)
{
struct value_print_options opts;
"show values +". If num_exp is null, this is unnecessary, since
"show values +" is not useful after "show values". */
if (from_tty && num_exp)
- {
- num_exp[0] = '+';
- num_exp[1] = '\0';
- }
+ set_repeat_arguments ("+");
}
\f
enum internalvar_kind
/* If the variable does not already exist create it and give it the
value given. If no value is given then the default is zero. */
static void
-init_if_undefined_command (char* args, int from_tty)
+init_if_undefined_command (const char* args, int from_tty)
{
struct internalvar* intvar;
/* Parse the expression - this is taken from set_command(). */
- struct expression *expr = parse_expression (args);
- register struct cleanup *old_chain =
- make_cleanup (free_current_contents, &expr);
+ expression_up expr = parse_expression (args);
/* Validate the expression.
Was the expression an assignment?
intvar = expr->elts[2].internalvar;
/* Only evaluate the expression if the lvalue is void.
- This may still fail if the expresssion is invalid. */
+ This may still fail if the expression is invalid. */
if (intvar->kind == INTERNALVAR_VOID)
- evaluate_expression (expr);
-
- do_cleanups (old_chain);
+ evaluate_expression (expr.get ());
}
return NULL;
}
-/* Complete NAME by comparing it to the names of internal variables.
- Returns a vector of newly allocated strings, or NULL if no matches
- were found. */
+/* Complete NAME by comparing it to the names of internal
+ variables. */
-VEC (char_ptr) *
-complete_internalvar (const char *name)
+void
+complete_internalvar (completion_tracker &tracker, const char *name)
{
- VEC (char_ptr) *result = NULL;
struct internalvar *var;
int len;
for (var = internalvars; var; var = var->next)
if (strncmp (var->name, name, len) == 0)
- {
- char *r = xstrdup (var->name);
-
- VEC_safe_push (char_ptr, result, r);
- }
-
- return result;
+ tracker.add_completion (make_unique_xstrdup (var->name));
}
/* Create an internal variable with name NAME and with a void value.
{
struct internalvar *var = XNEW (struct internalvar);
- var->name = concat (name, (char *)NULL);
+ var->name = xstrdup (name);
var->kind = INTERNALVAR_VOID;
var->next = internalvars;
internalvars = var;
on this value go back to affect the original internal variable.
Do not do this for INTERNALVAR_MAKE_VALUE variables, as those have
- no underlying modifyable state in the internal variable.
+ no underlying modifiable state in the internal variable.
Likewise, if the variable's value is a computed lvalue, we want
references to it to produce another computed lvalue, where
}
void
-set_internalvar_component (struct internalvar *var, int offset, int bitpos,
- int bitsize, struct value *newval)
+set_internalvar_component (struct internalvar *var,
+ LONGEST offset, LONGEST bitpos,
+ LONGEST bitsize, struct value *newval)
{
gdb_byte *addr;
struct gdbarch *arch;
default:
new_kind = INTERNALVAR_VALUE;
- new_data.value = value_copy (val);
- new_data.value->modifiable = 1;
+ struct value *copy = value_copy (val);
+ copy->modifiable = 1;
/* Force the value to be fetched from the target now, to avoid problems
later when this internalvar is referenced and the target is gone or
has changed. */
- if (value_lazy (new_data.value))
- value_fetch_lazy (new_data.value);
+ if (value_lazy (copy))
+ value_fetch_lazy (copy);
/* Release the value from the value chain to prevent it from being
deleted by free_all_values. From here on this function should not
call error () until new_data is installed into the var->u to avoid
leaking memory. */
- release_value (new_data.value);
+ new_data.value = release_value (copy).release ();
/* Internal variables which are created from values with a dynamic
location don't need the location property of the origin anymore.
switch (var->kind)
{
case INTERNALVAR_VALUE:
- value_free (var->u.value);
+ value_decref (var->u.value);
break;
case INTERNALVAR_STRING:
the implementation of the sub-command that is created when
registering an internal function. */
static void
-function_command (char *command, int from_tty)
+function_command (const char *command, int from_tty)
{
/* Do nothing. */
}
-/* Clean up if an internal function's command is destroyed. */
-static void
-function_destroyer (struct cmd_list_element *self, void *ignore)
+/* Helper function that does the work for add_internal_function. */
+
+static struct cmd_list_element *
+do_add_internal_function (const char *name, const char *doc,
+ internal_function_fn handler, void *cookie)
{
- xfree ((char *) self->name);
- xfree ((char *) self->doc);
+ struct internal_function *ifn;
+ struct internalvar *var = lookup_internalvar (name);
+
+ ifn = create_internal_function (name, handler, cookie);
+ set_internalvar_function (var, ifn);
+
+ return add_cmd (name, no_class, function_command, doc, &functionlist);
}
-/* Add a new internal function. NAME is the name of the function; DOC
- is a documentation string describing the function. HANDLER is
- called when the function is invoked. COOKIE is an arbitrary
- pointer which is passed to HANDLER and is intended for "user
- data". */
+/* See value.h. */
+
void
add_internal_function (const char *name, const char *doc,
internal_function_fn handler, void *cookie)
{
- struct cmd_list_element *cmd;
- struct internal_function *ifn;
- struct internalvar *var = lookup_internalvar (name);
+ do_add_internal_function (name, doc, handler, cookie);
+}
- ifn = create_internal_function (name, handler, cookie);
- set_internalvar_function (var, ifn);
+/* See value.h. */
- cmd = add_cmd (xstrdup (name), no_class, function_command, (char *) doc,
- &functionlist);
- cmd->destroyer = function_destroyer;
+void
+add_internal_function (gdb::unique_xmalloc_ptr<char> &&name,
+ gdb::unique_xmalloc_ptr<char> &&doc,
+ internal_function_fn handler, void *cookie)
+{
+ struct cmd_list_element *cmd
+ = do_add_internal_function (name.get (), doc.get (), handler, cookie);
+ doc.release ();
+ cmd->doc_allocated = 1;
+ name.release ();
+ cmd->name_allocated = 1;
}
/* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to
preserve_values (struct objfile *objfile)
{
htab_t copied_types;
- struct value_history_chunk *cur;
struct internalvar *var;
- int i;
/* Create the hash table. We allocate on the objfile's obstack, since
it is soon to be deleted. */
copied_types = create_copied_types_hash (objfile);
- for (cur = value_history_chain; cur; cur = cur->next)
- for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
- if (cur->values[i])
- preserve_one_value (cur->values[i], objfile, copied_types);
+ for (const value_ref_ptr &item : value_history)
+ preserve_one_value (item.get (), objfile, copied_types);
for (var = internalvars; var; var = var->next)
preserve_one_internalvar (var, objfile, copied_types);
}
static void
-show_convenience (char *ignore, int from_tty)
+show_convenience (const char *ignore, int from_tty)
{
struct gdbarch *gdbarch = get_current_arch ();
struct internalvar *var;
}
printf_filtered (("$%s = "), var->name);
- TRY
+ try
{
struct value *val;
val = value_of_internalvar (gdbarch, var);
value_print (val, gdb_stdout, &opts);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
- fprintf_filtered (gdb_stdout, _("<error: %s>"), ex.message);
+ fprintf_styled (gdb_stdout, metadata_style.style (),
+ _("<error: %s>"), ex.what ());
}
- END_CATCH
printf_filtered (("\n"));
}
}
}
\f
-/* Return the TYPE_CODE_XMETHOD value corresponding to WORKER. */
+
+/* See value.h. */
struct value *
-value_of_xmethod (struct xmethod_worker *worker)
+value_from_xmethod (xmethod_worker_up &&worker)
{
- if (worker->value == NULL)
- {
- struct value *v;
+ struct value *v;
- v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
- v->lval = lval_xcallable;
- v->location.xm_worker = worker;
- v->modifiable = 0;
- worker->value = v;
- }
+ v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
+ v->lval = lval_xcallable;
+ v->location.xm_worker = worker.release ();
+ v->modifiable = 0;
- return worker->value;
+ return v;
}
/* Return the type of the result of TYPE_CODE_XMETHOD value METHOD. */
struct type *
-result_type_of_xmethod (struct value *method, int argc, struct value **argv)
+result_type_of_xmethod (struct value *method, gdb::array_view<value *> argv)
{
gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
- && method->lval == lval_xcallable && argc > 0);
+ && method->lval == lval_xcallable && !argv.empty ());
- return get_xmethod_result_type (method->location.xm_worker,
- argv[0], argv + 1, argc - 1);
+ return method->location.xm_worker->get_result_type (argv[0], argv.slice (1));
}
/* Call the xmethod corresponding to the TYPE_CODE_XMETHOD value METHOD. */
struct value *
-call_xmethod (struct value *method, int argc, struct value **argv)
+call_xmethod (struct value *method, gdb::array_view<value *> argv)
{
gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
- && method->lval == lval_xcallable && argc > 0);
+ && method->lval == lval_xcallable && !argv.empty ());
- return invoke_xmethod (method->location.xm_worker,
- argv[0], argv + 1, argc - 1);
+ return method->location.xm_worker->invoke (argv[0], argv.slice (1));
}
\f
/* Extract a value as a C number (either long or double).
return unpack_long (value_type (val), value_contents (val));
}
-DOUBLEST
-value_as_double (struct value *val)
-{
- DOUBLEST foo;
- int inv;
-
- foo = unpack_double (value_type (val), value_contents (val), &inv);
- if (inv)
- error (_("Invalid floating value found in program."));
- return foo;
-}
-
/* 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. */
ABI-specific code is a more reasonable place to handle it. */
if (TYPE_CODE (value_type (val)) != TYPE_CODE_PTR
- && TYPE_CODE (value_type (val)) != TYPE_CODE_REF
+ && !TYPE_IS_REFERENCE (value_type (val))
&& gdbarch_integer_to_address_p (gdbarch))
return gdbarch_integer_to_address (gdbarch, value_type (val),
value_contents (val));
LONGEST
unpack_long (struct type *type, const gdb_byte *valaddr)
{
- enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+ enum bfd_endian byte_order = type_byte_order (type);
enum type_code code = TYPE_CODE (type);
int len = TYPE_LENGTH (type);
int nosign = TYPE_UNSIGNED (type);
case TYPE_CODE_CHAR:
case TYPE_CODE_RANGE:
case TYPE_CODE_MEMBERPTR:
- if (nosign)
- return extract_unsigned_integer (valaddr, len, byte_order);
- else
- return extract_signed_integer (valaddr, len, byte_order);
+ {
+ LONGEST result;
+ if (nosign)
+ result = extract_unsigned_integer (valaddr, len, byte_order);
+ else
+ result = extract_signed_integer (valaddr, len, byte_order);
+ if (code == TYPE_CODE_RANGE)
+ result += TYPE_RANGE_DATA (type)->bias;
+ return result;
+ }
case TYPE_CODE_FLT:
- return (LONGEST) extract_typed_floating (valaddr, type);
-
case TYPE_CODE_DECFLOAT:
- /* libdecnumber has a function to convert from decimal to integer, but
- it doesn't work when the decimal number has a fractional part. */
- return (LONGEST) decimal_to_doublest (valaddr, len, byte_order);
+ return target_float_to_longest (valaddr, type);
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
/* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
whether we want this to be true eventually. */
return extract_typed_address (valaddr, type);
default:
error (_("Value can't be converted to integer."));
}
- return 0; /* Placate lint. */
-}
-
-/* Return a double value from the specified type and address.
- INVP points to an int which is set to 0 for valid value,
- 1 for invalid value (bad float format). In either case,
- the returned double is OK to use. Argument is in target
- format, result is in host format. */
-
-DOUBLEST
-unpack_double (struct type *type, const gdb_byte *valaddr, int *invp)
-{
- enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
- enum type_code code;
- int len;
- int nosign;
-
- *invp = 0; /* Assume valid. */
- type = check_typedef (type);
- code = TYPE_CODE (type);
- len = TYPE_LENGTH (type);
- nosign = TYPE_UNSIGNED (type);
- if (code == TYPE_CODE_FLT)
- {
- /* NOTE: cagney/2002-02-19: There was a test here to see if the
- floating-point value was valid (using the macro
- INVALID_FLOAT). That test/macro have been removed.
-
- It turns out that only the VAX defined this macro and then
- only in a non-portable way. Fixing the portability problem
- wouldn't help since the VAX floating-point code is also badly
- bit-rotten. The target needs to add definitions for the
- methods gdbarch_float_format and gdbarch_double_format - these
- exactly describe the target floating-point format. The
- problem here is that the corresponding floatformat_vax_f and
- floatformat_vax_d values these methods should be set to are
- also not defined either. Oops!
-
- Hopefully someone will add both the missing floatformat
- definitions and the new cases for floatformat_is_valid (). */
-
- if (!floatformat_is_valid (floatformat_from_type (type), valaddr))
- {
- *invp = 1;
- return 0.0;
- }
-
- return extract_typed_floating (valaddr, type);
- }
- else if (code == TYPE_CODE_DECFLOAT)
- return decimal_to_doublest (valaddr, len, byte_order);
- else if (nosign)
- {
- /* Unsigned -- be sure we compensate for signed LONGEST. */
- return (ULONGEST) unpack_long (type, valaddr);
- }
- else
- {
- /* Signed -- we are OK with unpack_long. */
- return unpack_long (type, valaddr);
- }
}
/* Unpack raw data (copied from debugee, target byte order) at VALADDR
return unpack_long (type, valaddr);
}
+bool
+is_floating_value (struct value *val)
+{
+ struct type *type = check_typedef (value_type (val));
+
+ if (is_floating_type (type))
+ {
+ if (!target_float_is_valid (value_contents (val), type))
+ error (_("Invalid floating value found in program."));
+ return true;
+ }
+
+ return false;
+}
+
\f
/* Get the value of the FIELDNO'th field (which must be static) of
TYPE. */
reported as non-debuggable symbols. */
struct bound_minimal_symbol msym
= lookup_minimal_symbol (phys_name, NULL, NULL);
+ struct type *field_type = TYPE_FIELD_TYPE (type, fieldno);
if (!msym.minsym)
- return allocate_optimized_out_value (type);
+ retval = allocate_optimized_out_value (field_type);
else
- {
- retval = value_at_lazy (TYPE_FIELD_TYPE (type, fieldno),
- BMSYMBOL_VALUE_ADDRESS (msym));
- }
+ retval = value_at_lazy (field_type, BMSYMBOL_VALUE_ADDRESS (msym));
}
else
retval = value_of_variable (sym.symbol, sym.block);
{
check_type_length_before_alloc (new_encl_type);
val->contents
- = (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type));
+ .reset ((gdb_byte *) xrealloc (val->contents.release (),
+ TYPE_LENGTH (new_encl_type)));
}
val->enclosing_type = new_encl_type;
FIELDNO says which field. */
struct value *
-value_primitive_field (struct value *arg1, int offset,
+value_primitive_field (struct value *arg1, LONGEST offset,
int fieldno, struct type *arg_type)
{
struct value *v;
bit. Assume that the address, offset, and embedded offset
are sufficiently aligned. */
- int bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno);
- int container_bitsize = TYPE_LENGTH (type) * 8;
+ LONGEST bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno);
+ LONGEST container_bitsize = TYPE_LENGTH (type) * 8;
v = allocate_value_lazy (type);
v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno);
/* This field is actually a base subobject, so preserve the
entire object's contents for later references to virtual
bases, etc. */
- int boffset;
+ LONGEST boffset;
/* Lazy register values with offsets are not supported. */
if (VALUE_LVAL (arg1) == lval_register && value_lazy (arg1))
+ value_embedded_offset (arg1));
}
set_value_component_location (v, arg1);
- VALUE_REGNUM (v) = VALUE_REGNUM (arg1);
- VALUE_FRAME_ID (v) = VALUE_FRAME_ID (arg1);
return v;
}
struct value *
value_fn_field (struct value **arg1p, struct fn_field *f,
int j, struct type *type,
- int offset)
+ LONGEST offset)
{
struct value *v;
struct type *ftype = TYPE_FN_FIELD_TYPE (f, j);
}
v = allocate_value (ftype);
+ VALUE_LVAL (v) = lval_memory;
if (sym)
{
- set_value_address (v, BLOCK_START (SYMBOL_BLOCK_VALUE (sym)));
+ set_value_address (v, BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)));
}
else
{
set_value_address (v,
gdbarch_convert_from_func_ptr_addr
- (gdbarch, BMSYMBOL_VALUE_ADDRESS (msym), ¤t_target));
+ (gdbarch, BMSYMBOL_VALUE_ADDRESS (msym), current_top_target ()));
}
if (arg1p)
/* Unpack a bitfield of the specified FIELD_TYPE, from the object at
VALADDR, and store the result in *RESULT.
- The bitfield starts at BITPOS bits and contains BITSIZE bits.
+ The bitfield starts at BITPOS bits and contains BITSIZE bits; if
+ BITSIZE is zero, then the length is taken from FIELD_TYPE.
Extracting bits depends on endianness of the machine. Compute the
number of least significant bits to discard. For big endian machines,
static LONGEST
unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr,
- int bitpos, int bitsize)
+ LONGEST bitpos, LONGEST bitsize)
{
- enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (field_type));
+ enum bfd_endian byte_order = type_byte_order (field_type);
ULONGEST val;
ULONGEST valmask;
int lsbcount;
- int bytes_read;
- int read_offset;
+ LONGEST bytes_read;
+ LONGEST read_offset;
/* Read the minimum number of bytes required; there may not be
enough bytes to read an entire ULONGEST. */
if (bitsize)
bytes_read = ((bitpos % 8) + bitsize + 7) / 8;
else
- bytes_read = TYPE_LENGTH (field_type);
+ {
+ bytes_read = TYPE_LENGTH (field_type);
+ bitsize = 8 * bytes_read;
+ }
read_offset = bitpos / 8;
/* Extract bits. See comment above. */
- if (gdbarch_bits_big_endian (get_type_arch (field_type)))
+ if (byte_order == BFD_ENDIAN_BIG)
lsbcount = (bytes_read * 8 - bitpos % 8 - bitsize);
else
lsbcount = (bitpos % 8);
/* 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 ((bitsize > 0) && (bitsize < 8 * (int) sizeof (val)))
+ if (bitsize < 8 * (int) sizeof (val))
{
valmask = (((ULONGEST) 1) << bitsize) - 1;
val &= valmask;
int
unpack_value_field_as_long (struct type *type, const gdb_byte *valaddr,
- int embedded_offset, int fieldno,
+ LONGEST embedded_offset, int fieldno,
const struct value *val, LONGEST *result)
{
int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
void
unpack_value_bitfield (struct value *dest_val,
- int bitpos, int bitsize,
- const gdb_byte *valaddr, int embedded_offset,
+ LONGEST bitpos, LONGEST bitsize,
+ const gdb_byte *valaddr, LONGEST embedded_offset,
const struct value *val)
{
enum bfd_endian byte_order;
int src_bit_offset;
int dst_bit_offset;
- LONGEST num;
struct type *field_type = value_type (dest_val);
+ byte_order = type_byte_order (field_type);
+
/* First, unpack and sign extend the bitfield as if it was wholly
- available. Invalid/unavailable bits are read as zero, but that's
- OK, as they'll end up marked below. */
- byte_order = gdbarch_byte_order (get_type_arch (field_type));
- num = unpack_bits_as_long (field_type, valaddr + embedded_offset,
- bitpos, bitsize);
- store_signed_integer (value_contents_raw (dest_val),
- TYPE_LENGTH (field_type), byte_order, num);
+ valid. Optimized out/unavailable bits are read as zero, but
+ that's OK, as they'll end up marked below. If the VAL is
+ wholly-invalid we may have skipped allocating its contents,
+ though. See allocate_optimized_out_value. */
+ if (valaddr != NULL)
+ {
+ LONGEST num;
+
+ num = unpack_bits_as_long (field_type, valaddr + embedded_offset,
+ bitpos, bitsize);
+ store_signed_integer (value_contents_raw (dest_val),
+ TYPE_LENGTH (field_type), byte_order, num);
+ }
/* Now copy the optimized out / unavailability ranges to the right
bits. */
struct value *
value_field_bitfield (struct type *type, int fieldno,
const gdb_byte *valaddr,
- int embedded_offset, const struct value *val)
+ LONGEST embedded_offset, const struct value *val)
{
int bitpos = TYPE_FIELD_BITPOS (type, fieldno);
int bitsize = TYPE_FIELD_BITSIZE (type, fieldno);
void
modify_field (struct type *type, gdb_byte *addr,
- LONGEST fieldval, int bitpos, int bitsize)
+ LONGEST fieldval, LONGEST bitpos, LONGEST bitsize)
{
- enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+ enum bfd_endian byte_order = type_byte_order (type);
ULONGEST oword;
ULONGEST mask = (ULONGEST) -1 >> (8 * sizeof (ULONGEST) - bitsize);
- int bytesize;
+ LONGEST bytesize;
/* Normalize BITPOS. */
addr += bitpos / 8;
{
/* FIXME: would like to include fieldval in the message, but
we don't have a sprintf_longest. */
- warning (_("Value does not fit in %d bits."), bitsize);
+ warning (_("Value does not fit in %s bits."), plongest (bitsize));
/* Truncate it, otherwise adjoining fields may be corrupted. */
fieldval &= mask;
oword = extract_unsigned_integer (addr, bytesize, byte_order);
/* Shifting for bit field depends on endianness of the target machine. */
- if (gdbarch_bits_big_endian (get_type_arch (type)))
+ if (byte_order == BFD_ENDIAN_BIG)
bitpos = bytesize * 8 - bitpos - bitsize;
oword &= ~(mask << bitpos);
void
pack_long (gdb_byte *buf, struct type *type, LONGEST num)
{
- enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
- int len;
+ enum bfd_endian byte_order = type_byte_order (type);
+ LONGEST len;
type = check_typedef (type);
len = TYPE_LENGTH (type);
switch (TYPE_CODE (type))
{
+ case TYPE_CODE_RANGE:
+ num -= TYPE_RANGE_DATA (type)->bias;
+ /* Fall through. */
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
case TYPE_CODE_ENUM:
case TYPE_CODE_FLAGS:
case TYPE_CODE_BOOL:
- case TYPE_CODE_RANGE:
case TYPE_CODE_MEMBERPTR:
store_signed_integer (buf, len, byte_order, num);
break;
case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
case TYPE_CODE_PTR:
store_typed_address (buf, type, (CORE_ADDR) num);
break;
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_DECFLOAT:
+ target_float_from_longest (buf, type, num);
+ break;
+
default:
error (_("Unexpected type (%d) encountered for integer constant."),
TYPE_CODE (type));
static void
pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
{
- int len;
+ LONGEST len;
enum bfd_endian byte_order;
type = check_typedef (type);
len = TYPE_LENGTH (type);
- byte_order = gdbarch_byte_order (get_type_arch (type));
+ byte_order = type_byte_order (type);
switch (TYPE_CODE (type))
{
break;
case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
case TYPE_CODE_PTR:
store_typed_address (buf, type, (CORE_ADDR) num);
break;
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_DECFLOAT:
+ target_float_from_ulongest (buf, type, num);
+ break;
+
default:
error (_("Unexpected type (%d) encountered "
"for unsigned integer constant."),
return val;
}
+/* Create and return a value object of TYPE containing the value D. The
+ TYPE must be of TYPE_CODE_FLT, and must be large enough to hold D once
+ it is converted to target format. */
+
+struct value *
+value_from_host_double (struct type *type, double d)
+{
+ struct value *value = allocate_value (type);
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT);
+ target_float_from_host_double (value_contents_raw (value),
+ value_type (value), d);
+ return value;
+}
/* Create a value of type TYPE whose contents come from VALADDR, if it
is non-null, and whose memory address (in the inferior) is
v = allocate_value_lazy (type);
else
v = value_from_contents (type, valaddr);
- set_value_address (v, address);
VALUE_LVAL (v) = lval_memory;
+ set_value_address (v, address);
return v;
}
if (TYPE_DATA_LOCATION (resolved_type_no_typedef) != NULL
&& TYPE_DATA_LOCATION_KIND (resolved_type_no_typedef) == PROP_CONST)
address = TYPE_DATA_LOCATION_ADDR (resolved_type_no_typedef);
- set_value_address (v, address);
VALUE_LVAL (v) = lval_memory;
+ set_value_address (v, address);
return v;
}
return result;
}
-struct value *
-value_from_double (struct type *type, DOUBLEST num)
-{
- struct value *val = allocate_value (type);
- struct type *base_type = check_typedef (type);
- enum type_code code = TYPE_CODE (base_type);
-
- if (code == TYPE_CODE_FLT)
- {
- store_typed_floating (value_contents_raw (val), base_type, num);
- }
- else
- error (_("Unexpected type encountered for floating constant."));
-
- return val;
-}
-
-struct value *
-value_from_decfloat (struct type *type, const gdb_byte *dec)
-{
- struct value *val = allocate_value (type);
-
- memcpy (value_contents_raw (val), dec, TYPE_LENGTH (type));
- 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. */
return access_value_history (index);
}
+/* Get the component value (offset by OFFSET bytes) of a struct or
+ union WHOLE. Component's type is TYPE. */
+
+struct value *
+value_from_component (struct value *whole, struct type *type, LONGEST offset)
+{
+ struct value *v;
+
+ if (VALUE_LVAL (whole) == lval_memory && value_lazy (whole))
+ v = allocate_value_lazy (type);
+ else
+ {
+ v = allocate_value (type);
+ value_contents_copy (v, value_embedded_offset (v),
+ whole, value_embedded_offset (whole) + offset,
+ type_length_units (type));
+ }
+ v->offset = value_offset (whole) + offset + value_embedded_offset (whole);
+ set_value_component_location (v, whole);
+
+ return v;
+}
+
struct value *
coerce_ref_if_computed (const struct value *arg)
{
const struct lval_funcs *funcs;
- if (TYPE_CODE (check_typedef (value_type (arg))) != TYPE_CODE_REF)
+ if (!TYPE_IS_REFERENCE (check_typedef (value_type (arg))))
return NULL;
if (value_lval_const (arg) != lval_computed)
if (retval)
return retval;
- if (TYPE_CODE (value_type_arg_tmp) != TYPE_CODE_REF)
+ if (!TYPE_IS_REFERENCE (value_type_arg_tmp))
return arg;
enc_type = check_typedef (value_enclosing_type (arg));
return val->initialized;
}
+/* Helper for value_fetch_lazy when the value is a bitfield. */
+
+static void
+value_fetch_lazy_bitfield (struct value *val)
+{
+ gdb_assert (value_bitsize (val) != 0);
+
+ /* To read a lazy bitfield, read the entire enclosing value. This
+ prevents reading the same block of (possibly volatile) memory once
+ per bitfield. It would be even better to read only the containing
+ word, but we have no way to record that just specific bits of a
+ value have been fetched. */
+ struct value *parent = value_parent (val);
+
+ if (value_lazy (parent))
+ value_fetch_lazy (parent);
+
+ unpack_value_bitfield (val, value_bitpos (val), value_bitsize (val),
+ value_contents_for_printing (parent),
+ value_offset (val), parent);
+}
+
+/* Helper for value_fetch_lazy when the value is in memory. */
+
+static void
+value_fetch_lazy_memory (struct value *val)
+{
+ gdb_assert (VALUE_LVAL (val) == lval_memory);
+
+ CORE_ADDR addr = value_address (val);
+ struct type *type = check_typedef (value_enclosing_type (val));
+
+ if (TYPE_LENGTH (type))
+ read_value_memory (val, 0, value_stack (val),
+ addr, value_contents_all_raw (val),
+ type_length_units (type));
+}
+
+/* Helper for value_fetch_lazy when the value is in a register. */
+
+static void
+value_fetch_lazy_register (struct value *val)
+{
+ struct frame_info *next_frame;
+ int regnum;
+ struct type *type = check_typedef (value_type (val));
+ struct value *new_val = val, *mark = value_mark ();
+
+ /* Offsets are not supported here; lazy register values must
+ refer to the entire register. */
+ gdb_assert (value_offset (val) == 0);
+
+ while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
+ {
+ struct frame_id next_frame_id = VALUE_NEXT_FRAME_ID (new_val);
+
+ next_frame = frame_find_by_id (next_frame_id);
+ regnum = VALUE_REGNUM (new_val);
+
+ gdb_assert (next_frame != NULL);
+
+ /* Convertible register routines are used for multi-register
+ values and for interpretation in different types
+ (e.g. float or int from a double register). Lazy
+ register values should have the register's natural type,
+ so they do not apply. */
+ gdb_assert (!gdbarch_convert_register_p (get_frame_arch (next_frame),
+ regnum, type));
+
+ /* FRAME was obtained, above, via VALUE_NEXT_FRAME_ID.
+ Since a "->next" operation was performed when setting
+ this field, we do not need to perform a "next" operation
+ again when unwinding the register. That's why
+ frame_unwind_register_value() is called here instead of
+ get_frame_register_value(). */
+ new_val = frame_unwind_register_value (next_frame, regnum);
+
+ /* If we get another lazy lval_register value, it means the
+ register is found by reading it from NEXT_FRAME's next frame.
+ frame_unwind_register_value should never return a value with
+ the frame id pointing to NEXT_FRAME. If it does, it means we
+ either have two consecutive frames with the same frame id
+ in the frame chain, or some code is trying to unwind
+ behind get_prev_frame's back (e.g., a frame unwind
+ sniffer trying to unwind), bypassing its validations. In
+ any case, it should always be an internal error to end up
+ in this situation. */
+ if (VALUE_LVAL (new_val) == lval_register
+ && value_lazy (new_val)
+ && frame_id_eq (VALUE_NEXT_FRAME_ID (new_val), next_frame_id))
+ internal_error (__FILE__, __LINE__,
+ _("infinite loop while fetching a register"));
+ }
+
+ /* If it's still lazy (for instance, a saved register on the
+ stack), fetch it. */
+ if (value_lazy (new_val))
+ value_fetch_lazy (new_val);
+
+ /* Copy the contents and the unavailability/optimized-out
+ meta-data from NEW_VAL to VAL. */
+ set_value_lazy (val, 0);
+ value_contents_copy (val, value_embedded_offset (val),
+ new_val, value_embedded_offset (new_val),
+ type_length_units (type));
+
+ if (frame_debug)
+ {
+ struct gdbarch *gdbarch;
+ struct frame_info *frame;
+ /* VALUE_FRAME_ID is used here, instead of VALUE_NEXT_FRAME_ID,
+ so that the frame level will be shown correctly. */
+ frame = frame_find_by_id (VALUE_FRAME_ID (val));
+ regnum = VALUE_REGNUM (val);
+ gdbarch = get_frame_arch (frame);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "{ value_fetch_lazy "
+ "(frame=%d,regnum=%d(%s),...) ",
+ frame_relative_level (frame), regnum,
+ user_reg_map_regnum_to_name (gdbarch, regnum));
+
+ fprintf_unfiltered (gdb_stdlog, "->");
+ if (value_optimized_out (new_val))
+ {
+ fprintf_unfiltered (gdb_stdlog, " ");
+ val_print_optimized_out (new_val, gdb_stdlog);
+ }
+ else
+ {
+ int i;
+ const gdb_byte *buf = value_contents (new_val);
+
+ if (VALUE_LVAL (new_val) == lval_register)
+ fprintf_unfiltered (gdb_stdlog, " register=%d",
+ VALUE_REGNUM (new_val));
+ else if (VALUE_LVAL (new_val) == lval_memory)
+ fprintf_unfiltered (gdb_stdlog, " address=%s",
+ paddress (gdbarch,
+ value_address (new_val)));
+ else
+ fprintf_unfiltered (gdb_stdlog, " computed");
+
+ fprintf_unfiltered (gdb_stdlog, " bytes=");
+ fprintf_unfiltered (gdb_stdlog, "[");
+ for (i = 0; i < register_size (gdbarch, regnum); i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "]");
+ }
+
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+
+ /* Dispose of the intermediate values. This prevents
+ watchpoints from trying to watch the saved frame pointer. */
+ value_free_to_mark (mark);
+}
+
/* Load the actual content of a lazy value. Fetch the data from the
user's process and clear the lazy flag to indicate that the data in
the buffer is valid.
/* A value is either lazy, or fully fetched. The
availability/validity is only established as we try to fetch a
value. */
- gdb_assert (VEC_empty (range_s, val->optimized_out));
- gdb_assert (VEC_empty (range_s, val->unavailable));
+ gdb_assert (val->optimized_out.empty ());
+ gdb_assert (val->unavailable.empty ());
if (value_bitsize (val))
- {
- /* To read a lazy bitfield, read the entire enclosing value. This
- prevents reading the same block of (possibly volatile) memory once
- per bitfield. It would be even better to read only the containing
- word, but we have no way to record that just specific bits of a
- value have been fetched. */
- struct type *type = check_typedef (value_type (val));
- struct value *parent = value_parent (val);
-
- if (value_lazy (parent))
- value_fetch_lazy (parent);
-
- unpack_value_bitfield (val,
- value_bitpos (val), value_bitsize (val),
- value_contents_for_printing (parent),
- value_offset (val), parent);
- }
+ value_fetch_lazy_bitfield (val);
else if (VALUE_LVAL (val) == lval_memory)
- {
- CORE_ADDR addr = value_address (val);
- struct type *type = check_typedef (value_enclosing_type (val));
-
- if (TYPE_LENGTH (type))
- read_value_memory (val, 0, value_stack (val),
- addr, value_contents_all_raw (val),
- type_length_units (type));
- }
+ value_fetch_lazy_memory (val);
else if (VALUE_LVAL (val) == lval_register)
- {
- struct frame_info *frame;
- int regnum;
- struct type *type = check_typedef (value_type (val));
- struct value *new_val = val, *mark = value_mark ();
-
- /* Offsets are not supported here; lazy register values must
- refer to the entire register. */
- gdb_assert (value_offset (val) == 0);
-
- while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
- {
- struct frame_id frame_id = VALUE_FRAME_ID (new_val);
-
- frame = frame_find_by_id (frame_id);
- regnum = VALUE_REGNUM (new_val);
-
- gdb_assert (frame != NULL);
-
- /* Convertible register routines are used for multi-register
- values and for interpretation in different types
- (e.g. float or int from a double register). Lazy
- register values should have the register's natural type,
- so they do not apply. */
- gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame),
- regnum, type));
-
- new_val = get_frame_register_value (frame, regnum);
-
- /* If we get another lazy lval_register value, it means the
- register is found by reading it from the next frame.
- get_frame_register_value should never return a value with
- the frame id pointing to FRAME. If it does, it means we
- either have two consecutive frames with the same frame id
- in the frame chain, or some code is trying to unwind
- behind get_prev_frame's back (e.g., a frame unwind
- sniffer trying to unwind), bypassing its validations. In
- any case, it should always be an internal error to end up
- in this situation. */
- if (VALUE_LVAL (new_val) == lval_register
- && value_lazy (new_val)
- && frame_id_eq (VALUE_FRAME_ID (new_val), frame_id))
- internal_error (__FILE__, __LINE__,
- _("infinite loop while fetching a register"));
- }
-
- /* If it's still lazy (for instance, a saved register on the
- stack), fetch it. */
- if (value_lazy (new_val))
- value_fetch_lazy (new_val);
-
- /* Copy the contents and the unavailability/optimized-out
- meta-data from NEW_VAL to VAL. */
- set_value_lazy (val, 0);
- value_contents_copy (val, value_embedded_offset (val),
- new_val, value_embedded_offset (new_val),
- type_length_units (type));
-
- if (frame_debug)
- {
- struct gdbarch *gdbarch;
- frame = frame_find_by_id (VALUE_FRAME_ID (val));
- regnum = VALUE_REGNUM (val);
- gdbarch = get_frame_arch (frame);
-
- fprintf_unfiltered (gdb_stdlog,
- "{ value_fetch_lazy "
- "(frame=%d,regnum=%d(%s),...) ",
- frame_relative_level (frame), regnum,
- user_reg_map_regnum_to_name (gdbarch, regnum));
-
- fprintf_unfiltered (gdb_stdlog, "->");
- if (value_optimized_out (new_val))
- {
- fprintf_unfiltered (gdb_stdlog, " ");
- val_print_optimized_out (new_val, gdb_stdlog);
- }
- else
- {
- int i;
- const gdb_byte *buf = value_contents (new_val);
-
- if (VALUE_LVAL (new_val) == lval_register)
- fprintf_unfiltered (gdb_stdlog, " register=%d",
- VALUE_REGNUM (new_val));
- else if (VALUE_LVAL (new_val) == lval_memory)
- fprintf_unfiltered (gdb_stdlog, " address=%s",
- paddress (gdbarch,
- value_address (new_val)));
- else
- fprintf_unfiltered (gdb_stdlog, " computed");
-
- fprintf_unfiltered (gdb_stdlog, " bytes=");
- fprintf_unfiltered (gdb_stdlog, "[");
- for (i = 0; i < register_size (gdbarch, regnum); i++)
- fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
- fprintf_unfiltered (gdb_stdlog, "]");
- }
-
- fprintf_unfiltered (gdb_stdlog, " }\n");
- }
-
- /* Dispose of the intermediate values. This prevents
- watchpoints from trying to watch the saved frame pointer. */
- value_free_to_mark (mark);
- }
+ value_fetch_lazy_register (val);
else if (VALUE_LVAL (val) == lval_computed
&& value_computed_funcs (val)->read != NULL)
value_computed_funcs (val)->read (val);
return value_from_longest (builtin_type (gdbarch)->builtin_int, ret);
}
+/* Implementation of the convenience function $_creal. Extracts the
+ real part from a complex number. */
+
+static struct value *
+creal_internal_fn (struct gdbarch *gdbarch,
+ const struct language_defn *language,
+ void *cookie, int argc, struct value **argv)
+{
+ if (argc != 1)
+ error (_("You must provide one argument for $_creal."));
+
+ value *cval = argv[0];
+ type *ctype = check_typedef (value_type (cval));
+ if (TYPE_CODE (ctype) != TYPE_CODE_COMPLEX)
+ error (_("expected a complex number"));
+ return value_from_component (cval, TYPE_TARGET_TYPE (ctype), 0);
+}
+
+/* Implementation of the convenience function $_cimag. Extracts the
+ imaginary part from a complex number. */
+
+static struct value *
+cimag_internal_fn (struct gdbarch *gdbarch,
+ const struct language_defn *language,
+ void *cookie, int argc,
+ struct value **argv)
+{
+ if (argc != 1)
+ error (_("You must provide one argument for $_cimag."));
+
+ value *cval = argv[0];
+ type *ctype = check_typedef (value_type (cval));
+ if (TYPE_CODE (ctype) != TYPE_CODE_COMPLEX)
+ error (_("expected a complex number"));
+ return value_from_component (cval, TYPE_TARGET_TYPE (ctype),
+ TYPE_LENGTH (TYPE_TARGET_TYPE (ctype)));
+}
+
+#if GDB_SELF_TEST
+namespace selftests
+{
+
+/* Test the ranges_contain function. */
+
+static void
+test_ranges_contain ()
+{
+ std::vector<range> ranges;
+ range r;
+
+ /* [10, 14] */
+ r.offset = 10;
+ r.length = 5;
+ ranges.push_back (r);
+
+ /* [20, 24] */
+ r.offset = 20;
+ r.length = 5;
+ ranges.push_back (r);
+
+ /* [2, 6] */
+ SELF_CHECK (!ranges_contain (ranges, 2, 5));
+ /* [9, 13] */
+ SELF_CHECK (ranges_contain (ranges, 9, 5));
+ /* [10, 11] */
+ SELF_CHECK (ranges_contain (ranges, 10, 2));
+ /* [10, 14] */
+ SELF_CHECK (ranges_contain (ranges, 10, 5));
+ /* [13, 18] */
+ SELF_CHECK (ranges_contain (ranges, 13, 6));
+ /* [14, 18] */
+ SELF_CHECK (ranges_contain (ranges, 14, 5));
+ /* [15, 18] */
+ SELF_CHECK (!ranges_contain (ranges, 15, 4));
+ /* [16, 19] */
+ SELF_CHECK (!ranges_contain (ranges, 16, 4));
+ /* [16, 21] */
+ SELF_CHECK (ranges_contain (ranges, 16, 6));
+ /* [21, 21] */
+ SELF_CHECK (ranges_contain (ranges, 21, 1));
+ /* [21, 25] */
+ SELF_CHECK (ranges_contain (ranges, 21, 5));
+ /* [26, 28] */
+ SELF_CHECK (!ranges_contain (ranges, 26, 3));
+}
+
+/* Check that RANGES contains the same ranges as EXPECTED. */
+
+static bool
+check_ranges_vector (gdb::array_view<const range> ranges,
+ gdb::array_view<const range> expected)
+{
+ return ranges == expected;
+}
+
+/* Test the insert_into_bit_range_vector function. */
+
+static void
+test_insert_into_bit_range_vector ()
+{
+ std::vector<range> ranges;
+
+ /* [10, 14] */
+ {
+ insert_into_bit_range_vector (&ranges, 10, 5);
+ static const range expected[] = {
+ {10, 5}
+ };
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [10, 14] */
+ {
+ insert_into_bit_range_vector (&ranges, 11, 4);
+ static const range expected = {10, 5};
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [10, 14] [20, 24] */
+ {
+ insert_into_bit_range_vector (&ranges, 20, 5);
+ static const range expected[] = {
+ {10, 5},
+ {20, 5},
+ };
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [10, 14] [17, 24] */
+ {
+ insert_into_bit_range_vector (&ranges, 17, 5);
+ static const range expected[] = {
+ {10, 5},
+ {17, 8},
+ };
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [2, 8] [10, 14] [17, 24] */
+ {
+ insert_into_bit_range_vector (&ranges, 2, 7);
+ static const range expected[] = {
+ {2, 7},
+ {10, 5},
+ {17, 8},
+ };
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [2, 14] [17, 24] */
+ {
+ insert_into_bit_range_vector (&ranges, 9, 1);
+ static const range expected[] = {
+ {2, 13},
+ {17, 8},
+ };
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [2, 14] [17, 24] */
+ {
+ insert_into_bit_range_vector (&ranges, 9, 1);
+ static const range expected[] = {
+ {2, 13},
+ {17, 8},
+ };
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+
+ /* [2, 33] */
+ {
+ insert_into_bit_range_vector (&ranges, 4, 30);
+ static const range expected = {2, 32};
+ SELF_CHECK (check_ranges_vector (ranges, expected));
+ }
+}
+
+} /* namespace selftests */
+#endif /* GDB_SELF_TEST */
+
void
_initialize_values (void)
{
Return 1 if the expression is void, zero otherwise."),
isvoid_internal_fn, NULL);
+ add_internal_function ("_creal", _("\
+Extract the real part of a complex number.\n\
+Usage: $_creal (expression)\n\
+Return the real part of a complex number, the type depends on the\n\
+type of a complex number."),
+ creal_internal_fn, NULL);
+
+ add_internal_function ("_cimag", _("\
+Extract the imaginary part of a complex number.\n\
+Usage: $_cimag (expression)\n\
+Return the imaginary part of a complex number, the type depends on the\n\
+type of a complex number."),
+ cimag_internal_fn, NULL);
+
add_setshow_zuinteger_unlimited_cmd ("max-value-size",
class_support, &max_value_size, _("\
Set maximum sized value gdb will load from the inferior."), _("\
set_max_value_size,
show_max_value_size,
&setlist, &showlist);
+#if GDB_SELF_TEST
+ selftests::register_test ("ranges_contain", selftests::test_ranges_contain);
+ selftests::register_test ("insert_into_bit_range_vector",
+ selftests::test_insert_into_bit_range_vector);
+#endif
+}
+
+/* See value.h. */
+
+void
+finalize_values ()
+{
+ all_values.clear ();
}