On 18 Sep 2014, at 01:01, Will Andrews <w...@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

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to