diff options
author | kaiw <kaiw@FreeBSD.org> | 2014-01-20 01:35:14 +0000 |
---|---|---|
committer | kaiw <kaiw@FreeBSD.org> | 2014-01-20 01:35:14 +0000 |
commit | cb3a8568bd4e3f2bf20a1c342c6957d1a568a5df (patch) | |
tree | 0161ffedd29f7d6a703f7ef5caf630097481c8fc /cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c | |
parent | 9ccc946cdb76c29bc6ec126ee139bdc025baf0a3 (diff) | |
download | FreeBSD-src-cb3a8568bd4e3f2bf20a1c342c6957d1a568a5df.zip FreeBSD-src-cb3a8568bd4e3f2bf20a1c342c6957d1a568a5df.tar.gz |
Clang 3.4 will sometimes emit DIE for struct/union member before
emitting the DIE for the type of that member. ctfconvert can not
handle this properly and will calculate a wrong member bit offset.
Same struct/union type from different .o file will be treated as
different types when their member bit offsets are different, and
gets added/merged multiple times. This will in turn cause many other
structs/pointers/typedefs that refer to the duplicated struct/union
gets added/merged multiple times and eventually causes numerous
duplicated CTF types in the kernel.debug file.
The simple workaround here is to make use of DW_AT_byte_size attribute
of the member DIE to calculate the bits occupied by the member's type,
without actually resolving the type.
Diffstat (limited to 'cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c')
-rw-r--r-- | cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c index 8725f15..15060f3 100644 --- a/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c +++ b/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c @@ -938,7 +938,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, maxsz=0; + Dwarf_Unsigned sz, bysz, bitsz, bitoff, maxsz=0; Dwarf_Die mem; mlist_t *ml, **mlastp; iidesc_t *ii; @@ -1013,8 +1013,26 @@ die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp, #if BYTE_ORDER == _BIG_ENDIAN ml->ml_offset += bitoff; #else - ml->ml_offset += tdesc_bitsize(ml->ml_type) - bitoff - - ml->ml_size; + /* + * Note that Clang 3.4 will sometimes generate + * member DIE before generating the DIE for the + * member's type. The code can not handle this + * properly so that tdesc_bitsize(ml->ml_type) will + * return 0 because ml->ml_type is unknown. As a + * result, a wrong member offset will be calculated. + * To workaround this, we can instead try to + * retrieve the value of DW_AT_byte_size attribute + * which stores the byte size of the space occupied + * by the type. If this attribute exists, its value + * should equal to tdesc_bitsize(ml->ml_type)/NBBY. + */ + if (die_unsigned(dw, mem, DW_AT_byte_size, &bysz, 0) && + bysz > 0) + ml->ml_offset += bysz * NBBY - bitoff - + ml->ml_size; + else + ml->ml_offset += tdesc_bitsize(ml->ml_type) - + bitoff - ml->ml_size; #endif } |