/* Low level packing and unpacking of values for GDB, the GNU Debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "user-regs.h"
#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
{
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
type (type_),
enclosing_type (type_)
{
- location.address = 0;
}
~value ()
}
else if (VALUE_LVAL (this) == lval_xcallable)
delete location.xm_worker;
-
- xfree (contents);
}
DISABLE_COPY_AND_ASSIGN (value);
/* 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. Note also the member embedded_offset
/* Actual contents of the value. Target byte-order. NULL or not
valid if lazy is nonzero. */
- gdb_byte *contents = nullptr;
+ 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
}
/* Compare the available/valid contents. */
- if (memcmp_with_bit_offsets (val1->contents, offset1,
- val2->contents, offset2, l) != 0)
+ if (memcmp_with_bit_offsets (val1->contents.get (), offset1,
+ val2->contents.get (), offset2, l) != 0)
return false;
length -= h;
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)));
}
}
void
set_value_parent (struct value *value, struct value *parent)
{
- value->parent = value_ref_ptr (value_incref (parent));
+ 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 (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 *
fetch it. */
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 !value->optimized_out.empty ();
return all_values.back ().get ();
}
-/* Take a reference to VAL. VAL will not be deallocated until all
- references are released. */
+/* See value.h. */
-struct value *
+void
value_incref (struct value *val)
{
val->reference_count++;
- return val;
}
/* Release a reference to VAL, which was acquired with value_incref.
value_ref_ptr
release_value (struct value *val)
{
- struct value *v;
-
if (val == nullptr)
return value_ref_ptr ();
/* 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 (value_incref (val));
+ return value_ref_ptr::new_reference (val);
}
/* See value.h. */
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
struct value *
access_value_history (int num)
{
- int i;
int absnum = num;
if (absnum <= 0)
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.get ());
}
for (var = internalvars; var; var = var->next)
if (strncmp (var->name, name, len) == 0)
- {
- gdb::unique_xmalloc_ptr<char> copy (xstrdup (var->name));
-
- tracker.add_completion (std::move (copy));
- }
+ 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
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).release ();
+ 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.
{
htab_t copied_types;
struct internalvar *var;
- int i;
/* Create the hash table. We allocate on the objfile's obstack, since
it is soon to be deleted. */
}
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"));
}
/* 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 method->location.xm_worker->get_result_type
- (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 method->location.xm_worker->invoke (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).
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:
case TYPE_CODE_DECFLOAT:
default:
error (_("Value can't be converted to integer."));
}
- return 0; /* Placate lint. */
}
/* Unpack raw data (copied from debugee, target byte order) at VALADDR
{
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;
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)
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;
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
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.
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 *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);
- }
+ 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 $_cimag. 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 ();
}