type: add c99 variable length array support
The dwarf standard allow certain attributes to be expressed as dwarf expressions rather than constants. For instance upper-/lowerbound attributes. In case of a c99 variable length array the upperbound is a dynamic attribute. With this change c99 vla behave the same as with static arrays. 1| void foo (size_t n) { 2| int ary[n]; 3| memset(ary, 0, sizeof(ary)); 4| } (gdb) print ary $1 = {0 <repeats 42 times>} * dwarf2loc.c (dwarf2_locexpr_baton_eval): New function. (dwarf2_evaluate_property): New function. * dwarf2loc.h (dwarf2_evaluate_property): New function prototype. * dwarf2read.c (attr_to_dynamic_prop): New function. (read_subrange_type): Use attr_to_dynamic_prop to read high bound attribute. * gdbtypes.c: Include dwarf2loc.h. (is_dynamic_type): New function. (resolve_dynamic_type): New function. (resolve_dynamic_bounds): New function. (get_type_length): New function. (check_typedef): Use get_type_length to compute type length. * gdbtypes.h (TYPE_HIGH_BOUND_KIND): New macro. (TYPE_LOW_BOUND_KIND): New macro. (is_dynamic_type): New function prototype. * value.c (value_from_contents_and_address): Call resolve_dynamic_type to resolve dynamic properties of the type. Update comment. * valops.c (get_value_at, value_at, value_at_lazy): Update comment.
This commit is contained in:
parent
729efb1317
commit
37c1ab67a3
8 changed files with 437 additions and 90 deletions
|
@ -1,3 +1,24 @@
|
||||||
|
2014-04-11 Sanimir Agovic <sanimir.agovic@intel.com>
|
||||||
|
|
||||||
|
* dwarf2loc.c (dwarf2_locexpr_baton_eval): New function.
|
||||||
|
(dwarf2_evaluate_property): New function.
|
||||||
|
* dwarf2loc.h (dwarf2_evaluate_property): New function prototype.
|
||||||
|
* dwarf2read.c (attr_to_dynamic_prop): New function.
|
||||||
|
(read_subrange_type): Use attr_to_dynamic_prop to read high bound
|
||||||
|
attribute.
|
||||||
|
* gdbtypes.c: Include dwarf2loc.h.
|
||||||
|
(is_dynamic_type): New function.
|
||||||
|
(resolve_dynamic_type): New function.
|
||||||
|
(resolve_dynamic_bounds): New function.
|
||||||
|
(get_type_length): New function.
|
||||||
|
(check_typedef): Use get_type_length to compute type length.
|
||||||
|
* gdbtypes.h (TYPE_HIGH_BOUND_KIND): New macro.
|
||||||
|
(TYPE_LOW_BOUND_KIND): New macro.
|
||||||
|
(is_dynamic_type): New function prototype.
|
||||||
|
* value.c (value_from_contents_and_address): Call resolve_dynamic_type
|
||||||
|
to resolve dynamic properties of the type. Update comment.
|
||||||
|
* valops.c (get_value_at, value_at, value_at_lazy): Update comment.
|
||||||
|
|
||||||
2014-04-11 Sanimir Agovic <sanimir.agovic@intel.com>
|
2014-04-11 Sanimir Agovic <sanimir.agovic@intel.com>
|
||||||
|
|
||||||
* dwarf2read.c (read_subrange_type): Use struct bound_prop for
|
* dwarf2read.c (read_subrange_type): Use struct bound_prop for
|
||||||
|
|
119
gdb/dwarf2loc.c
119
gdb/dwarf2loc.c
|
@ -2432,6 +2432,125 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame,
|
||||||
return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu, 0);
|
return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Evaluates a dwarf expression and stores the result in VAL, expecting
|
||||||
|
that the dwarf expression only produces a single CORE_ADDR. ADDR is a
|
||||||
|
context (location of a variable) and might be needed to evaluate the
|
||||||
|
location expression.
|
||||||
|
Returns 1 on success, 0 otherwise. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
|
||||||
|
CORE_ADDR addr, CORE_ADDR *valp)
|
||||||
|
{
|
||||||
|
struct dwarf_expr_context *ctx;
|
||||||
|
struct dwarf_expr_baton baton;
|
||||||
|
struct objfile *objfile;
|
||||||
|
struct cleanup *cleanup;
|
||||||
|
|
||||||
|
if (dlbaton == NULL || dlbaton->size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ctx = new_dwarf_expr_context ();
|
||||||
|
cleanup = make_cleanup_free_dwarf_expr_context (ctx);
|
||||||
|
|
||||||
|
baton.frame = get_selected_frame (NULL);
|
||||||
|
baton.per_cu = dlbaton->per_cu;
|
||||||
|
|
||||||
|
objfile = dwarf2_per_cu_objfile (dlbaton->per_cu);
|
||||||
|
|
||||||
|
ctx->gdbarch = get_objfile_arch (objfile);
|
||||||
|
ctx->addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
|
||||||
|
ctx->ref_addr_size = dwarf2_per_cu_ref_addr_size (dlbaton->per_cu);
|
||||||
|
ctx->offset = dwarf2_per_cu_text_offset (dlbaton->per_cu);
|
||||||
|
ctx->funcs = &dwarf_expr_ctx_funcs;
|
||||||
|
ctx->baton = &baton;
|
||||||
|
|
||||||
|
dwarf_expr_eval (ctx, dlbaton->data, dlbaton->size);
|
||||||
|
|
||||||
|
switch (ctx->location)
|
||||||
|
{
|
||||||
|
case DWARF_VALUE_REGISTER:
|
||||||
|
case DWARF_VALUE_MEMORY:
|
||||||
|
case DWARF_VALUE_STACK:
|
||||||
|
*valp = dwarf_expr_fetch_address (ctx, 0);
|
||||||
|
if (ctx->location == DWARF_VALUE_REGISTER)
|
||||||
|
*valp = dwarf_expr_read_addr_from_reg (&baton, *valp);
|
||||||
|
do_cleanups (cleanup);
|
||||||
|
return 1;
|
||||||
|
case DWARF_VALUE_LITERAL:
|
||||||
|
*valp = extract_signed_integer (ctx->data, ctx->len,
|
||||||
|
gdbarch_byte_order (ctx->gdbarch));
|
||||||
|
do_cleanups (cleanup);
|
||||||
|
return 1;
|
||||||
|
/* Unsupported dwarf values. */
|
||||||
|
case DWARF_VALUE_OPTIMIZED_OUT:
|
||||||
|
case DWARF_VALUE_IMPLICIT_POINTER:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_cleanups (cleanup);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See dwarf2loc.h. */
|
||||||
|
|
||||||
|
int
|
||||||
|
dwarf2_evaluate_property (const struct dynamic_prop *prop, CORE_ADDR address,
|
||||||
|
CORE_ADDR *value)
|
||||||
|
{
|
||||||
|
if (prop == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (prop->kind)
|
||||||
|
{
|
||||||
|
case PROP_LOCEXPR:
|
||||||
|
{
|
||||||
|
const struct dwarf2_property_baton *baton = prop->data.baton;
|
||||||
|
|
||||||
|
if (dwarf2_locexpr_baton_eval (&baton->locexpr, address, value))
|
||||||
|
{
|
||||||
|
if (baton->referenced_type)
|
||||||
|
{
|
||||||
|
struct value *val = value_at (baton->referenced_type, *value);
|
||||||
|
|
||||||
|
*value = value_as_address (val);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_LOCLIST:
|
||||||
|
{
|
||||||
|
struct dwarf2_property_baton *baton = prop->data.baton;
|
||||||
|
struct frame_info *frame = get_selected_frame (NULL);
|
||||||
|
CORE_ADDR pc = get_frame_address_in_block (frame);
|
||||||
|
const gdb_byte *data;
|
||||||
|
struct value *val;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
|
||||||
|
if (data != NULL)
|
||||||
|
{
|
||||||
|
val = dwarf2_evaluate_loc_desc (baton->referenced_type, frame, data,
|
||||||
|
size, baton->loclist.per_cu);
|
||||||
|
if (!value_optimized_out (val))
|
||||||
|
{
|
||||||
|
*value = value_as_address (val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_CONST:
|
||||||
|
*value = prop->data.const_val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
|
/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,14 @@ struct value *dwarf2_evaluate_loc_desc (struct type *type,
|
||||||
size_t size,
|
size_t size,
|
||||||
struct dwarf2_per_cu_data *per_cu);
|
struct dwarf2_per_cu_data *per_cu);
|
||||||
|
|
||||||
|
/* Converts a dynamic property into a static one. ADDR is the address of
|
||||||
|
the object currently being evaluated and might be nedded.
|
||||||
|
Returns 1 if PROP could be converted and the static value is passed back
|
||||||
|
into VALUE, otherwise returns 0. */
|
||||||
|
|
||||||
|
int dwarf2_evaluate_property (const struct dynamic_prop *prop,
|
||||||
|
CORE_ADDR addr, CORE_ADDR *value);
|
||||||
|
|
||||||
CORE_ADDR dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu,
|
CORE_ADDR dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu,
|
||||||
unsigned int addr_index);
|
unsigned int addr_index);
|
||||||
|
|
||||||
|
@ -135,6 +143,26 @@ struct dwarf2_loclist_baton
|
||||||
unsigned char from_dwo;
|
unsigned char from_dwo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A dynamic property is either expressed as a single location expression
|
||||||
|
or a location list. If the property is an indirection, pointing to
|
||||||
|
another die, keep track of the targeted type in REFERENCED_TYPE. */
|
||||||
|
|
||||||
|
struct dwarf2_property_baton
|
||||||
|
{
|
||||||
|
/* If the property is an indirection, we need to evaluate the location
|
||||||
|
LOCEXPR or LOCLIST in the context of the type REFERENCED_TYPE.
|
||||||
|
If NULL, the location is the actual value of the property. */
|
||||||
|
struct type *referenced_type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
/* Location expression. */
|
||||||
|
struct dwarf2_locexpr_baton locexpr;
|
||||||
|
|
||||||
|
/* Location list to be evaluated in the context of REFERENCED_TYPE. */
|
||||||
|
struct dwarf2_loclist_baton loclist;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
|
extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
|
||||||
extern const struct symbol_computed_ops dwarf2_loclist_funcs;
|
extern const struct symbol_computed_ops dwarf2_loclist_funcs;
|
||||||
|
|
||||||
|
|
106
gdb/dwarf2read.c
106
gdb/dwarf2read.c
|
@ -14405,6 +14405,84 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
|
||||||
return set_die_type (die, type, cu);
|
return set_die_type (die, type, cu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse dwarf attribute if it's a block, reference or constant and put the
|
||||||
|
resulting value of the attribute into struct bound_prop.
|
||||||
|
Returns 1 if ATTR could be resolved into PROP, 0 otherwise. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
|
||||||
|
struct dwarf2_cu *cu, struct dynamic_prop *prop)
|
||||||
|
{
|
||||||
|
struct dwarf2_property_baton *baton;
|
||||||
|
struct obstack *obstack = &cu->objfile->objfile_obstack;
|
||||||
|
|
||||||
|
if (attr == NULL || prop == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (attr_form_is_block (attr))
|
||||||
|
{
|
||||||
|
baton = obstack_alloc (obstack, sizeof (*baton));
|
||||||
|
baton->referenced_type = NULL;
|
||||||
|
baton->locexpr.per_cu = cu->per_cu;
|
||||||
|
baton->locexpr.size = DW_BLOCK (attr)->size;
|
||||||
|
baton->locexpr.data = DW_BLOCK (attr)->data;
|
||||||
|
prop->data.baton = baton;
|
||||||
|
prop->kind = PROP_LOCEXPR;
|
||||||
|
gdb_assert (prop->data.baton != NULL);
|
||||||
|
}
|
||||||
|
else if (attr_form_is_ref (attr))
|
||||||
|
{
|
||||||
|
struct dwarf2_cu *target_cu = cu;
|
||||||
|
struct die_info *target_die;
|
||||||
|
struct attribute *target_attr;
|
||||||
|
|
||||||
|
target_die = follow_die_ref (die, attr, &target_cu);
|
||||||
|
target_attr = dwarf2_attr (target_die, DW_AT_location, target_cu);
|
||||||
|
if (target_attr == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (attr_form_is_section_offset (target_attr))
|
||||||
|
{
|
||||||
|
baton = obstack_alloc (obstack, sizeof (*baton));
|
||||||
|
baton->referenced_type = die_type (target_die, target_cu);
|
||||||
|
fill_in_loclist_baton (cu, &baton->loclist, target_attr);
|
||||||
|
prop->data.baton = baton;
|
||||||
|
prop->kind = PROP_LOCLIST;
|
||||||
|
gdb_assert (prop->data.baton != NULL);
|
||||||
|
}
|
||||||
|
else if (attr_form_is_block (target_attr))
|
||||||
|
{
|
||||||
|
baton = obstack_alloc (obstack, sizeof (*baton));
|
||||||
|
baton->referenced_type = die_type (target_die, target_cu);
|
||||||
|
baton->locexpr.per_cu = cu->per_cu;
|
||||||
|
baton->locexpr.size = DW_BLOCK (target_attr)->size;
|
||||||
|
baton->locexpr.data = DW_BLOCK (target_attr)->data;
|
||||||
|
prop->data.baton = baton;
|
||||||
|
prop->kind = PROP_LOCEXPR;
|
||||||
|
gdb_assert (prop->data.baton != NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
|
||||||
|
"dynamic property");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (attr_form_is_constant (attr))
|
||||||
|
{
|
||||||
|
prop->data.const_val = dwarf2_get_attr_constant_value (attr, 0);
|
||||||
|
prop->kind = PROP_CONST;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwarf2_invalid_attrib_class_complaint (dwarf_form_name (attr->form),
|
||||||
|
dwarf2_name (die, cu));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the given DW_AT_subrange DIE. */
|
/* Read the given DW_AT_subrange DIE. */
|
||||||
|
|
||||||
static struct type *
|
static struct type *
|
||||||
|
@ -14478,27 +14556,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
|
||||||
die->offset.sect_off, objfile_name (cu->objfile));
|
die->offset.sect_off, objfile_name (cu->objfile));
|
||||||
|
|
||||||
attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
|
attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
|
||||||
if (attr)
|
if (!attr_to_dynamic_prop (attr, die, cu, &high))
|
||||||
{
|
|
||||||
if (attr_form_is_block (attr) || attr_form_is_ref (attr))
|
|
||||||
{
|
|
||||||
/* GCC encodes arrays with unspecified or dynamic length
|
|
||||||
with a DW_FORM_block1 attribute or a reference attribute.
|
|
||||||
FIXME: GDB does not yet know how to handle dynamic
|
|
||||||
arrays properly, treat them as arrays with unspecified
|
|
||||||
length for now.
|
|
||||||
|
|
||||||
FIXME: jimb/2003-09-22: GDB does not really know
|
|
||||||
how to handle arrays of unspecified length
|
|
||||||
either; we just represent them as zero-length
|
|
||||||
arrays. Choose an appropriate upper bound given
|
|
||||||
the lower bound we've computed above. */
|
|
||||||
high.data.const_val = low.data.const_val - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
high.data.const_val = dwarf2_get_attr_constant_value (attr, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
attr = dwarf2_attr (die, DW_AT_count, cu);
|
attr = dwarf2_attr (die, DW_AT_count, cu);
|
||||||
if (attr)
|
if (attr)
|
||||||
|
@ -14569,12 +14627,6 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
|
||||||
|
|
||||||
range_type = create_range_type (NULL, orig_base_type, &low, &high);
|
range_type = create_range_type (NULL, orig_base_type, &low, &high);
|
||||||
|
|
||||||
/* Mark arrays with dynamic length at least as an array of unspecified
|
|
||||||
length. GDB could check the boundary but before it gets implemented at
|
|
||||||
least allow accessing the array elements. */
|
|
||||||
if (attr && attr_form_is_block (attr))
|
|
||||||
TYPE_HIGH_BOUND_KIND (range_type) = PROP_UNDEFINED;
|
|
||||||
|
|
||||||
/* Ada expects an empty array on no boundary attributes. */
|
/* Ada expects an empty array on no boundary attributes. */
|
||||||
if (attr == NULL && cu->language != language_ada)
|
if (attr == NULL && cu->language != language_ada)
|
||||||
TYPE_HIGH_BOUND_KIND (range_type) = PROP_UNDEFINED;
|
TYPE_HIGH_BOUND_KIND (range_type) = PROP_UNDEFINED;
|
||||||
|
|
183
gdb/gdbtypes.c
183
gdb/gdbtypes.c
|
@ -853,6 +853,17 @@ create_static_range_type (struct type *result_type, struct type *index_type,
|
||||||
return result_type;
|
return result_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Predicate tests whether BOUNDS are static. Returns 1 if all bounds values
|
||||||
|
are static, otherwise returns 0. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
has_static_range (const struct range_bounds *bounds)
|
||||||
|
{
|
||||||
|
return (bounds->low.kind == PROP_CONST
|
||||||
|
&& bounds->high.kind == PROP_CONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set *LOWP and *HIGHP to the lower and upper bounds of discrete type
|
/* Set *LOWP and *HIGHP to the lower and upper bounds of discrete type
|
||||||
TYPE. Return 1 if type is a range type, 0 if it is discrete (and
|
TYPE. Return 1 if type is a range type, 0 if it is discrete (and
|
||||||
bounds will fit in LONGEST), or -1 otherwise. */
|
bounds will fit in LONGEST), or -1 otherwise. */
|
||||||
|
@ -986,13 +997,15 @@ create_array_type_with_stride (struct type *result_type,
|
||||||
struct type *range_type,
|
struct type *range_type,
|
||||||
unsigned int bit_stride)
|
unsigned int bit_stride)
|
||||||
{
|
{
|
||||||
LONGEST low_bound, high_bound;
|
|
||||||
|
|
||||||
if (result_type == NULL)
|
if (result_type == NULL)
|
||||||
result_type = alloc_type_copy (range_type);
|
result_type = alloc_type_copy (range_type);
|
||||||
|
|
||||||
TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
|
TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
|
||||||
TYPE_TARGET_TYPE (result_type) = element_type;
|
TYPE_TARGET_TYPE (result_type) = element_type;
|
||||||
|
if (has_static_range (TYPE_RANGE_DATA (range_type)))
|
||||||
|
{
|
||||||
|
LONGEST low_bound, high_bound;
|
||||||
|
|
||||||
if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
|
if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
|
||||||
low_bound = high_bound = 0;
|
low_bound = high_bound = 0;
|
||||||
CHECK_TYPEDEF (element_type);
|
CHECK_TYPEDEF (element_type);
|
||||||
|
@ -1007,6 +1020,18 @@ create_array_type_with_stride (struct type *result_type,
|
||||||
else
|
else
|
||||||
TYPE_LENGTH (result_type) =
|
TYPE_LENGTH (result_type) =
|
||||||
TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
|
TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This type is dynamic and its length needs to be computed
|
||||||
|
on demand. In the meantime, avoid leaving the TYPE_LENGTH
|
||||||
|
undefined by setting it to zero. Although we are not expected
|
||||||
|
to trust TYPE_LENGTH in this case, setting the size to zero
|
||||||
|
allows us to avoid allocating objects of random sizes in case
|
||||||
|
we accidently do. */
|
||||||
|
TYPE_LENGTH (result_type) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
TYPE_NFIELDS (result_type) = 1;
|
TYPE_NFIELDS (result_type) = 1;
|
||||||
TYPE_FIELDS (result_type) =
|
TYPE_FIELDS (result_type) =
|
||||||
(struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
|
(struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
|
||||||
|
@ -1585,6 +1610,121 @@ stub_noname_complaint (void)
|
||||||
complaint (&symfile_complaints, _("stub type has NULL name"));
|
complaint (&symfile_complaints, _("stub type has NULL name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See gdbtypes.h. */
|
||||||
|
|
||||||
|
int
|
||||||
|
is_dynamic_type (struct type *type)
|
||||||
|
{
|
||||||
|
type = check_typedef (type);
|
||||||
|
|
||||||
|
if (TYPE_CODE (type) == TYPE_CODE_REF)
|
||||||
|
type = check_typedef (TYPE_TARGET_TYPE (type));
|
||||||
|
|
||||||
|
switch (TYPE_CODE (type))
|
||||||
|
{
|
||||||
|
case TYPE_CODE_ARRAY:
|
||||||
|
{
|
||||||
|
const struct type *range_type;
|
||||||
|
|
||||||
|
gdb_assert (TYPE_NFIELDS (type) == 1);
|
||||||
|
range_type = TYPE_INDEX_TYPE (type);
|
||||||
|
if (!has_static_range (TYPE_RANGE_DATA (range_type)))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return is_dynamic_type (TYPE_TARGET_TYPE (type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolves dynamic bound values of an array type TYPE to static ones.
|
||||||
|
ADDRESS might be needed to resolve the subrange bounds, it is the location
|
||||||
|
of the associated array. */
|
||||||
|
|
||||||
|
static struct type *
|
||||||
|
resolve_dynamic_bounds (struct type *type, CORE_ADDR addr)
|
||||||
|
{
|
||||||
|
CORE_ADDR value;
|
||||||
|
struct type *elt_type;
|
||||||
|
struct type *range_type;
|
||||||
|
struct type *ary_dim;
|
||||||
|
const struct dynamic_prop *prop;
|
||||||
|
const struct dwarf2_locexpr_baton *baton;
|
||||||
|
struct dynamic_prop low_bound, high_bound;
|
||||||
|
|
||||||
|
if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
|
||||||
|
{
|
||||||
|
struct type *copy = copy_type (type);
|
||||||
|
|
||||||
|
TYPE_TARGET_TYPE (copy)
|
||||||
|
= resolve_dynamic_bounds (TYPE_TARGET_TYPE (type), addr);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_assert (TYPE_CODE (type) == TYPE_CODE_ARRAY);
|
||||||
|
|
||||||
|
elt_type = type;
|
||||||
|
range_type = check_typedef (TYPE_INDEX_TYPE (elt_type));
|
||||||
|
|
||||||
|
prop = &TYPE_RANGE_DATA (range_type)->low;
|
||||||
|
if (dwarf2_evaluate_property (prop, addr, &value))
|
||||||
|
{
|
||||||
|
low_bound.kind = PROP_CONST;
|
||||||
|
low_bound.data.const_val = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
low_bound.kind = PROP_UNDEFINED;
|
||||||
|
low_bound.data.const_val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop = &TYPE_RANGE_DATA (range_type)->high;
|
||||||
|
if (dwarf2_evaluate_property (prop, addr, &value))
|
||||||
|
{
|
||||||
|
high_bound.kind = PROP_CONST;
|
||||||
|
high_bound.data.const_val = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
high_bound.kind = PROP_UNDEFINED;
|
||||||
|
high_bound.data.const_val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ary_dim = check_typedef (TYPE_TARGET_TYPE (elt_type));
|
||||||
|
|
||||||
|
if (ary_dim != NULL && TYPE_CODE (ary_dim) == TYPE_CODE_ARRAY)
|
||||||
|
elt_type = resolve_dynamic_bounds (TYPE_TARGET_TYPE (type), addr);
|
||||||
|
else
|
||||||
|
elt_type = TYPE_TARGET_TYPE (type);
|
||||||
|
|
||||||
|
range_type = create_range_type (NULL,
|
||||||
|
TYPE_TARGET_TYPE (range_type),
|
||||||
|
&low_bound, &high_bound);
|
||||||
|
return create_array_type (copy_type (type),
|
||||||
|
elt_type,
|
||||||
|
range_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See gdbtypes.h */
|
||||||
|
|
||||||
|
struct type *
|
||||||
|
resolve_dynamic_type (struct type *type, CORE_ADDR addr)
|
||||||
|
{
|
||||||
|
struct type *real_type = check_typedef (type);
|
||||||
|
struct type *resolved_type;
|
||||||
|
|
||||||
|
if (!is_dynamic_type (real_type))
|
||||||
|
return type;
|
||||||
|
|
||||||
|
resolved_type = resolve_dynamic_bounds (type, addr);
|
||||||
|
|
||||||
|
return resolved_type;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the real type of TYPE. This function returns the real type,
|
/* Find the real type of TYPE. This function returns the real type,
|
||||||
after removing all layers of typedefs, and completing opaque or stub
|
after removing all layers of typedefs, and completing opaque or stub
|
||||||
types. Completion changes the TYPE argument, but stripping of
|
types. Completion changes the TYPE argument, but stripping of
|
||||||
|
@ -1760,45 +1900,6 @@ check_typedef (struct type *type)
|
||||||
{
|
{
|
||||||
/* Nothing we can do. */
|
/* Nothing we can do. */
|
||||||
}
|
}
|
||||||
else if (TYPE_CODE (type) == TYPE_CODE_ARRAY
|
|
||||||
&& TYPE_NFIELDS (type) == 1
|
|
||||||
&& (TYPE_CODE (range_type = TYPE_INDEX_TYPE (type))
|
|
||||||
== TYPE_CODE_RANGE))
|
|
||||||
{
|
|
||||||
/* Now recompute the length of the array type, based on its
|
|
||||||
number of elements and the target type's length.
|
|
||||||
Watch out for Ada null Ada arrays where the high bound
|
|
||||||
is smaller than the low bound. */
|
|
||||||
const LONGEST low_bound = TYPE_LOW_BOUND (range_type);
|
|
||||||
const LONGEST high_bound = TYPE_HIGH_BOUND (range_type);
|
|
||||||
ULONGEST len;
|
|
||||||
|
|
||||||
if (high_bound < low_bound)
|
|
||||||
len = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* For now, we conservatively take the array length to be 0
|
|
||||||
if its length exceeds UINT_MAX. The code below assumes
|
|
||||||
that for x < 0, (ULONGEST) x == -x + ULONGEST_MAX + 1,
|
|
||||||
which is technically not guaranteed by C, but is usually true
|
|
||||||
(because it would be true if x were unsigned with its
|
|
||||||
high-order bit on). It uses the fact that
|
|
||||||
high_bound-low_bound is always representable in
|
|
||||||
ULONGEST and that if high_bound-low_bound+1 overflows,
|
|
||||||
it overflows to 0. We must change these tests if we
|
|
||||||
decide to increase the representation of TYPE_LENGTH
|
|
||||||
from unsigned int to ULONGEST. */
|
|
||||||
ULONGEST ulow = low_bound, uhigh = high_bound;
|
|
||||||
ULONGEST tlen = TYPE_LENGTH (target_type);
|
|
||||||
|
|
||||||
len = tlen * (uhigh - ulow + 1);
|
|
||||||
if (tlen == 0 || (len / tlen - 1 + ulow) != uhigh
|
|
||||||
|| len > UINT_MAX)
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
TYPE_LENGTH (type) = len;
|
|
||||||
TYPE_TARGET_STUB (type) = 0;
|
|
||||||
}
|
|
||||||
else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
|
else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
|
||||||
{
|
{
|
||||||
TYPE_LENGTH (type) = TYPE_LENGTH (target_type);
|
TYPE_LENGTH (type) = TYPE_LENGTH (target_type);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
/* Internal type definitions for GDB.
|
/* Internal type definitions for GDB.
|
||||||
|
|
||||||
Copyright (C) 1992-2014 Free Software Foundation, Inc.
|
Copyright (C) 1992-2014 Free Software Foundation, Inc.
|
||||||
|
@ -1682,6 +1683,15 @@ extern void get_unsigned_type_max (struct type *, ULONGEST *);
|
||||||
|
|
||||||
extern void get_signed_type_minmax (struct type *, LONGEST *, LONGEST *);
|
extern void get_signed_type_minmax (struct type *, LONGEST *, LONGEST *);
|
||||||
|
|
||||||
|
/* * Resolve all dynamic values of a type e.g. array bounds to static values.
|
||||||
|
ADDR specifies the location of the variable the type is bound to.
|
||||||
|
If TYPE has no dynamic properties return TYPE; otherwise a new type with
|
||||||
|
static properties is returned. */
|
||||||
|
extern struct type *resolve_dynamic_type (struct type *type, CORE_ADDR addr);
|
||||||
|
|
||||||
|
/* * Predicate if the type has dynamic values, which are not resolved yet. */
|
||||||
|
extern int is_dynamic_type (struct type *type);
|
||||||
|
|
||||||
extern struct type *check_typedef (struct type *);
|
extern struct type *check_typedef (struct type *);
|
||||||
|
|
||||||
#define CHECK_TYPEDEF(TYPE) \
|
#define CHECK_TYPEDEF(TYPE) \
|
||||||
|
|
15
gdb/valops.c
15
gdb/valops.c
|
@ -900,7 +900,10 @@ value_one (struct type *type)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function for value_at, value_at_lazy, and value_at_lazy_stack. */
|
/* Helper function for value_at, value_at_lazy, and value_at_lazy_stack.
|
||||||
|
The type of the created value may differ from the passed type TYPE.
|
||||||
|
Make sure to retrieve the returned values's new type after this call
|
||||||
|
e.g. in case the type is a variable length array. */
|
||||||
|
|
||||||
static struct value *
|
static struct value *
|
||||||
get_value_at (struct type *type, CORE_ADDR addr, int lazy)
|
get_value_at (struct type *type, CORE_ADDR addr, int lazy)
|
||||||
|
@ -925,7 +928,10 @@ get_value_at (struct type *type, CORE_ADDR addr, int lazy)
|
||||||
value_at_lazy instead. value_at_lazy simply records the address of
|
value_at_lazy instead. value_at_lazy simply records the address of
|
||||||
the data and sets the lazy-evaluation-required flag. The lazy flag
|
the data and sets the lazy-evaluation-required flag. The lazy flag
|
||||||
is tested in the value_contents macro, which is used if and when
|
is tested in the value_contents macro, which is used if and when
|
||||||
the contents are actually required.
|
the contents are actually required. The type of the created value
|
||||||
|
may differ from the passed type TYPE. Make sure to retrieve the
|
||||||
|
returned values's new type after this call e.g. in case the type
|
||||||
|
is a variable length array.
|
||||||
|
|
||||||
Note: value_at does *NOT* handle embedded offsets; perform such
|
Note: value_at does *NOT* handle embedded offsets; perform such
|
||||||
adjustments before or after calling it. */
|
adjustments before or after calling it. */
|
||||||
|
@ -936,7 +942,10 @@ value_at (struct type *type, CORE_ADDR addr)
|
||||||
return get_value_at (type, addr, 0);
|
return get_value_at (type, addr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */
|
/* Return a lazy value with type TYPE located at ADDR (cf. value_at).
|
||||||
|
The type of the created value may differ from the passed type TYPE.
|
||||||
|
Make sure to retrieve the returned values's new type after this call
|
||||||
|
e.g. in case the type is a variable length array. */
|
||||||
|
|
||||||
struct value *
|
struct value *
|
||||||
value_at_lazy (struct type *type, CORE_ADDR addr)
|
value_at_lazy (struct type *type, CORE_ADDR addr)
|
||||||
|
|
19
gdb/value.c
19
gdb/value.c
|
@ -3319,32 +3319,39 @@ value_from_ulongest (struct type *type, ULONGEST num)
|
||||||
|
|
||||||
|
|
||||||
/* Create a value representing a pointer of type TYPE to the address
|
/* Create a value representing a pointer of type TYPE to the address
|
||||||
ADDR. */
|
ADDR. The type of the created value may differ from the passed
|
||||||
|
type TYPE. Make sure to retrieve the returned values's new type
|
||||||
|
after this call e.g. in case of an variable length array. */
|
||||||
|
|
||||||
struct value *
|
struct value *
|
||||||
value_from_pointer (struct type *type, CORE_ADDR addr)
|
value_from_pointer (struct type *type, CORE_ADDR addr)
|
||||||
{
|
{
|
||||||
struct value *val = allocate_value (type);
|
struct type *resolved_type = resolve_dynamic_type (type, addr);
|
||||||
|
struct value *val = allocate_value (resolved_type);
|
||||||
|
|
||||||
store_typed_address (value_contents_raw (val), check_typedef (type), addr);
|
store_typed_address (value_contents_raw (val),
|
||||||
|
check_typedef (resolved_type), addr);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Create a value of type TYPE whose contents come from VALADDR, if it
|
/* Create a value of type TYPE whose contents come from VALADDR, if it
|
||||||
is non-null, and whose memory address (in the inferior) is
|
is non-null, and whose memory address (in the inferior) is
|
||||||
ADDRESS. */
|
ADDRESS. The type of the created value may differ from the passed
|
||||||
|
type TYPE. Make sure to retrieve values new type after this call. */
|
||||||
|
|
||||||
struct value *
|
struct value *
|
||||||
value_from_contents_and_address (struct type *type,
|
value_from_contents_and_address (struct type *type,
|
||||||
const gdb_byte *valaddr,
|
const gdb_byte *valaddr,
|
||||||
CORE_ADDR address)
|
CORE_ADDR address)
|
||||||
{
|
{
|
||||||
|
struct type *resolved_type = resolve_dynamic_type (type, address);
|
||||||
struct value *v;
|
struct value *v;
|
||||||
|
|
||||||
if (valaddr == NULL)
|
if (valaddr == NULL)
|
||||||
v = allocate_value_lazy (type);
|
v = allocate_value_lazy (resolved_type);
|
||||||
else
|
else
|
||||||
v = value_from_contents (type, valaddr);
|
v = value_from_contents (resolved_type, valaddr);
|
||||||
set_value_address (v, address);
|
set_value_address (v, address);
|
||||||
VALUE_LVAL (v) = lval_memory;
|
VALUE_LVAL (v) = lval_memory;
|
||||||
return v;
|
return v;
|
||||||
|
|
Loading…
Reference in a new issue