[was: ctf: use HOST_WIDE_INT for type bit sizes
https://gcc.gnu.org/pipermail/gcc-patches/2025-August/693262.html
Changed from previous:
- Fix similar truncation in member offset translation
- Restrict test to 64-bit targets ]
DWARF to CTF translation for type bit sizes was using uint32_t, and for
member offsets was inadvertently using unsigned int via get_AT_unsigned.
For very large struct types, at least one of these could be truncated
causing incorrect encoding of the struct type and member offsets.
Use HOST_WIDE_INT to avoid these truncation issues and fix the encoding
for large structs.
Tested on x86_64-pc-linux-gnu and that host for aarch64 and
arm cortex-m3 cross targets.
PR debug/121411
gcc/
* dwarf2ctf.cc (ctf_get_AT_data_member_location) Use AT_unsigned
when fetching AT_bit_offset and AT_data_member_location. Simplify.
(ctf_die_bitsize): Return unsigned HOST_WIDE_INT instead of
uint32_t.
(gen_ctf_base_type, gen_ctf_sou_type, gen_ctf_enumeration_type):
Adapt accordingly.
gcc/testsuite/
* gcc.dg/debug/ctf/ctf-struct-3.c: New test.
---
gcc/dwarf2ctf.cc | 34 +++++++++----------
gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c | 32 +++++++++++++++++
2 files changed, 48 insertions(+), 18 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c
diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc
index f8b305b6c4a..4b49b23f078 100644
--- a/gcc/dwarf2ctf.cc
+++ b/gcc/dwarf2ctf.cc
@@ -87,8 +87,8 @@ ctf_get_AT_data_member_location (dw_die_ref die)
/* The field location (in bits) can be determined from
either a DW_AT_data_member_location attribute or a
DW_AT_data_bit_offset attribute. */
- if (get_AT (die, DW_AT_data_bit_offset))
- field_location = get_AT_unsigned (die, DW_AT_data_bit_offset);
+ if ((attr = get_AT (die, DW_AT_data_bit_offset)))
+ field_location = AT_unsigned (attr);
else
{
attr = get_AT (die, DW_AT_data_member_location);
@@ -102,16 +102,12 @@ ctf_get_AT_data_member_location (dw_die_ref die)
== dw_val_class_unsigned_const);
field_location = descr->dw_loc_oprnd1.v.val_unsigned * 8;
}
- else
- {
- attr = get_AT (die, DW_AT_data_member_location);
- if (attr && AT_class (attr) == dw_val_class_const)
- field_location = AT_int (attr) * 8;
- else
- field_location = (get_AT_unsigned (die,
- DW_AT_data_member_location)
- * 8);
- }
+ else if (attr && AT_class (attr) == dw_val_class_const)
+ field_location = AT_int (attr) * 8;
+ else if (attr)
+ field_location = AT_unsigned (attr) * 8;
+
+ /* Otherwise the location is non-existant, e.g. for union members. */
}
return field_location;
@@ -199,7 +195,7 @@ gen_ctf_unknown_type (ctf_container_ref ctfc)
If no DW_AT_byte_size nor DW_AT_bit_size are defined, this function
returns 0. */
-static uint32_t
+static unsigned HOST_WIDE_INT
ctf_die_bitsize (dw_die_ref die)
{
dw_attr_node *attr_byte_size = get_AT (die, DW_AT_byte_size);
@@ -225,7 +221,9 @@ gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
ctf_encoding_t ctf_encoding = {0, 0, 0};
unsigned int encoding = get_AT_unsigned (type, DW_AT_encoding);
- unsigned int bit_size = ctf_die_bitsize (type);
+ /* Bit size for the base types handled here should never be extremely large
+ (BITSIZE_MAXWIDTH at the upper end for _BitInt). */
+ unsigned int bit_size = (unsigned int) ctf_die_bitsize (type);
const char * name_string = get_AT_string (type, DW_AT_name);
switch (encoding)
@@ -514,7 +512,7 @@ gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref
modifier)
static ctf_dtdef_ref
gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
{
- uint32_t bit_size = ctf_die_bitsize (sou);
+ unsigned HOST_WIDE_INT bit_size = ctf_die_bitsize (sou);
int declaration_p = get_AT_flag (sou, DW_AT_declaration);
const char *sou_name = get_AT_string (sou, DW_AT_name);
@@ -564,7 +562,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou,
uint32_t kind)
{
dw_attr_node *attr;
HOST_WIDE_INT bitpos = 0;
- HOST_WIDE_INT bitsize = ctf_die_bitsize (c);
+ unsigned HOST_WIDE_INT bitsize = ctf_die_bitsize (c);
HOST_WIDE_INT bit_offset;
/* The bit offset is given in bits and it may be
@@ -581,7 +579,7 @@ gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou,
uint32_t kind)
bitpos = field_location + bit_offset;
else
{
- HOST_WIDE_INT bit_size;
+ unsigned HOST_WIDE_INT bit_size;
attr = get_AT (c, DW_AT_byte_size);
if (attr)
@@ -730,7 +728,7 @@ static ctf_dtdef_ref
gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
{
const char *enum_name = get_AT_string (enumeration, DW_AT_name);
- unsigned int bit_size = ctf_die_bitsize (enumeration);
+ unsigned HOST_WIDE_INT bit_size = ctf_die_bitsize (enumeration);
unsigned int signedness = get_AT_unsigned (enumeration, DW_AT_encoding);
int declaration_p = get_AT_flag (enumeration, DW_AT_declaration);
diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c
b/gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c
new file mode 100644
index 00000000000..bf0be87c7c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-struct-3.c
@@ -0,0 +1,32 @@
+/* PR debug/121411.
+ Test for compilation of very large struct types.
+ The ctt_size for the struct shall encode CTF_LSIZE_SENT to indicate the
+ large struct encoding is used. */
+
+/* { dg-do compile { target { lp64 || llp64 } } } */
+/* { dg-options "-O0 -gctf -dA" } */
+
+struct huge
+{ /* bit offset */
+ unsigned char a1[0xffffffff]; /* 0 */
+ unsigned char a2[0xffffffff]; /* 7fffffff8 */
+ char x; /* ffffffff0 */
+ char y; /* ffffffff8 */
+ char z; /* 1000000000 */
+};
+
+struct huge v;
+
+/* Verify struct is encoded with large type encoding format. */
+/* { dg-final { scan-assembler-times "0x1a000005\[\t \]+\[^\n\]*ctt_info" 1 }
} */
+/* { dg-final { scan-assembler-times "0xffffffff\[\t \]+\[^\n\]*ctt_size" 1 }
} */
+/* { dg-final { scan-assembler-times "0x2\[\t \]+\[^\n\]*ctt_lsizehi" 1 } } */
+/* { dg-final { scan-assembler-times "ctt_lsizelo" 1 } } */
+
+/* Verify member offsets are correct for large offsets. */
+/* { dg-final { scan-assembler-times "0x7\[\t \]+\[^\n\]*ctlm_offsethi" 1 } }
*/
+/* { dg-final { scan-assembler-times "0xf\[\t \]+\[^\n\]*ctlm_offsethi" 2 } }
*/
+/* { dg-final { scan-assembler-times "0x10\[\t \]+\[^\n\]*ctlm_offsethi" 1 } }
*/
+
+/* { dg-final { scan-assembler-times "0xfffffff8\[\t \]+\[^\n\]*ctlm_offsetlo"
2 } } */
+/* { dg-final { scan-assembler-times "0xfffffff0\[\t \]+\[^\n\]*ctlm_offsetlo"
1 } } */
--
2.47.2