elftoolchain update?
Kai Wang
kaiw27 at gmail.com
Thu Oct 2 09:11:55 UTC 2014
Hello,
Thanks for the backtrace and analysis.
I attached a patch for libdwarf and ctfconvert to fix the crash issue.
The libdwarf patch is the same as Will submitted, it adds check for NULL
attribute.
The ctfconvert patch fixes some issue with die_name(). We can't let
die_name()
return NULL because we need the empty string "" for type name comparison.
Instead I added checks for empty string when creating variables and
functions.
However, this patch only fixes the crash issue. ctfconvert will still fail
and
complains "unresolved types" when invoked on devd (or other C++ objects)
The problem is that ctfconvert doesn't understand any C++ DWARF types,
for example: class, namespace, templates etc. Then I checked the Dtrace
CTF format:
sys/cddl/contrib/opensolaris/uts/common/sys/ctf.h
It seems to me that CTF can only support ANSI C ? Did anyone ever use
Dtrace with C++ program and get debugging info?
/Kai
2014-09-18 20:46 GMT+02:00 Dimitry Andric <dim at freebsd.org>:
> On 18 Sep 2014, at 01:01, Will Andrews <will at freebsd.org> wrote:
> > I see there have been a lot of updates & fixes to elftoolchain since
> > the last import into FreeBSD/head nearly 8 months ago. Are there any
> > plans to update the import?
> >
> > I'm asking because it appears that ctfconvert currently crashes
> > (specifically, due to a bug in dwarf_attrval_unsigned()), if you try
> > to use it on C++ object files.
> >
> > This is easily demonstrated by applying this patch to FreeBSD/head and
> > building sbin/devd with WITH_CTF=1:
> > http://people.freebsd.org/~will/add-ctfconvert-to-cpp-object-files.diff
> >
> > Justin Gibbs (cc'd) posted about this issue in February, and it's
> > still a problem:
> >
> http://lists.freebsd.org/pipermail/freebsd-toolchain/2014-February/001121.html
>
> In that previous thread, I was not able to reproduce any problems with
> ctfconvert or ctfmerge, but I have tried it again just now, and I think
> it is a problem in libdwarf.
>
> The crash goes like this:
>
> Program received signal SIGSEGV, Segmentation fault.
> [Switching to Thread 28803080 (LWP 100196)]
> 0x280bb75d in dwarf_attrval_unsigned (die=0x28941f10, attr=73,
> valp=0xbfbfdea0, err=0xbfbfe0a4) at
> /usr/src/lib/libdwarf/../../contrib/elftoolchain/libdwarf/dwarf_attrval.c:186
> 186 switch (at->at_form) {
> (gdb) bt
> #0 0x280bb75d in dwarf_attrval_unsigned (die=0x28941f10, attr=73,
> valp=0xbfbfdea0, err=0xbfbfe0a4) at
> /usr/src/lib/libdwarf/../../contrib/elftoolchain/libdwarf/dwarf_attrval.c:186
> #1 0x08052a45 in die_attr_ref (dw=0xbfbfe0a0, die=0x28941f10, name=73) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:417
> #2 0x08052844 in die_lookup_pass1 (dw=0xbfbfe0a0, die=0x28941f10,
> name=73) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:476
> #3 0x08052380 in die_variable_create (dw=0xbfbfe0a0, die=0x28941f10,
> off=83907, tdp=0x0) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:1680
> #4 0x08050940 in die_create_one (dw=0xbfbfe0a0, die=0x28941f10) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:1793
> #5 0x0804fa94 in die_create (dw=0xbfbfe0a0, die=0x28941f10) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:1800
> #6 0x0804f368 in dw_read (td=0x2881c040, elf=0x28830040,
> filename=0xbfbfe83e "devd.o") at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:2003
> #7 0x0804eb6e in file_read (td=0x2881c040, filename=0xbfbfe83e "devd.o",
> ignore_non_c=0) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c:115
> #8 0x0804e7ca in main (argc=5, argv=0xbfbfe694) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/ctfconvert.c:236
> (gdb) print at
> $1 = (Dwarf_Attribute) 0x0
>
> Looking at dwarf_attrval_unsigned(), you can see 'at' being NULL-checked
> in line 163, but if the _dwarf_attr_find() call on line 164 then also
> returns NULL, the switch on line 186 will segfault as above:
>
> 140 int
> 141 dwarf_attrval_unsigned(Dwarf_Die die, Dwarf_Half attr,
> Dwarf_Unsigned *valp, Dwarf_Error *err)
> 142 {
> 143 Dwarf_Attribute at;
> ...
> 157 if ((at = _dwarf_attr_find(die, attr)) == NULL && attr !=
> DW_AT_type) {
> 158 DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
> 159 return (DW_DLV_NO_ENTRY);
> 160 }
> 161
> 162 die1 = NULL;
> 163 if (at == NULL &&
> 164 (at = _dwarf_attr_find(die, DW_AT_abstract_origin)) !=
> NULL) {
> ...
> 184 }
> 185
> 186 switch (at->at_form) {
> ...
>
> I'm not sure what kind of error code should be returned when the second
> _dwarf_attr_find() fails, though. Or if that is some sort of problem
> with a symbol? If I go to frame 3 (die_variable_create), the name seems
> to be the empty string, but not a NULL pointer:
>
> (gdb) frame 3
> #3 0x08052380 in die_variable_create (dw=0xbfbfe0a0, die=0x28941f10,
> off=83907, tdp=0x0) at
> /usr/src/cddl/usr.bin/ctfconvert/../../../cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c:1680
> 1680 ii->ii_dtype = die_lookup_pass1(dw, die, DW_AT_type);
> (gdb) print name
> $2 = 0x2892dc90 ""
>
> The name is looked up on line 1674, where nameless objects are supposed
> to be skipped:
>
> 1666 static void
> 1667 die_variable_create(dwarf_t *dw, Dwarf_Die die, Dwarf_Off off,
> tdesc_t *tdp __unused)
> 1668 {
> 1669 iidesc_t *ii;
> 1670 char *name;
> 1671
> 1672 debug(3, "die %llu: creating object definition\n", off);
> 1673
> 1674 if (die_isdecl(dw, die) || (name = die_name(dw, die)) ==
> NULL)
> 1675 return; /* skip prototypes and nameless objects */
> 1676
> 1677 ii = xcalloc(sizeof (iidesc_t));
> 1678 ii->ii_type = die_isglobal(dw, die) ? II_GVAR : II_SVAR;
> 1679 ii->ii_name = name;
> 1680 ii->ii_dtype = die_lookup_pass1(dw, die, DW_AT_type);
>
> However, die_name() does not ever seem to return NULL (the code to
> return the empty string was added by Kai in r261246):
>
> 425 static char *
> 426 die_name(dwarf_t *dw, Dwarf_Die die)
> 427 {
> 428 char *str = NULL;
> 429
> 430 (void) die_string(dw, die, DW_AT_name, &str, 0);
> 431 if (str == NULL)
> 432 str = xstrdup("");
> 433
> 434 return (str);
> 435 }
>
> There are quite a lot of places in this file where the result of
> die_name() is explicitly checked against NULL, so maybe always returning
> an empty string was not such a good idea. It may have been done to
> avoid another segfault.
>
> The way forward is probably to:
> * fix the situation in dwarf_attrval_unsigned(), returning a sensible
> error value if both lookups fail.
> * make die_name() return a NULL pointer again, or explicitly check for
> the empty string in die_variable_create().
>
> -Dimitry
>
>
-------------- next part --------------
Index: cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
===================================================================
--- cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c (revision 272394)
+++ cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c (working copy)
@@ -990,8 +990,7 @@
* info for anon structs, though recent versions are fixed (gcc
* bug 11816).
*/
- if ((ml->ml_name = die_name(dw, mem)) == NULL)
- ml->ml_name = NULL;
+ ml->ml_name = die_name(dw, mem);
ml->ml_type = die_lookup_pass1(dw, mem, DW_AT_type);
debug(3, "die_sou_create(): ml_type = %p t_id = %d\n",
@@ -1132,7 +1131,11 @@
for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) {
if (ml->ml_size == 0) {
mt = tdesc_basetype(ml->ml_type);
-
+ if (mt == NULL) {
+ /* Probably C++ types. */
+ dw->dw_nunres++;
+ return (1);
+ }
if ((ml->ml_size = tdesc_bitsize(mt)) != 0)
continue;
@@ -1594,13 +1597,17 @@
}
}
- if (die_isdecl(dw, die) || (name = die_name(dw, die)) == NULL) {
- /*
- * We process neither prototypes nor subprograms without
- * names.
- */
+ /*
+ * We process neither prototypes nor subprograms without
+ * names.
+ */
+ name = die_name(dw, die);
+ if (*name == '\0') {
+ free(name);
return;
}
+ if (die_isdecl(dw, die))
+ return;
ii = xcalloc(sizeof (iidesc_t));
ii->ii_type = die_isglobal(dw, die) ? II_GFUN : II_SFUN;
@@ -1626,11 +1633,7 @@
if (die_tag(dw, arg) != DW_TAG_formal_parameter)
continue;
- if ((name1 = die_name(dw, arg)) == NULL) {
- terminate("die %llu: func arg %d has no name\n",
- off, ii->ii_nargs + 1);
- }
-
+ name1 = die_name(dw, arg);
if (strcmp(name1, "...") == 0) {
free(name1);
ii->ii_vargs = 1;
@@ -1671,8 +1674,14 @@
debug(3, "die %llu: creating object definition\n", off);
- if (die_isdecl(dw, die) || (name = die_name(dw, die)) == NULL)
- return; /* skip prototypes and nameless objects */
+ /* skip prototypes and nameless objects */
+ name = die_name(dw, die);
+ if (*name == '\0') {
+ free(name);
+ return;
+ }
+ if (die_isdecl(dw, die))
+ return;
ii = xcalloc(sizeof (iidesc_t));
ii->ii_type = die_isglobal(dw, die) ? II_GVAR : II_SVAR;
@@ -1991,7 +2000,8 @@
free(prod);
}
- if ((dw.dw_cuname = die_name(&dw, cu)) != NULL) {
+ dw.dw_cuname = die_name(&dw, cu);
+ if (*dw.dw_cuname != '\0') {
char *base = xstrdup(basename(dw.dw_cuname));
free(dw.dw_cuname);
dw.dw_cuname = base;
Index: contrib/elftoolchain/libdwarf/dwarf_attrval.c
===================================================================
--- contrib/elftoolchain/libdwarf/dwarf_attrval.c (revision 272394)
+++ contrib/elftoolchain/libdwarf/dwarf_attrval.c (working copy)
@@ -160,8 +160,12 @@
}
die1 = NULL;
- if (at == NULL &&
- (at = _dwarf_attr_find(die, DW_AT_abstract_origin)) != NULL) {
+ if (at == NULL) {
+ at = _dwarf_attr_find(die, DW_AT_abstract_origin);
+ if (at == NULL) {
+ DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
+ return (DW_DLV_NO_ENTRY);
+ }
switch (at->at_form) {
case DW_FORM_ref1:
case DW_FORM_ref2:
More information about the freebsd-toolchain
mailing list