From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8526 invoked by alias); 10 Apr 2014 14:21:49 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 8516 invoked by uid 89); 10 Apr 2014 14:21:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.6 required=5.0 tests=AWL,BAYES_00 autolearn=ham version=3.3.2 X-HELO: rock.gnat.com Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Thu, 10 Apr 2014 14:21:45 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id ED9D411612D; Thu, 10 Apr 2014 10:21:43 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 2p5UDQYL2ywC; Thu, 10 Apr 2014 10:21:43 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id 85809116110; Thu, 10 Apr 2014 10:21:43 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 5C2D2E0E11; Thu, 10 Apr 2014 07:21:46 -0700 (PDT) Date: Thu, 10 Apr 2014 14:21:00 -0000 From: Joel Brobecker To: Sanimir Agovic Cc: gdb-patches@sourceware.org, tromey@redhat.com Subject: Re: [PATCH v6 03/15] type: add c99 variable length array support Message-ID: <20140410142146.GA15965@adacore.com> References: <1397133617-26681-1-git-send-email-sanimir.agovic@intel.com> <1397133617-26681-4-git-send-email-sanimir.agovic@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1397133617-26681-4-git-send-email-sanimir.agovic@intel.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-SW-Source: 2014-04/txt/msg00178.txt.bz2 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 } > > 2013-10-18 Sanimir Agovic > Keven Boell > > * 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 > --- > 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