[PATCH v6 03/15] type: add c99 variable length array support

Joel Brobecker brobecker@adacore.com
Thu Apr 10 14:21:00 GMT 2014


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



More information about the Gdb-patches mailing list