From: Roland McGrath Date: Mon, 2 Feb 2009 04:40:36 +0000 (-0800) Subject: Implement attribute values in dwarf_edit. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8516006aa34f2cab2b969e84f0109cfcc88bf2c9;p=thirdparty%2Felfutils.git Implement attribute values in dwarf_edit. --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 7b1d37e9d..cbd457dfc 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,7 @@ +2009-02-01 Roland McGrath + + * c++/edit-values.cc: New file. + 2009-01-28 Roland McGrath * c++/dwarf: Add line table support. diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf index 14f2947f0..c79a77c09 100644 --- a/libdw/c++/dwarf +++ b/libdw/c++/dwarf @@ -225,6 +225,7 @@ namespace elfutils { return !(*this == other); } + }; // One DWARF object file. @@ -1236,9 +1237,11 @@ namespace elfutils if (empty ()) return (other.empty () || std::find_if (other.begin (), other.end (), - nonempty ()) == other.end ()); + nonempty () + ) == other.end ()); if (!is_list ()) - return !other.is_list () && location () == other.location (); + return (!other.is_list () && !other.empty () + && location () == other.location ()); return other.is_list () && subr::container_equal (*this, other); } diff --git a/libdw/c++/dwarf_edit b/libdw/c++/dwarf_edit index 3235199bf..1a8df1e8a 100644 --- a/libdw/c++/dwarf_edit +++ b/libdw/c++/dwarf_edit @@ -51,6 +51,7 @@ #define _ELFUTILS_DWARF_EDIT 1 #include "dwarf" +#include /* Read the comments for elfutils::dwarf first. @@ -80,13 +81,7 @@ namespace elfutils { public: class compile_units; - - // XXX later - class attr_value : public dwarf::attr_value - { - public: - attr_value (const dwarf::attr_value &v) : dwarf::attr_value (v) {} - }; + class attr_value; class debug_info_entry { @@ -220,17 +215,20 @@ namespace elfutils { friend class dwarf_edit; private: + typedef std::list _base; + // Default constructor: an empty container, no CUs. inline compile_units () {} // Constructor copying CUs from input container. template compile_units(const input &units) - : std::list (units.begin (), units.end ()) - {} + : _base (units.begin (), units.end ()) {} public: typedef compile_unit value_type; + typedef _base::iterator iterator; + typedef _base::const_iterator const_iterator; inline compile_unit &new_unit () { @@ -242,7 +240,7 @@ namespace elfutils template bool operator== (const other_children &other) const { - return std::equal (begin (), end (), other.begin ()); + return subr::container_equal (*this, other); } template bool operator!= (const other_children &other) const @@ -251,6 +249,790 @@ namespace elfutils } }; + // Same as set>. + class range_list : public dwarf::arange_list + { + public: + template + range_list (const list &other) + : dwarf::arange_list (other.begin (), other.end ()) {} + }; + + class source_file + { + private: + std::string _m_name; + ::Dwarf_Word _m_mtime; + ::Dwarf_Word _m_size; + + public: + source_file () : _m_name (), _m_mtime (0), _m_size (0) {} + source_file (const std::string &n, ::Dwarf_Word m = 0, ::Dwarf_Word s = 0) + : _m_name (n), _m_mtime (m), _m_size (s) {} + + template + source_file (const file &other) + : _m_name (other.name ()), + _m_mtime (other.mtime ()), _m_size (other.size ()) {} + + template + inline source_file &operator= (const file &other) + { + _m_name = other.name (); + _m_mtime = other.mtime (); + _m_size = other.size (); + return *this; + } + inline source_file &operator= (const std::string &n) + { + _m_name = n; + _m_mtime = 0; + _m_size = 0; + return *this; + } + inline source_file &operator= (const char *n) + { + _m_name = n; + _m_mtime = 0; + _m_size = 0; + return *this; + } + + inline std::string &name () + { + return _m_name; + } + inline const std::string &name () const + { + return _m_name; + } + inline ::Dwarf_Word &mtime () + { + return _m_mtime; + } + inline ::Dwarf_Word mtime () const + { + return _m_mtime; + } + inline ::Dwarf_Word &size () + { + return _m_size; + } + inline ::Dwarf_Word size () const + { + return _m_size; + } + + template + bool operator== (const other_file &other) const + { + if (mtime () != 0) + { + ::Dwarf_Word other_mtime = other.mtime (); + if (other_mtime != 0 && other_mtime != mtime ()) + return false; + } + if (size () != 0) + { + ::Dwarf_Word other_size = other.size (); + if (other_size != 0 && other_size != size ()) + return false; + } + return name () == other.name (); + } + template + inline bool operator!= (const other_file &other) const + { + return !(*this == other); + } + }; + + // This describes a CU's directory table, a simple array of strings. + class directory_table : public std::vector + { + private: + typedef std::vector _base; + + public: + directory_table () {} + + template + directory_table (const table &other) + : _base (other.begin (), other.end ()) {} + + template + inline bool operator== (const table &other) const + { + return size () == other.size () && subr::container_equal (*this, other); + } + template + inline bool operator!= (const table &other) const + { + return !(*this == other); + } + }; + + class line_entry + { + private: + ::Dwarf_Addr _m_addr; // XXX dwfl, reloc + source_file _m_file; + unsigned int _m_line; + unsigned int _m_column; + + enum flag_bit + { + flag_statement, + flag_basic_block, + flag_end_sequence, + flag_prologue_end, + flag_epilogue_begin, + flag_count + }; + std::bitset _m_flags; + + public: + line_entry (::Dwarf_Addr addr) + : _m_addr (addr), _m_file (), _m_line (0), _m_column (0) {} + + template + line_entry (const entry &other) + : _m_addr (0), _m_file (), _m_line (0), _m_column (0) + { + *this = other; + } + + template + line_entry &operator= (const entry &other) + { + _m_addr = other.address (); + _m_file = other.file (); + _m_line = other.line (); + _m_column = other.column (); + statement () = other.statement (); + basic_block () = other.basic_block (); + end_sequence () = other.end_sequence (); + prologue_end () = other.prologue_end (); + epilogue_begin () = other.epilogue_begin (); + return *this; + } + + inline ::Dwarf_Addr &address () + { + return _m_addr; + } + inline ::Dwarf_Addr address () const + { + return _m_addr; + } + inline source_file &file () + { + return _m_file; + } + inline const source_file &file () const + { + return _m_file; + } + inline unsigned int &line () + { + return _m_line; + } + inline unsigned int line () const + { + return _m_line; + } + inline unsigned int &column () + { + return _m_column; + } + inline unsigned int column () const + { + return _m_column; + } + +#define _DWARF_EDIT_LE_FLAG(what) \ + bool what () const \ + { \ + return _m_flags[flag_##what]; \ + } \ + std::bitset::reference what () \ + { \ + return _m_flags[flag_##what]; \ + } + _DWARF_EDIT_LE_FLAG (statement) + _DWARF_EDIT_LE_FLAG (basic_block) + _DWARF_EDIT_LE_FLAG (end_sequence) + _DWARF_EDIT_LE_FLAG (prologue_end) + _DWARF_EDIT_LE_FLAG (epilogue_begin) +#undef _DWARF_EDIT_LE_FLAG + + template + bool operator< (const entry &other) const + { + return address () < other.address (); + } + template + bool operator> (const entry &other) const + { + return address () > other.address (); + } + template + bool operator<= (const entry &other) const + { + return address () <= other.address (); + } + template + bool operator>= (const entry &other) const + { + return address () >= other.address (); + } + + template + inline bool operator== (const entry &other) const + { + return (address () == other.address () + && line () == other.line () + && column () == other.column () + && statement () == other.statement () + && basic_block () == other.basic_block () + && end_sequence () == other.end_sequence () + && prologue_end () == other.prologue_end () + && epilogue_begin () == other.epilogue_begin () + && file () == other.file ()); + } + template + inline bool operator!= (const entry &other) const + { + return !(*this == other); + } + }; + + class line_table : public std::vector + { + private: + typedef std::vector _base; + + public: + typedef _base::size_type size_type; + typedef _base::difference_type difference_type; + typedef _base::value_type value_type; + typedef _base::iterator iterator; + typedef _base::const_iterator const_iterator; + + line_table () {} + + template + line_table (const table &other) : _base (other.begin (), other.end ()) {} + + template + inline bool operator== (const table &other) const + { + return size () == other.size () && subr::container_equal (*this, other); + } + template + inline bool operator!= (const table &other) const + { + return !(*this == other); + } + + // Look up by matching address. + iterator find (::Dwarf_Addr); + const_iterator find (::Dwarf_Addr) const; + }; + + class line_info_table + { + private: + directory_table _m_dirs; + line_table _m_lines; + + public: + line_info_table () : _m_dirs (), _m_lines () {} + + template + line_info_table (const table &other) + : _m_dirs (other.include_directories ()), _m_lines (other.lines ()) {} + + template + inline line_info_table &operator= (const table &other) + { + _m_dirs = directory_table (other.include_directories ()); + _m_lines = line_table (other.lines ()); + return *this; + } + + inline directory_table &include_directories () + { + return _m_dirs; + } + inline const directory_table &include_directories () const + { + return _m_dirs; + } + inline line_table &lines () + { + return _m_lines; + } + inline const line_table &lines () const + { + return _m_lines; + } + + template + inline bool operator== (const table &other) const + { + return (include_directories () == other.include_directories () + && lines () == other.lines ()); + } + template + inline bool operator!= (const table &other) const + { + return !(*this == other); + } + }; + + class location_attr : public std::map > + { + private: + typedef std::map > _base; + + public: + typedef _base::size_type size_type; + typedef _base::difference_type difference_type; + typedef _base::key_type key_type; + typedef _base::mapped_type mapped_type; + typedef _base::value_type value_type; + typedef _base::iterator iterator; + typedef _base::const_iterator const_iterator; + + inline location_attr () : _base () {} + inline location_attr (const location_attr &other) + : _base (static_cast (other)) {} + template + inline location_attr (const loc &other) : _base () + { + *this = other; + } + + template + inline location_attr &operator= (const loc &other) + { + clear (); + if (other.empty ()) + ; + else if (other.is_list ()) + for (typename loc::const_iterator i = other.begin (); + i != other.end (); + ++i) + { + const typename loc::mapped_type &x = (*i).second; + (*this)[(*i).first] = mapped_type (x.begin (), x.end ()); + } + else + (*this)[key_type (0, -1)] = other.location (); + return *this; + } + + inline bool is_list () const + { + if (empty ()) + return false; + if (size () > 1) + return true; + + const key_type &elt = begin ()->first; + return !(elt.first == 0 && elt.second == (Dwarf_Addr) -1); + } + + inline mapped_type &location () + { + if (empty ()) + return (*this)[key_type (0, -1)]; + + value_type &v = *begin (); + if (v.first.first != 0 || v.first.second != (Dwarf_Addr) -1 + || size () > 1) + throw std::runtime_error ("location is list, not single location"); + + return v.second; + } + inline const mapped_type &location () const + { + if (size () == 1) + { + const value_type &v = *begin (); + if (v.first.first == 0 && v.first.second == (Dwarf_Addr) -1) + return v.second; + } + throw std::runtime_error ("location is list, not single location"); + } + }; + + private: + class value_dispatch + { + public: + virtual ~value_dispatch () {} + }; + + struct value_string : public value_dispatch, public std::string + { + template + value_string (const string &s) : std::string (s) {} + + std::string to_string () const + { + std::string result ("\""); + result += *this; + result += "\""; + return result; + } + }; + + struct value_identifier : public value_string + { + template + value_identifier (const id &s) : value_string (s) {} + }; + + struct value_reference : public value_dispatch + { + debug_info_entry::children::iterator ref; + value_reference (const debug_info_entry::children::iterator &i) + : ref (i) {} + + template // XXX dummy + value_reference (const iter &i) : ref () {} + }; + struct value_unit_reference : public value_dispatch + { + compile_units::iterator ref; + value_unit_reference (const compile_units::iterator &i) : ref (i) {} + + template // XXX dummy + value_unit_reference (const iter &i) : ref () {} + }; + + struct value_flag : public value_dispatch + { + bool flag; + value_flag (bool t) : flag (t) {} + }; + + struct value_address : public value_dispatch + { + // XXX dwfl, reloc + ::Dwarf_Addr addr; + value_address (::Dwarf_Addr a) : addr (a) {} + }; + + struct value_rangelistptr : public value_dispatch, public range_list + { + template + value_rangelistptr (const list &other) : range_list (other) {} + }; + + struct value_lineptr : public value_dispatch, public line_info_table + { + template + value_lineptr (const table &other) : line_info_table (other) {} + }; + + struct value_constant : public value_dispatch + { + union + { + ::Dwarf_Word word; + ::Dwarf_Sword sword; + }; + value_constant (::Dwarf_Word x) : word (x) {} + }; + + struct value_constant_block : public value_dispatch, + public std::vector + { + template + value_constant_block (const block &b) + : std::vector (b.begin (), b.end ()) {} + }; + + struct value_dwarf_constant : public value_constant + { + value_dwarf_constant (unsigned int x) : value_constant (x) {} + }; + + struct value_source_file : public value_dispatch, public source_file + { + template + value_source_file (const file &other) : source_file (other) {} + }; + + struct value_source_line : public value_dispatch + { + unsigned int n; + value_source_line (unsigned int m) : n (m) {} + }; + typedef value_source_line value_source_column; + + struct value_macptr : public value_dispatch {}; + + struct value_location : public value_dispatch, public location_attr + { + template + value_location (const loc &other) : location_attr (other) {} + }; + + public: + class attr_value + { + private: + value_dispatch *_m_value; + + template + inline void init (const value &other) + { + switch (other.what_space ()) + { + case dwarf::VS_identifier: + _m_value = new value_identifier (other.identifier ()); + break; + case dwarf::VS_string: + _m_value = new value_string (other.string ()); + break; + case dwarf::VS_flag: + _m_value = new value_flag (other.flag ()); + break; + case dwarf::VS_rangelistptr: + _m_value = new value_rangelistptr (other.ranges ()); + break; + case dwarf::VS_lineptr: + _m_value = new value_lineptr (other.line_info ()); + break; + case dwarf::VS_address: + _m_value = new value_address (other.address ()); + break; + case dwarf::VS_constant: + _m_value = new value_constant (other.constant ()); + break; + case dwarf::VS_source_line: + _m_value = new value_source_line (other.source_line ()); + break; + case dwarf::VS_source_column: + _m_value = new value_source_column (other.source_column ()); + break; + case dwarf::VS_source_file: + _m_value = new value_source_file (other.source_file ()); + break; + case dwarf::VS_dwarf_constant: + _m_value = new value_dwarf_constant (other.constant ()); // XXX + break; + case dwarf::VS_reference: + _m_value = new value_reference (other.reference ()); + break; + case dwarf::VS_unit_reference: + _m_value = new value_unit_reference (other.unit_reference ()); + break; + case dwarf::VS_location: + _m_value = new value_location (other.location ()); + break; +#if 0 + case dwarf::VS_macptr: + _m_value = new value_macptr (other.macptr ()); + break; +#endif + default: + case dwarf::VS_discr_list: + throw std::runtime_error ("XXX unimplemented"); + } + } + + template + inline flavor &variant () const + { + flavor *p = dynamic_cast (_m_value); + if (p == NULL) + throw std::runtime_error ("wrong value type"); + return *p; + } + + public: + attr_value (const attr_value &other) : _m_value (NULL) + { + init (other); + } + template + attr_value (const value &other) : _m_value (NULL) + { + init (other); + } + + attr_value () : _m_value (NULL) {} + + ~attr_value () + { + if (_m_value != NULL) + delete _m_value; + } + + inline attr_value &operator= (const attr_value &other) + { + if (_m_value != NULL) + { + delete _m_value; + _m_value = NULL; + } + init (other); + return *this; + } + template + inline attr_value &operator= (const value &other) + { + if (_m_value != NULL) + { + delete _m_value; + _m_value = NULL; + } + init (other); + return *this; + } + + dwarf::value_space what_space () const; + std::string to_string () const; + + inline bool &flag () const + { + return variant ().flag; + } + + // XXX dwfl, reloc + inline ::Dwarf_Addr &address () const + { + return variant ().addr; + } + + inline debug_info_entry::children::iterator reference () const + { + return variant ().ref; + } + inline compile_units::iterator unit_reference () const + { + return variant ().ref; + } + + inline location_attr &location () const + { + return static_cast (variant ()); + } + + inline std::string &string () const + { + return static_cast (variant ()); + } + inline std::string &identifier () const + { + return string (); + } + + inline dwarf_edit::source_file &source_file () const + { + return static_cast + (variant ()); + } + + inline unsigned int &source_line () const + { + return variant ().n; + } + + inline unsigned int &source_column () const + { + return variant ().n; + } + + inline ::Dwarf_Word &constant () const + { + return variant ().word; + } + + inline ::Dwarf_Sword &signed_constant () const + { + return variant ().sword; + } + + inline std::vector &constant_block () const + { + return static_cast &> + (variant ()); + } + + // dwarf_constant<> + + inline range_list &ranges () const + { + return static_cast (variant ()); + } + + inline line_info_table &line_info () const + { + return static_cast (variant ()); + } + + // macptr + + template + inline bool operator== (const value &other) const + { + const dwarf::value_space what = what_space (); + if (likely (other.what_space () == what)) + switch (what) + { + case dwarf::VS_identifier: + return identifier () == other.identifier (); + case dwarf::VS_string: + return string () == other.string (); + case dwarf::VS_reference: + return reference () == other.reference (); + case dwarf::VS_unit_reference: + return unit_reference () == other.unit_reference (); + case dwarf::VS_flag: + return flag () == other.flag (); + case dwarf::VS_rangelistptr: + return ranges () == other.ranges (); + case dwarf::VS_lineptr: + return line_info () == other.line_info (); + case dwarf::VS_constant: + return constant () == other.constant (); + case dwarf::VS_source_file: + return source_file () == other.source_file (); + case dwarf::VS_source_line: + return source_line () == other.source_line (); + case dwarf::VS_source_column: + return source_column () == other.source_column (); + case dwarf::VS_address: + return address () == other.address (); + case dwarf::VS_location: + return location () == other.location (); + case dwarf::VS_dwarf_constant: + return constant () == other.constant (); // XXX +#if 0 + case dwarf::VS_macptr: + return macptr () == other.macptr (); +#endif + default: + case dwarf::VS_discr_list: + throw std::runtime_error ("XXX unimplemented"); + } + return false; + } + template + inline bool operator!= (const value &other) const + { + return !(*this == other); + } + }; + private: compile_units _m_units; diff --git a/libdw/c++/edit-values.cc b/libdw/c++/edit-values.cc new file mode 100644 index 000000000..c579c6764 --- /dev/null +++ b/libdw/c++/edit-values.cc @@ -0,0 +1,91 @@ +/* elfutils::dwarf_edit attribute value interfaces. + 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_edit" + +using namespace elfutils; + + +dwarf::value_space +dwarf_edit::attr_value::what_space () const +{ + if (typeid (*_m_value) == typeid (value_flag)) + return dwarf::VS_flag; + if (typeid (*_m_value) == typeid (value_dwarf_constant)) + return dwarf::VS_dwarf_constant; + if (typeid (*_m_value) == typeid (value_reference)) + return dwarf::VS_reference; + if (typeid (*_m_value) == typeid (value_unit_reference)) + return dwarf::VS_unit_reference; + if (typeid (*_m_value) == typeid (value_lineptr)) + return dwarf::VS_lineptr; + if (typeid (*_m_value) == typeid (value_macptr)) + return dwarf::VS_macptr; + if (typeid (*_m_value) == typeid (value_rangelistptr)) + return dwarf::VS_rangelistptr; + if (typeid (*_m_value) == typeid (value_identifier)) + return dwarf::VS_identifier; + if (typeid (*_m_value) == typeid (value_string)) + return dwarf::VS_string; + if (typeid (*_m_value) == typeid (value_source_file)) + return dwarf::VS_source_file; + if (typeid (*_m_value) == typeid (value_source_line)) + return dwarf::VS_source_line; + if (typeid (*_m_value) == typeid (value_source_column)) + return dwarf::VS_source_column; + if (typeid (*_m_value) == typeid (value_address)) + return dwarf::VS_address; + if (typeid (*_m_value) == typeid (value_constant)) + return dwarf::VS_constant; + if (typeid (*_m_value) == typeid (value_location)) + return dwarf::VS_location; + + throw std::runtime_error ("XXX impossible"); +} diff --git a/src/Makefile.am b/src/Makefile.am index 7e2e9aad8..032c621c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,7 +83,8 @@ libar_a_SOURCES = arlib.c arlib2.c # XXX need to figure out C++ dso crapola libdwplusplus_SOURCES = ../libdw/c++/values.cc ../libdw/c++/known.cc \ - ../libdw/c++/line_info.cc + ../libdw/c++/line_info.cc \ + ../libdw/c++/edit-values.cc dwarfcmp_SOURCES = dwarfcmp.cc dwarfcmp_SOURCES += $(libdwplusplus_SOURCES)