[02/23] dwarf: add DW_AT_data_location support

Message ID 1401861266-6240-3-git-send-email-keven.boell@intel.com
State New, archived
Headers

Commit Message

Keven Boell June 4, 2014, 5:54 a.m. UTC
  An object might have a descriptor proceeding the actual value.
To point the debugger to the actually value of an object
DW_AT_data_location is used for. For example the compile may
emit for this entity:

  1| int foo[N];

the following descriptor:

struct array {
  size_t size;
  void*  data; // DW_AT_data_location describes this location
}

This allows GDB to print the actual data of an type.

2014-05-28  Sanimir Agovic  <sanimir.agovic@intel.com>
            Keven Boell  <keven.boell@intel.com>

	* dwarf2read.c (set_die_type): Parse and save DW_AT_data_location
	attribute.
	* gdbtypes.c (is_dynamic_type): Consider a type being dynamic if
	the data location has not yet been resolved.
	(resolve_dynamic_type): Evaluate data location baton
	if present and save its value.
	* gdbtypes.h <main_type>: Add data_location.
	(TYPE_DATA_LOCATION): New macro.
	(TYPE_DATA_LOCATION_ADDR): New macro.
	(TYPE_DATA_LOCATION_IS_ADDRESS): New macro.
	* value.c: Include dwarf2loc.h.
	(value_fetch_lazy): Use data location addres to read value from
	memory.
	(coerce_ref): Construct new value from data location.

Change-Id: Ic633fa125efdb5e438204e4f80bb3a1c97758b12

Signed-off-by: Keven Boell <keven.boell@intel.com>
---
 gdb/dwarf2read.c |   15 +++++++++++++++
 gdb/gdbtypes.c   |   29 +++++++++++++++++++++++++++--
 gdb/gdbtypes.h   |   14 ++++++++++++++
 gdb/value.c      |    8 +++++++-
 4 files changed, 63 insertions(+), 3 deletions(-)
  

Comments

Joel Brobecker June 10, 2014, 12:10 p.m. UTC | #1
Hello,

> An object might have a descriptor proceeding the actual value.
> To point the debugger to the actually value of an object
> DW_AT_data_location is used for. For example the compile may
> emit for this entity:
> 
>   1| int foo[N];
> 
> the following descriptor:
> 
> struct array {
>   size_t size;
>   void*  data; // DW_AT_data_location describes this location
> }
> 
> This allows GDB to print the actual data of an type.
> 
> 2014-05-28  Sanimir Agovic  <sanimir.agovic@intel.com>
>             Keven Boell  <keven.boell@intel.com>
> 
> 	* dwarf2read.c (set_die_type): Parse and save DW_AT_data_location
> 	attribute.
> 	* gdbtypes.c (is_dynamic_type): Consider a type being dynamic if
> 	the data location has not yet been resolved.
> 	(resolve_dynamic_type): Evaluate data location baton
> 	if present and save its value.
> 	* gdbtypes.h <main_type>: Add data_location.
> 	(TYPE_DATA_LOCATION): New macro.
> 	(TYPE_DATA_LOCATION_ADDR): New macro.
> 	(TYPE_DATA_LOCATION_IS_ADDRESS): New macro.
> 	* value.c: Include dwarf2loc.h.
> 	(value_fetch_lazy): Use data location addres to read value from
> 	memory.
> 	(coerce_ref): Construct new value from data location.

Here are some comments and questions, but it would be nice,  IMO, if
the patch was also reviewed by Tom, particularly since it introduces
a new field in struct main_type, which is a size-sensitive, I think.

Also, it would be nice if you could include a copy of the actual
DWARF output in the revision log of your patch, for easy reference
of what you're trying to support.

> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index 6ebfffc..7a0f7f4 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -21499,6 +21499,7 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
>  {
>    struct dwarf2_per_cu_offset_and_type **slot, ofs;
>    struct objfile *objfile = cu->objfile;
> +  struct attribute *attr;
>  
>    /* For Ada types, make sure that the gnat-specific data is always
>       initialized (if not already set).  There are a few types where
> @@ -21513,6 +21514,20 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
>        && !HAVE_GNAT_AUX_INFO (type))
>      INIT_GNAT_SPECIFIC (type);
>  
> +  /* Read DW_AT_data_location and set in type.  */
> +  attr = dwarf2_attr (die, DW_AT_data_location, cu);
> +  if (attr_form_is_block (attr))

Here (in set_die_type), why do you limit the processing the block-form
data_location attributes? Why not just call attr_to_dynamic_prop
regardless of the form, and let that function deal with whatever
the form is? In other words, trop the form check and just keep
the following bit:

> +      struct dynamic_prop prop;
> +
> +      if (attr_to_dynamic_prop (attr, die, cu, &prop))
> +	{
> +	  TYPE_DATA_LOCATION (type)
> +	    = obstack_alloc (&objfile->objfile_obstack, sizeof (prop));
> +	  *TYPE_DATA_LOCATION (type) = prop;
> +	}

> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -1635,8 +1635,12 @@ is_dynamic_type (struct type *type)
>  	   or the elements it contains have a dynamic contents.  */
>  	if (is_dynamic_type (TYPE_INDEX_TYPE (type)))
>  	  return 1;
> -	else
> -	  return is_dynamic_type (TYPE_TARGET_TYPE (type));
> +	else if (TYPE_DATA_LOCATION (type) != NULL
> +          && (TYPE_DATA_LOCATION_KIND (type) == PROP_LOCEXPR
> +              || TYPE_DATA_LOCATION_KIND (type) == PROP_LOCLIST))
> +    return 1;
> +  else
> +    return is_dynamic_type (TYPE_TARGET_TYPE (type));

The comment needs to be updated. Your change is also splitting
the "if bounds or contents is dynamic" logic. Perhaps you could
simply add the data-location check at the start of the function
with a command that says: A type which has a data_location which
[bla bla] is a dynamic type


> +  type = resolved_type;
> +
> +  /* Resolve data_location attribute.  */
> +  prop = TYPE_DATA_LOCATION (type);
> +  if (dwarf2_evaluate_property (prop, addr, &value))
> +    {
> +      TYPE_DATA_LOCATION_ADDR (type) = value;
> +      TYPE_DATA_LOCATION_KIND (type) = PROP_CONST;
> +    }
> +  else
> +    TYPE_DATA_LOCATION (type) = NULL;

Here, I do not understand why you override TYPE, instead of just
using RESOLVED_TYPE directly.

> @@ -722,6 +722,10 @@ struct main_type
>  
>      struct func_type *func_stuff;
>    } type_specific;
> +
> +  /* * Indirection to actual data.  */
> +
> +  struct dynamic_prop *data_location;

I'd like to have a comment which is a little more descriptive of
what this field contains. Someone who reads this comment should be
able to understand it without having to grep for this field to
get an idea of how this field is used.

> +/* Attribute accessors for VLA support.  */

I think this comment is too specific. Although this field is
instroduced to support VLAs, descriptors can probably be used
in other contexts. I don't think you really need a comment,
in this case, though.

> +#define TYPE_DATA_LOCATION(thistype) \
> +  TYPE_MAIN_TYPE(thistype)->data_location
> +#define TYPE_DATA_LOCATION_BATON(thistype) \
> +  TYPE_DATA_LOCATION (thistype)->data.baton
> +#define TYPE_DATA_LOCATION_ADDR(thistype) \
> +  TYPE_DATA_LOCATION (thistype)->data.const_val
> +#define TYPE_DATA_LOCATION_KIND(thistype) \
> +  TYPE_DATA_LOCATION (thistype)->kind
> +
>  /* Moto-specific stuff for FORTRAN arrays.  */
>  
>  #define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \
> diff --git a/gdb/value.c b/gdb/value.c
> index d125a09..1c88dfd 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -3635,8 +3635,14 @@ value_fetch_lazy (struct value *val)
>      }
>    else if (VALUE_LVAL (val) == lval_memory)
>      {
> -      CORE_ADDR addr = value_address (val);
>        struct type *type = check_typedef (value_enclosing_type (val));
> +      CORE_ADDR addr;
> +
> +      if (TYPE_DATA_LOCATION (type) != NULL
> +	  && TYPE_DATA_LOCATION_KIND (type) == PROP_CONST)
> +	addr = TYPE_DATA_LOCATION_ADDR (type);
> +      else
> +	addr = value_address (val);

I am wondering if this part shouldn't be in value_address itself.
WDYT? Tom?

>  
>        if (TYPE_LENGTH (type))
>  	read_value_memory (val, 0, value_stack (val),
> -- 
> 1.7.9.5
  
Keven Boell June 11, 2014, 12:29 p.m. UTC | #2
Hi Joel,

I've addressed your comments and the changes will be part of patch series v2.

Keven


> Hello,
> 
>> An object might have a descriptor proceeding the actual value.
>> To point the debugger to the actually value of an object
>> DW_AT_data_location is used for. For example the compile may
>> emit for this entity:
>>
>>   1| int foo[N];
>>
>> the following descriptor:
>>
>> struct array {
>>   size_t size;
>>   void*  data; // DW_AT_data_location describes this location
>> }
>>
>> This allows GDB to print the actual data of an type.
>>
>> 2014-05-28  Sanimir Agovic  <sanimir.agovic@intel.com>
>>             Keven Boell  <keven.boell@intel.com>
>>
>> 	* dwarf2read.c (set_die_type): Parse and save DW_AT_data_location
>> 	attribute.
>> 	* gdbtypes.c (is_dynamic_type): Consider a type being dynamic if
>> 	the data location has not yet been resolved.
>> 	(resolve_dynamic_type): Evaluate data location baton
>> 	if present and save its value.
>> 	* gdbtypes.h <main_type>: Add data_location.
>> 	(TYPE_DATA_LOCATION): New macro.
>> 	(TYPE_DATA_LOCATION_ADDR): New macro.
>> 	(TYPE_DATA_LOCATION_IS_ADDRESS): New macro.
>> 	* value.c: Include dwarf2loc.h.
>> 	(value_fetch_lazy): Use data location addres to read value from
>> 	memory.
>> 	(coerce_ref): Construct new value from data location.
> 
> Here are some comments and questions, but it would be nice,  IMO, if
> the patch was also reviewed by Tom, particularly since it introduces
> a new field in struct main_type, which is a size-sensitive, I think.
> 
> Also, it would be nice if you could include a copy of the actual
> DWARF output in the revision log of your patch, for easy reference
> of what you're trying to support.
> 
>> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
>> index 6ebfffc..7a0f7f4 100644
>> --- a/gdb/dwarf2read.c
>> +++ b/gdb/dwarf2read.c
>> @@ -21499,6 +21499,7 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
>>  {
>>    struct dwarf2_per_cu_offset_and_type **slot, ofs;
>>    struct objfile *objfile = cu->objfile;
>> +  struct attribute *attr;
>>  
>>    /* For Ada types, make sure that the gnat-specific data is always
>>       initialized (if not already set).  There are a few types where
>> @@ -21513,6 +21514,20 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
>>        && !HAVE_GNAT_AUX_INFO (type))
>>      INIT_GNAT_SPECIFIC (type);
>>  
>> +  /* Read DW_AT_data_location and set in type.  */
>> +  attr = dwarf2_attr (die, DW_AT_data_location, cu);
>> +  if (attr_form_is_block (attr))
> 
> Here (in set_die_type), why do you limit the processing the block-form
> data_location attributes? Why not just call attr_to_dynamic_prop
> regardless of the form, and let that function deal with whatever
> the form is? In other words, trop the form check and just keep
> the following bit:
> 
>> +      struct dynamic_prop prop;
>> +
>> +      if (attr_to_dynamic_prop (attr, die, cu, &prop))
>> +	{
>> +	  TYPE_DATA_LOCATION (type)
>> +	    = obstack_alloc (&objfile->objfile_obstack, sizeof (prop));
>> +	  *TYPE_DATA_LOCATION (type) = prop;
>> +	}

Good catch, there is no reason to limit the processing here.

> 
>> --- a/gdb/gdbtypes.c
>> +++ b/gdb/gdbtypes.c
>> @@ -1635,8 +1635,12 @@ is_dynamic_type (struct type *type)
>>  	   or the elements it contains have a dynamic contents.  */
>>  	if (is_dynamic_type (TYPE_INDEX_TYPE (type)))
>>  	  return 1;
>> -	else
>> -	  return is_dynamic_type (TYPE_TARGET_TYPE (type));
>> +	else if (TYPE_DATA_LOCATION (type) != NULL
>> +          && (TYPE_DATA_LOCATION_KIND (type) == PROP_LOCEXPR
>> +              || TYPE_DATA_LOCATION_KIND (type) == PROP_LOCLIST))
>> +    return 1;
>> +  else
>> +    return is_dynamic_type (TYPE_TARGET_TYPE (type));
> 
> The comment needs to be updated. Your change is also splitting
> the "if bounds or contents is dynamic" logic. Perhaps you could
> simply add the data-location check at the start of the function
> with a command that says: A type which has a data_location which
> [bla bla] is a dynamic type

I've updated the comment.

> 
> 
>> +  type = resolved_type;
>> +
>> +  /* Resolve data_location attribute.  */
>> +  prop = TYPE_DATA_LOCATION (type);
>> +  if (dwarf2_evaluate_property (prop, addr, &value))
>> +    {
>> +      TYPE_DATA_LOCATION_ADDR (type) = value;
>> +      TYPE_DATA_LOCATION_KIND (type) = PROP_CONST;
>> +    }
>> +  else
>> +    TYPE_DATA_LOCATION (type) = NULL;
> 
> Here, I do not understand why you override TYPE, instead of just
> using RESOLVED_TYPE directly.

I did this for improving the readability, however maybe this is just confusing. I changed it.

> 
>> @@ -722,6 +722,10 @@ struct main_type
>>  
>>      struct func_type *func_stuff;
>>    } type_specific;
>> +
>> +  /* * Indirection to actual data.  */
>> +
>> +  struct dynamic_prop *data_location;
> 
> I'd like to have a comment which is a little more descriptive of
> what this field contains. Someone who reads this comment should be
> able to understand it without having to grep for this field to
> get an idea of how this field is used.

Done.

> 
>> +/* Attribute accessors for VLA support.  */
> 
> I think this comment is too specific. Although this field is
> instroduced to support VLAs, descriptors can probably be used
> in other contexts. I don't think you really need a comment,
> in this case, though.

Done.

> 
>> +#define TYPE_DATA_LOCATION(thistype) \
>> +  TYPE_MAIN_TYPE(thistype)->data_location
>> +#define TYPE_DATA_LOCATION_BATON(thistype) \
>> +  TYPE_DATA_LOCATION (thistype)->data.baton
>> +#define TYPE_DATA_LOCATION_ADDR(thistype) \
>> +  TYPE_DATA_LOCATION (thistype)->data.const_val
>> +#define TYPE_DATA_LOCATION_KIND(thistype) \
>> +  TYPE_DATA_LOCATION (thistype)->kind
>> +
>>  /* Moto-specific stuff for FORTRAN arrays.  */
>>  
>>  #define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \
>> diff --git a/gdb/value.c b/gdb/value.c
>> index d125a09..1c88dfd 100644
>> --- a/gdb/value.c
>> +++ b/gdb/value.c
>> @@ -3635,8 +3635,14 @@ value_fetch_lazy (struct value *val)
>>      }
>>    else if (VALUE_LVAL (val) == lval_memory)
>>      {
>> -      CORE_ADDR addr = value_address (val);
>>        struct type *type = check_typedef (value_enclosing_type (val));
>> +      CORE_ADDR addr;
>> +
>> +      if (TYPE_DATA_LOCATION (type) != NULL
>> +	  && TYPE_DATA_LOCATION_KIND (type) == PROP_CONST)
>> +	addr = TYPE_DATA_LOCATION_ADDR (type);
>> +      else
>> +	addr = value_address (val);
> 
> I am wondering if this part shouldn't be in value_address itself.
> WDYT? Tom?
> 
>>  
>>        if (TYPE_LENGTH (type))
>>  	read_value_memory (val, 0, value_stack (val),
>> -- 
>> 1.7.9.5
>
  
Jan Kratochvil June 14, 2014, 1:21 p.m. UTC | #3
On Tue, 10 Jun 2014 14:10:14 +0200, Joel Brobecker wrote:
> > --- a/gdb/gdbtypes.c
> > +++ b/gdb/gdbtypes.c
> > @@ -1635,8 +1635,12 @@ is_dynamic_type (struct type *type)
> >  	   or the elements it contains have a dynamic contents.  */
> >  	if (is_dynamic_type (TYPE_INDEX_TYPE (type)))
> >  	  return 1;
> > -	else
> > -	  return is_dynamic_type (TYPE_TARGET_TYPE (type));
> > +	else if (TYPE_DATA_LOCATION (type) != NULL
> > +          && (TYPE_DATA_LOCATION_KIND (type) == PROP_LOCEXPR
> > +              || TYPE_DATA_LOCATION_KIND (type) == PROP_LOCLIST))
> > +    return 1;
> > +  else
> > +    return is_dynamic_type (TYPE_TARGET_TYPE (type));
> 
> The comment needs to be updated. Your change is also splitting
> the "if bounds or contents is dynamic" logic. Perhaps you could
> simply add the data-location check at the start of the function
> with a command that says: A type which has a data_location which
> [bla bla] is a dynamic type

The indentation is somehow incorrect there.


Jan
  

Patch

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 6ebfffc..7a0f7f4 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -21499,6 +21499,7 @@  set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
 {
   struct dwarf2_per_cu_offset_and_type **slot, ofs;
   struct objfile *objfile = cu->objfile;
+  struct attribute *attr;
 
   /* For Ada types, make sure that the gnat-specific data is always
      initialized (if not already set).  There are a few types where
@@ -21513,6 +21514,20 @@  set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
       && !HAVE_GNAT_AUX_INFO (type))
     INIT_GNAT_SPECIFIC (type);
 
+  /* Read DW_AT_data_location and set in type.  */
+  attr = dwarf2_attr (die, DW_AT_data_location, cu);
+  if (attr_form_is_block (attr))
+    {
+      struct dynamic_prop prop;
+
+      if (attr_to_dynamic_prop (attr, die, cu, &prop))
+	{
+	  TYPE_DATA_LOCATION (type)
+	    = obstack_alloc (&objfile->objfile_obstack, sizeof (prop));
+	  *TYPE_DATA_LOCATION (type) = prop;
+	}
+    }
+
   if (dwarf2_per_objfile->die_type_hash == NULL)
     {
       dwarf2_per_objfile->die_type_hash =
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2a0cfe4..c12c159 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1635,8 +1635,12 @@  is_dynamic_type (struct type *type)
 	   or the elements it contains have a dynamic contents.  */
 	if (is_dynamic_type (TYPE_INDEX_TYPE (type)))
 	  return 1;
-	else
-	  return is_dynamic_type (TYPE_TARGET_TYPE (type));
+	else if (TYPE_DATA_LOCATION (type) != NULL
+          && (TYPE_DATA_LOCATION_KIND (type) == PROP_LOCEXPR
+              || TYPE_DATA_LOCATION_KIND (type) == PROP_LOCLIST))
+    return 1;
+  else
+    return is_dynamic_type (TYPE_TARGET_TYPE (type));
 	break;
       }
     default:
@@ -1728,6 +1732,8 @@  resolve_dynamic_type (struct type *type, CORE_ADDR addr)
 {
   struct type *real_type = check_typedef (type);
   struct type *resolved_type = type;
+  const struct dynamic_prop *prop;
+  CORE_ADDR value;
 
   if (!is_dynamic_type (real_type))
     return type;
@@ -1759,6 +1765,18 @@  resolve_dynamic_type (struct type *type, CORE_ADDR addr)
 	break;
     }
 
+  type = resolved_type;
+
+  /* Resolve data_location attribute.  */
+  prop = TYPE_DATA_LOCATION (type);
+  if (dwarf2_evaluate_property (prop, addr, &value))
+    {
+      TYPE_DATA_LOCATION_ADDR (type) = value;
+      TYPE_DATA_LOCATION_KIND (type) = PROP_CONST;
+    }
+  else
+    TYPE_DATA_LOCATION (type) = NULL;
+
   return resolved_type;
 }
 
@@ -3968,6 +3986,13 @@  copy_type_recursive (struct objfile *objfile,
       *TYPE_RANGE_DATA (new_type) = *TYPE_RANGE_DATA (type);
     }
 
+  /* Copy the data location information.  */
+  if (TYPE_DATA_LOCATION (type) != NULL)
+    {
+      TYPE_DATA_LOCATION (new_type) = xmalloc (sizeof (struct dynamic_prop));
+      *TYPE_DATA_LOCATION (new_type) = *TYPE_DATA_LOCATION (type);
+    }
+
   /* Copy pointers to other types.  */
   if (TYPE_TARGET_TYPE (type))
     TYPE_TARGET_TYPE (new_type) = 
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 86b1d62..c6d14d2 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -722,6 +722,10 @@  struct main_type
 
     struct func_type *func_stuff;
   } type_specific;
+
+  /* * Indirection to actual data.  */
+
+  struct dynamic_prop *data_location;
 };
 
 /* * A ``struct type'' describes a particular instance of a type, with
@@ -1201,6 +1205,16 @@  extern void allocate_gnat_aux_type (struct type *);
 #define TYPE_LOW_BOUND_KIND(range_type) \
   TYPE_RANGE_DATA(range_type)->low.kind
 
+/* Attribute accessors for VLA support.  */
+#define TYPE_DATA_LOCATION(thistype) \
+  TYPE_MAIN_TYPE(thistype)->data_location
+#define TYPE_DATA_LOCATION_BATON(thistype) \
+  TYPE_DATA_LOCATION (thistype)->data.baton
+#define TYPE_DATA_LOCATION_ADDR(thistype) \
+  TYPE_DATA_LOCATION (thistype)->data.const_val
+#define TYPE_DATA_LOCATION_KIND(thistype) \
+  TYPE_DATA_LOCATION (thistype)->kind
+
 /* Moto-specific stuff for FORTRAN arrays.  */
 
 #define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \
diff --git a/gdb/value.c b/gdb/value.c
index d125a09..1c88dfd 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3635,8 +3635,14 @@  value_fetch_lazy (struct value *val)
     }
   else if (VALUE_LVAL (val) == lval_memory)
     {
-      CORE_ADDR addr = value_address (val);
       struct type *type = check_typedef (value_enclosing_type (val));
+      CORE_ADDR addr;
+
+      if (TYPE_DATA_LOCATION (type) != NULL
+	  && TYPE_DATA_LOCATION_KIND (type) == PROP_CONST)
+	addr = TYPE_DATA_LOCATION_ADDR (type);
+      else
+	addr = value_address (val);
 
       if (TYPE_LENGTH (type))
 	read_value_memory (val, 0, value_stack (val),