[RFA/DWARF] Set enum type "flag_enum" and "unsigned" flags at type creation.

Joel Brobecker brobecker@adacore.com
Mon Feb 17 20:20:00 GMT 2014


Ping?

Thank you!

On Mon, Jan 27, 2014 at 08:19:17AM +0400, Joel Brobecker wrote:
> Hello,
> 
> Consider the following Ada code:
> 
>    --  An array whose index is an enumeration type with 128 enumerators.
>    type Enum_T is (Enum_000, Enum_001, [...], Enum_128);
>    type Table is array (Enum_T) of Boolean;
> 
> When the compiler is configured to generate pure DWARF debugging info,
> trying to print type Table's description yields:
> 
>     ptype pck.table
>     type = array (enum_000 .. -128) of boolean
> 
> The expected output was:
> 
>     ptype pck.table
>     type = array (enum_000 .. enum_128) of boolean
> 
> The DWARF debugging info for our array looks like this:
> 
>     <1><44>: Abbrev Number: 5 (DW_TAG_array_type)
>        <45>   DW_AT_name        : pck__table
>        <50>   DW_AT_type        : <0x28>
>     <2><54>: Abbrev Number: 6 (DW_TAG_subrange_type)
>        <55>   DW_AT_type        : <0x5c>
>        <59>   DW_AT_lower_bound : 0
>        <5a>   DW_AT_upper_bound : 128
> 
> The array index type is, by construction with the DWARF standard,
> a subrange of our enumeration type, defined as follow:
> 
>     <2><5b>: Abbrev Number: 0
>     <1><5c>: Abbrev Number: 7 (DW_TAG_enumeration_type)
>        <5d>   DW_AT_name        : pck__enum_t
>        <69>   DW_AT_byte_size   : 1
>     <2><6b>: Abbrev Number: 8 (DW_TAG_enumerator)
>        <6c>   DW_AT_name        : pck__enum_000
>        <7a>   DW_AT_const_value : 0
>     [etc]
> 
> Therefore, while processing these DIEs, the array index type ends
> up being a TYPE_CODE_RANGE whose target type is our enumeration type.
> But the problem is that we read the upper bound as a negative value
> (-128), which is then used as is by the type printer to print the
> array upper bound. This negative value explains the "-128" in the
> output.
> 
> To understand why the range type's upper bound is read as a negative
> value, one needs to look at how it is determined, in read_subrange_type:
> 
>   orig_base_type = die_type (die, cu);
>   base_type = check_typedef (orig_base_type);
>   [... high is first correctly read as 128, but then ...]
>   if (!TYPE_UNSIGNED (base_type) && (high & negative_mask))
>     high |= negative_mask;
> 
> The negative_mask is applied, here, because BASE_TYPE->FLAG_UNSIGNED
> is not set. And the reason for that is because the base_type was only
> partially constructed during the call to die_type. While the enum
> is constructed on the fly by read_enumeration_type, its flag_unsigned
> flag is only set later on, while creating the symbols corresponding to
> the enum type's enumerators (see process_enumeration_scope), after
> we've already finished creating our range type - and therefore too
> late.
> 
> My first naive attempt at fixing this problem consisted in extracting
> the part in process_enumeration_scope which processes all enumerators,
> to generate the associated symbols, but more importantly set the type's
> various flags when necessary. However, this does not always work well,
> because we're still in the subrange_type's scope, and it might be
> different from the scope where the enumeration type is defined.
> 
> So, instead, what this patch does to fix the issue is to extract
> from process_enumeration_scope the part that determines whether
> the enumeration type should have the flag_unsigned and/or the
> flag_flag_enum flags set. It turns out that, aside from the code
> implementing the loop, this part is fairly independent of the symbol
> creation. With that part extracted, we can then use it at the end
> of our enumeration type creation, to produce a type which should now
> no longer need any adjustment.
> 
> Once the enumeration type produced is correctly marked as unsigned,
> the subrange type's upper bound is then correctly read as an unsigned
> value, therefore giving us an upper bound of 128 instead of -128.
> 
> gdb/ChangeLog:
> 
>         * dwarf2read.c (update_enumeration_type_from_children): New
>         function, mostly extracted from process_structure_scope.
>         (read_enumeration_type): Call update_enumeration_type_from_children.
>         (process_enumeration_scope): Do not set THIS_TYPE's flag_unsigned
>         and flag_flag_enum fields.
> 
> gdb/testsuite/ChangeLog:
> 
>         * gdb.dwarf2/arr-subrange.c, gdb.dwarf2/arr-subrange.exp: New files.
> 
> Tested on x86_64-linux.  Ok to commit?
> 
> Thanks,
> -- 
> Joel
> 
> ---
>  gdb/dwarf2read.c                          | 82 ++++++++++++++++++++-----
>  gdb/testsuite/gdb.dwarf2/arr-subrange.c   | 20 +++++++
>  gdb/testsuite/gdb.dwarf2/arr-subrange.exp | 99 +++++++++++++++++++++++++++++++
>  3 files changed, 185 insertions(+), 16 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.dwarf2/arr-subrange.c
>  create mode 100644 gdb/testsuite/gdb.dwarf2/arr-subrange.exp
> 
> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
> index 54c538a..ba7623f 100644
> --- a/gdb/dwarf2read.c
> +++ b/gdb/dwarf2read.c
> @@ -13080,6 +13080,69 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
>      new_symbol (die, type, cu);
>  }
>  
> +/* Assuming DIE is an enumeration type, and TYPE is its associated type,
> +   update TYPE using some information only available in DIE's children.  */
> +
> +static void
> +update_enumeration_type_from_children (struct die_info *die,
> +				       struct type *type,
> +				       struct dwarf2_cu *cu)
> +{
> +  struct obstack obstack;
> +  struct die_info *child_die = die->child;
> +  int unsigned_enum = 1;
> +  int flag_enum = 1;
> +  ULONGEST mask = 0;
> +  struct cleanup *old_chain;
> +
> +  obstack_init (&obstack);
> +  old_chain = make_cleanup_obstack_free (&obstack);
> +
> +  while (child_die != NULL && child_die->tag)
> +    {
> +      struct attribute *attr;
> +      LONGEST value;
> +      const gdb_byte *bytes;
> +      struct dwarf2_locexpr_baton *baton;
> +      const char *name;
> +      if (child_die->tag != DW_TAG_enumerator)
> +	continue;
> +
> +      attr = dwarf2_attr (child_die, DW_AT_const_value, cu);
> +      if (attr == NULL)
> +	continue;
> +
> +      name = dwarf2_name (child_die, cu);
> +      if (name == NULL)
> +	name = "<anonymous enumerator>";
> +
> +      dwarf2_const_value_attr (attr, type, name, &obstack, cu,
> +			       &value, &bytes, &baton);
> +      if (value < 0)
> +	{
> +	  unsigned_enum = 0;
> +	  flag_enum = 0;
> +	}
> +      else if ((mask & value) != 0)
> +	flag_enum = 0;
> +      else
> +	mask |= value;
> +
> +      /* If we already know that the enum type is neither unsigned, nor
> +	 a flag type, no need to look at the rest of the enumerates.  */
> +      if (!unsigned_enum && !flag_enum)
> +	break;
> +      child_die = sibling_die (child_die);
> +    }
> +
> +  if (unsigned_enum)
> +    TYPE_UNSIGNED (type) = 1;
> +  if (flag_enum)
> +    TYPE_FLAG_ENUM (type) = 1;
> +
> +  do_cleanups (old_chain);
> +}
> +
>  /* Given a DW_AT_enumeration_type die, set its type.  We do not
>     complete the type's fields yet, or create any symbols.  */
>  
> @@ -13129,6 +13192,9 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
>    if (die_is_declaration (die, cu))
>      TYPE_STUB (type) = 1;
>  
> +  /* Finish the creation of this type by using the enum's children.  */
> +  update_enumeration_type_from_children (die, type, cu);
> +
>    return set_die_type (die, type, cu);
>  }
>  
> @@ -13153,10 +13219,7 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
>        struct symbol *sym;
>        struct field *fields = NULL;
>        int num_fields = 0;
> -      int unsigned_enum = 1;
>        const char *name;
> -      int flag_enum = 1;
> -      ULONGEST mask = 0;
>  
>        child_die = die->child;
>        while (child_die && child_die->tag)
> @@ -13171,15 +13234,6 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
>  	      if (name)
>  		{
>  		  sym = new_symbol (child_die, this_type, cu);
> -		  if (SYMBOL_VALUE (sym) < 0)
> -		    {
> -		      unsigned_enum = 0;
> -		      flag_enum = 0;
> -		    }
> -		  else if ((mask & SYMBOL_VALUE (sym)) != 0)
> -		    flag_enum = 0;
> -		  else
> -		    mask |= SYMBOL_VALUE (sym);
>  
>  		  if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0)
>  		    {
> @@ -13210,10 +13264,6 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
>  		  sizeof (struct field) * num_fields);
>  	  xfree (fields);
>  	}
> -      if (unsigned_enum)
> -	TYPE_UNSIGNED (this_type) = 1;
> -      if (flag_enum)
> -	TYPE_FLAG_ENUM (this_type) = 1;
>      }
>  
>    /* If we are reading an enum from a .debug_types unit, and the enum
> diff --git a/gdb/testsuite/gdb.dwarf2/arr-subrange.c b/gdb/testsuite/gdb.dwarf2/arr-subrange.c
> new file mode 100644
> index 0000000..978ef8d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/arr-subrange.c
> @@ -0,0 +1,20 @@
> +/* Copyright 2014 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +int
> +main (void)
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.dwarf2/arr-subrange.exp b/gdb/testsuite/gdb.dwarf2/arr-subrange.exp
> new file mode 100644
> index 0000000..9847c13
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/arr-subrange.exp
> @@ -0,0 +1,99 @@
> +# Copyright 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +load_lib dwarf.exp
> +
> +# This test can only be run on targets which support DWARF-2 and use gas.
> +if {![dwarf2_support]} {
> +    return 0
> +}
> +
> +standard_testfile arr-subrange.c arr-subrange-dw.S
> +
> +# Make some DWARF for the test.
> +set asm_file [standard_output_file $srcfile2]
> +Dwarf::assemble $asm_file {
> +    cu {} {
> + 	DW_TAG_compile_unit {
> +                {DW_AT_language @DW_LANG_Ada95}
> +                {DW_AT_name     foo.adb}
> +                {DW_AT_comp_dir /tmp}
> +                {DW_AT_low_pc   0x1000}
> +                {DW_AT_high_pc  0x2000}
> +            } {
> +	    declare_labels boolean_label typedef_label array_label enum_label
> +
> +            boolean_label: DW_TAG_base_type {
> +                {DW_AT_byte_size 1 DW_FORM_sdata}
> +                {DW_AT_encoding  @DW_ATE_boolean}
> +                {DW_AT_name      boolean}
> +            }
> +
> +            typedef_label: DW_TAG_typedef {
> +                {DW_AT_name pck__table}
> +                {DW_AT_type :$array_label}
> +            }
> +
> +	    array_label: DW_TAG_array_type {
> +		{DW_AT_name pck__table}
> +		{DW_AT_type :$boolean_label}
> +	    } {
> +		DW_TAG_subrange_type {
> +		    {DW_AT_type        :$enum_label}
> +		    {DW_AT_lower_bound 0   DW_FORM_data1}
> +		    {DW_AT_upper_bound 128 DW_FORM_data1}
> +		}
> +	    }
> +
> +	    enum_label: DW_TAG_enumeration_type {
> +		{DW_AT_name      pck__enum_t}
> +                {DW_AT_byte_size 1 DW_FORM_sdata}
> +            } {
> +                DW_TAG_enumerator {
> +                    {DW_AT_name        pck__enum_000}
> +                    {DW_AT_const_value 0 DW_FORM_sdata}
> +                }
> +                DW_TAG_enumerator {
> +                    {DW_AT_name        pck__enum_001}
> +                    {DW_AT_const_value 1 DW_FORM_sdata}
> +                }
> +                DW_TAG_enumerator {
> +                    {DW_AT_name        pck__enum_128}
> +                    {DW_AT_const_value 128 DW_FORM_sdata}
> +                }
> +	    }
> +	}
> +    }
> +}
> +
> +if  {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \
> +	  object {nodebug}] != ""} {
> +    return -1
> +}
> +
> +if  {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} {
> +    return -1
> +}
> +
> +if  {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \
> +	  "${binfile}" executable {}] != ""} {
> +    return -1
> +}
> +
> +clean_restart ${testfile}
> +
> +gdb_test_no_output "set language ada"
> +
> +gdb_test "ptype pck.table" \
> +         "type = array \\(enum_000 \\.\\. enum_128\\) of boolean"
> -- 
> 1.8.3.2

-- 
Joel



More information about the Gdb-patches mailing list