Re: how to support C type qualifiers applied to arrays?

Jim Blandy
2006-12-15T22:36:28Z

"Gary Funck" <gary@intrepid.com> writes:
> The main difficulty is that GCC doesn't create new qualified
> types for declarations. Rather, it sets TREE_READONLY()
> and TREE_THIS_VOLATILE() in the DECL node for declarations
> such as:
>
> volatile int A[10];

Ugh. That's a shame. Can't dwarf2out.c fix things up as it builds
the tree of struct die_structs from the GCC 'tree' type tree?

> Structures add an additional wrinkle:
>
> struct s_struct
> {
> int a;
> float b;
> char c[10];
> };
> volatile struct s_struct S;
>
> Here, GCC sets TREE_THIS_VOLATILE in the DECL node of S,
> but does not attempt to clone the type description of
> s_struct, and to populate the volatile qualifier across all
> contained member types. This works for GCC because it
> propagates the qualifiers as it evaluates expressions.
> Thus when evaluating S.c[10], GCC starts with the knowledge
> that S is volatile, thus S.c is volatile, and S.c[1] is
> volatile.

Okay --- this is a different problem altogether. This one is indeed
GDB's fault: referring to a field of a volatile- or const-qualified
structure should get you a member with the same qualifiers. ISO/IEC
9899:1999 (E), 6.5.2.3 paragraph 3 says:

A postfix expression followed by the . operator and an identifier
designates a member of a structure or union object. The value is
that of the named member, and is an lvalue if the first expression
is an lvalue. If the first expression has qualified type, the
result has the so-qualified version of the type of the designated
member.

GDB doesn't implement the behavior described in that that last
sentence.

GCC, however, is producing the right DWARF for this (in Fedora Core
5, at least):

$ cat volatile-struct.c
struct s_struct
{
int a;
float b;
char c[10];
};
volatile struct s_struct S;
$ gcc -c -g volatile-struct.c
$ readelf -wi volatile-struct.o
The section .debug_info contains:

Compilation Unit @ offset 0x0:
Length: 226
Version: 2
Abbrev Offset: 0
Pointer Size: 4
<0>: Abbrev Number: 1 (DW_TAG_compile_unit)
DW_AT_stmt_list : 0
DW_AT_high_pc : 0
DW_AT_low_pc : 0
DW_AT_producer : GNU C 4.1.1 20060525 (Red Hat 4.1.1-1)
DW_AT_language : 1 (ANSI C)
DW_AT_name : volatile-struct.c
DW_AT_comp_dir : /home/jimb/play
<1><62>: Abbrev Number: 2 (DW_TAG_structure_type)
DW_AT_sibling : <98>
DW_AT_name : s_struct
DW_AT_byte_size : 20
DW_AT_decl_file : 1
DW_AT_decl_line : 2
<2><73>: Abbrev Number: 3 (DW_TAG_member)
DW_AT_name : a
DW_AT_decl_file : 1
DW_AT_decl_line : 3
DW_AT_type : <98>
DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
<2><7f>: Abbrev Number: 3 (DW_TAG_member)
DW_AT_name : b
DW_AT_decl_file : 1
DW_AT_decl_line : 4
DW_AT_type : <9f>
DW_AT_data_member_location: 2 byte block: 23 4 (DW_OP_plus_uconst: 4)
<2><8b>: Abbrev Number: 3 (DW_TAG_member)
DW_AT_name : c
DW_AT_decl_file : 1
DW_AT_decl_line : 5
DW_AT_type : <a8>
DW_AT_data_member_location: 2 byte block: 23 8 (DW_OP_plus_uconst: 8)
<1><98>: Abbrev Number: 4 (DW_TAG_base_type)
DW_AT_name : int
DW_AT_byte_size : 4
DW_AT_encoding : 5 (signed)
<1><9f>: Abbrev Number: 4 (DW_TAG_base_type)
DW_AT_name : float
DW_AT_byte_size : 4
DW_AT_encoding : 4 (float)
<1><a8>: Abbrev Number: 5 (DW_TAG_array_type)
DW_AT_sibling : <b8>
DW_AT_type : <c8>
<2><b1>: Abbrev Number: 6 (DW_TAG_subrange_type)
DW_AT_type : <b8>
DW_AT_upper_bound : 9
<1><b8>: Abbrev Number: 4 (DW_TAG_base_type)
DW_AT_name : unsigned int
DW_AT_byte_size : 4
DW_AT_encoding : 7 (unsigned)
<1><c8>: Abbrev Number: 4 (DW_TAG_base_type)
DW_AT_name : char
DW_AT_byte_size : 1
DW_AT_encoding : 6 (signed char)
<1><d0>: Abbrev Number: 7 (DW_TAG_variable)
DW_AT_name : S
DW_AT_decl_file : 1
DW_AT_decl_line : 7
DW_AT_type : <e0>
DW_AT_external : 1
DW_AT_location : 5 byte block: 3 0 0 0 0 (DW_OP_addr: 0)
<1><e0>: Abbrev Number: 8 (DW_TAG_volatile_type)
DW_AT_type : <62>

$

Note that we've got (making up some notation, but I think it's clear
enough):

variable "S" {
type: &volatile_type {
type: &structure_type "s_struct" { ... }
}
}

Which is exactly what it should be: a volatile qualifier applied to a
structure type. The DWARF info should not contain a separate instance
of s_struct with volatile qualifiers propagated down to all its
members; that's GDB's job.

But as we've agreed before, the debug info for the array case you
originally posted is wrong:

$ cat volatile-array.c
volatile int A[10];
$ gcc -g -c volatile-array.c
$ readelf -wi volatile-array.o
The section .debug_info contains:

Compilation Unit @ offset 0x0:
Length: 154
Version: 2
Abbrev Offset: 0
Pointer Size: 4
<0>: Abbrev Number: 1 (DW_TAG_compile_unit)
DW_AT_stmt_list : 0
DW_AT_high_pc : 0
DW_AT_low_pc : 0
DW_AT_producer : GNU C 4.1.1 20060525 (Red Hat 4.1.1-1)
DW_AT_language : 1 (ANSI C)
DW_AT_name : volatile-array.c
DW_AT_comp_dir : /home/jimb/play
<1><61>: Abbrev Number: 2 (DW_TAG_array_type)
DW_AT_sibling : <71>
DW_AT_type : <81>
<2><6a>: Abbrev Number: 3 (DW_TAG_subrange_type)
DW_AT_type : <71>
DW_AT_upper_bound : 9
<1><71>: Abbrev Number: 4 (DW_TAG_base_type)
DW_AT_name : unsigned int
DW_AT_byte_size : 4
DW_AT_encoding : 7 (unsigned)
<1><81>: Abbrev Number: 4 (DW_TAG_base_type)
DW_AT_name : int
DW_AT_byte_size : 4
DW_AT_encoding : 5 (signed)
<1><88>: Abbrev Number: 5 (DW_TAG_variable)
DW_AT_name : A
DW_AT_decl_file : 1
DW_AT_decl_line : 1
DW_AT_type : <98>
DW_AT_external : 1
DW_AT_location : 5 byte block: 3 0 0 0 0 (DW_OP_addr: 0)
<1><98>: Abbrev Number: 6 (DW_TAG_volatile_type)
DW_AT_type : <61>

$

The DWARF type should reflect 'volatile' applied to the element type,
as it's written in the C code:

variable "A" {
type: &array_type {
type: &volatile_type {
type: &base_type "int" { ... }
}
}
}

whereas the DWARF above is:

variable "A" {
type: &volatile_type {
type: &array_type {
type: base_type "int" { ... }
}
}
}

> For GCC to fix the problem, it need to rewrite the type
> definition for the type of S, along these lines:
>
> typedef volatile int v_int;
> typedef volatile float v_float;
> typedef volatile char v_char;
> struct v_s_struct
> {
> v_int a;
> v_float b;
> v_char c[10];
> };
> typedef volatile struct v_s_struct v_s_t;
> v_s_t S;
>
> Typedefs above are used to illustrate that "volatile" must
> be factored to the lowest level types of the components,
> and must also appear at the struct level to accommodate
> operations on the entire structure.

Just to be clear: GCC should *not* perform the transformation you're
suggesting here and record the result in the DWARF info. GDB should
propagate the qualifiers itself.