private:
typedef dwarf_data::attributes_type<dwarf_output, value> _base;
-
size_t _m_hash;
inline attributes_type ()
protected:
typedef std::vector<die_info_pair *> _base;
-
size_t _m_hash;
inline void set_hash ()
set_hash ();
}
- inline const _base &info () const
- {
- return *this;
- }
-
struct deref
: public std::unary_function<die_info_pair *,
const debug_info_entry &>
inline void reify_children () const;
public:
+ inline const _base &info () const
+ {
+ return *this;
+ }
+
friend class subr::hashed_hasher<children_type>;
typedef subr::hashed_hasher<children_type> hasher;
};
};
- typedef std::vector<debug_info_entry::pointer> die_ref_vect;
-
struct shape_type
{
struct form_constraint_t
friend class subr::hashed_hasher<shape_type>;
typedef subr::hashed_hasher<shape_type> hasher;
- shape_type (const debug_info_entry::pointer &ref,
+ shape_type (const debug_info_entry &die,
const dwarf_output::die_info &info);
inline bool operator== (const shape_type &other) const
struct shape_info
{
+ typedef std::vector<std::reference_wrapper<const debug_info_entry>>
+ die_ref_vect;
+
// We keep list of users of this shape. That will make it
// simpler to evaluate the space trade-offs when we generate
// actual abbrevs from this shape.
die_ref_vect _m_users;
- // Instances. Instance is a sequence of concrete forms in the
- // order matching that of shape_type::_m_attrs. Each shape can
- // produce several instances to ideally cover its users. The
- // second element of the pair is unique code assigned to that
- // instance, or 0 if no code was assigned yet.
- // XXX is size_t enough? Use uintptr_t?
- typedef std::pair<std::vector<int>, size_t> instance_type;
- typedef std::vector<instance_type> instances_type;
- instances_type _m_instances;
+ // Instances. Each shape can produce several instances to
+ // ideally cover its users. The second element of the pair is
+ // unique code assigned to that instance, or 0 if no code was
+ // assigned yet. XXX is size_t enough? Use uintptr_t?
+ struct instance_type
+ {
+ typedef std::map<int, int> forms_type;
+ forms_type forms; // attribute->form
+ size_t code; // or 0 if not assigned yet
+ instance_type () : code (0) {}
+ };
+ typedef std::vector<instance_type> instance_vec;
+ instance_vec _m_instances;
- shape_info (debug_info_entry::pointer ref)
+ shape_info (debug_info_entry const &die)
{
- add_user (ref);
+ add_user (die);
}
- void add_user (debug_info_entry::pointer ref)
+ void add_user (debug_info_entry const &die)
{
- _m_users.push_back (ref);
+ _m_users.push_back (std::ref (die));
}
void instantiate (shape_type const &shape,
+ dwarf_output_collector &col,
bool addr_64, bool dwarf_64);
void build_data (shape_type const &shape,
instance_type const &inst,
section_appender &appender);
};
- typedef std::tr1::unordered_map<shape_type, shape_info,
- shape_type::hasher> shape_map;
- shape_map _m_shapes;
-
typedef debug_info_entry::attributes_type::value_type attribute;
typedef dwarf_data::compile_unit<dwarf_output> compile_unit;
public:
// Constructor for an empty file, can add to its compile_units ().
- inline dwarf_output ()
- : _m_output_built (false)
- {}
+ inline dwarf_output () {}
// Constructor copying CUs from an input file (can be any of dwarf,
// dwarf_edit, or dwarf_output).
inline dwarf_output (const input &dw, dwarf_output_collector &c,
copier<input> maker = copier<input> ())
: _m_units (dw.compile_units (), maker (c))
- , _m_output_built (false)
{}
template<typename file>
bool addr_64, bool big_endian);
void add_shape (debug_info_entry &die, bool last_sibling);
-
- bool _m_output_built;
- void build_output (bool addr_64, bool dwarf_64);
};
// Explicit specializations.
std::queue<value::value_reference *> _m_refs;
std::bitset<2> _m_with_sibling;
unsigned int _m_uses;
- size_t abbrev_code; // Or 0 if unassigned.
- dwarf_output::shape_info::instance_type *instance;
+
+ dwarf_output::shape_info::instance_vec::iterator abbrev_ptr;
inline die_info ()
: _m_refs (), _m_with_sibling (), _m_uses (0)
- , abbrev_code (0)
{}
inline ~die_info ()
}
inline void placed (const debug_info_entry::pointer &ref,
- bool have_sibling)
- {
- ++_m_uses;
- _m_with_sibling[have_sibling] = true;
-
- if (_m_refs.empty ())
- {
- subr::nothing dummy;
- self (new value::value_reference (ref, dummy));
- }
- else
- for (size_t n = _m_refs.size (); n > 0; --n)
- {
- value::value_reference *self_ref = _m_refs.front ();
- self_ref->ref = ref;
- _m_refs.pop ();
- _m_refs.push (self_ref);
- }
-
- /* xxx yyy create shapes afterwards
- shape_type shape (ref, *this);
- shape_map::iterator st = _m_shapes.find (shape);
- if (st != _m_shapes.end ())
- st->second.add_user (&x.first);
- else
- _m_shapes.insert (std::make_pair (shape, shape_info (x)));
- */
- }
+ bool have_sibling);
};
/* This is the wrapper in the guts of a children_type iterator.
/* This is called when a children_type is installed freshly in the collector.
Fill in its back pointers. */
inline void
- dwarf_output::debug_info_entry::children_type::reify_children () const
+ dwarf_output::debug_info_entry::children_type::reify_children() const
{
_base::const_iterator i = _base::begin ();
bool have_sibling = i != _base::end ();
typedef subr::identity_map<die_type, die_info> die_map;
die_map _m_unique;
+ // Set of shapes.
+ typedef std::tr1::unordered_map<dwarf_output::shape_type,
+ dwarf_output::shape_info,
+ dwarf_output::shape_type::hasher>
+ shape_map;
+ shape_map _m_shapes;
+
inline die_info_pair *add_entry (int tag,
const children_type *children,
const attrs_type *attrs)
public:
inline dwarf_output_collector ()
: _m_total (0)
+ , _m_output_built (false)
{}
static void die_stats (const die_map::value_type &elt)
<< " unique of " << _m_total << " total DIEs\n";
std::for_each (_m_unique.begin (), _m_unique.end (), die_stats);
}
+
+ bool _m_output_built;
+ void build_output (bool addr_64, bool dwarf_64);
};
+ inline void
+ dwarf_output::die_info::placed (const debug_info_entry::pointer &ref,
+ bool have_sibling)
+ {
+ ++_m_uses;
+ _m_with_sibling[have_sibling] = true;
+
+ if (_m_refs.empty ())
+ {
+ subr::nothing dummy;
+ self (new value::value_reference (ref, dummy));
+ }
+ else
+ for (size_t n = _m_refs.size (); n > 0; --n)
+ {
+ value::value_reference *self_ref = _m_refs.front ();
+ self_ref->ref = ref;
+ _m_refs.pop ();
+ _m_refs.push (self_ref);
+ }
+ }
+
struct dwarf_output::value::circular_reference
: public dwarf_output::value::value_reference
{
const compile_units::iterator &out)
{
typename tracker::walk into (_m_tracker, in, out);
-
*out = unit_copier (this, *in).final ()->first;
}
}
dwarf_output::shape_type::shape_type
- (const debug_info_entry::pointer &ref,
+ (const debug_info_entry &die,
const dwarf_output::die_info &info)
- : _m_tag (ref->tag ())
- , _m_has_children (ref->has_children ())
+ : _m_tag (die.tag ())
+ , _m_has_children (die.has_children ())
, _m_hash (8675309 << _m_has_children)
{
- if (info._m_with_sibling[true] && ref->has_children ())
+ if (info._m_with_sibling[true] && die.has_children ())
_m_attrs.push_back (DW_AT_sibling);
for (debug_info_entry::attributes_type::const_iterator it
- = ref->attributes ().begin ();
- it != ref->attributes ().end (); ++it)
+ = die.attributes ().begin ();
+ it != die.attributes ().end (); ++it)
_m_attrs.push_back (it->first);
// Sort it, but leave sibling attribute at the beginning.
subr::hash_combine (_m_hash, *it);
}
-namespace
-{
- struct abbreviation
- {
- dwarf_output::die_ref_vect _m_users;
- std::vector <int> _m_forms;
-
- abbreviation (std::vector <int> forms)
- : _m_forms (forms)
- {}
- };
-}
-
namespace
{
template <class Iterator>
void
dwarf_output::shape_info::instantiate
(dwarf_output::shape_type const &shape,
+ dwarf_output_collector &col,
bool addr_64, bool dwarf_64)
{
+ // Prevent instance pointers from invalidation upon push_back.
+ _m_instances.reserve (_m_users.size ());
+
for (die_ref_vect::const_iterator it = _m_users.begin ();
it != _m_users.end (); ++it)
{
instance_type inst;
- debug_info_entry const &die = **it;
+ debug_info_entry const &die = *it;
debug_info_entry::attributes_type const &attribs = die.attributes ();
for (shape_type::attrs_vec::const_iterator at = shape._m_attrs.begin ();
at != shape._m_attrs.end (); ++at)
assert (form != -1);
}
}
- inst.first.push_back (form);
+ inst.forms.insert (std::make_pair (name, form));
}
- std::cout << "Need to add to instance map." << std::endl;
+
+ die_info &i = col._m_unique.find (die)->second;
+ i.abbrev_ptr = _m_instances.end ();
_m_instances.push_back (inst);
}
{
std::back_insert_iterator<section_appender> inserter
= std::back_inserter (appender);
- ::dw_write_uleb128 (inserter, inst.second);
+ ::dw_write_uleb128 (inserter, inst.code);
::dw_write_uleb128 (inserter, shape._m_tag);
*inserter++ = shape._m_has_children ? DW_CHILDREN_yes : DW_CHILDREN_no;
- // We iterate shape attribute map in parallel with instance
- // attribute forms. They are stored in the same order. We get
- // attribute name from attribute map, and concrete form from
- // instance.
- assert (shape._m_attrs.size () == inst.first.size ());
- dwarf_output::shape_type::attrs_vec::const_iterator at
- = shape._m_attrs.begin ();
- for (instance_type::first_type::const_iterator it = inst.first.begin ();
- it != inst.first.end (); ++it)
+ assert (shape._m_attrs.size () == inst.forms.size ());
+ for (instance_type::forms_type::const_iterator it = inst.forms.begin ();
+ it != inst.forms.end (); ++it)
{
// ULEB128 name & form
- ::dw_write_uleb128 (inserter, *at++);
- ::dw_write_uleb128 (inserter, *it);
+ ::dw_write_uleb128 (inserter, it->first);
+ ::dw_write_uleb128 (inserter, it->second);
}
// 0 for name & form to terminate the abbreviation
}
void
-dwarf_output::build_output (bool addr_64, bool dwarf_64)
+dwarf_output_collector::build_output (bool addr_64, bool dwarf_64)
{
size_t code = 0;
- for (dwarf_output::shape_map::iterator it = _m_shapes.begin ();
+ for (die_map::const_iterator it = _m_unique.begin ();
+ it != _m_unique.end (); ++it)
+ {
+ dwarf_output::shape_type shape (it->first, it->second);
+ dwarf_output_collector::shape_map::iterator st
+ = _m_shapes.find (shape);
+ if (st != _m_shapes.end ())
+ st->second.add_user (it->first);
+ else
+ {
+ dwarf_output::shape_info i (it->first);
+ _m_shapes.insert (std::make_pair (shape, i));
+ }
+ }
+
+ for (shape_map::iterator it = _m_shapes.begin ();
it != _m_shapes.end (); ++it)
{
- it->second.instantiate (it->first, addr_64, dwarf_64);
- for (dwarf_output::shape_info::instances_type::iterator jt
+ it->second.instantiate (it->first, *this, addr_64, dwarf_64);
+ for (dwarf_output::shape_info::instance_vec::iterator jt
= it->second._m_instances.begin ();
jt != it->second._m_instances.end (); ++jt)
- jt->second = ++code;
+ jt->code = ++code;
}
_m_output_built = true;
void
dwarf_output::output_debug_abbrev (section_appender &appender,
- __unused dwarf_output_collector &c,
+ dwarf_output_collector &c,
bool addr_64)
{
- if (!_m_output_built)
+ if (!c._m_output_built)
/* xxx we need to decide on dwarf_64 as soon as here. That's not
good. We will probably have to build debug_info and
abbreviations in parallel, and dump abbreviations after
debug_info is done and we know how big the data were. */
- build_output (addr_64, false /* xxx dwarf_64 */);
+ c.build_output (addr_64, false /* xxx dwarf_64 */);
- for (dwarf_output::shape_map::iterator it = _m_shapes.begin ();
- it != _m_shapes.end (); ++it)
- for (dwarf_output::shape_info::instances_type::const_iterator jt
+ for (dwarf_output_collector::shape_map::iterator it = c._m_shapes.begin ();
+ it != c._m_shapes.end (); ++it)
+ for (dwarf_output::shape_info::instance_vec::const_iterator jt
= it->second._m_instances.begin ();
jt != it->second._m_instances.end (); ++jt)
it->second.build_data (it->first, *jt, appender);
cu_local_recomputer (new local_ref_recomputer (cu_start))
{}
- void dump (dwarf_output::debug_info_entry const &die,
+ void dump (dwarf_output::die_info_pair const &info_pair,
gap &sibling_gap,
unsigned level)
{
" ";
static char const *tail = spaces + strlen (spaces);
__attribute__ ((unused)) char const *pad = tail - level * 2;
- //std::cout << pad << "CHILD " << dwarf_tag_string (die.tag ()) << " ";
-
- std::back_insert_iterator <section_appender> inserter
- = std::back_inserter (appender);
-
- /* Find shape instance. XXX We currently have to iterate
- through all the shapes. Fix later. */
- dwarf_output::shape_type const *shape = NULL;
- dwarf_output::shape_info const *info = NULL;
- size_t instance_id = (size_t)-1;
+ dwarf_output::debug_info_entry const &die = info_pair.first;
+ dwarf_output::die_info const &info = info_pair.second;
/*
- for (dwarf_output::shape_map::iterator st = c._m_shapes.begin ();
- st != c._m_shapes.end (); ++st)
- {
- dwarf_output::shape_info::instance_map::const_iterator
- instance_it = st->second._m_instance_map.find (ref);
- if (instance_it != st->second._m_instance_map.end ())
- {
- assert (shape == NULL && info == NULL);
-
- shape = &st->first;
- info = &st->second;
- instance_id = instance_it->second;
- }
- }
+ std::cout << pad << "CHILD " << dwarf_tag_string (die.tag ())
+ << " " << std::flush;
*/
- assert (shape != NULL && info != NULL);
+
+ std::back_insert_iterator <section_appender> inserter
+ = std::back_inserter (appender);
/* Record where the DIE begins. */
die_off [die.offset ()] = appender.size ();
- // xxx handle non-CU-local
/* Our instance. */
- dwarf_output::shape_info::instance_type const &instance
- = info->_m_instances[instance_id];
- size_t code = instance.second;
- ::dw_write_uleb128 (inserter, code);
+ dwarf_output::shape_info::instance_type const &instance = *info.abbrev_ptr;
+ ::dw_write_uleb128 (inserter, instance.code);
//std::cout << " " << code << std::endl;
/* Dump attribute values. */
debug_info_entry::attributes_type const &attribs = die.attributes ();
- std::vector<int>::const_iterator form_it = instance.first.begin ();
- for (dwarf_output::shape_type::attrs_vec::const_iterator
- at = shape->_m_attrs.begin ();
- at != shape->_m_attrs.end (); ++at)
+ for (dwarf_output::shape_info::instance_type::forms_type::const_iterator
+ at = instance.forms.begin (); at != instance.forms.end (); ++at)
{
- int name = *at;
- int form = *form_it++;
+ int name = at->first;
+ int form = at->second;
if (name == DW_AT_sibling)
{
// XXX in fact we want to handle this case just like any
// other CU-local reference. So also use this below (or
- // better reuse single piece of code).
+ // better reuse single piece of code for reference
+ // handling).
size_t gap_size
= ::form_width (form, addr_64, false /* xxx dwarf_64 */);
sibling_gap = gap (appender, gap_size,
dwarf::value_space vs = value.what_space ();
/*
- std::cout << pad << " " << dwarf_attr_string (name)
- << ": " << dwarf_form_string (form) << " ";
+ std::cout << pad << " " << dwarf_attr_string (name)
+ << ": " << dwarf_form_string (form) << " ";
*/
switch (vs)
{
};
//std::cout << std::endl;
}
- assert (form_it == instance.first.end ());
if (!die.children ().empty ())
{
gap my_sibling_gap;
- for (compile_unit::children_type::const_iterator jt
- = die.children ().begin (); jt != die.children ().end (); ++jt)
+ for (std::vector<dwarf_output::die_info_pair *>::const_iterator jt
+ = die.children ().info ().begin ();
+ jt != die.children ().info ().end (); ++jt)
{
if (my_sibling_gap.valid ())
{
- die_backpatch.push_back (std::make_pair (my_sibling_gap,
- jt->offset ()));
+ die_backpatch.push_back
+ (std::make_pair (my_sibling_gap,
+ (*jt)->first.offset ()));
my_sibling_gap = gap ();
}
- dump (*jt, my_sibling_gap, level + 1);
+ dump (**jt, my_sibling_gap, level + 1);
}
*inserter++ = 0;
}
}
};
-void
-dwarf_output::output_debug_info (section_appender &appender,
- __unused dwarf_output_collector &c,
- strtab &debug_str,
- str_backpatch_vec &str_backpatch,
- bool addr_64, bool big_endian)
-{
- /* We request appender directly, because we depend on .alloc method
- being implemented, which is not the case for std containers.
- Alternative approach would use purely random access
- iterator-based solution, which would be considerable amount of
- work (and bugs) and would involve memory overhead for holding all
- these otherwise useless Elf_Data pointers that we've allocated in
- the past. So just ditch it and KISS. */
-
- if (!_m_output_built)
- build_output (addr_64, false /* dwarf_64 */);
-
- std::back_insert_iterator <section_appender> inserter
- = std::back_inserter (appender);
-
- for (compile_units::const_iterator it = _m_units.begin ();
- it != _m_units.end (); ++it)
- {
- // Remember where the unit started for back-patching of size.
- size_t cu_start = appender.size ();
-
- // Unit length.
- gap length_gap (appender, 4 /*XXX dwarf64*/, big_endian);
-
- // Version.
- ::dw_write<2> (appender.alloc (2), 3, big_endian);
-
- // Debug abbrev offset. Use the single abbrev table that we
- // emit at offset 0.
- ::dw_write<4> (appender.alloc (4), 0, big_endian);
-
- // Size in bytes of an address on the target architecture.
- *inserter++ = addr_64 ? 8 : 4;
-
- die_off_map die_off;
- die_backpatch_vec die_backpatch;
-
- //std::cout << "UNIT " << it->_m_cu_die << std::endl;
- gap fake_gap;
- recursive_dumper (*this, appender, debug_str, addr_64,
- die_off, die_backpatch, str_backpatch,
- big_endian, cu_start)
- .dump (*it, fake_gap, 0);
+ void
+ dwarf_output::output_debug_info (section_appender &appender,
+ dwarf_output_collector &c,
+ strtab &debug_str,
+ str_backpatch_vec &str_backpatch,
+ bool addr_64, bool big_endian)
+ {
+ /* We request appender directly, because we depend on .alloc method
+ being implemented, which is not the case for std containers.
+ Alternative approach would use purely random access
+ iterator-based solution, which would be considerable amount of
+ work (and bugs) and would involve memory overhead for holding all
+ these otherwise useless Elf_Data pointers that we've allocated in
+ the past. So just ditch it and KISS. */
+
+ if (!c._m_output_built)
+ c.build_output (addr_64, false /* dwarf_64 */);
+
+ std::back_insert_iterator <section_appender> inserter
+ = std::back_inserter (appender);
+
+ for (compile_units::const_iterator it = _m_units.begin ();
+ it != _m_units.end (); ++it)
+ {
+ // Remember where the unit started for back-patching of size.
+ size_t cu_start = appender.size ();
+
+ // Unit length.
+ gap length_gap (appender, 4 /*XXX dwarf64*/, big_endian);
+
+ // Version.
+ ::dw_write<2> (appender.alloc (2), 3, big_endian);
+
+ // Debug abbrev offset. Use the single abbrev table that we
+ // emit at offset 0.
+ ::dw_write<4> (appender.alloc (4), 0, big_endian);
+
+ // Size in bytes of an address on the target architecture.
+ *inserter++ = addr_64 ? 8 : 4;
+
+ die_off_map die_off;
+ die_backpatch_vec die_backpatch;
+
+ //std::cout << "UNIT " << it->_m_cu_die << std::endl;
+ gap fake_gap;
+ recursive_dumper (*this, appender, debug_str, addr_64,
+ die_off, die_backpatch, str_backpatch,
+ big_endian, cu_start)
+ .dump (*c._m_unique.find (*it), fake_gap, 0);
assert (!fake_gap.valid ());
std::for_each (die_backpatch.begin (), die_backpatch.end (),