diff options
author | Pedro F. Giffuni <pfg@FreeBSD.org> | 2013-07-26 00:28:19 +0000 |
---|---|---|
committer | Pedro F. Giffuni <pfg@FreeBSD.org> | 2013-07-26 00:28:19 +0000 |
commit | c7cdfecc89a74be5407ba79d8c10d2257660e2ef (patch) | |
tree | 3835e545a57881bdfab8b9c6b637002224d90e6d /cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c | |
parent | f1bd660622f79e7493b62544e9230fd983f935dc (diff) | |
download | src-c7cdfecc89a74be5407ba79d8c10d2257660e2ef.tar.gz src-c7cdfecc89a74be5407ba79d8c10d2257660e2ef.zip |
Fix a segfault in ctfmerge due to a bug in gcc.
GCC can generate bogus dwarf attributes with DW_AT_byte_size
set to 0xFFFFFFFF.
The issue was originaly detected in NetBSD but it has been
adapted for portability and to avoid compiler warnings.
Reference:
https://www.illumos.org/issues/3776
Obtained from: NetBSD
MFC after: 1 month
Notes
Notes:
svn path=/head/; revision=253661
Diffstat (limited to 'cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c')
-rw-r--r-- | cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c index 19aeff2c7942..c7f785eb0446 100644 --- a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c +++ b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c @@ -674,6 +674,13 @@ die_array_create(dwarf_t *dw, Dwarf_Die arr, Dwarf_Off off, tdesc_t *tdp) tdesc_t *dimtdp; int flags; + /* Check for bogus gcc DW_AT_byte_size attribute */ + if (uval == (unsigned)-1) { + printf("dwarf.c:%s() working around bogus -1 DW_AT_byte_size\n", + __func__); + uval = 0; + } + tdp->t_size = uval; /* @@ -760,6 +767,12 @@ die_enum_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off, tdesc_t *tdp) tdp->t_type = ENUM; (void) die_unsigned(dw, die, DW_AT_byte_size, &uval, DW_ATTR_REQ); + /* Check for bogus gcc DW_AT_byte_size attribute */ + if (uval == (unsigned)-1) { + printf("dwarf.c:%s() working around bogus -1 DW_AT_byte_size\n", + __func__); + uval = 0; + } tdp->t_size = uval; if ((mem = die_child(dw, die)) != NULL) { @@ -873,7 +886,7 @@ static void die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp, int type, const char *typename) { - Dwarf_Unsigned sz, bitsz, bitoff; + Dwarf_Unsigned sz, bitsz, bitoff, maxsz=0; Dwarf_Die mem; mlist_t *ml, **mlastp; iidesc_t *ii; @@ -929,6 +942,8 @@ die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp, ml->ml_name = NULL; ml->ml_type = die_lookup_pass1(dw, mem, DW_AT_type); + debug(3, "die_sou_create(): ml_type = %p t_id = %d\n", + ml->ml_type, ml->ml_type->t_id); if (die_mem_offset(dw, mem, DW_AT_data_member_location, &mloff, 0)) { @@ -956,8 +971,24 @@ die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp, *mlastp = ml; mlastp = &ml->ml_next; + + /* Find the size of the largest member to work around a gcc + * bug. See GCC Bugzilla 35998. + */ + if (maxsz < ml->ml_size) + maxsz = ml->ml_size; + } while ((mem = die_sibling(dw, mem)) != NULL); + /* See if we got a bogus DW_AT_byte_size. GCC will sometimes + * emit this. + */ + if (sz == (unsigned)-1) { + printf("dwarf.c:%s() working around bogus -1 DW_AT_byte_size\n", + __func__); + tdp->t_size = maxsz / 8; /* maxsz is in bits, t_size is bytes */ + } + /* * GCC will attempt to eliminate unused types, thus decreasing the * size of the emitted dwarf. That is, if you declare a foo_t in your @@ -1054,7 +1085,7 @@ die_sou_resolve(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private) } if (ml->ml_size != 0 && mt->t_type == INTRINSIC && - mt->t_intr->intr_nbits != ml->ml_size) { + mt->t_intr->intr_nbits != (int)ml->ml_size) { /* * This member is a bitfield, and needs to reference * an intrinsic type with the same width. If the @@ -1370,6 +1401,13 @@ die_base_create(dwarf_t *dw, Dwarf_Die base, Dwarf_Off off, tdesc_t *tdp) */ (void) die_unsigned(dw, base, DW_AT_byte_size, &sz, DW_ATTR_REQ); + /* Check for bogus gcc DW_AT_byte_size attribute */ + if (sz == (unsigned)-1) { + printf("dwarf.c:%s() working around bogus -1 DW_AT_byte_size\n", + __func__); + sz = 0; + } + if (tdp->t_name == NULL) terminate("die %llu: base type without name\n", off); |