This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

tracking a dwarf-print --output issue


Hi,

Haven't been making much progress on dwarfcmp and dwarf_output. But
mostly because of catching up on my c++ knowledge. My template-foo is
still a little weak. The caching bug example is a little tricky to track
down because of the interaction between the comparator and dwarf_output.
So I was searching for an example that could be shown by just
dwarf-print --output. Here is an issue that shows up with dwarf-print
--output that seems different from the caching bug. But I haven't made
much progress on it. Lets explain what I am seeing and maybe that makes
things more clear. This is on the dwarf-hacking branch, because on the
dwarf branch without caching enabled, it will never finish the
dwarf_output part.

$ tests/dwarf-print --output src/dwarfcmp
[... lots of output and then ...]
/usr/lib/gcc/x86_64-redhat-linux/4.4.4/../../../../include/c
++/4.4.4/debug/safe_iterator.h:175:
    error: attempt to dereference a singular iterator.

Objects involved in the operation:
iterator "this" @ 0x0x44a1738 {
type =
N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPKPSt4pairIKN8elfutils12dwarf_output16debug_info_entryENS5_8die_infoEENSt6__norm6vectorISA_SaISA_EEEEENSt7__debug6vectorISA_SF_EEEE (constant iterator);
  state = singular;
}
Aborted (core dumped)

I put the binary here http://mjw.fedorapeople.org/dwarfcmp.gz just in
case it is specific to my build. I haven't been able to find something
smaller that produced the same.

A "singular iterator" is a "null iterator", one which hasn't been
initialized to a value, so dereferencing it isn't possible.

This happens in the wrapped_input_iterator:

#4  0x000000000040edc0 in
elfutils::subr::wrapped_input_iterator<std::__debug::vector<elfutils::dwarf_output::die_info_pair*, std::allocator<elfutils::dwarf_output::die_info_pair*> >, elfutils::dwarf_output::debug_info_entry::children_type::deref, elfutils::dwarf_output::debug_info_entry const>::operator-> (
    this=0x3158738) at /home/mark/src/elfutils/libdw/c++/subr.hh:694

  template<typename arg_type>
  inline wrapped_input_iterator (const _base &i, const arg_type &arg)
    : _base (static_cast<_base> (i)), _m_wrapper (arg)
    {}
[...]
    inline element *operator-> () const
    {
      return &(_m_wrapper (_base::operator* ()));
    }

So this is just the dereference of i. Which is a vector of
dwarf_output::die_info_pair pointers. It would be nice if given this
frame one could easily step into the derefence operator, so one could
more easily see what is going and what an uninitialized iterator really
looks like. But I couldn't figure out how to make gdb to that.

The die_info_pair comes from

#5  0x00000000004386ad in
prewalk_attr<elfutils::dwarf_output::debug_info_entry::attributes_type>
(attr=..., 
    refs=std::tr1::unordered_map with 495 elements = {...})
    at /home/mark/src/elfutils/tests/print-die.cc:214

template<typename attrs_type>
void
prewalk_attr (const typename attrs_type::value_type &attr, refs_map
&refs)
{
  if (attr.second.what_space () == dwarf::VS_reference
      && refs.insert (make_pair (attr.second.reference ()->identity (),
				 next_ref)).second)
    ++next_ref;
}

Although gdb doesn't make it immediately clear this is about the
attr.second reference() call.

(gdb) whatis attr.second
type = elfutils::dwarf_output::attr_value

(gdb) whatis attr.second.reference()
Cannot evaluate function -- may be inlined

But

    class attr_value
      : public dwarf_data::attr_value<dwarf_output, value>

and

    template<class impl, typename vw = value<impl> >
    class attr_value

plus

      typename vw::value_cell_type *_m_value;
      typedef typename impl::debug_info_entry::pointer die_ptr;

defines

      inline const die_ptr &reference () const
      {
	return variant<typename vw::value_reference> ().ref;
      }

      inline die_ptr &reference ()
      {
	return variant<typename vw::value_reference> ().ref;
      }

I admit that I find this pretty hard to read. My c++ template foo is
very weak and the round and angle brackets make my head hurt. But this
is the notation used for template functions. And indeed we have:

      template<typename flavor>
      inline flavor &variant ()
      {
	flavor *p;
	return vw::variant (p, _m_value);
      }

Which seems just a fancy casting template function:

      template<typename flavor>
      static inline flavor &
      variant (flavor *&result, value_dispatch *&value)
      {
	assert (alloc_values);
	if (value == NULL)
	 {
	   result = new flavor;
	   value = result;
	   return *result;
	 }
	result = dynamic_cast<flavor *> (value);
	if (result == NULL)
	  throw std::runtime_error ("wrong value type");
	return *result;
      }

For the dwarf_output value_reference:

      struct value_reference : public value_dispatch
      {
	typedef typename impl::debug_info_entry::pointer value_type;
	value_type ref;

Which indeed has a ref field. So we actually just have a
dwarf_output::debug_info_entry::pointer which seems to be defined as 

      typedef children_type::iterator pointer;

And there we find out vector subclass that contains die_info_pair*s.

      class children_type
	: public std::vector<die_info_pair *>

And that has indeed the identity() function we saw at the start:

      inline dwarf::debug_info_entry::identity_type identity () const
      {
	return (uintptr_t) this;
      }

So it seems that what is really going wrong is that there is an
die_info_pair* element of this vector on which -> identity () doesn't
work because it is NULL/uninitialized.

If we look up the stack a bit more we realize that vector is the
representation of the attributes of the dwarf_output debug_info_entry.
the die printer prewalks the die tree to collect all die attributes
which have reference types to put them in a reference map.

#6  0x00000000004387d5 in
attr_walker<elfutils::dwarf_output::debug_info_entry::attributes_type,
prewalk_attr [with attrs_type =
elfutils::dwarf_output::debug_info_entry::attributes_type]>::walk(const
elfutils::dwarf_output::debug_info_entry::attributes_type &, refs_map &)
(attrs=..., 
    r=std::tr1::unordered_map with 495 elements = {...})
    at /home/mark/src/elfutils/tests/print-die.cc:175
#7  0x0000000000406fe5 in
prewalk_attrs<elfutils::dwarf_output::debug_info_entry::attributes_type>
(attrs=..., 
    refs=std::tr1::unordered_map with 495 elements = {...})
    at /home/mark/src/elfutils/tests/print-die.cc:224
#8  0x0000000000406a53 in prewalk_die<elfutils::dwarf_output> (die=..., 
    refs=std::tr1::unordered_map with 495 elements = {...})
    at /home/mark/src/elfutils/tests/print-die.cc:235
#9  0x000000000040699d in prewalk_die<elfutils::dwarf_output> (die=..., 
    refs=std::tr1::unordered_map with 495 elements = {...})
    at /home/mark/src/elfutils/tests/print-die.cc:233
#10 0x0000000000405cb7 in print_cu<elfutils::dwarf_output> (cu=...,
limit=0, 
    refs=std::tr1::unordered_map with 495 elements = {...})
    at /home/mark/src/elfutils/tests/print-die.cc:303

So the next step is figuring out how this "bad" or uninitialized
reference attribute got put in the attributes list of this DIE.

To be continued when I figure out how these uninitialized values are
represented, so we can catch them earlier when they are put in the
vector itself.

Cheers,

Mark


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]