Module Name: src
Committed By: darran
Date: Tue Jan 10 08:42:22 UTC 2012
Modified Files:
src/external/cddl/osnet/dist/tools/ctf/cvt: ctf.c dwarf.c
Log Message:
Fix a segfault in ctfmerge.
GCC can generate bogus dwarf attributes with DW_AT_byte_size set to 0xFFFFFFFF.
See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35998 .
GCC is currently doing this for external/bsd/tmux/dist/compat/imsg-buffer.c:
readelf -a --debug-dump imsg-buffer.o
...
<2><6e3>: Abbrev Number: 32 (DW_TAG_union_type)
<6e4> DW_AT_byte_size : 0xffffffff
<6e8> DW_AT_decl_file : 1
<6e9> DW_AT_decl_line : 229
<6ea> DW_AT_sibling : <0x705>
This resulted in ctfconvert generating a faulty CTF entry which then caused the
segfault in ctfmerge.
The fix has ctfconvert check for the bogus 0xFFFFFFFF value and works around it.
It also adds some protection to ctfmerge to avoid the segfault and fail
more gracefully if the error should occur in the future.
To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c
cvs rdiff -u -r1.4 -r1.5 src/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c
diff -u src/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c:1.5 src/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c:1.6
--- src/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c:1.5 Thu Mar 11 23:26:33 2010
+++ src/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c Tue Jan 10 08:42:22 2012
@@ -53,6 +53,10 @@
*/
char *curfile;
+
+/* The number of types. */
+static int ntypes=0;
+
#define CTF_BUF_CHUNK_SIZE (64 * 1024)
#define RES_BUF_CHUNK_SIZE (64 * 1024)
@@ -1048,6 +1052,9 @@ resurrect_types(ctf_header_t *h, tdata_t
(*mpp)->ml_type = tdarr[ctm->ctm_type];
(*mpp)->ml_offset = ctm->ctm_offset;
(*mpp)->ml_size = 0;
+ if (ctm->ctm_type > ntypes) {
+ parseterminate("Invalid member type ctm_type=%d", ctm->ctm_type);
+ }
}
} else {
for (i = 0, mpp = &tdp->t_members; i < vlen;
@@ -1064,6 +1071,9 @@ resurrect_types(ctf_header_t *h, tdata_t
(*mpp)->ml_offset =
(int)CTF_LMEM_OFFSET(ctlm);
(*mpp)->ml_size = 0;
+ if (ctlm->ctlm_type > ntypes) {
+ parseterminate("Invalid lmember type ctlm_type=%d", ctlm->ctlm_type);
+ }
}
}
@@ -1177,9 +1187,10 @@ ctf_parse(ctf_header_t *h, caddr_t buf,
{
tdata_t *td = tdata_new();
tdesc_t **tdarr;
- int ntypes = count_types(h, buf);
int idx, i;
+ ntypes = count_types(h, buf);
+
/* shudder */
tdarr = xcalloc(sizeof (tdesc_t *) * (ntypes + 1));
tdarr[0] = NULL;
Index: src/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c
diff -u src/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c:1.4 src/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c:1.5
--- src/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c:1.4 Wed Feb 24 21:53:26 2010
+++ src/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c Tue Jan 10 08:42:22 2012
@@ -678,6 +678,12 @@ die_array_create(dwarf_t *dw, Dwarf_Die
tdesc_t *dimtdp;
int flags;
+ /* Check for bogus gcc DW_AT_byte_size attribute */
+ if (uval == 0xffffffff) {
+ printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+ uval = 0;
+ }
+
tdp->t_size = uval;
/*
@@ -764,6 +770,11 @@ die_enum_create(dwarf_t *dw, Dwarf_Die d
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 == 0xffffffff) {
+ printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+ uval = 0;
+ }
tdp->t_size = uval;
if ((mem = die_child(dw, die)) != NULL) {
@@ -877,7 +888,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;
@@ -933,6 +944,8 @@ die_sou_create(dwarf_t *dw, Dwarf_Die st
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)) {
@@ -960,8 +973,21 @@ die_sou_create(dwarf_t *dw, Dwarf_Die st
*mlastp = ml;
mlastp = &ml->ml_next;
+
+ /* work out the size of the largest member to work around a gcc bug */
+ 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 == 0xffffffff) {
+ printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\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
@@ -1030,7 +1056,7 @@ die_sou_resolve(tdesc_t *tdp, tdesc_t **
if (tdp->t_flags & TDESC_F_RESOLVED)
return (1);
- debug(3, "resolving sou %s\n", tdesc_name(tdp));
+ debug(3, "resolving sou %s [%d]\n", tdesc_name(tdp), tdp->t_id);
for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) {
if (ml->ml_size == 0) {
@@ -1383,6 +1409,12 @@ die_base_create(dwarf_t *dw, Dwarf_Die b
*/
(void) die_unsigned(dw, base, DW_AT_byte_size, &sz, DW_ATTR_REQ);
+ /* Check for bogus gcc DW_AT_byte_size attribute */
+ if (sz == 0xffffffff) {
+ printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+ sz = 0;
+ }
+
if (tdp->t_name == NULL)
terminate("die %llu: base type without name\n", off);