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