From 10477b25258633b30308c6da9908ac8fa85fd32c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 30 Sep 2009 16:47:45 +0200 Subject: [PATCH] Dissect writer to several files * having everything in output-shape.cc was becoming unwieldy --- libdw/Makefile.am | 7 +- libdw/c++/dwarf_output | 44 +- libdw/c++/emit-abbrev.cc | 693 +++++++++++++ libdw/c++/emit-info.cc | 351 +++++++ libdw/c++/emit-line.cc | 492 +++++++++ libdw/c++/emit-misc.hh | 462 +++++++++ libdw/c++/emit-other.cc | 133 +++ libdw/c++/output-shape.cc | 2002 ------------------------------------- libdw/c++/writer.cc | 168 ++++ 9 files changed, 2344 insertions(+), 2008 deletions(-) create mode 100644 libdw/c++/emit-abbrev.cc create mode 100644 libdw/c++/emit-info.cc create mode 100644 libdw/c++/emit-line.cc create mode 100644 libdw/c++/emit-misc.hh create mode 100644 libdw/c++/emit-other.cc delete mode 100644 libdw/c++/output-shape.cc create mode 100644 libdw/c++/writer.cc diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 519e621aa..a9f92a698 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -107,7 +107,12 @@ libdwpp_a_SOURCES = c++/values.cc \ c++/known.cc \ c++/line_info.cc \ c++/edit-values.cc \ - c++/output-values.cc c++/output-shape.cc + c++/output-values.cc \ + c++/writer.cc \ + c++/emit-abbrev.cc \ + c++/emit-info.cc \ + c++/emit-line.cc \ + c++/emit-other.cc if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/c++/dwarf_output b/libdw/c++/dwarf_output index 481314838..c848adbbf 100644 --- a/libdw/c++/dwarf_output +++ b/libdw/c++/dwarf_output @@ -976,9 +976,9 @@ namespace elfutils class standard_opcode; class extended_opcode; - void write_string (std::string const &str, - int form, - section_appender &appender); + inline void write_string (std::string const &str, + int form, + section_appender &appender); template void write_var (Iterator it, unsigned width, uint64_t value); @@ -996,11 +996,45 @@ namespace elfutils void write_block (IteratorOut it, int form, IteratorIn begin, IteratorIn end); - /// @throws dwarf_32_not_enough - void assert_fits_32 (uint64_t value) const; + inline void write_version (section_appender &appender, unsigned version); + + // Check that the value fits into 32-bits if !dwarf_64. If it + // doesn't, throw an exception. The client will then be able to + // restart the process with dwarf_64 == true. + inline void + assert_fits_32 (uint64_t value) const + { + if (!_m_config.dwarf_64 && value > (uint64_t)(uint32_t)-1) + throw dwarf_32_not_enough (); + } public: + template + static inline void write_uleb128 (Iterator it, uint64_t value); + + template + static inline void write_sleb128 (Iterator it, int64_t value); + + template + static inline void write_u1 (Iterator it, uint8_t value); + + template + static inline void write_u2 (Iterator it, uint16_t value, bool big_endian); + + template + static inline void write_u4 (Iterator it, uint32_t value, bool big_endian); + + template + static inline void write_u8 (Iterator it, uint64_t value, bool big_endian); + + static inline bool source_file_is_string (int tag, int attr); + + /* Return width of data stored with given form. For block forms, + return width of length field. */ + size_t + static inline form_width (int form, bool addr_64, bool dwarf_64); + struct dwarf_32_not_enough : public std::runtime_error { diff --git a/libdw/c++/emit-abbrev.cc b/libdw/c++/emit-abbrev.cc new file mode 100644 index 000000000..f1e85a61d --- /dev/null +++ b/libdw/c++/emit-abbrev.cc @@ -0,0 +1,693 @@ +/* elfutils::dwarf_output abbrev generation. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include +#include + +#include "dwarf_output" +#include "emit-misc.hh" + +using namespace elfutils; +#define __unused __attribute__ ((unused)) + +namespace +{ + struct null_constraint_t + : public dwarf_output::shape_type::form_constraint_t + { + virtual bool satisfied (__unused dwarf_output::debug_info_entry const &die, + __unused int attr, + __unused dwarf_output::attr_value const &value) const + { + return true; + } + + virtual bool equal (form_constraint_t const *other) const; + } null_constraint; + + bool + null_constraint_t::equal (form_constraint_t const *other) const + { + return other == &null_constraint; + } + + + struct cu_local_ref_constraint_t + : public dwarf_output::shape_type::form_constraint_t + { + virtual bool satisfied (__unused dwarf_output::debug_info_entry const &die, + __unused int attr, + __unused dwarf_output::attr_value const &value) const + { + return true; // xxx + } + + virtual bool equal (form_constraint_t const *other) const; + } cu_local_ref_constraint; + + bool + cu_local_ref_constraint_t::equal (form_constraint_t const *other) const + { + return other == &cu_local_ref_constraint; + } + + + struct noreloc_constraint_t + : public dwarf_output::shape_type::form_constraint_t + { + virtual bool satisfied (__unused dwarf_output::debug_info_entry const &die, + __unused int attr, + __unused dwarf_output::attr_value const &value) const + { + return true; // xxx + } + + virtual bool equal (form_constraint_t const *other) const; + } noreloc_constraint; + + bool + noreloc_constraint_t::equal (form_constraint_t const *other) const + { + return other == &noreloc_constraint; + } + + + struct constraint_and + : public dwarf_output::shape_type::form_constraint_t + { + form_constraint_t const *a; + form_constraint_t const *b; + + constraint_and (form_constraint_t const *aa, + form_constraint_t const *bb) + : a (aa), b (bb) + {} + + virtual bool satisfied (dwarf_output::debug_info_entry const &die, + int attr, + dwarf_output::attr_value const &value) const + { + return a->satisfied (die, attr, value) + && b->satisfied (die, attr, value); + } + + virtual bool equal (form_constraint_t const *other) const + { + if (constraint_and const *o + = dynamic_cast (other)) + return (a->equal (o->a) && b->equal(o->b)) + || (b->equal (o->a) && a->equal(o->b)); + else + return false; + } + }; +} + +dwarf_output::shape_type::candidate_form::candidate_form + (int a_form, form_constraint_t const *a_constraint) + : _m_hash (0) // xxx + , form (a_form) + , constraint (a_constraint ?: &null_constraint) +{} + +namespace +{ + struct ref_forms_t + : public dwarf_output::shape_type::candidate_form_vec + { + ref_forms_t () + { + typedef dwarf_output::shape_type::candidate_form + candidate_form; + static constraint_and local_noreloc_constaint (&cu_local_ref_constraint, + &noreloc_constraint); + add (DW_FORM_ref_addr); + add (candidate_form (DW_FORM_ref8, &cu_local_ref_constraint)); + add (candidate_form (DW_FORM_ref4, &cu_local_ref_constraint)); + add (candidate_form (DW_FORM_ref2, &local_noreloc_constaint)); + add (candidate_form (DW_FORM_ref1, &local_noreloc_constaint)); + add (candidate_form (DW_FORM_ref_udata, &local_noreloc_constaint)); + } + } ref_forms; + + inline dwarf_output::shape_type::candidate_form_vec const & + candidate_forms (int tag, int attr, const dwarf_output::attr_value &value) + { + // import some types into the namespace + typedef dwarf_output::shape_type::candidate_form + candidate_form; + typedef dwarf_output::shape_type::candidate_form_vec + candidate_form_vec; + typedef dwarf_output::shape_type::form_constraint_t + form_constraint_t; + + /* Having the most spacious form first means that simple sweep + that picks the first suitable form picks that biggest one, + meaning the form will be able to hold whatever data + necessary. + Having variable length the last means that in case of tie, + fixed length forms that are easy to read win. */ + static candidate_form_vec block_forms = candidate_form_vec () + .add (DW_FORM_block4) + .add (DW_FORM_block2) + .add (DW_FORM_block1) + .add (DW_FORM_block); + + static candidate_form_vec const_forms = candidate_form_vec () + .add (DW_FORM_data8) + .add (DW_FORM_data4) + .add (candidate_form (DW_FORM_data2, &noreloc_constraint)) + .add (candidate_form (DW_FORM_data1, &noreloc_constraint)) + .add (candidate_form (DW_FORM_udata, &noreloc_constraint)) // xxx & nopatch constaint + .add (candidate_form (DW_FORM_sdata, &noreloc_constraint));// xxx & nopatch constaint + + static candidate_form_vec string_forms = candidate_form_vec () + .add (DW_FORM_string) + .add (DW_FORM_strp) + ; + + switch (value.what_space ()) + { + case dwarf::VS_address: + { + static candidate_form_vec forms = candidate_form_vec () + .add(DW_FORM_addr); + return forms; + } + + case dwarf::VS_flag: + { + static candidate_form_vec forms = candidate_form_vec () + .add (DW_FORM_flag) + //.add (DW_FORM_flag_present) // xxx DWARF4 + ; + return forms; + } + + case dwarf::VS_reference: + return ::ref_forms; + + case dwarf::VS_string: + case dwarf::VS_identifier: + return string_forms; + + case dwarf::VS_constant: + if (!value.constant_is_integer ()) + return block_forms; + /* Fall through. */ + + case dwarf::VS_dwarf_constant: + case dwarf::VS_source_line: + case dwarf::VS_source_column: + return const_forms; + + case dwarf::VS_location: + if (!value.location ().is_list ()) + return block_forms; + /* Fall through. */ + + case dwarf::VS_lineptr: + case dwarf::VS_macptr: + case dwarf::VS_rangelistptr: + /* This can be either data4 or data8 depending on the size of + the offset to the client data that we are trying to encode. + In DWARF 4, the only available offset is DW_FORM_sec_offset, + which is 4 bytes in 32-bit dwarf and 8 bytes in 64-bit. */ + { + static candidate_form_vec forms = candidate_form_vec () + //.add (DW_FORM_sec_offset) // xxx DWARF4 + .add (DW_FORM_data8) + .add (DW_FORM_data4) + ; + return forms; + } + + case dwarf::VS_source_file: + if (dwarf_output::writer::source_file_is_string (tag, attr)) + return string_forms; + else + return const_forms; + + case dwarf::VS_discr_list: + return block_forms; + } + + throw std::logic_error ("strange value_space"); + } + + bool + numerical_p (int tag, int attr, const dwarf_output::attr_value &value) + { + dwarf::value_space vs = value.what_space (); + + switch (vs) + { + case dwarf::VS_flag: + case dwarf::VS_macptr: + case dwarf::VS_constant: + case dwarf::VS_dwarf_constant: + case dwarf::VS_source_line: + case dwarf::VS_source_column: + case dwarf::VS_address: + + // We can optimize strings here, too, we just take the length of + // the string as the value to encode, and treat it specially. + case dwarf::VS_string: + case dwarf::VS_identifier: + return true; + + case dwarf::VS_reference: // xxx this one is numerical in + // principle, but optimizing + // references is fun on its own and + // for much later + case dwarf::VS_discr_list: + case dwarf::VS_rangelistptr: // xxx same here + return false; + + case dwarf::VS_location: + if (!value.location ().is_list ()) + return true; + else + return false; // xxx and here, too + + case dwarf::VS_source_file: + if (dwarf_output::writer::source_file_is_string (tag, attr)) + return true; + else + return false; // xxx and here, too + + // Require that .debug_line is emitted before .debug_info. + case dwarf::VS_lineptr: + // xxx but we need to move numerical_value_to_optimize to + // writer. + return false; + } + + abort (); + } + + uint64_t + numerical_value_to_optimize (int tag, int attr, + const dwarf_output::attr_value &value) + { + dwarf::value_space vs = value.what_space (); + + switch (vs) + { + case dwarf::VS_flag: + return !!value.flag (); + + case dwarf::VS_macptr: + return 0; /* xxx */ + + case dwarf::VS_constant: + if (value.constant_is_integer ()) + return value.constant (); + else + return value.constant_block ().size (); + + case dwarf::VS_dwarf_constant: + return value.dwarf_constant (); + + case dwarf::VS_source_line: + return value.source_line (); + + case dwarf::VS_source_column: + return value.source_column (); + + case dwarf::VS_address: + return value.address (); + + case dwarf::VS_source_file: + if (!dwarf_output::writer::source_file_is_string (tag, attr)) + return 0; /* xxx */ + /* fall-through */ + + case dwarf::VS_string: + case dwarf::VS_identifier: + return value.string ().size (); + + case dwarf::VS_rangelistptr: + case dwarf::VS_reference: + case dwarf::VS_discr_list: + case dwarf::VS_lineptr: + abort (); + + case dwarf::VS_location: + if (!value.location ().is_list ()) + return value.location ().location ().size (); + else + abort (); + } + + abort (); + } +} + +dwarf_output::shape_type::shape_type (const debug_info_entry &die, + const dwarf_output::die_info &info) + : _m_tag (die.tag ()) + , _m_with_sibling (info._m_with_sibling) + , _m_has_children (die.has_children ()) + , _m_hash (8675309 << _m_has_children) +{ + for (debug_info_entry::attributes_type::const_iterator it + = die.attributes ().begin (); + it != die.attributes ().end (); ++it) + _m_attrs.push_back (it->first); + std::sort (_m_attrs.begin (), _m_attrs.end ()); + + // Make sure the hash is computed based on canonical order of + // (unique) attributes, not based on order in which the attributes + // are in DIE. + for (attrs_vec::const_iterator it = _m_attrs.begin (); + it != _m_attrs.end (); ++it) + subr::hash_combine (_m_hash, *it); +} + +namespace +{ + class CountingIterator + { + size_t &_m_count; + + public: + CountingIterator (size_t &count) + : _m_count (count) + {} + + CountingIterator (CountingIterator const ©) + : _m_count (copy._m_count) + {} + + CountingIterator &operator= (CountingIterator const &other) + { + _m_count = other._m_count; + return *this; + } + + CountingIterator &operator++ (int) + { + _m_count++; + return *this; + } + + struct ref + { + template + ref &operator= (T t __attribute__ ((unused))) + { + return *this; + } + }; + + ref operator *() + { + return ref (); + } + }; + + size_t + numerical_encoded_length (uint64_t value, int form, + bool addr_64, bool dwarf_64) + { + switch (form) + { + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_exprloc: + case DW_FORM_indirect: + case DW_FORM_block: + case DW_FORM_sdata: + { + size_t count = 0; + CountingIterator counter (count); + if (form == DW_FORM_sdata) + dwarf_output::writer::write_sleb128 (counter, value); + else + dwarf_output::writer::write_uleb128 (counter, value); + return count; + } + + // xxx string logic should be extracted and treated using + // different pass + case DW_FORM_string: + return value + 1; /* For strings, we yield string length plus + terminating zero. */ + + default: + return dwarf_output::writer::form_width (form, addr_64, dwarf_64); + } + } + + bool + numerical_value_fits_form (uint64_t value, int form, bool addr_64) + { + switch (form) + { + case DW_FORM_flag_present: + return value == 1; + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_block1: + return value <= (uint8_t)-1; + + case DW_FORM_data2: + case DW_FORM_ref2: + case DW_FORM_block2: + return value <= (uint16_t)-1; + + case DW_FORM_ref_addr: + case DW_FORM_strp: + case DW_FORM_sec_offset: + // We simply assume that these dwarf_64-dependent forms can + // contain any value. If dwarf_64==false && value > 32bit, we + // throw an exception when we try to write that value. + return true; + + case DW_FORM_string: + // This can hold anything. + return true; + + case DW_FORM_addr: + if (addr_64) + return true; + /* fall-through */ + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_block4: + return value <= (uint64_t)(uint32_t)-1; + + /* 64-bit forms. Everything fits there. */ + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_exprloc: + case DW_FORM_indirect: + case DW_FORM_block: + case DW_FORM_sdata: + return true; + } + + throw std::runtime_error + (std::string ("Don't know whether value fits ") + + dwarf_form_string (form)); + } +} + +void +dwarf_output::shape_info::instantiate + (dwarf_output::shape_type const &shape, + dwarf_output_collector &col, + bool addr_64, bool dwarf_64) +{ + bool with_sibling = shape._m_with_sibling[true] && shape._m_has_children; + bool without_sibling = shape._m_with_sibling[false] || !with_sibling; + + struct + { + void operator () (instance_type &inst, + debug_info_entry const &die, int attr, + bool my_addr_64, bool my_dwarf_64) + { + // Optimization of sibling attribute will be done afterward. + // For now just stick the biggest form in there. + int form; + if (attr == DW_AT_sibling) + form = DW_FORM_ref8; + else + { + int tag = die.tag (); + dwarf_output::attr_value const &value + = die.attributes ().find (attr)->second; + shape_type::candidate_form_vec const &candidates + = ::candidate_forms (tag, attr, value); + + if (!numerical_p (tag, attr, value)) + { + form = -1; + + // Just take the first form matching the + // constraints, we will optimize in separate sweep. + // Assume that candidates are stored in order from + // the most capacitous to the least. + for (shape_type::candidate_form_vec::const_iterator ct + = candidates.begin (); + ct != candidates.end (); ++ct) + if (ct->constraint->satisfied (die, attr, value)) + { + form = ct->form; + break; + } + assert (form != -1); + } + else + { + size_t best_len = 0; + form = -1; + + uint64_t opt_val + = numerical_value_to_optimize (tag, attr, value); + + for (shape_type::candidate_form_vec::const_iterator ct + = candidates.begin (); + ct != candidates.end (); ++ct) + if (ct->constraint->satisfied (die, attr, value) + && numerical_value_fits_form (opt_val, ct->form, + my_addr_64)) + { + size_t len + = numerical_encoded_length (opt_val, ct->form, + my_addr_64, my_dwarf_64); + if (form == -1 || len < best_len) + { + form = ct->form; + if (len == 1) // you can't top that + break; + best_len = len; + } + } + assert (form != -1); + } + } + inst.forms.insert (std::make_pair (attr, form)); + } + } handle_attrib; + + for (die_ref_vect::const_iterator it = _m_users.begin (); + it != _m_users.end (); ++it) + { + instance_type inst; + debug_info_entry const &die = *it; + for (shape_type::attrs_vec::const_iterator at = shape._m_attrs.begin (); + at != shape._m_attrs.end (); ++at) + handle_attrib (inst, die, *at, addr_64, dwarf_64); + + die_info &i = col._m_unique.find (die)->second; + if (without_sibling) + i.abbrev_ptr[false] = _m_instances.insert (inst).first; + + if (with_sibling) + { + handle_attrib (inst, die, DW_AT_sibling, addr_64, dwarf_64); + i.abbrev_ptr[true] = _m_instances.insert (inst).first; + } + } + + // xxx: instance merging? Locate instances A and B (and C and ...?) + // such that instance X can be created that covers all users of A + // and B, and such that the space saved by removing the + // abbreviations A and B tops the overhead of introducing non-ideal + // (wrt users of A and B) X and moving all the users over to it. + + // Hmm, except that the is-advantageous math involves number of + // users of the abbrev, and we don't know number of users before we + // do the dissection of the tree to imported partial units. +} + +void +dwarf_output::shape_info::build_data + (dwarf_output::shape_type const &shape, + dwarf_output::shape_info::instance_type const &inst, + section_appender &appender) +{ + std::back_insert_iterator inserter + = std::back_inserter (appender); + dwarf_output::writer::write_uleb128 (inserter, inst.code); + dwarf_output::writer::write_uleb128 (inserter, shape._m_tag); + *inserter++ = shape._m_has_children ? DW_CHILDREN_yes : DW_CHILDREN_no; + + for (instance_type::forms_type::const_iterator it = inst.forms.begin (); + it != inst.forms.end (); ++it) + { + // ULEB128 name & form + dwarf_output::writer::write_uleb128 (inserter, it->first); + dwarf_output::writer::write_uleb128 (inserter, it->second); + } + + // 0 for name & form to terminate the abbreviation + *inserter++ = 0; + *inserter++ = 0; +} + +void +dwarf_output::writer::output_debug_abbrev (section_appender &appender) +{ + for (shape_map::iterator it = _m_shapes.begin (); + it != _m_shapes.end (); ++it) + for (dwarf_output::shape_info::instance_set::iterator jt + = it->second._m_instances.begin (); + jt != it->second._m_instances.end (); ++jt) + it->second.build_data (it->first, *jt, appender); + + appender.push_back (0); // terminate table +} diff --git a/libdw/c++/emit-info.cc b/libdw/c++/emit-info.cc new file mode 100644 index 000000000..618ab3ec2 --- /dev/null +++ b/libdw/c++/emit-info.cc @@ -0,0 +1,351 @@ +/* elfutils::dwarf_output generation of .debug_info + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include + +#include "dwarf_output" +#include "../../src/dwarf-opcodes.h" +#include "emit-misc.hh" + +using namespace elfutils; +#define __unused __attribute__ ((unused)) + +class dwarf_output::writer::dump_die_tree +{ + // [(gap, die offset)] + typedef std::vector> die_backpatch_vec; + + writer &_m_parent; + section_appender &appender; + die_off_map die_off; + die_backpatch_vec die_backpatch; + uint64_t _m_cu_start; + size_t level; + line_info_table const *lines; + + static const bool debug = false; + +public: + class step_t + { + dump_die_tree &_m_dumper; + + public: + gap sibling_gap; + + step_t (dump_die_tree &dumper, + __unused die_info_pair const &info_pair, + __unused step_t *previous) + : _m_dumper (dumper), + sibling_gap (dumper._m_parent) + { + ++_m_dumper.level; + } + + ~step_t () + { + --_m_dumper.level; + } + + void before_children () {} + void after_recursion () {} + + void after_children () + { + _m_dumper.appender.push_back (0); + } + + void before_recursion () + { + if (sibling_gap.valid ()) + { + sibling_gap.patch (_m_dumper.appender.size ()); + sibling_gap = gap (_m_dumper._m_parent); + } + } + }; + friend class step_t; + + dump_die_tree (writer &writer, + section_appender &a_appender, + uint64_t cu_start) + : _m_parent (writer), + appender (a_appender), + _m_cu_start (cu_start), + level (0), + lines (NULL) + { + } + + void visit_die (dwarf_output::die_info_pair const &info_pair, + step_t &step, + bool has_sibling) + { + static char const spaces[] = + " " + " " + " "; + static char const *tail = spaces + strlen (spaces); + char const *pad = tail - level * 2; + + debug_info_entry const &die = info_pair.first; + die_info const &info = info_pair.second; + int tag = die.tag (); + + std::back_insert_iterator inserter + = std::back_inserter (appender); + + /* Record where the DIE begins. */ + // xxx in fact, we can meet "the same" DIE several times in the + // tree. But since they are all equal, it doesn't matter which + // one we end up resolving our references to. Except for + // siblings, which we handle differently. + die_off [die.offset ()] = appender.size (); + if (debug) + std::cout << pad << "CHILD " << dwarf_tag_string (die.tag ()) + << " [0x" << std::hex << die_off [die.offset ()] << std::dec << "]" + << " " << std::flush; + + /* Our instance. */ + die_info::abbrev_ptr_map::const_iterator xt + = info.abbrev_ptr.find (die.has_children () && has_sibling); + assert (xt != info.abbrev_ptr.end ()); + shape_info::instance_type const &instance = *xt->second; + dwarf_output::writer::write_uleb128 (inserter, instance.code); + + if (debug) + std::cout << " " << instance.code << std::endl; + + /* Dump attribute values. */ + debug_info_entry::attributes_type const &attribs = die.attributes (); + for (shape_info::instance_type::forms_type::const_iterator + at = instance.forms.begin (); at != instance.forms.end (); ++at) + { + int attr = at->first; + int form = at->second; + if (attr == DW_AT_sibling) + { + if (debug) + std::cout << pad << " " << dwarf_attr_string (attr) + << ":" << dwarf_form_string (form) + << " sibling=" << info._m_with_sibling[false] + << ":" << info._m_with_sibling[true] + << std::endl; + step.sibling_gap = gap (_m_parent, appender, form, _m_cu_start); + continue; + } + + debug_info_entry::attributes_type::const_iterator + vt = attribs.find (attr); + assert (vt != attribs.end ()); + + attr_value const &value = vt->second; + if (false && debug) + std::cout << ":" << value.to_string () << std::endl; + + dwarf::value_space vs = value.what_space (); + + switch (vs) + { + case dwarf::VS_flag: + if (form == DW_FORM_flag) + *appender.alloc (1) = !!value.flag (); + else + assert (form == DW_FORM_flag_present); + break; + + case dwarf::VS_lineptr: + { + if (lines != NULL) + throw std::runtime_error + ("Another DIE with lineptr attribute?!"); + + lines = &value.line_info (); + line_offsets_map::const_iterator it + = _m_parent._m_line_offsets.find (lines); + if (it == _m_parent._m_line_offsets.end ()) + throw std::runtime_error + ("Emit .debug_line before .debug_info"); + _m_parent.write_form (inserter, form, it->second.table_offset); + } + break; + + case dwarf::VS_rangelistptr: + _m_parent._m_range_backpatch.push_back + (std::make_pair (gap (_m_parent, appender, form), + &value.ranges ())); + break; + + case dwarf::VS_macptr: + _m_parent.write_form (inserter, form, 0 /*xxx*/); + break; + + case dwarf::VS_constant: + if (value.constant_is_integer ()) + _m_parent.write_form (inserter, form, value.constant ()); + else + _m_parent.write_block (inserter, form, + value.constant_block ().begin (), + value.constant_block ().end ()); + break; + + case dwarf::VS_dwarf_constant: + _m_parent.write_form (inserter, form, value.dwarf_constant ()); + break; + + case dwarf::VS_source_line: + _m_parent.write_form (inserter, form, value.source_line ()); + break; + + case dwarf::VS_source_column: + _m_parent.write_form (inserter, form, value.source_column ()); + break; + + case dwarf::VS_string: + _m_parent.write_string (value.string (), form, appender); + break; + + case dwarf::VS_identifier: + _m_parent.write_string (value.identifier (), form, appender); + break; + + case dwarf::VS_source_file: + if (dwarf_output::writer::source_file_is_string (tag, attr)) + _m_parent.write_string (value.source_file ().name (), + form, appender); + else + { + assert (lines != NULL); + writer::line_offsets_map::const_iterator + it = _m_parent._m_line_offsets.find (lines); + assert (it != _m_parent._m_line_offsets.end ()); + writer::line_offsets::source_file_map::const_iterator + jt = it->second.source_files.find (value.source_file ()); + assert (jt != it->second.source_files.end ()); + _m_parent.write_form (inserter, form, jt->second); + } + break; + + case dwarf::VS_address: + _m_parent.write_form (inserter, form, value.address ()); + break; + + case dwarf::VS_reference: + { + assert (form == DW_FORM_ref_addr); + die_backpatch.push_back + (std::make_pair (gap (_m_parent, appender, form), + value.reference ()->offset ())); + } + break; + + case dwarf::VS_location: + if (!value.location ().is_list ()) + _m_parent.write_block (inserter, form, + value.location ().location ().begin (), + value.location ().location ().end ()); + else + _m_parent._m_loc_backpatch.push_back + (std::make_pair (gap (_m_parent, appender, form), + &value.location ())); + break; + + case dwarf::VS_discr_list: + throw std::runtime_error ("Can't handle VS_discr_list."); + }; + } + } + + void before_traversal () {} + + void after_traversal () + { + for (die_backpatch_vec::const_iterator it = die_backpatch.begin (); + it != die_backpatch.end (); ++it) + { + die_off_map::const_iterator jt = die_off.find (it->second); + if (jt == die_off.end ()) + std::cout << "can't find offset " << it->second << std::endl; + else + { + assert (jt != die_off.end ()); + it->first.patch (jt->second); + } + } + } +}; + +void +dwarf_output::writer::output_debug_info (section_appender &appender) +{ + std::back_insert_iterator inserter + = std::back_inserter (appender); + + for (compile_units::const_iterator it = _m_dw._m_units.begin (); + it != _m_dw._m_units.end (); ++it) + { + // Remember where the unit started for DIE offset calculation. + size_t cu_start = appender.size (); + + length_field lf (*this, appender); + write_version (appender, 3); + + // Debug abbrev offset. Use the single abbrev table that we + // emit at offset 0. + ::dw_write<4> (appender.alloc (4), 0, _m_config.big_endian); + + // Size in bytes of an address on the target architecture. + *inserter++ = _m_config.addr_64 ? 8 : 4; + + dump_die_tree dumper (*this, appender, cu_start); + ::traverse_die_tree (dumper, *_m_col._m_unique.find (*it)); + + lf.finish (); + } +} diff --git a/libdw/c++/emit-line.cc b/libdw/c++/emit-line.cc new file mode 100644 index 000000000..130ccf5b0 --- /dev/null +++ b/libdw/c++/emit-line.cc @@ -0,0 +1,492 @@ +/* elfutils::dwarf_output line number program generation. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include + +#include "dwarf_output" +#include "../../src/dwarf-opcodes.h" +#include "emit-misc.hh" + +using namespace elfutils; +#define __unused __attribute__ ((unused)) + +class dwarf_output::writer::linenum_prog_instruction +{ + writer &_m_parent; + std::vector const &_m_operands; + std::vector::const_iterator _m_op_it; + +protected: + std::vector _m_buf; + + linenum_prog_instruction (writer &parent, + std::vector const &operands) + : _m_parent (parent), + _m_operands (operands), + _m_op_it (_m_operands.begin ()) + {} + +public: + void arg (uint64_t value) + { + assert (_m_op_it != _m_operands.end ()); + _m_parent.write_form (std::back_inserter (_m_buf), *_m_op_it++, value); + } + + void arg (std::string const &value) + { + assert (_m_op_it != _m_operands.end ()); + int form = *_m_op_it++; + assert (form == DW_FORM_string); + + std::copy (value.begin (), value.end (), std::back_inserter (_m_buf)); + _m_buf.push_back (0); + } + + void write (section_appender &appender) + { + assert (_m_op_it == _m_operands.end ()); + std::copy (_m_buf.begin (), _m_buf.end (), + std::back_inserter (appender)); + } +}; + +class dwarf_output::writer::standard_opcode + : public dwarf_output::writer::linenum_prog_instruction +{ + int _m_opcode; + + static std::vector const &build_arglist (int opcode) + { + static struct arglist + : public std::map > + { + arglist () + { +#define DW_LNS_0(OP) \ + (*this)[OP]; +#define DW_LNS_1(OP, OP1) \ + (*this)[OP].push_back (OP1); + + DW_LNS_OPERANDS; + +#undef DW_LNS_1 +#undef DW_LNS_0 + } + } const operands; + + arglist::const_iterator it = operands.find (opcode); + assert (it != operands.end ()); + return it->second; + } + +public: + standard_opcode (writer &parent, int opcode) + : linenum_prog_instruction (parent, build_arglist (opcode)), + _m_opcode (opcode) + {} + + template + inline standard_opcode &arg (T const &value) + { + linenum_prog_instruction::arg (value); + return *this; + } + + void write (section_appender &appender) + { + appender.push_back (_m_opcode); + linenum_prog_instruction::write (appender); + } +}; + +class dwarf_output::writer::extended_opcode + : public dwarf_output::writer::linenum_prog_instruction +{ + int _m_opcode; + + static std::vector const &build_arglist (int opcode) + { + static struct arglist + : public std::map > + { + arglist () + { +#define DW_LNE_0(OP) \ + (*this)[OP]; +#define DW_LNE_1(OP, OP1) \ + (*this)[OP].push_back (OP1); +#define DW_LNE_4(OP, OP1, OP2, OP3, OP4) \ + (*this)[OP].push_back (OP1); \ + (*this)[OP].push_back (OP2); \ + (*this)[OP].push_back (OP3); \ + (*this)[OP].push_back (OP4); + + DW_LNE_OPERANDS; + +#undef DW_LNE_4 +#undef DW_LNE_1 +#undef DW_LNE_0 + } + } const operands; + + arglist::const_iterator it = operands.find (opcode); + assert (it != operands.end ()); + return it->second; + } + +public: + extended_opcode (writer &parent, int opcode) + : linenum_prog_instruction (parent, build_arglist (opcode)), + _m_opcode (opcode) + {} + + template + inline extended_opcode &arg (T const &value) + { + linenum_prog_instruction::arg (value); + return *this; + } + + void write (section_appender &appender) + { + appender.push_back (0); + dwarf_output::writer::write_uleb128 (std::back_inserter (appender), + _m_buf.size () + 1); + appender.push_back (_m_opcode); + linenum_prog_instruction::write (appender); + } +}; + +class dwarf_output::writer::line_offsets::add_die_ref_files +{ + line_offsets::source_file_map &_m_files; + +public: + struct step_t + { + step_t (__unused add_die_ref_files &adder, + __unused die_info_pair const &info_pair, + __unused step_t *previous) + {} + + void before_children () {} + void after_children () {} + void before_recursion () {} + void after_recursion () {} + }; + + add_die_ref_files (line_offsets::source_file_map &files) : _m_files (files) {} + + void visit_die (dwarf_output::die_info_pair const &info_pair, + __unused step_t &step, + __unused bool has_sibling) + { + debug_info_entry const &die = info_pair.first; + + debug_info_entry::attributes_type const &attribs = die.attributes (); + for (debug_info_entry::attributes_type::const_iterator at + = attribs.begin (); at != attribs.end (); ++at) + { + attr_value const &value = at->second; + dwarf::value_space vs = value.what_space (); + + if (vs == dwarf::VS_source_file + && !dwarf_output::writer::source_file_is_string (die.tag (), + at->first)) + _m_files.insert (std::make_pair (value.source_file (), 0)); + } + } + + void before_traversal () {} + void after_traversal () {} +}; + +dwarf_output::writer:: +line_offsets::line_offsets (__unused writer const &wr, + dwarf_output::line_table const &lines, + ::Dwarf_Off off) + : table_offset (off) +{ + // We need to include all files referenced through DW_AT_*_file and + // all files used in line number program. + for (dwarf_output::line_table::const_iterator line_it = lines.begin (); + line_it != lines.end (); ++line_it) + { + dwarf_output::line_entry const &entry = *line_it; + dwarf_output::source_file const &file = entry.file (); + line_offsets::source_file_map::const_iterator sfit + = source_files.find (file); + if (sfit == source_files.end ()) + source_files.insert (std::make_pair (file, 0)); + } + + for (compile_units::const_iterator it = wr._m_dw._m_units.begin (); + it != wr._m_dw._m_units.end (); ++it) + if (&it->lines () == &lines) + { + add_die_ref_files adder (source_files); + ::traverse_die_tree (adder, *wr._m_col._m_unique.find (*it)); + } + + // Assign numbers to source files. + size_t file_idx = 0; + for (line_offsets::source_file_map::iterator sfit = source_files.begin (); + sfit != source_files.end (); ++sfit) + sfit->second = ++file_idx; +} + +void +dwarf_output::writer::output_debug_line (section_appender &appender) +{ + std::back_insert_iterator inserter + = std::back_inserter (appender); + + for (subr::value_set::const_iterator it + = _m_col._m_line_info.begin (); + it != _m_col._m_line_info.end (); ++it) + { + dwarf_output::line_info_table const < = it->second; + dwarf_output::line_table const &lines = lt.lines (); + + line_offsets offset_tab (*this, lines, appender.size ()); + // the table is inserted in _m_line_offsets at the loop's end + + length_field table_length (*this, appender); + write_version (appender, 3); + length_field header_length (*this, appender); + + // minimum_instruction_length + unsigned minimum_instruction_length = 1; + appender.push_back (minimum_instruction_length); + + // default_is_stmt + bool default_is_stmt = true; + appender.push_back (default_is_stmt ? 1 : 0); + + // line_base, line_range + appender.push_back (uint8_t (int8_t (0))); + appender.push_back (1); + +#define DW_LNS_0(OP) 0, +#define DW_LNS_1(OP, OP1) 1, + uint8_t opcode_lengths[] = { + DW_LNS_OPERANDS + }; +#undef DW_LNS_1 +#undef DW_LNS_0 + + // opcode_base + appender.push_back (sizeof (opcode_lengths) + 1); + + // standard_opcode_lengths (array of ubyte) + std::copy (opcode_lengths, opcode_lengths + sizeof (opcode_lengths), + inserter); + + // include_directories + dwarf_output::directory_table const &dirs = lt.include_directories (); + for (dwarf_output::directory_table::const_iterator dir_it + = dirs.begin (); dir_it != dirs.end (); ++dir_it) + if (*dir_it != "") + { + std::copy (dir_it->begin (), dir_it->end (), inserter); + *inserter++ = 0; + } + *inserter++ = 0; + + // file_names + for (line_offsets::source_file_map::const_iterator sfit + = offset_tab.source_files.begin (); + sfit != offset_tab.source_files.end (); ++sfit) + { + dwarf_output::source_file const &sf = sfit->first; + + // Find the best-fitting directory for this filename. + size_t dir_index = 0; + size_t match_len = 0; + for (dwarf_output::directory_table::const_iterator dir_it + = dirs.begin () + 1; dir_it != dirs.end (); ++dir_it) + { + std::string const &dir = *dir_it; + if (dir.length () > match_len + && sf.name ().substr (0, dir.length ()) == dir) + { + dir_index = dir_it - dirs.begin (); + match_len = dir.length (); + } + } + + std::string fn = sf.name ().substr (match_len + 1); + std::copy (fn.begin (), fn.end (), inserter); + *inserter++ = 0; + write_uleb128 (inserter, dir_index); + write_uleb128 (inserter, sf.mtime ()); + write_uleb128 (inserter, sf.size ()); + } + *inserter++ = 0; + + header_length.finish (); + + // Now emit the "meat" of the table: the line number program. + struct registers + { + ::Dwarf_Addr addr; + unsigned file; + unsigned line; + unsigned column; + bool is_stmt; + bool default_is_stmt; + + void init () + { + addr = 0; + file = 1; + line = 1; + column = 0; + is_stmt = default_is_stmt; + } + + explicit registers (bool b) + : default_is_stmt (b) + { + init (); + } + } reg (default_is_stmt); + + for (dwarf_output::line_table::const_iterator line_it = lines.begin (); + line_it != lines.end (); ++line_it) + { + dwarf_output::line_entry const &entry = *line_it; + ::Dwarf_Addr addr = entry.address (); + unsigned file = offset_tab.source_files.find (entry.file ())->second; + unsigned line = entry.line (); + unsigned column = entry.column (); + bool is_stmt = entry.statement (); + +#if 0 + std::cout << std::hex << addr << std::dec + << "\t" << file + << "\t" << line + << "\t" << column + << "\t" << is_stmt + << "\t" << entry.end_sequence () << std::endl; +#endif + +#define ADVANCE_OPCODE(WHAT, STEP, OPCODE) \ + { \ + __typeof (WHAT) const &what = WHAT; \ + __typeof (WHAT) const ®_what = reg.WHAT; \ + unsigned step = STEP; \ + if (what != reg_what) \ + { \ + __typeof (WHAT) delta = what - reg_what;\ + __typeof (WHAT) advance = delta / step; \ + assert (advance * step == delta); \ + standard_opcode (*this, OPCODE) \ + .arg (advance) \ + .write (appender); \ + } \ + } + +#define SET_OPCODE(WHAT, OPCODE) \ + { \ + __typeof (WHAT) const &what = WHAT; \ + __typeof (WHAT) const ®_what = reg.WHAT; \ + if (what != reg_what) \ + standard_opcode (*this, OPCODE) \ + .arg (what) \ + .write (appender); \ + } + +#define SIMPLE_OPCODE(WHAT, OPCODE) \ + if (entry.WHAT ()) \ + standard_opcode (*this, OPCODE) \ + .write (appender); + + ADVANCE_OPCODE (addr, minimum_instruction_length, DW_LNS_advance_pc); + SET_OPCODE (file, DW_LNS_set_file); + ADVANCE_OPCODE (line, 1, DW_LNS_advance_line); + SET_OPCODE (column, DW_LNS_set_column); + SIMPLE_OPCODE (basic_block, DW_LNS_set_basic_block); + SIMPLE_OPCODE (prologue_end, DW_LNS_set_prologue_end); + SIMPLE_OPCODE (epilogue_begin, DW_LNS_set_epilogue_begin); + + if (is_stmt != reg.is_stmt) + standard_opcode (*this, DW_LNS_negate_stmt) + .write (appender); + +#undef SIMPLE_OPCODE +#undef SET_OPCODE +#undef ADVANCE_OPCODE + + if (entry.end_sequence ()) + { + extended_opcode (*this, DW_LNE_end_sequence) + .write (appender); + reg.init (); + } + else + { + standard_opcode (*this, DW_LNS_copy) + .write (appender); + + reg.addr = addr; + reg.file = file; + reg.line = line; + reg.column = column; + reg.is_stmt = is_stmt; + } + } + + table_length.finish (); + + if (!_m_line_offsets.insert (std::make_pair (<, offset_tab)).second) + throw std::runtime_error ("duplicate line table address"); + } +} diff --git a/libdw/c++/emit-misc.hh b/libdw/c++/emit-misc.hh new file mode 100644 index 000000000..5da98e0d1 --- /dev/null +++ b/libdw/c++/emit-misc.hh @@ -0,0 +1,462 @@ +/* elfutils::dwarf_output abbrev generation. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include +#include "dwarf_output" +#include "../../src/dwarfstrings.h" +using namespace elfutils; + +namespace +{ + template struct width_to_int; + + template <> struct width_to_int <0> + { + typedef uint8_t unsigned_t; + static uint8_t bswap (uint8_t value) { return value; } + }; + + template <> struct width_to_int <1> + : width_to_int <0> + {}; + + template <> struct width_to_int <2> + { + typedef uint16_t unsigned_t; + static uint16_t bswap (uint16_t value) { return bswap_16 (value); } + }; + + template <> struct width_to_int <4> + { + typedef uint32_t unsigned_t; + static uint32_t bswap (uint32_t value) { return bswap_32 (value); } + }; + + template <> struct width_to_int <8> + { + typedef uint64_t unsigned_t; + static uint64_t bswap (uint64_t value) { return bswap_64 (value); } + }; + + template + void dw_write (Iterator it, + typename width_to_int::unsigned_t value, + bool big_endian) + { + if (big_endian) + value = width_to_int::bswap (value); + + for (int i = 0; i < width; ++i) + { + *it++ = (uint8_t)value & 0xffUL; + value >>= 8; + } + } +} + +template +void +dwarf_output::writer::write_uleb128 (Iterator it, uint64_t value) +{ + do + { + uint8_t byte = value & 0x7fULL; + value >>= 7; + if (value != 0) + byte |= 0x80; + *it++ = byte; + } + while (value != 0); +} + +template +void +dwarf_output::writer::write_sleb128 (Iterator it, int64_t value) +{ + bool more = true; + do + { + uint8_t byte = value & 0x7fULL; + value >>= 7; + if ((value == 0 && !(byte & 0x40)) + || (value == -1 && (byte & 0x40))) + more = false; + else + byte |= 0x80; + + *it++ = byte; + } + while (more); +} + +template +void +dwarf_output::writer::write_u1 (Iterator it, uint8_t value) +{ + ::dw_write<1> (it, value, false); +} + +template +void +dwarf_output::writer::write_u2 (Iterator it, uint16_t value, bool big_endian) +{ + ::dw_write<2> (it, value, big_endian); +} + +template +void +dwarf_output::writer::write_u4 (Iterator it, uint32_t value, bool big_endian) +{ + ::dw_write<4> (it, value, big_endian); +} + +template +void +dwarf_output::writer::write_u8 (Iterator it, uint64_t value, bool big_endian) +{ + ::dw_write<8> (it, value, big_endian); +} + +namespace +{ + template + void + traverse_die_tree (Visitor &visitor, + die_info_pair const &top_info_pair) + { + class recursive_traversal + { + Visitor &visitor; + + public: + recursive_traversal (Visitor &a_visitor) + : visitor (a_visitor) + { + } + + void traverse (typename Visitor::step_t &step, + die_info_pair const &info_pair, + bool has_sibling) + { + dwarf_output::debug_info_entry const &die = info_pair.first; + + visitor.visit_die (info_pair, step, has_sibling); + if (!die.children ().empty ()) + { + typename Visitor::step_t my_step (visitor, info_pair, &step); + my_step.before_children (); + for (typename std::vector::const_iterator jt + = die.children ().info ().begin (); ;) + { + die_info_pair const &dip = **jt++; + bool my_has_sibling = jt != die.children ().info ().end (); + my_step.before_recursion (); + traverse (my_step, dip, my_has_sibling); + my_step.after_recursion (); + if (!my_has_sibling) + break; + } + my_step.after_children (); + } + } + }; + + visitor.before_traversal (); + typename Visitor::step_t step (visitor, top_info_pair, NULL); + recursive_traversal (visitor) + .traverse (step, top_info_pair, false); + visitor.after_traversal (); + } +} + + +bool +dwarf_output::writer::source_file_is_string (int tag, int attr) +{ + switch (attr) + { + case DW_AT_decl_file: + case DW_AT_call_file: + return false; + + case DW_AT_comp_dir: + return true; + + case DW_AT_name: + switch (tag) + { + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + return true; + } + } + + throw std::runtime_error ("can't decide whether source_file_is_string"); +} + +/* Return width of data stored with given form. For block forms, + return width of length field. */ +size_t +dwarf_output::writer::form_width (int form, bool addr_64, bool dwarf_64) +{ + switch (form) + { + case DW_FORM_flag_present: + return 0; + + case DW_FORM_block1: + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + return 1; + + case DW_FORM_block2: + case DW_FORM_data2: + case DW_FORM_ref2: + return 2; + + case DW_FORM_block4: + case DW_FORM_data4: + case DW_FORM_ref4: + return 4; + + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + return 8; + + case DW_FORM_addr: + return addr_64 ? 8 : 4; + + case DW_FORM_ref_addr: + case DW_FORM_strp: + case DW_FORM_sec_offset: + return dwarf_64 ? 8 : 4; + + case DW_FORM_block: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_exprloc: + case DW_FORM_indirect: + throw std::runtime_error + (std::string ("Can't compute width of LEB128 form ") + + dwarf_form_string (form)); + + case DW_FORM_string: + throw std::runtime_error + ("You shouldn't need the width of DW_FORM_string."); + } + + throw std::runtime_error + (std::string ("Don't know length of ") + dwarf_form_string (form)); +} + +class dwarf_output::writer::length_field +{ + writer &_m_parent; + elfutils::section_appender &_m_appender; + const gap _m_length_gap; + const size_t _m_cu_start; + bool _m_finished; + + inline gap alloc_gap (elfutils::section_appender &appender) const + { + if (_m_parent._m_config.dwarf_64) + dwarf_output::writer::write_u4 (appender.alloc (4), -1, + _m_parent._m_config.big_endian); + gap g (_m_parent, appender, DW_FORM_ref_addr); + g.set_base (appender.size ()); + return g; + } + +public: + inline length_field (writer &parent, + elfutils::section_appender &appender) + : _m_parent (parent), + _m_appender (appender), + _m_length_gap (alloc_gap (appender)), + _m_cu_start (appender.size ()), + _m_finished (false) + {} + + inline void finish () + { + assert (!_m_finished); + _m_length_gap.patch (_m_appender.size ()); + _m_finished = true; + } +}; + +template +void +dwarf_output::writer::write_form (Iterator it, int form, uint64_t value) +{ + switch (form) + { + case DW_FORM_flag_present: + return; + + case DW_FORM_flag: + assert (value == 1 || value == 0); + case DW_FORM_block1: + case DW_FORM_data1: + case DW_FORM_ref1: + write_u1 (it, value); + return; + + case DW_FORM_block2: + case DW_FORM_data2: + case DW_FORM_ref2: + write_u2 (it, value, _m_config.big_endian); + return; + + case DW_FORM_block4: + case DW_FORM_data4: + case DW_FORM_ref4: + write_u4 (it, value, _m_config.big_endian); + return; + + case DW_FORM_data8: + case DW_FORM_ref8: + write_u8 (it, value, _m_config.big_endian); + return; + + case DW_FORM_addr: + write_64 (it, _m_config.addr_64, value); + return; + + case DW_FORM_ref_addr: + case DW_FORM_strp: + case DW_FORM_sec_offset: + assert_fits_32 (value); + write_64 (it, _m_config.dwarf_64, value); + return; + + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_exprloc: + case DW_FORM_indirect: + write_uleb128 (it, value); + return; + + case DW_FORM_sdata: + write_sleb128 (it, value); + return; + } + + throw std::runtime_error (std::string ("Don't know how to write ") + + dwarf_form_string (form)); +} + +inline void +dwarf_output::writer::write_string (std::string const &str, + int form, + section_appender &appender) +{ + if (form == DW_FORM_string) + { + std::copy (str.begin (), str.end (), + std::back_inserter (appender)); + appender.push_back (0); + } + else + { + assert (form == DW_FORM_strp); + + _m_str_backpatch.push_back + (std::make_pair (gap (*this, appender, form), + _m_debug_str.add (str))); + } +} + +template +void +dwarf_output::writer::write_var (Iterator it, unsigned width, uint64_t value) +{ + switch (width) + { + case 8: + write_u8 (it, value, _m_config.big_endian); + break; + case 4: + write_u4 (it, value, _m_config.big_endian); + break; + case 2: + write_u2 (it, value, _m_config.big_endian); + break; + case 1: + write_u1 (it, value); + case 0: + break; + default: + throw std::runtime_error ("Width has to be 0, 1, 2, 4 or 8."); + } +} + +template +void +dwarf_output::writer::write_block (IteratorOut it, int form, + IteratorIn begin, IteratorIn end) +{ + assert (form == DW_FORM_block + || form == DW_FORM_block1 + || form == DW_FORM_block2 + || form == DW_FORM_block4); + + write_form (it, form, end - begin); + std::copy (begin, end, it); +} + +void +dwarf_output::writer::write_version (section_appender &appender, + unsigned version) +{ + write_u2 (appender.alloc (2), version, _m_config.big_endian); +} diff --git a/libdw/c++/emit-other.cc b/libdw/c++/emit-other.cc new file mode 100644 index 000000000..b7a541b8b --- /dev/null +++ b/libdw/c++/emit-other.cc @@ -0,0 +1,133 @@ +/* elfutils::dwarf_output routines for generation of various debug sections + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include +#include "dwarf_output" +#include "emit-misc.hh" + +using namespace elfutils; + +void +dwarf_output::writer::output_debug_ranges (section_appender &appender) +{ + std::back_insert_iterator inserter + = std::back_inserter (appender); + + for (subr::value_set::const_iterator + it = _m_col._m_ranges.begin (); it != _m_col._m_ranges.end (); ++it) + { + dwarf_output::range_list const &rl = it->second; + if (!_m_range_offsets.insert (std::make_pair (&rl, appender.size ())) + .second) + throw std::runtime_error ("duplicate range table address"); + + for (dwarf_output::range_list::const_iterator range_it = rl.begin (); + range_it != rl.end (); ++range_it) + { + write_form (inserter, DW_FORM_addr, range_it->first); + write_form (inserter, DW_FORM_addr, range_it->second); + } + + // end of list entry + write_form (inserter, DW_FORM_addr, 0); + write_form (inserter, DW_FORM_addr, 0); + } +} + +void +dwarf_output::writer::output_debug_loc (section_appender &appender) +{ + typedef std::set loc_set; + loc_set locations; + + for (dwarf_output_collector::die_map::const_iterator it + = _m_col._m_unique.begin (); + it != _m_col._m_unique.end (); ++it) + { + debug_info_entry const &die = it->first; + for (debug_info_entry::attributes_type::const_iterator + at = die.attributes ().begin (); + at != die.attributes ().end (); ++at) + { + attr_value const &value = at->second; + dwarf::value_space vs = value.what_space (); + + if (vs == dwarf::VS_location) + { + dwarf_output::location_attr const &loc = value.location (); + if (loc.is_list ()) + locations.insert (&loc); + } + } + } + + std::back_insert_iterator inserter + = std::back_inserter (appender); + for (loc_set::const_iterator it = locations.begin (); + it != locations.end (); ++it) + { + dwarf_output::location_attr const &loc = **it; + if (!_m_loc_offsets.insert (std::make_pair (&loc, appender.size ())) + .second) + throw std::runtime_error ("duplicate loc table address"); + + for (dwarf_output::location_attr::const_iterator jt = loc.begin (); + jt != loc.end (); ++jt) + { + write_form (inserter, DW_FORM_addr, jt->first.first); + write_form (inserter, DW_FORM_addr, jt->first.second); + write_form (inserter, DW_FORM_data2, jt->second.size ()); + std::copy (jt->second.begin (), jt->second.end (), inserter); + } + + // end of list entry + write_form (inserter, DW_FORM_addr, 0); + write_form (inserter, DW_FORM_addr, 0); + } +} diff --git a/libdw/c++/output-shape.cc b/libdw/c++/output-shape.cc deleted file mode 100644 index 14e48ef14..000000000 --- a/libdw/c++/output-shape.cc +++ /dev/null @@ -1,2002 +0,0 @@ -/* elfutils::dwarf_output abbrev generation. - Copyright (C) 2009 Red Hat, Inc. - This file is part of Red Hat elfutils. - - Red Hat elfutils is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by the - Free Software Foundation; version 2 of the License. - - Red Hat elfutils is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License along - with Red Hat elfutils; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. - - In addition, as a special exception, Red Hat, Inc. gives You the - additional right to link the code of Red Hat elfutils with code licensed - under any Open Source Initiative certified open source license - (http://www.opensource.org/licenses/index.php) which requires the - distribution of source code with any binary distribution and to - distribute linked combinations of the two. Non-GPL Code permitted under - this exception must only link to the code of Red Hat elfutils through - those well defined interfaces identified in the file named EXCEPTION - found in the source code files (the "Approved Interfaces"). The files - of Non-GPL Code may instantiate templates or use macros or inline - functions from the Approved Interfaces without causing the resulting - work to be covered by the GNU General Public License. Only Red Hat, - Inc. may make changes or additions to the list of Approved Interfaces. - Red Hat's grant of this exception is conditioned upon your not adding - any new exceptions. If you wish to add a new Approved Interface or - exception, please contact Red Hat. You must obey the GNU General Public - License in all respects for all of the Red Hat elfutils code and other - code used in conjunction with Red Hat elfutils except the Non-GPL Code - covered by this exception. If you modify this file, you may extend this - exception to your version of the file, but you are not obligated to do - so. If you do not wish to provide this exception without modification, - you must delete this exception statement from your version and license - this file solely under the GPL without exception. - - Red Hat elfutils is an included package of the Open Invention Network. - An included package of the Open Invention Network is a package for which - Open Invention Network licensees cross-license their patents. No patent - license is granted, either expressly or impliedly, by designation as an - included package. Should you wish to participate in the Open Invention - Network licensing program, please visit www.openinventionnetwork.com - . */ - -#include -#include -#include -#include -#include -#include -#include "dwarf_output" -#include "../../src/dwarfstrings.h" -#include "../../src/dwarf-opcodes.h" - -using namespace elfutils; - -#define __unused __attribute__ ((unused)) - -namespace -{ - struct null_constraint_t - : public dwarf_output::shape_type::form_constraint_t - { - virtual bool satisfied (__unused dwarf_output::debug_info_entry const &die, - __unused int attr, - __unused dwarf_output::attr_value const &value) const - { - return true; - } - - virtual bool equal (form_constraint_t const *other) const; - } null_constraint; - - bool - null_constraint_t::equal (form_constraint_t const *other) const - { - return other == &null_constraint; - } - - - struct cu_local_ref_constraint_t - : public dwarf_output::shape_type::form_constraint_t - { - virtual bool satisfied (__unused dwarf_output::debug_info_entry const &die, - __unused int attr, - __unused dwarf_output::attr_value const &value) const - { - return true; // xxx - } - - virtual bool equal (form_constraint_t const *other) const; - } cu_local_ref_constraint; - - bool - cu_local_ref_constraint_t::equal (form_constraint_t const *other) const - { - return other == &cu_local_ref_constraint; - } - - - struct noreloc_constraint_t - : public dwarf_output::shape_type::form_constraint_t - { - virtual bool satisfied (__unused dwarf_output::debug_info_entry const &die, - __unused int attr, - __unused dwarf_output::attr_value const &value) const - { - return true; // xxx - } - - virtual bool equal (form_constraint_t const *other) const; - } noreloc_constraint; - - bool - noreloc_constraint_t::equal (form_constraint_t const *other) const - { - return other == &noreloc_constraint; - } - - - struct constraint_and - : public dwarf_output::shape_type::form_constraint_t - { - form_constraint_t const *a; - form_constraint_t const *b; - - constraint_and (form_constraint_t const *aa, - form_constraint_t const *bb) - : a (aa), b (bb) - {} - - virtual bool satisfied (dwarf_output::debug_info_entry const &die, - int attr, - dwarf_output::attr_value const &value) const - { - return a->satisfied (die, attr, value) - && b->satisfied (die, attr, value); - } - - virtual bool equal (form_constraint_t const *other) const - { - if (constraint_and const *o - = dynamic_cast (other)) - return (a->equal (o->a) && b->equal(o->b)) - || (b->equal (o->a) && a->equal(o->b)); - else - return false; - } - }; -} - -dwarf_output::shape_type::candidate_form::candidate_form - (int a_form, form_constraint_t const *a_constraint) - : _m_hash (0) // xxx - , form (a_form) - , constraint (a_constraint ?: &null_constraint) -{} - -namespace -{ - struct ref_forms_t - : public dwarf_output::shape_type::candidate_form_vec - { - ref_forms_t () - { - typedef dwarf_output::shape_type::candidate_form - candidate_form; - static constraint_and local_noreloc_constaint (&cu_local_ref_constraint, - &noreloc_constraint); - add (DW_FORM_ref_addr); - add (candidate_form (DW_FORM_ref8, &cu_local_ref_constraint)); - add (candidate_form (DW_FORM_ref4, &cu_local_ref_constraint)); - add (candidate_form (DW_FORM_ref2, &local_noreloc_constaint)); - add (candidate_form (DW_FORM_ref1, &local_noreloc_constaint)); - add (candidate_form (DW_FORM_ref_udata, &local_noreloc_constaint)); - } - } ref_forms; - - bool - source_file_is_string (int tag, int attr) - { - switch (attr) - { - case DW_AT_decl_file: - case DW_AT_call_file: - return false; - - case DW_AT_comp_dir: - return true; - - case DW_AT_name: - switch (tag) - { - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - return true; - } - } - - throw std::runtime_error ("can't decide whether source_file_is_string"); - } - - inline dwarf_output::shape_type::candidate_form_vec const & - candidate_forms (int tag, int attr, const dwarf_output::attr_value &value) - { - // import some types into the namespace - typedef dwarf_output::shape_type::candidate_form - candidate_form; - typedef dwarf_output::shape_type::candidate_form_vec - candidate_form_vec; - typedef dwarf_output::shape_type::form_constraint_t - form_constraint_t; - - /* Having the most spacious form first means that simple sweep - that picks the first suitable form picks that biggest one, - meaning the form will be able to hold whatever data - necessary. - Having variable length the last means that in case of tie, - fixed length forms that are easy to read win. */ - static candidate_form_vec block_forms = candidate_form_vec () - .add (DW_FORM_block4) - .add (DW_FORM_block2) - .add (DW_FORM_block1) - .add (DW_FORM_block); - - static candidate_form_vec const_forms = candidate_form_vec () - .add (DW_FORM_data8) - .add (DW_FORM_data4) - .add (candidate_form (DW_FORM_data2, &noreloc_constraint)) - .add (candidate_form (DW_FORM_data1, &noreloc_constraint)) - .add (candidate_form (DW_FORM_udata, &noreloc_constraint)) // xxx & nopatch constaint - .add (candidate_form (DW_FORM_sdata, &noreloc_constraint));// xxx & nopatch constaint - - static candidate_form_vec string_forms = candidate_form_vec () - .add (DW_FORM_string) - .add (DW_FORM_strp) - ; - - switch (value.what_space ()) - { - case dwarf::VS_address: - { - static candidate_form_vec forms = candidate_form_vec () - .add(DW_FORM_addr); - return forms; - } - - case dwarf::VS_flag: - { - static candidate_form_vec forms = candidate_form_vec () - .add (DW_FORM_flag) - //.add (DW_FORM_flag_present) // xxx DWARF4 - ; - return forms; - } - - case dwarf::VS_reference: - return ::ref_forms; - - case dwarf::VS_string: - case dwarf::VS_identifier: - return string_forms; - - case dwarf::VS_constant: - if (!value.constant_is_integer ()) - return block_forms; - /* Fall through. */ - - case dwarf::VS_dwarf_constant: - case dwarf::VS_source_line: - case dwarf::VS_source_column: - return const_forms; - - case dwarf::VS_location: - if (!value.location ().is_list ()) - return block_forms; - /* Fall through. */ - - case dwarf::VS_lineptr: - case dwarf::VS_macptr: - case dwarf::VS_rangelistptr: - /* This can be either data4 or data8 depending on the size of - the offset to the client data that we are trying to encode. - In DWARF 4, the only available offset is DW_FORM_sec_offset, - which is 4 bytes in 32-bit dwarf and 8 bytes in 64-bit. */ - { - static candidate_form_vec forms = candidate_form_vec () - //.add (DW_FORM_sec_offset) // xxx DWARF4 - .add (DW_FORM_data8) - .add (DW_FORM_data4) - ; - return forms; - } - - case dwarf::VS_source_file: - if (source_file_is_string (tag, attr)) - return string_forms; - else - return const_forms; - - case dwarf::VS_discr_list: - return block_forms; - } - - throw std::logic_error ("strange value_space"); - } - - bool - numerical_p (int tag, int attr, const dwarf_output::attr_value &value) - { - dwarf::value_space vs = value.what_space (); - - switch (vs) - { - case dwarf::VS_flag: - case dwarf::VS_macptr: - case dwarf::VS_constant: - case dwarf::VS_dwarf_constant: - case dwarf::VS_source_line: - case dwarf::VS_source_column: - case dwarf::VS_address: - - // We can optimize strings here, too, we just take the length of - // the string as the value to encode, and treat it specially. - case dwarf::VS_string: - case dwarf::VS_identifier: - return true; - - case dwarf::VS_reference: // xxx this one is numerical in - // principle, but optimizing - // references is fun on its own and - // for much later - case dwarf::VS_discr_list: - case dwarf::VS_rangelistptr: // xxx same here - return false; - - case dwarf::VS_location: - if (!value.location ().is_list ()) - return true; - else - return false; // xxx and here, too - - case dwarf::VS_source_file: - if (source_file_is_string (tag, attr)) - return true; - else - return false; // xxx and here, too - - // Require that .debug_line is emitted before .debug_info. - case dwarf::VS_lineptr: - // xxx but we need to move numerical_value_to_optimize to - // writer. - return false; - } - - abort (); - } - - uint64_t - numerical_value_to_optimize (int tag, int attr, - const dwarf_output::attr_value &value) - { - dwarf::value_space vs = value.what_space (); - - switch (vs) - { - case dwarf::VS_flag: - return !!value.flag (); - - case dwarf::VS_macptr: - return 0; /* xxx */ - - case dwarf::VS_constant: - if (value.constant_is_integer ()) - return value.constant (); - else - return value.constant_block ().size (); - - case dwarf::VS_dwarf_constant: - return value.dwarf_constant (); - - case dwarf::VS_source_line: - return value.source_line (); - - case dwarf::VS_source_column: - return value.source_column (); - - case dwarf::VS_address: - return value.address (); - - case dwarf::VS_source_file: - if (!source_file_is_string (tag, attr)) - return 0; /* xxx */ - /* fall-through */ - - case dwarf::VS_string: - case dwarf::VS_identifier: - return value.string ().size (); - - case dwarf::VS_rangelistptr: - case dwarf::VS_reference: - case dwarf::VS_discr_list: - case dwarf::VS_lineptr: - abort (); - - case dwarf::VS_location: - if (!value.location ().is_list ()) - return value.location ().location ().size (); - else - abort (); - } - - abort (); - } -} - -dwarf_output::shape_type::shape_type (const debug_info_entry &die, - const dwarf_output::die_info &info) - : _m_tag (die.tag ()) - , _m_with_sibling (info._m_with_sibling) - , _m_has_children (die.has_children ()) - , _m_hash (8675309 << _m_has_children) -{ - for (debug_info_entry::attributes_type::const_iterator it - = die.attributes ().begin (); - it != die.attributes ().end (); ++it) - _m_attrs.push_back (it->first); - std::sort (_m_attrs.begin (), _m_attrs.end ()); - - // Make sure the hash is computed based on canonical order of - // (unique) attributes, not based on order in which the attributes - // are in DIE. - for (attrs_vec::const_iterator it = _m_attrs.begin (); - it != _m_attrs.end (); ++it) - subr::hash_combine (_m_hash, *it); -} - -namespace -{ - template - void - dw_write_uleb128 (Iterator it, uint64_t value) - { - do - { - uint8_t byte = value & 0x7fULL; - value >>= 7; - if (value != 0) - byte |= 0x80; - *it++ = byte; - } - while (value != 0); - } - - template - void - dw_write_sleb128 (Iterator it, int64_t value) - { - bool more = true; - do - { - uint8_t byte = value & 0x7fULL; - value >>= 7; - if ((value == 0 && !(byte & 0x40)) - || (value == -1 && (byte & 0x40))) - more = false; - else - byte |= 0x80; - - *it++ = byte; - } - while (more); - } - - template struct width_to_int; - - template <> struct width_to_int <0> - { - typedef uint8_t unsigned_t; - static uint8_t bswap (uint8_t value) { return value; } - }; - - template <> struct width_to_int <1> - : width_to_int <0> - {}; - - template <> struct width_to_int <2> - { - typedef uint16_t unsigned_t; - static uint16_t bswap (uint16_t value) { return bswap_16 (value); } - }; - - template <> struct width_to_int <4> - { - typedef uint32_t unsigned_t; - static uint32_t bswap (uint32_t value) { return bswap_32 (value); } - }; - - template <> struct width_to_int <8> - { - typedef uint64_t unsigned_t; - static uint64_t bswap (uint64_t value) { return bswap_64 (value); } - }; - - template - void dw_write (Iterator it, - typename width_to_int::unsigned_t value, - bool big_endian) - { - if (big_endian) - value = width_to_int::bswap (value); - - for (int i = 0; i < width; ++i) - { - *it++ = (uint8_t)value & 0xffUL; - value >>= 8; - } - } - -} -template -void -dwarf_output::writer::write_var (Iterator it, unsigned width, uint64_t value) -{ - switch (width) - { - case 8: - ::dw_write<8> (it, value, _m_config.big_endian); - break; - case 4: - ::dw_write<4> (it, value, _m_config.big_endian); - break; - case 2: - ::dw_write<2> (it, value, _m_config.big_endian); - break; - case 1: - ::dw_write<1> (it, value, _m_config.big_endian); - case 0: - break; - default: - throw std::runtime_error ("Width has to be 0, 1, 2, 4 or 8."); - } -} - -// Check that the value fits into 32-bits if !dwarf_64. If it -// doesn't throw an exception. The client will then be able to -// restart the process with dwarf_64 == true. -void -dwarf_output::writer::assert_fits_32 (uint64_t value) const -{ - if (!_m_config.dwarf_64 && value > (uint64_t)(uint32_t)-1) - throw dwarf_output::writer::dwarf_32_not_enough (); -} - -dwarf_output::writer::configuration::configuration (bool a_big_endian, - bool a_addr_64, - bool a_dwarf_64) - : big_endian (a_big_endian), - addr_64 (a_addr_64), - dwarf_64 (a_dwarf_64) -{} - -template -void -dwarf_output::writer::write_form (Iterator it, int form, uint64_t value) -{ - switch (form) - { - case DW_FORM_flag_present: - return; - -#define HANDLE_DATA_REF(W) \ - case DW_FORM_data##W: \ - case DW_FORM_ref##W: \ - dw_write (it, value, _m_config.big_endian); \ - return - - case DW_FORM_flag: - assert (value == 1 || value == 0); - case DW_FORM_block1: - HANDLE_DATA_REF (1); - - case DW_FORM_block2: - HANDLE_DATA_REF (2); - - case DW_FORM_block4: - HANDLE_DATA_REF (4); - - HANDLE_DATA_REF (8); - -#undef HANDLE_DATA_REF - - case DW_FORM_addr: - write_64 (it, _m_config.addr_64, value); - return; - - case DW_FORM_ref_addr: - case DW_FORM_strp: - case DW_FORM_sec_offset: - assert_fits_32 (value); - write_64 (it, _m_config.dwarf_64, value); - return; - - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_exprloc: - case DW_FORM_indirect: - dw_write_uleb128 (it, value); - return; - - case DW_FORM_sdata: - dw_write_sleb128 (it, value); - return; - } - - throw std::runtime_error (std::string ("Don't know how to write ") - + dwarf_form_string (form)); -} - -template -void -dwarf_output::writer::write_block (IteratorOut it, int form, - IteratorIn begin, IteratorIn end) -{ - assert (form == DW_FORM_block - || form == DW_FORM_block1 - || form == DW_FORM_block2 - || form == DW_FORM_block4); - - write_form (it, form, end - begin); - std::copy (begin, end, it); -} - -namespace -{ - class CountingIterator - { - size_t &_m_count; - - public: - CountingIterator (size_t &count) - : _m_count (count) - {} - - CountingIterator (CountingIterator const ©) - : _m_count (copy._m_count) - {} - - CountingIterator &operator= (CountingIterator const &other) - { - _m_count = other._m_count; - return *this; - } - - CountingIterator &operator++ (int) - { - _m_count++; - return *this; - } - - struct ref - { - template - ref &operator= (T t __attribute__ ((unused))) - { - return *this; - } - }; - - ref operator *() - { - return ref (); - } - }; - - /* Return width of data stored with given form. For block forms, - return width of length field. */ - size_t - form_width (int form, bool addr_64, bool dwarf_64) - { - switch (form) - { - case DW_FORM_flag_present: - return 0; - - case DW_FORM_block1: - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - return 1; - - case DW_FORM_block2: - case DW_FORM_data2: - case DW_FORM_ref2: - return 2; - - case DW_FORM_block4: - case DW_FORM_data4: - case DW_FORM_ref4: - return 4; - - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - return 8; - - case DW_FORM_addr: - return addr_64 ? 8 : 4; - - case DW_FORM_ref_addr: - case DW_FORM_strp: - case DW_FORM_sec_offset: - return dwarf_64 ? 8 : 4; - - case DW_FORM_block: - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_exprloc: - case DW_FORM_indirect: - throw std::runtime_error - (std::string ("Can't compute width of LEB128 form ") - + dwarf_form_string (form)); - - case DW_FORM_string: - throw std::runtime_error - ("You shouldn't need the width of DW_FORM_string."); - } - - throw std::runtime_error - (std::string ("Don't know length of ") + dwarf_form_string (form)); - } - - size_t - numerical_encoded_length (uint64_t value, int form, - bool addr_64, bool dwarf_64) - { - switch (form) - { - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_exprloc: - case DW_FORM_indirect: - case DW_FORM_block: - case DW_FORM_sdata: - { - size_t count = 0; - CountingIterator counter (count); - if (form == DW_FORM_sdata) - dw_write_sleb128 (counter, value); - else - dw_write_uleb128 (counter, value); - return count; - } - - // xxx string logic should be extracted and treated using - // different pass - case DW_FORM_string: - return value + 1; /* For strings, we yield string length plus - terminating zero. */ - - default: - return form_width (form, addr_64, dwarf_64); - } - } - - bool - numerical_value_fits_form (uint64_t value, int form, bool addr_64) - { - switch (form) - { - case DW_FORM_flag_present: - return value == 1; - - case DW_FORM_flag: - case DW_FORM_data1: - case DW_FORM_ref1: - case DW_FORM_block1: - return value <= (uint8_t)-1; - - case DW_FORM_data2: - case DW_FORM_ref2: - case DW_FORM_block2: - return value <= (uint16_t)-1; - - case DW_FORM_ref_addr: - case DW_FORM_strp: - case DW_FORM_sec_offset: - // We simply assume that these dwarf_64-dependent forms can - // contain any value. If dwarf_64==false && value > 32bit, we - // throw an exception when we try to write that value. - return true; - - case DW_FORM_string: - // This can hold anything. - return true; - - case DW_FORM_addr: - if (addr_64) - return true; - /* fall-through */ - case DW_FORM_data4: - case DW_FORM_ref4: - case DW_FORM_block4: - return value <= (uint64_t)(uint32_t)-1; - - /* 64-bit forms. Everything fits there. */ - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_exprloc: - case DW_FORM_indirect: - case DW_FORM_block: - case DW_FORM_sdata: - return true; - } - - throw std::runtime_error - (std::string ("Don't know whether value fits ") - + dwarf_form_string (form)); - } - - void - write_version (section_appender &appender, - bool big_endian, - unsigned version) - { - ::dw_write<2> (appender.alloc (2), version, big_endian); - } -} - -void -dwarf_output::writer::write_string (std::string const &str, - int form, - section_appender &appender) -{ - if (form == DW_FORM_string) - { - std::copy (str.begin (), str.end (), - std::back_inserter (appender)); - appender.push_back (0); - } - else - { - assert (form == DW_FORM_strp); - - _m_str_backpatch.push_back - (std::make_pair (gap (*this, appender, form), - _m_debug_str.add (str))); - } -} - -void -dwarf_output::shape_info::instantiate - (dwarf_output::shape_type const &shape, - dwarf_output_collector &col, - bool addr_64, bool dwarf_64) -{ - bool with_sibling = shape._m_with_sibling[true] && shape._m_has_children; - bool without_sibling = shape._m_with_sibling[false] || !with_sibling; - - struct - { - void operator () (instance_type &inst, - debug_info_entry const &die, int attr, - bool my_addr_64, bool my_dwarf_64) - { - // Optimization of sibling attribute will be done afterward. - // For now just stick the biggest form in there. - int form; - if (attr == DW_AT_sibling) - form = DW_FORM_ref8; - else - { - int tag = die.tag (); - dwarf_output::attr_value const &value - = die.attributes ().find (attr)->second; - shape_type::candidate_form_vec const &candidates - = ::candidate_forms (tag, attr, value); - - if (!numerical_p (tag, attr, value)) - { - form = -1; - - // Just take the first form matching the - // constraints, we will optimize in separate sweep. - // Assume that candidates are stored in order from - // the most capacitous to the least. - for (shape_type::candidate_form_vec::const_iterator ct - = candidates.begin (); - ct != candidates.end (); ++ct) - if (ct->constraint->satisfied (die, attr, value)) - { - form = ct->form; - break; - } - assert (form != -1); - } - else - { - size_t best_len = 0; - form = -1; - - uint64_t opt_val - = numerical_value_to_optimize (tag, attr, value); - - for (shape_type::candidate_form_vec::const_iterator ct - = candidates.begin (); - ct != candidates.end (); ++ct) - if (ct->constraint->satisfied (die, attr, value) - && numerical_value_fits_form (opt_val, ct->form, - my_addr_64)) - { - size_t len - = numerical_encoded_length (opt_val, ct->form, - my_addr_64, my_dwarf_64); - if (form == -1 || len < best_len) - { - form = ct->form; - if (len == 1) // you can't top that - break; - best_len = len; - } - } - assert (form != -1); - } - } - inst.forms.insert (std::make_pair (attr, form)); - } - } handle_attrib; - - for (die_ref_vect::const_iterator it = _m_users.begin (); - it != _m_users.end (); ++it) - { - instance_type inst; - debug_info_entry const &die = *it; - for (shape_type::attrs_vec::const_iterator at = shape._m_attrs.begin (); - at != shape._m_attrs.end (); ++at) - handle_attrib (inst, die, *at, addr_64, dwarf_64); - - die_info &i = col._m_unique.find (die)->second; - if (without_sibling) - i.abbrev_ptr[false] = _m_instances.insert (inst).first; - - if (with_sibling) - { - handle_attrib (inst, die, DW_AT_sibling, addr_64, dwarf_64); - i.abbrev_ptr[true] = _m_instances.insert (inst).first; - } - } - - // xxx: instance merging? Locate instances A and B (and C and ...?) - // such that instance X can be created that covers all users of A - // and B, and such that the space saved by removing the - // abbreviations A and B tops the overhead of introducing non-ideal - // (wrt users of A and B) X and moving all the users over to it. - - // Hmm, except that the is-advantageous math involves number of - // users of the abbrev, and we don't know number of users before we - // do the dissection of the tree to imported partial units. -} - -void -dwarf_output::shape_info::build_data - (dwarf_output::shape_type const &shape, - dwarf_output::shape_info::instance_type const &inst, - section_appender &appender) -{ - std::back_insert_iterator inserter - = std::back_inserter (appender); - ::dw_write_uleb128 (inserter, inst.code); - ::dw_write_uleb128 (inserter, shape._m_tag); - *inserter++ = shape._m_has_children ? DW_CHILDREN_yes : DW_CHILDREN_no; - - for (instance_type::forms_type::const_iterator it = inst.forms.begin (); - it != inst.forms.end (); ++it) - { - // ULEB128 name & form - ::dw_write_uleb128 (inserter, it->first); - ::dw_write_uleb128 (inserter, it->second); - } - - // 0 for name & form to terminate the abbreviation - *inserter++ = 0; - *inserter++ = 0; -} - -dwarf_output::writer::gap::gap (writer &parent) - : _m_parent (parent), - _m_ptr (NULL) -{} - -dwarf_output::writer::gap::gap (writer &parent, section_appender &appender, - int form, uint64_t base) - : _m_parent (parent), - _m_ptr (appender.alloc (::form_width (form, parent._m_config.addr_64, - parent._m_config.dwarf_64))), - _m_form (form), - _m_base (base) -{} - -dwarf_output::writer::gap::gap (writer &parent, unsigned char *ptr, - int form, uint64_t base) - : _m_parent (parent), - _m_ptr (ptr), - _m_form (form), - _m_base (base) -{} - -dwarf_output::writer::gap & -dwarf_output::writer::gap::operator= (gap const &other) -{ - assert (&_m_parent == &other._m_parent); - _m_ptr = other._m_ptr; - _m_form = other._m_form; - _m_base = other._m_base; - return *this; -} - -void -dwarf_output::writer::gap::patch (uint64_t value) const -{ - _m_parent.write_form (_m_ptr, _m_form, value - _m_base); -} - -namespace -{ - template - void - traverse_die_tree (Visitor &visitor, - die_info_pair const &top_info_pair) - { - class recursive_traversal - { - Visitor &visitor; - - public: - recursive_traversal (Visitor &a_visitor) - : visitor (a_visitor) - { - } - - void traverse (typename Visitor::step_t &step, - die_info_pair const &info_pair, - bool has_sibling) - { - dwarf_output::debug_info_entry const &die = info_pair.first; - - visitor.visit_die (info_pair, step, has_sibling); - if (!die.children ().empty ()) - { - typename Visitor::step_t my_step (visitor, info_pair, &step); - my_step.before_children (); - for (typename std::vector::const_iterator jt - = die.children ().info ().begin (); ;) - { - die_info_pair const &dip = **jt++; - bool my_has_sibling = jt != die.children ().info ().end (); - my_step.before_recursion (); - traverse (my_step, dip, my_has_sibling); - my_step.after_recursion (); - if (!my_has_sibling) - break; - } - my_step.after_children (); - } - } - }; - - visitor.before_traversal (); - typename Visitor::step_t step (visitor, top_info_pair, NULL); - recursive_traversal (visitor) - .traverse (step, top_info_pair, false); - visitor.after_traversal (); - } -} - -class dwarf_output::writer::dump_die_tree -{ - // [(gap, die offset)] - typedef std::vector> die_backpatch_vec; - - writer &_m_parent; - section_appender &appender; - die_off_map die_off; - die_backpatch_vec die_backpatch; - uint64_t _m_cu_start; - size_t level; - line_info_table const *lines; - - static const bool debug = false; - -public: - class step_t - { - dump_die_tree &_m_dumper; - - public: - gap sibling_gap; - - step_t (dump_die_tree &dumper, - __unused die_info_pair const &info_pair, - __unused step_t *previous) - : _m_dumper (dumper), - sibling_gap (dumper._m_parent) - { - ++_m_dumper.level; - } - - ~step_t () - { - --_m_dumper.level; - } - - void before_children () {} - void after_recursion () {} - - void after_children () - { - _m_dumper.appender.push_back (0); - } - - void before_recursion () - { - if (sibling_gap.valid ()) - { - sibling_gap.patch (_m_dumper.appender.size ()); - sibling_gap = gap (_m_dumper._m_parent); - } - } - }; - friend class step_t; - - dump_die_tree (writer &writer, - section_appender &a_appender, - uint64_t cu_start) - : _m_parent (writer), - appender (a_appender), - _m_cu_start (cu_start), - level (0), - lines (NULL) - { - } - - void visit_die (dwarf_output::die_info_pair const &info_pair, - step_t &step, - bool has_sibling) - { - static char const spaces[] = - " " - " " - " "; - static char const *tail = spaces + strlen (spaces); - char const *pad = tail - level * 2; - - debug_info_entry const &die = info_pair.first; - die_info const &info = info_pair.second; - int tag = die.tag (); - - std::back_insert_iterator inserter - = std::back_inserter (appender); - - /* Record where the DIE begins. */ - // xxx in fact, we can meet "the same" DIE several times in the - // tree. But since they are all equal, it doesn't matter which - // one we end up resolving our references to. Except for - // siblings, which we handle differently. - die_off [die.offset ()] = appender.size (); - if (debug) - std::cout << pad << "CHILD " << dwarf_tag_string (die.tag ()) - << " [0x" << std::hex << die_off [die.offset ()] << std::dec << "]" - << " " << std::flush; - - /* Our instance. */ - die_info::abbrev_ptr_map::const_iterator xt - = info.abbrev_ptr.find (die.has_children () && has_sibling); - assert (xt != info.abbrev_ptr.end ()); - shape_info::instance_type const &instance = *xt->second; - ::dw_write_uleb128 (inserter, instance.code); - - if (debug) - std::cout << " " << instance.code << std::endl; - - /* Dump attribute values. */ - debug_info_entry::attributes_type const &attribs = die.attributes (); - for (shape_info::instance_type::forms_type::const_iterator - at = instance.forms.begin (); at != instance.forms.end (); ++at) - { - int attr = at->first; - int form = at->second; - if (attr == DW_AT_sibling) - { - if (debug) - std::cout << pad << " " << dwarf_attr_string (attr) - << ":" << dwarf_form_string (form) - << " sibling=" << info._m_with_sibling[false] - << ":" << info._m_with_sibling[true] - << std::endl; - step.sibling_gap = gap (_m_parent, appender, form, _m_cu_start); - continue; - } - - debug_info_entry::attributes_type::const_iterator - vt = attribs.find (attr); - assert (vt != attribs.end ()); - - attr_value const &value = vt->second; - if (false && debug) - std::cout << ":" << value.to_string () << std::endl; - - dwarf::value_space vs = value.what_space (); - - switch (vs) - { - case dwarf::VS_flag: - if (form == DW_FORM_flag) - *appender.alloc (1) = !!value.flag (); - else - assert (form == DW_FORM_flag_present); - break; - - case dwarf::VS_lineptr: - { - if (lines != NULL) - throw std::runtime_error - ("Another DIE with lineptr attribute?!"); - - lines = &value.line_info (); - line_offsets_map::const_iterator it - = _m_parent._m_line_offsets.find (lines); - if (it == _m_parent._m_line_offsets.end ()) - throw std::runtime_error - ("Emit .debug_line before .debug_info"); - _m_parent.write_form (inserter, form, it->second.table_offset); - } - break; - - case dwarf::VS_rangelistptr: - _m_parent._m_range_backpatch.push_back - (std::make_pair (gap (_m_parent, appender, form), - &value.ranges ())); - break; - - case dwarf::VS_macptr: - _m_parent.write_form (inserter, form, 0 /*xxx*/); - break; - - case dwarf::VS_constant: - if (value.constant_is_integer ()) - _m_parent.write_form (inserter, form, value.constant ()); - else - _m_parent.write_block (inserter, form, - value.constant_block ().begin (), - value.constant_block ().end ()); - break; - - case dwarf::VS_dwarf_constant: - _m_parent.write_form (inserter, form, value.dwarf_constant ()); - break; - - case dwarf::VS_source_line: - _m_parent.write_form (inserter, form, value.source_line ()); - break; - - case dwarf::VS_source_column: - _m_parent.write_form (inserter, form, value.source_column ()); - break; - - case dwarf::VS_string: - _m_parent.write_string (value.string (), form, appender); - break; - - case dwarf::VS_identifier: - _m_parent.write_string (value.identifier (), form, appender); - break; - - case dwarf::VS_source_file: - if (source_file_is_string (tag, attr)) - _m_parent.write_string (value.source_file ().name (), - form, appender); - else - { - assert (lines != NULL); - writer::line_offsets_map::const_iterator - it = _m_parent._m_line_offsets.find (lines); - assert (it != _m_parent._m_line_offsets.end ()); - writer::line_offsets::source_file_map::const_iterator - jt = it->second.source_files.find (value.source_file ()); - assert (jt != it->second.source_files.end ()); - _m_parent.write_form (inserter, form, jt->second); - } - break; - - case dwarf::VS_address: - _m_parent.write_form (inserter, form, value.address ()); - break; - - case dwarf::VS_reference: - { - assert (form == DW_FORM_ref_addr); - die_backpatch.push_back - (std::make_pair (gap (_m_parent, appender, form), - value.reference ()->offset ())); - } - break; - - case dwarf::VS_location: - if (!value.location ().is_list ()) - _m_parent.write_block (inserter, form, - value.location ().location ().begin (), - value.location ().location ().end ()); - else - _m_parent._m_loc_backpatch.push_back - (std::make_pair (gap (_m_parent, appender, form), - &value.location ())); - break; - - case dwarf::VS_discr_list: - throw std::runtime_error ("Can't handle VS_discr_list."); - }; - } - } - - void before_traversal () {} - - void after_traversal () - { - for (die_backpatch_vec::const_iterator it = die_backpatch.begin (); - it != die_backpatch.end (); ++it) - { - die_off_map::const_iterator jt = die_off.find (it->second); - if (jt == die_off.end ()) - std::cout << "can't find offset " << it->second << std::endl; - else - { - assert (jt != die_off.end ()); - it->first.patch (jt->second); - } - } - } -}; - -dwarf_output::writer::writer (dwarf_output_collector &col, - dwarf_output &dw, - bool big_endian, bool addr_64, bool dwarf_64, - strtab &debug_str) - : _m_config (big_endian, addr_64, dwarf_64), - _m_col (col), - _m_dw (dw), - _m_debug_str (debug_str) -{ - size_t code = 0; - for (dwarf_output_collector::die_map::const_iterator it - = col._m_unique.begin (); - it != col._m_unique.end (); ++it) - { - dwarf_output::shape_type shape (it->first, it->second); - shape_map::iterator st = _m_shapes.find (shape); - if (st != _m_shapes.end ()) - st->second.add_user (it->first); - else - { - dwarf_output::shape_info info (it->first); - _m_shapes.insert (std::make_pair (shape, info)); - } - } - - for (shape_map::iterator it = _m_shapes.begin (); - it != _m_shapes.end (); ++it) - { - it->second.instantiate (it->first, col, addr_64, dwarf_64); - for (dwarf_output::shape_info::instance_set::iterator jt - = it->second._m_instances.begin (); - jt != it->second._m_instances.end (); ++jt) - jt->code = ++code; - } -} - -void -dwarf_output::writer::output_debug_abbrev (section_appender &appender) -{ - for (shape_map::iterator it = _m_shapes.begin (); - it != _m_shapes.end (); ++it) - for (dwarf_output::shape_info::instance_set::iterator jt - = it->second._m_instances.begin (); - jt != it->second._m_instances.end (); ++jt) - it->second.build_data (it->first, *jt, appender); - - appender.push_back (0); // terminate table -} - -class dwarf_output::writer::length_field -{ - writer &_m_parent; - elfutils::section_appender &_m_appender; - const gap _m_length_gap; - const size_t _m_cu_start; - bool _m_finished; - - gap alloc_gap (elfutils::section_appender &appender) const - { - if (_m_parent._m_config.dwarf_64) - ::dw_write<4> (appender.alloc (4), -1, _m_parent._m_config.big_endian); - gap g (_m_parent, appender, DW_FORM_ref_addr); - g.set_base (appender.size ()); - return g; - } - -public: - length_field (writer &parent, - elfutils::section_appender &appender) - : _m_parent (parent), - _m_appender (appender), - _m_length_gap (alloc_gap (appender)), - _m_cu_start (appender.size ()), - _m_finished (false) - {} - - void finish () - { - assert (!_m_finished); - _m_length_gap.patch (_m_appender.size ()); - _m_finished = true; - } -}; - -void -dwarf_output::writer::output_debug_info (section_appender &appender) -{ - std::back_insert_iterator inserter - = std::back_inserter (appender); - - for (compile_units::const_iterator it = _m_dw._m_units.begin (); - it != _m_dw._m_units.end (); ++it) - { - // Remember where the unit started for DIE offset calculation. - size_t cu_start = appender.size (); - - length_field lf (*this, appender); - ::write_version (appender, _m_config.big_endian, 3); - - // Debug abbrev offset. Use the single abbrev table that we - // emit at offset 0. - ::dw_write<4> (appender.alloc (4), 0, _m_config.big_endian); - - // Size in bytes of an address on the target architecture. - *inserter++ = _m_config.addr_64 ? 8 : 4; - - dump_die_tree dumper (*this, appender, cu_start); - ::traverse_die_tree (dumper, *_m_col._m_unique.find (*it)); - - lf.finish (); - } -} - -class dwarf_output::writer::linenum_prog_instruction -{ - writer &_m_parent; - std::vector const &_m_operands; - std::vector::const_iterator _m_op_it; - -protected: - std::vector _m_buf; - - linenum_prog_instruction (writer &parent, - std::vector const &operands) - : _m_parent (parent), - _m_operands (operands), - _m_op_it (_m_operands.begin ()) - {} - -public: - void arg (uint64_t value) - { - assert (_m_op_it != _m_operands.end ()); - _m_parent.write_form (std::back_inserter (_m_buf), *_m_op_it++, value); - } - - void arg (std::string const &value) - { - assert (_m_op_it != _m_operands.end ()); - int form = *_m_op_it++; - assert (form == DW_FORM_string); - - std::copy (value.begin (), value.end (), std::back_inserter (_m_buf)); - _m_buf.push_back (0); - } - - void write (section_appender &appender) - { - assert (_m_op_it == _m_operands.end ()); - std::copy (_m_buf.begin (), _m_buf.end (), - std::back_inserter (appender)); - } -}; - -class dwarf_output::writer::standard_opcode - : public dwarf_output::writer::linenum_prog_instruction -{ - int _m_opcode; - - static std::vector const &build_arglist (int opcode) - { - static struct arglist - : public std::map > - { - arglist () - { -#define DW_LNS_0(OP) \ - (*this)[OP]; -#define DW_LNS_1(OP, OP1) \ - (*this)[OP].push_back (OP1); - - DW_LNS_OPERANDS; - -#undef DW_LNS_1 -#undef DW_LNS_0 - } - } const operands; - - arglist::const_iterator it = operands.find (opcode); - assert (it != operands.end ()); - return it->second; - } - -public: - standard_opcode (writer &parent, int opcode) - : linenum_prog_instruction (parent, build_arglist (opcode)), - _m_opcode (opcode) - {} - - template - inline standard_opcode &arg (T const &value) - { - linenum_prog_instruction::arg (value); - return *this; - } - - void write (section_appender &appender) - { - appender.push_back (_m_opcode); - linenum_prog_instruction::write (appender); - } -}; - -class dwarf_output::writer::extended_opcode - : public dwarf_output::writer::linenum_prog_instruction -{ - int _m_opcode; - - static std::vector const &build_arglist (int opcode) - { - static struct arglist - : public std::map > - { - arglist () - { -#define DW_LNE_0(OP) \ - (*this)[OP]; -#define DW_LNE_1(OP, OP1) \ - (*this)[OP].push_back (OP1); -#define DW_LNE_4(OP, OP1, OP2, OP3, OP4) \ - (*this)[OP].push_back (OP1); \ - (*this)[OP].push_back (OP2); \ - (*this)[OP].push_back (OP3); \ - (*this)[OP].push_back (OP4); - - DW_LNE_OPERANDS; - -#undef DW_LNE_4 -#undef DW_LNE_1 -#undef DW_LNE_0 - } - } const operands; - - arglist::const_iterator it = operands.find (opcode); - assert (it != operands.end ()); - return it->second; - } - -public: - extended_opcode (writer &parent, int opcode) - : linenum_prog_instruction (parent, build_arglist (opcode)), - _m_opcode (opcode) - {} - - template - inline extended_opcode &arg (T const &value) - { - linenum_prog_instruction::arg (value); - return *this; - } - - void write (section_appender &appender) - { - appender.push_back (0); - ::dw_write_uleb128 (std::back_inserter (appender), _m_buf.size () + 1); - appender.push_back (_m_opcode); - linenum_prog_instruction::write (appender); - } -}; - -class dwarf_output::writer::line_offsets::add_die_ref_files -{ - line_offsets::source_file_map &_m_files; - -public: - struct step_t - { - step_t (__unused add_die_ref_files &adder, - __unused die_info_pair const &info_pair, - __unused step_t *previous) - {} - - void before_children () {} - void after_children () {} - void before_recursion () {} - void after_recursion () {} - }; - - add_die_ref_files (line_offsets::source_file_map &files) : _m_files (files) {} - - void visit_die (dwarf_output::die_info_pair const &info_pair, - __unused step_t &step, - __unused bool has_sibling) - { - debug_info_entry const &die = info_pair.first; - - debug_info_entry::attributes_type const &attribs = die.attributes (); - for (debug_info_entry::attributes_type::const_iterator at - = attribs.begin (); at != attribs.end (); ++at) - { - attr_value const &value = at->second; - dwarf::value_space vs = value.what_space (); - - if (vs == dwarf::VS_source_file - && !source_file_is_string (die.tag (), at->first)) - _m_files.insert (std::make_pair (value.source_file (), 0)); - } - } - - void before_traversal () {} - void after_traversal () {} -}; - -dwarf_output::writer:: -line_offsets::line_offsets (__unused writer const &wr, - dwarf_output::line_table const &lines, - ::Dwarf_Off off) - : table_offset (off) -{ - // We need to include all files referenced through DW_AT_*_file and - // all files used in line number program. - for (dwarf_output::line_table::const_iterator line_it = lines.begin (); - line_it != lines.end (); ++line_it) - { - dwarf_output::line_entry const &entry = *line_it; - dwarf_output::source_file const &file = entry.file (); - line_offsets::source_file_map::const_iterator sfit - = source_files.find (file); - if (sfit == source_files.end ()) - source_files.insert (std::make_pair (file, 0)); - } - - for (compile_units::const_iterator it = wr._m_dw._m_units.begin (); - it != wr._m_dw._m_units.end (); ++it) - if (&it->lines () == &lines) - { - add_die_ref_files adder (source_files); - ::traverse_die_tree (adder, *wr._m_col._m_unique.find (*it)); - } - - // Assign numbers to source files. - size_t file_idx = 0; - for (line_offsets::source_file_map::iterator sfit = source_files.begin (); - sfit != source_files.end (); ++sfit) - sfit->second = ++file_idx; -} - -void -dwarf_output::writer::output_debug_line (section_appender &appender) -{ - std::back_insert_iterator inserter - = std::back_inserter (appender); - - for (subr::value_set::const_iterator it - = _m_col._m_line_info.begin (); - it != _m_col._m_line_info.end (); ++it) - { - dwarf_output::line_info_table const < = it->second; - dwarf_output::line_table const &lines = lt.lines (); - - line_offsets offset_tab (*this, lines, appender.size ()); - // the table is inserted in _m_line_offsets at the loop's end - - length_field table_length (*this, appender); - ::write_version (appender, _m_config.big_endian, 3); - length_field header_length (*this, appender); - - // minimum_instruction_length - unsigned minimum_instruction_length = 1; - appender.push_back (minimum_instruction_length); - - // default_is_stmt - bool default_is_stmt = true; - appender.push_back (default_is_stmt ? 1 : 0); - - // line_base, line_range - appender.push_back (uint8_t (int8_t (0))); - appender.push_back (1); - -#define DW_LNS_0(OP) 0, -#define DW_LNS_1(OP, OP1) 1, - uint8_t opcode_lengths[] = { - DW_LNS_OPERANDS - }; -#undef DW_LNS_1 -#undef DW_LNS_0 - - // opcode_base - appender.push_back (sizeof (opcode_lengths) + 1); - - // standard_opcode_lengths (array of ubyte) - std::copy (opcode_lengths, opcode_lengths + sizeof (opcode_lengths), - inserter); - - // include_directories - dwarf_output::directory_table const &dirs = lt.include_directories (); - for (dwarf_output::directory_table::const_iterator dir_it - = dirs.begin (); dir_it != dirs.end (); ++dir_it) - if (*dir_it != "") - { - std::copy (dir_it->begin (), dir_it->end (), inserter); - *inserter++ = 0; - } - *inserter++ = 0; - - // file_names - for (line_offsets::source_file_map::const_iterator sfit - = offset_tab.source_files.begin (); - sfit != offset_tab.source_files.end (); ++sfit) - { - dwarf_output::source_file const &sf = sfit->first; - - // Find the best-fitting directory for this filename. - size_t dir_index = 0; - size_t match_len = 0; - for (dwarf_output::directory_table::const_iterator dir_it - = dirs.begin () + 1; dir_it != dirs.end (); ++dir_it) - { - std::string const &dir = *dir_it; - if (dir.length () > match_len - && sf.name ().substr (0, dir.length ()) == dir) - { - dir_index = dir_it - dirs.begin (); - match_len = dir.length (); - } - } - - std::string fn = sf.name ().substr (match_len + 1); - std::copy (fn.begin (), fn.end (), inserter); - *inserter++ = 0; - ::dw_write_uleb128 (inserter, dir_index); - ::dw_write_uleb128 (inserter, sf.mtime ()); - ::dw_write_uleb128 (inserter, sf.size ()); - } - *inserter++ = 0; - - header_length.finish (); - - // Now emit the "meat" of the table: the line number program. - struct registers - { - ::Dwarf_Addr addr; - unsigned file; - unsigned line; - unsigned column; - bool is_stmt; - bool default_is_stmt; - - void init () - { - addr = 0; - file = 1; - line = 1; - column = 0; - is_stmt = default_is_stmt; - } - - explicit registers (bool b) - : default_is_stmt (b) - { - init (); - } - } reg (default_is_stmt); - - for (dwarf_output::line_table::const_iterator line_it = lines.begin (); - line_it != lines.end (); ++line_it) - { - dwarf_output::line_entry const &entry = *line_it; - ::Dwarf_Addr addr = entry.address (); - unsigned file = offset_tab.source_files.find (entry.file ())->second; - unsigned line = entry.line (); - unsigned column = entry.column (); - bool is_stmt = entry.statement (); - -#if 0 - std::cout << std::hex << addr << std::dec - << "\t" << file - << "\t" << line - << "\t" << column - << "\t" << is_stmt - << "\t" << entry.end_sequence () << std::endl; -#endif - -#define ADVANCE_OPCODE(WHAT, STEP, OPCODE) \ - { \ - __typeof (WHAT) const &what = WHAT; \ - __typeof (WHAT) const ®_what = reg.WHAT; \ - unsigned step = STEP; \ - if (what != reg_what) \ - { \ - __typeof (WHAT) delta = what - reg_what;\ - __typeof (WHAT) advance = delta / step; \ - assert (advance * step == delta); \ - standard_opcode (*this, OPCODE) \ - .arg (advance) \ - .write (appender); \ - } \ - } - -#define SET_OPCODE(WHAT, OPCODE) \ - { \ - __typeof (WHAT) const &what = WHAT; \ - __typeof (WHAT) const ®_what = reg.WHAT; \ - if (what != reg_what) \ - standard_opcode (*this, OPCODE) \ - .arg (what) \ - .write (appender); \ - } - -#define SIMPLE_OPCODE(WHAT, OPCODE) \ - if (entry.WHAT ()) \ - standard_opcode (*this, OPCODE) \ - .write (appender); - - ADVANCE_OPCODE (addr, minimum_instruction_length, DW_LNS_advance_pc); - SET_OPCODE (file, DW_LNS_set_file); - ADVANCE_OPCODE (line, 1, DW_LNS_advance_line); - SET_OPCODE (column, DW_LNS_set_column); - SIMPLE_OPCODE (basic_block, DW_LNS_set_basic_block); - SIMPLE_OPCODE (prologue_end, DW_LNS_set_prologue_end); - SIMPLE_OPCODE (epilogue_begin, DW_LNS_set_epilogue_begin); - - if (is_stmt != reg.is_stmt) - standard_opcode (*this, DW_LNS_negate_stmt) - .write (appender); - -#undef SIMPLE_OPCODE -#undef SET_OPCODE -#undef ADVANCE_OPCODE - - if (entry.end_sequence ()) - { - extended_opcode (*this, DW_LNE_end_sequence) - .write (appender); - reg.init (); - } - else - { - standard_opcode (*this, DW_LNS_copy) - .write (appender); - - reg.addr = addr; - reg.file = file; - reg.line = line; - reg.column = column; - reg.is_stmt = is_stmt; - } - } - - table_length.finish (); - - if (!_m_line_offsets.insert (std::make_pair (<, offset_tab)).second) - throw std::runtime_error ("duplicate line table address"); - } -} - -void -dwarf_output::writer::output_debug_ranges (section_appender &appender) -{ - std::back_insert_iterator inserter - = std::back_inserter (appender); - - for (subr::value_set::const_iterator - it = _m_col._m_ranges.begin (); it != _m_col._m_ranges.end (); ++it) - { - dwarf_output::range_list const &rl = it->second; - if (!_m_range_offsets.insert (std::make_pair (&rl, appender.size ())) - .second) - throw std::runtime_error ("duplicate range table address"); - - for (dwarf_output::range_list::const_iterator range_it = rl.begin (); - range_it != rl.end (); ++range_it) - { - write_form (inserter, DW_FORM_addr, range_it->first); - write_form (inserter, DW_FORM_addr, range_it->second); - } - - // end of list entry - write_form (inserter, DW_FORM_addr, 0); - write_form (inserter, DW_FORM_addr, 0); - } -} - -void -dwarf_output::writer::output_debug_loc (section_appender &appender) -{ - typedef std::set loc_set; - loc_set locations; - - for (dwarf_output_collector::die_map::const_iterator it - = _m_col._m_unique.begin (); - it != _m_col._m_unique.end (); ++it) - { - debug_info_entry const &die = it->first; - for (debug_info_entry::attributes_type::const_iterator - at = die.attributes ().begin (); - at != die.attributes ().end (); ++at) - { - attr_value const &value = at->second; - dwarf::value_space vs = value.what_space (); - - if (vs == dwarf::VS_location) - { - dwarf_output::location_attr const &loc = value.location (); - if (loc.is_list ()) - locations.insert (&loc); - } - } - } - - std::back_insert_iterator inserter - = std::back_inserter (appender); - for (loc_set::const_iterator it = locations.begin (); - it != locations.end (); ++it) - { - dwarf_output::location_attr const &loc = **it; - if (!_m_loc_offsets.insert (std::make_pair (&loc, appender.size ())) - .second) - throw std::runtime_error ("duplicate loc table address"); - - for (dwarf_output::location_attr::const_iterator jt = loc.begin (); - jt != loc.end (); ++jt) - { - write_form (inserter, DW_FORM_addr, jt->first.first); - write_form (inserter, DW_FORM_addr, jt->first.second); - write_form (inserter, DW_FORM_data2, jt->second.size ()); - std::copy (jt->second.begin (), jt->second.end (), inserter); - } - - // end of list entry - write_form (inserter, DW_FORM_addr, 0); - write_form (inserter, DW_FORM_addr, 0); - } -} - -void -dwarf_output::writer::apply_patches () -{ - for (str_backpatch_vec::const_iterator it = _m_str_backpatch.begin (); - it != _m_str_backpatch.end (); ++it) - it->first.patch (ebl_strtaboffset (it->second)); - - for (range_backpatch_vec::const_iterator it = _m_range_backpatch.begin (); - it != _m_range_backpatch.end (); ++it) - { - range_offsets_map::const_iterator ot = _m_range_offsets.find (it->second); - if (ot == _m_range_offsets.end ()) - // no point mentioning the key, since it's just a memory - // address... - throw std::runtime_error (".debug_ranges ref not found"); - it->first.patch (ot->second); - } - - for (loc_backpatch_vec::const_iterator it = _m_loc_backpatch.begin (); - it != _m_loc_backpatch.end (); ++it) - { - loc_offsets_map::const_iterator ot = _m_loc_offsets.find (it->second); - if (ot == _m_loc_offsets.end ()) - // no point mentioning the key, since it's just a memory - // address... - throw std::runtime_error (".debug_loc ref not found"); - it->first.patch (ot->second); - } -} diff --git a/libdw/c++/writer.cc b/libdw/c++/writer.cc new file mode 100644 index 000000000..729af705d --- /dev/null +++ b/libdw/c++/writer.cc @@ -0,0 +1,168 @@ +/* elfutils::dwarf_output implementation of writer itself. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include + +#include "dwarf_output" +#include "emit-misc.hh" +using namespace elfutils; + +dwarf_output::writer::gap::gap (writer &parent) + : _m_parent (parent), + _m_ptr (NULL) +{} + +dwarf_output::writer::gap::gap (writer &parent, section_appender &appender, + int form, uint64_t base) + : _m_parent (parent), + _m_ptr (appender.alloc (writer::form_width (form, parent._m_config.addr_64, + parent._m_config.dwarf_64))), + _m_form (form), + _m_base (base) +{} + +dwarf_output::writer::gap::gap (writer &parent, unsigned char *ptr, + int form, uint64_t base) + : _m_parent (parent), + _m_ptr (ptr), + _m_form (form), + _m_base (base) +{} + +dwarf_output::writer::gap & +dwarf_output::writer::gap::operator= (gap const &other) +{ + assert (&_m_parent == &other._m_parent); + _m_ptr = other._m_ptr; + _m_form = other._m_form; + _m_base = other._m_base; + return *this; +} + +void +dwarf_output::writer::gap::patch (uint64_t value) const +{ + _m_parent.write_form (_m_ptr, _m_form, value - _m_base); +} + + +dwarf_output::writer::configuration::configuration (bool a_big_endian, + bool a_addr_64, + bool a_dwarf_64) + : big_endian (a_big_endian), + addr_64 (a_addr_64), + dwarf_64 (a_dwarf_64) +{} + + +dwarf_output::writer::writer (dwarf_output_collector &col, + dwarf_output &dw, + bool big_endian, bool addr_64, bool dwarf_64, + strtab &debug_str) + : _m_config (big_endian, addr_64, dwarf_64), + _m_col (col), + _m_dw (dw), + _m_debug_str (debug_str) +{ + size_t code = 0; + for (dwarf_output_collector::die_map::const_iterator it + = col._m_unique.begin (); + it != col._m_unique.end (); ++it) + { + dwarf_output::shape_type shape (it->first, it->second); + shape_map::iterator st = _m_shapes.find (shape); + if (st != _m_shapes.end ()) + st->second.add_user (it->first); + else + { + dwarf_output::shape_info info (it->first); + _m_shapes.insert (std::make_pair (shape, info)); + } + } + + for (shape_map::iterator it = _m_shapes.begin (); + it != _m_shapes.end (); ++it) + { + it->second.instantiate (it->first, col, addr_64, dwarf_64); + for (dwarf_output::shape_info::instance_set::iterator jt + = it->second._m_instances.begin (); + jt != it->second._m_instances.end (); ++jt) + jt->code = ++code; + } +} + +void +dwarf_output::writer::apply_patches () +{ + for (str_backpatch_vec::const_iterator it = _m_str_backpatch.begin (); + it != _m_str_backpatch.end (); ++it) + it->first.patch (ebl_strtaboffset (it->second)); + + for (range_backpatch_vec::const_iterator it = _m_range_backpatch.begin (); + it != _m_range_backpatch.end (); ++it) + { + range_offsets_map::const_iterator ot = _m_range_offsets.find (it->second); + if (ot == _m_range_offsets.end ()) + // no point mentioning the key, since it's just a memory + // address... + throw std::runtime_error (".debug_ranges ref not found"); + it->first.patch (ot->second); + } + + for (loc_backpatch_vec::const_iterator it = _m_loc_backpatch.begin (); + it != _m_loc_backpatch.end (); ++it) + { + loc_offsets_map::const_iterator ot = _m_loc_offsets.find (it->second); + if (ot == _m_loc_offsets.end ()) + // no point mentioning the key, since it's just a memory + // address... + throw std::runtime_error (".debug_loc ref not found"); + it->first.patch (ot->second); + } +} -- 2.47.3