This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH v6 03/15] type: add c99 variable length array support
- From: Joel Brobecker <brobecker at adacore dot com>
- To: Sanimir Agovic <sanimir dot agovic at intel dot com>
- Cc: gdb-patches at sourceware dot org, tromey at redhat dot com
- Date: Thu, 10 Apr 2014 07:21:46 -0700
- Subject: Re: [PATCH v6 03/15] type: add c99 variable length array support
- Authentication-results: sourceware.org; auth=none
- References: <1397133617-26681-1-git-send-email-sanimir dot agovic at intel dot com> <1397133617-26681-4-git-send-email-sanimir dot agovic at intel dot com>
On Thu, Apr 10, 2014 at 02:40:05PM +0200, Sanimir Agovic wrote:
> 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>}
>
> 2013-10-18 Sanimir Agovic <sanimir.agovic@intel.com>
> Keven Boell <keven.boell@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.
LGTM. Pre-approved with the following minor corrections outlined below.
It's nice to see that there were even more simplifications that could
be made after abandonning types deep copies!
>
>
> Signed-off-by: Sanimir Agovic <sanimir.agovic@intel.com>
> ---
> gdb/dwarf2loc.c | 119 +++++++++++++++++++++++++++++++++
> gdb/dwarf2loc.h | 28 ++++++++
> gdb/dwarf2read.c | 106 +++++++++++++++++++++--------
> gdb/gdbtypes.c | 199 +++++++++++++++++++++++++++++++++++++++++--------------
> gdb/gdbtypes.h | 10 +++
> gdb/valops.c | 15 ++++-
> gdb/value.c | 19 ++++--
> 7 files changed, 409 insertions(+), 87 deletions(-)
>
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index 2b1f323..d903322 100644
> --- a/gdb/dwarf2loc.c
> +++ b/gdb/dwarf2loc.c
> @@ -2431,6 +2431,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);
> }
>
> +/* 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. */
>
> diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
> index 9bc8ca5..94d9c5f 100644
> --- a/gdb/dwarf2loc.h
> +++ b/gdb/dwarf2loc.h
> @@ -90,6 +90,14 @@ struct value *dwarf2_evaluate_loc_desc (struct type *type,
> size_t size,
> 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,
> unsigned int addr_index);
>
> @@ -135,6 +143,26 @@ struct dwarf2_loclist_baton
> 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 TYPE. */
> + struct dwarf2_loclist_baton loclist;
I missed that one in my first review, but I think you meant
REFERENCED_TYPE, rather than TYPE?
> + };
> +};
> +
> extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
> extern const struct symbol_computed_ops dwarf2_loclist_funcs;
>
> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index 101065b..436d0db 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -14252,6 +14252,84 @@ read_base_type (struct die_info *die, struct dwarf2_cu *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. */
>
> static struct type *
> @@ -14325,27 +14403,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
> die->offset.sect_off, objfile_name (cu->objfile));
>
> attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
> - if (attr)
> - {
> - 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
> + if (!attr_to_dynamic_prop (attr, die, cu, &high))
> {
> attr = dwarf2_attr (die, DW_AT_count, cu);
> if (attr)
> @@ -14409,12 +14467,6 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
>
> 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. */
> if (attr == NULL && cu->language != language_ada)
> TYPE_HIGH_BOUND_KIND (range_type) = PROP_UNDEFINED;
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 7f0269c..ce582f8 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -853,6 +853,17 @@ create_static_range_type (struct type *result_type, struct type *index_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
> TYPE. Return 1 if type is a range type, 0 if it is discrete (and
> bounds will fit in LONGEST), or -1 otherwise. */
> @@ -982,24 +993,31 @@ create_array_type (struct type *result_type,
> struct type *element_type,
> struct type *range_type)
> {
> - LONGEST low_bound, high_bound;
> -
> if (result_type == NULL)
> result_type = alloc_type_copy (range_type);
>
> TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
> TYPE_TARGET_TYPE (result_type) = element_type;
> - if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
> - low_bound = high_bound = 0;
> - CHECK_TYPEDEF (element_type);
> - /* Be careful when setting the array length. Ada arrays can be
> - empty arrays with the high_bound being smaller than the low_bound.
> - In such cases, the array length should be zero. */
> - if (high_bound < low_bound)
> - TYPE_LENGTH (result_type) = 0;
> +
> + 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)
> + low_bound = high_bound = 0;
> + CHECK_TYPEDEF (element_type);
> + /* Be careful when setting the array length. Ada arrays can be
> + empty arrays with the high_bound being smaller than the low_bound.
> + In such cases, the array length should be zero. */
> + if (high_bound < low_bound)
> + TYPE_LENGTH (result_type) = 0;
> + else
> + TYPE_LENGTH (result_type) =
> + TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
> + }
> else
> - TYPE_LENGTH (result_type) =
> - TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
> + TYPE_LENGTH (result_type) = 0;
Thanks for making that change. I think it'd be worth while explaining
why we set the length to zero. How about the following:
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_FIELDS (result_type) =
> (struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
> @@ -1530,6 +1548,124 @@ stub_noname_complaint (void)
> 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);
There was a small nit-pick request here, and since you're going to be
touching this code again (see below), would you mind...
Joel> Small formatting nit-pick (while we're touching this code):
Joel>
Joel> range_type = create_range_type (NULL,
Joel> TYPE_TARGET_TYPE (range_type),
Joel> &low_bound, &high_bound);
> + elt_type = create_array_type (copy_type (type),
> + elt_type,
> + range_type);
> +
> + return elt_type;
Can you avoid assigning the array types being created to elt_type
(possibly confusing), and just do...
return create_array_type (copy_type (type), elt_type, range_type);
... instead?
> +}
> +
> +/* 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,
> after removing all layers of typedefs, and completing opaque or stub
> types. Completion changes the TYPE argument, but stripping of
> @@ -1705,45 +1841,6 @@ check_typedef (struct type *type)
> {
> /* 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)
> {
> TYPE_LENGTH (type) = TYPE_LENGTH (target_type);
> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
> index f6e68c5..36e4a5f 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -1,3 +1,4 @@
> +
> /* Internal type definitions for GDB.
>
> Copyright (C) 1992-2013 Free Software Foundation, Inc.
> @@ -1574,6 +1575,15 @@ extern struct type *lookup_unsigned_typename (const struct language_defn *,
> extern struct type *lookup_signed_typename (const struct language_defn *,
> struct gdbarch *, const char *);
>
> +/* 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 *);
>
> #define CHECK_TYPEDEF(TYPE) \
> diff --git a/gdb/valops.c b/gdb/valops.c
> index 5c7bb89..eefa8c6 100644
> --- a/gdb/valops.c
> +++ b/gdb/valops.c
> @@ -902,7 +902,10 @@ value_one (struct type *type)
> 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 *
> get_value_at (struct type *type, CORE_ADDR addr, int lazy)
> @@ -927,7 +930,10 @@ get_value_at (struct type *type, CORE_ADDR addr, int lazy)
> value_at_lazy instead. value_at_lazy simply records the address of
> 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
> - 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
> adjustments before or after calling it. */
> @@ -938,7 +944,10 @@ value_at (struct type *type, CORE_ADDR addr)
> 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 *
> value_at_lazy (struct type *type, CORE_ADDR addr)
> diff --git a/gdb/value.c b/gdb/value.c
> index a64e7e1..993157f 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -3178,32 +3178,39 @@ value_from_ulongest (struct type *type, ULONGEST num)
>
>
> /* 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 *
> 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;
> }
>
>
> /* Create a value of type TYPE whose contents come from VALADDR, if it
> 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 *
> value_from_contents_and_address (struct type *type,
> const gdb_byte *valaddr,
> CORE_ADDR address)
> {
> + struct type *resolved_type = resolve_dynamic_type (type, address);
> struct value *v;
>
> if (valaddr == NULL)
> - v = allocate_value_lazy (type);
> + v = allocate_value_lazy (resolved_type);
> else
> - v = value_from_contents (type, valaddr);
> + v = value_from_contents (resolved_type, valaddr);
> set_value_address (v, address);
> VALUE_LVAL (v) = lval_memory;
> return v;
> --
> 1.8.4.2
--
Joel