]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Start at attr value interfaces, unfinished.
authorRoland McGrath <roland@redhat.com>
Mon, 26 Jan 2009 10:45:41 +0000 (02:45 -0800)
committerRoland McGrath <roland@redhat.com>
Mon, 26 Jan 2009 10:45:41 +0000 (02:45 -0800)
libdw/c++/dwarf
libdw/c++/dwarf-knowledge.cc [new file with mode: 0644]
libdw/c++/known.cc [new file with mode: 0644]
libdw/c++/values.cc [new file with mode: 0644]
libdw/libdwP.h
src/Makefile.am
src/dwarfcmp.cc

index 1f5dcd9f9448aad6d931d46257fad938c183b1f1..b64d3fb560c7f4d4a8abf9658a4b073ee86f9e15 100644 (file)
@@ -60,6 +60,7 @@
 #include <sstream>
 #include <list>
 #include <map>
+#include <set>
 #include <stack>
 #include <algorithm>
 #include <functional>
@@ -167,10 +168,6 @@ namespace elfutils
     static const char *known_attribute (int);
     static const char *known_tag (int);
 
-    static inline std::string attribute_name (int code)
-    {
-      return known_name<known_attribute> (code);
-    }
     static inline std::string tag_name (int code)
     {
       return known_name<known_tag> (code);
@@ -183,6 +180,12 @@ namespace elfutils
       return attribute_name (code);
     }
 
+    static inline std::string attribute_name (const unsigned int code)
+    {
+      return known_name<known_attribute> (code);
+    }
+
+
   private:
     // XXX make this an instance method to include irritant context
     static void throw_libdw (void) // XXX raises (...)
@@ -293,6 +296,8 @@ namespace elfutils
 
     class attribute;
     class attr_value;
+    class location_attr;
+    class range_list;
 
     class debug_info_entry
     {
@@ -304,6 +309,7 @@ namespace elfutils
       }
 
       friend class dwarf;
+      friend class attr_value;
     protected:
 
       inline debug_info_entry ()
@@ -617,7 +623,7 @@ namespace elfutils
              if ((*i).tag () == ::DW_TAG_imported_unit)
                // We have an imported unit.  Look at its referent.
                _m_stack.push ((*i).attributes ().at (::DW_AT_import)
-                              .ref ().raw_children ().begin ());
+                              .reference ().raw_children ().begin ());
              else
                // This is some other DIE.  Iterate on it.
                break;
@@ -779,26 +785,370 @@ namespace elfutils
       }
     };
 
+    class compile_unit : public debug_info_entry
+    {
+    public:
+      inline compile_unit (const debug_info_entry &die)
+       : debug_info_entry (die) {}
+
+      /*
+       containers/iterators:
+
+       lines
+       macros
+
+       abbrevs (punt)
+
+      */
+    };
+
+    // These are the kinds of values that attributes can have.
+    enum value_space
+      {
+       // These spaces refer purely to DWARF concepts.
+       VS_flag,                // Boolean.
+       VS_dwarf_constant,      // Known DW_X_* space of integer constants.
+       VS_discr_list,          // Block as used for DW_AT_discr_list.
+       VS_reference,           // Pointer to another DIE.
+       VS_unit_reference,      // Pointer to another CU DIE.
+       VS_lineptr,             // Pointer into .debug_line section.
+       VS_macptr,              // Pointer into .debug_macinfo section.
+       VS_rangelistptr,        // Pointer into .debug_ranges section.
+
+       // These spaces refer to textual details of the program source.
+       VS_identifier,          // String, identifier in source language.
+       VS_string,              // String, miscellaneous use.
+       VS_source_file,         // Source file, string or index into file table.
+       VS_source_line,         // Line number in source file.
+       VS_source_column,       // Column number in source file.
+
+       // These spaces refer to target-format values in the debuggee.
+       VS_address,        // Address constant.
+       VS_constant,       // Other constant, integer or in target formats.
+       VS_location,       // Location expression or location list.
+      };
+
+    /* A source file can be just a file name.  When represented in the
+       .debug_line file table, it can also have a modtime and a file size.
+       If the modtime or size stored is zero, it doesn't count.  */
+    class source_file
+    {
+      friend class attr_value;
+    private:
+      ::Dwarf_Attribute _m_attr;
+      inline ::Dwarf_Attribute *thisattr () const
+      {
+       return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+      }
+
+      source_file (const Dwarf_Attribute &attr) : _m_attr (attr) {}
+
+    public:
+      std::string to_string () const;
+
+      const char *name () const;
+      ::Dwarf_Word mtime () const;
+      ::Dwarf_Word size () const;
+
+      template<typename other_file>
+      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 !strcmp (name (), other.name ());
+      }
+
+      template<typename other_file>
+      inline bool operator!= (const other_file &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
     // This describes the value of an attribute.
-    // XXX dummy for now
     class attr_value
     {
+      friend class attribute;
+      friend class location_attr;
+      friend class range_list;
+    private:
+      const ::Dwarf_Attribute _m_attr;
+      inline ::Dwarf_Attribute *thisattr () const
+      {
+       return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+      }
+
+      attr_value (const ::Dwarf_Attribute &attr) : _m_attr (attr) {}
+
     public:
-      attr_value () {}
-      attr_value (const attr_value &v) {}
+      // not copyable, don't worry about ref lifetime(?)
+      // attr_value (const attr_value &v) : _m_attr (v.attr) {}
+
+      value_space what_space () const;
+
+      std::string to_string () const;
+
+      inline debug_info_entry reference () const
+      {
+       debug_info_entry result;
+       xif (::dwarf_formref_die (thisattr (), result.thisdie ()) == NULL);
+       return result;
+      }
+      inline compile_unit unit_reference () const
+      {
+       return reference ();
+      }
+
+      // XXX reloc, dwfl
+      ::Dwarf_Addr address () const;
+
+      bool flag () const;
+
+      const location_attr location () const;
+
+      const char *string () const;
+      inline const char *identifier () const
+      {
+       return string ();
+      }
+
+      const class source_file source_file () const;
+
+      // XXX reloc
+      ::Dwarf_Word constant () const;
+      ::Dwarf_Sword signed_constant () const;
+      // XXX better type??
+      std::string constant_block () const;
+
+      // XXX known enums
+      // dwarf_enum dwarf_constant () const;
+
+      inline const range_list ranges () const
+      {
+       return range_list (*this);
+      }
+
+      // XXX lineptr
+      // XXX macptr
 
-      inline bool operator== (const attr_value &other) const
+      template<typename value>
+      inline bool operator== (const value &other) const
       {
-       return true;            // XXX dummy value comparison always true
+       const value_space what = what_space ();
+       if (other.what_space () == what)
+         switch (what)
+           {
+           case VS_reference:
+           case VS_unit_reference:
+             // return reference () == other.reference ();
+             return true;      // XXX temporary stub
+
+           case VS_flag:
+             return flag () == other.flag ();
+
+           case VS_rangelistptr:
+             return ranges () == other.ranges ();
+
+           case VS_lineptr:    // XXX punt for now, treat as constant
+           case VS_macptr:     // XXX punt for now, treat as constant
+             /*FALLTHRU*/
+           case VS_constant:
+           case VS_dwarf_constant:
+           case VS_source_line:
+           case VS_source_column:
+             return constant () == other.constant ();
+
+           case VS_identifier:
+             return !strcmp (identifier (), other.identifier ());
+
+           case VS_string:
+             return !strcmp (string (), other.string ());
+
+           case VS_address:
+             return address () == other.address ();
+
+           case VS_source_file:
+             return source_file () == other.source_file ();
+
+           case VS_location:
+             return location () == other; // XXX
+
+           case VS_discr_list:
+             throw std::runtime_error ("XXX unimplemented");
+           }
+       return false;
       }
       inline bool operator!= (const attr_value &other) const
       {
        return !(*this == other);
       }
+    };
+
+    /* A location attribute yields a location expression.
+       Either it's a single expression, or a map of PC to location.  */
+    class location_attr
+    {
+      friend class attr_value;
+    private:
+      const attr_value _m_attr;
+
+      location_attr (const attr_value &attr) : _m_attr (attr) {}
+
+      bool singleton () const; // XXX temp hack
+
+    public:
+      std::string to_string () const;
+
+      template<typename other_attr>
+      bool operator== (const other_attr &other) const
+      {
+       // XXX hack
+       if (singleton ())
+         return _m_attr.constant_block () == other.constant_block ();
+       // loclistptr XXX punt for now, treat as constant
+       return _m_attr.constant () == other.constant ();
+      }
+
+      template<typename other_file>
+      inline bool operator!= (const other_file &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    /* The DW_AT_ranges attribute yields a range list.
+       This is equivalent to unordered_set<pair<Dwarf_Addr, Dwarf_Addr> >.  */
+    class range_list
+    {
+      friend class attr_value;
+    private:
+      const attr_value _m_attr;
+
+      range_list (const attr_value &attr) : _m_attr (attr) {}
+
+    public:
+      typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type;
+      typedef key_type value_type;
+
+      range_list (const range_list &other) : _m_attr (other._m_attr) {}
+
+      std::string to_string () const;
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, value_type>
+      {
+       friend class range_list;
+      private:
+       ::Dwarf_Addr _m_base;
+       ::Dwarf_Addr _m_begin;
+       ::Dwarf_Addr _m_end;
+       ::Dwarf_CU *_m_cu;
+       ptrdiff_t _m_offset;
+
+       inline const_iterator () // end () value
+         : _m_base (-1), _m_begin (0), _m_end (0), _m_cu (NULL), _m_offset (1)
+       {}
+       const_iterator (Dwarf_Attribute *);
+
+      public:
+       inline const_iterator (const const_iterator &i)
+         : _m_base (i._m_base), _m_cu (i._m_cu), _m_offset (i._m_offset) {}
+
+       inline value_type operator* () const
+       {
+         return std::make_pair (_m_base + _m_begin, _m_base + _m_end);
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_base = other._m_base;
+         _m_begin = other._m_begin;
+         _m_end = other._m_end;
+         _m_cu = other._m_cu;
+         _m_offset = other._m_offset;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return _m_offset == other._m_offset;
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       const_iterator &operator++ (); // prefix
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+      };
+
+      const_iterator begin () const
+      {
+       return const_iterator (_m_attr.thisattr ());
+      }
+      const_iterator end () const
+      {
+       return const_iterator ();
+      }
+
+      const_iterator find (const key_type &match)
+      {
+       return std::find (begin (), end (), match);
+      }
+
+    private:
+      struct entry_contains
+       : public std::binary_function<key_type, ::Dwarf_Addr, bool>
+      {
+       inline bool operator() (const key_type &range, const ::Dwarf_Addr addr)
+         const
+       {
+         return addr >= range.first && addr < range.second;
+       }
+      };
+
+    public:
+      const_iterator find (const ::Dwarf_Addr addr) const
+      {
+       return std::find_if (begin (), end (),
+                            std::bind2nd (entry_contains (), addr));
+      }
+
+      inline operator std::set<key_type> () const
+      {
+       return std::set<key_type> (begin (), end ());
+      }
 
-      debug_info_entry ref () const
+      template<typename ranges>
+      inline bool operator== (const ranges &other) const
       {
-       return debug_info_entry (); // XXX dummy hack
+       /* Our container is unordered (i.e., in file order).  A range list
+           is conceptually equal if all the pairs match, regardless of the
+           order.  But the std::equal algorithm will compare corresponding
+           elements in order.  So we need an ordered set for comparison.  */
+       const std::set<key_type> mine = *this;
+       const std::set<key_type> his = other;
+       return mine == his;
+      }
+      template<typename ranges>
+      inline bool operator!= (const ranges &other) const
+      {
+       return !(*this == other);
       }
     };
 
@@ -806,11 +1156,11 @@ namespace elfutils
     class attribute
     {
       friend class debug_info_entry::raw_attributes::const_iterator;
+      friend class attr_value;
     private:
-      const ::Dwarf_Attribute _m_attr;
       inline ::Dwarf_Attribute *thisattr () const
       {
-       return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+       return second.thisattr ();
       }
 
       class lhs
@@ -829,14 +1179,14 @@ namespace elfutils
       };
 
       attribute (const ::Dwarf_Attribute &attr)
-       : _m_attr (attr), first (*this) {}
+       : first (*this), second (attr) {}
 
     public:
       lhs first;
       attr_value second;
 
       inline attribute (const attribute &a)
-       : _m_attr (a._m_attr), first (*this) {}
+       : first (*this), second (a.second) {}
 
       // This lets pair<...> x = (attribute) y work.
       template<typename value>
@@ -855,23 +1205,14 @@ namespace elfutils
       {
        return !(*this == other);
       }
-    };
-
-    class compile_unit : public debug_info_entry
-    {
-    public:
-      inline compile_unit (const debug_info_entry &die)
-       : debug_info_entry (die) {}
-
-      /*
-       containers/iterators:
-
-       lines
-       macros
-
-       abbrevs (punt)
 
-      */
+      inline std::string to_string () const
+      {
+       std::string result = attribute_name (::dwarf_whatattr (thisattr ()));
+       result += "=";
+       result += second.to_string ();
+       return result;
+      }
     };
 
     // Container for raw CUs in file order, intended to be compatible
diff --git a/libdw/c++/dwarf-knowledge.cc b/libdw/c++/dwarf-knowledge.cc
new file mode 100644 (file)
index 0000000..b7827a4
--- /dev/null
@@ -0,0 +1,158 @@
+#include <config.h>
+#include "dwarf"
+
+using namespace std;
+using namespace elfutils;
+
+#define VS(what)       (1U << dwarf::VS_##what)
+
+/* Return a bitmask of value spaces expected for this attribute of this tag.
+   Primarily culled from the DWARF 3 spec: 7.5.4, Figure 20.  */
+
+static unsigned int
+expected_value_space (int attr, int tag)
+{
+
+  switch (attr)
+    {
+    case DW_AT_sibling:
+    case DW_AT_common_reference:
+    case DW_AT_containing_type:
+    case DW_AT_default_value:
+    case DW_AT_abstract_origin:
+    case DW_AT_base_types:
+    case DW_AT_friend:
+    case DW_AT_priority:
+    case DW_AT_specification:
+    case DW_AT_type:
+    case DW_AT_use_location:
+    case DW_AT_data_location:
+    case DW_AT_extension:
+    case DW_AT_small:
+    case DW_AT_object_pointer:
+    case DW_AT_namelist_item:
+      return VS(reference);
+
+    case DW_AT_location:
+    case DW_AT_string_length:
+    case DW_AT_return_addr:
+    case DW_AT_data_member_location:
+    case DW_AT_frame_base:
+    case DW_AT_segment:
+    case DW_AT_static_link:
+    case DW_AT_vtable_elem_location:
+      return VS(location);
+
+    case DW_AT_name:
+      switch (tag)
+       {
+       case DW_TAG_compile_unit:
+       case DW_TAG_partial_unit:
+         return VS(source_file);
+       default:
+         return VS(identifier);
+       }
+
+    case DW_AT_ordering:
+    case DW_AT_language:
+    case DW_AT_visibility:
+    case DW_AT_inline:
+    case DW_AT_accessibility:
+    case DW_AT_address_class:
+    case DW_AT_calling_convention:
+    case DW_AT_encoding:
+    case DW_AT_identifier_case:
+    case DW_AT_virtuality:
+    case DW_AT_endianity:
+      return VS(dwarf_constant);
+
+    case DW_AT_byte_size:
+    case DW_AT_byte_stride:
+    case DW_AT_bit_offset:
+    case DW_AT_bit_size:
+    case DW_AT_lower_bound:
+    case DW_AT_upper_bound:
+    case DW_AT_count:
+    case DW_AT_allocated:
+    case DW_AT_associated:
+      return VS(reference) | VS(constant);
+
+    case DW_AT_stmt_list:
+      return VS(lineptr);
+    case DW_AT_macro_info:
+      return VS(macptr);
+    case DW_AT_ranges:
+      return VS(rangelistptr);
+
+    case DW_AT_low_pc:
+    case DW_AT_high_pc:
+    case DW_AT_entry_pc:
+      return VS(address);
+
+    case DW_AT_discr:
+      return VS(reference);
+    case DW_AT_discr_value:
+      return VS(constant);
+    case DW_AT_discr_list:
+      return VS(discr_list);
+
+    case DW_AT_import:
+      return VS(unit_reference);
+
+    case DW_AT_comp_dir:
+      return VS(source_file);
+
+    case DW_AT_const_value:
+      return VS(constant) | VS(string);
+
+    case DW_AT_is_optional:
+    case DW_AT_prototyped:
+    case DW_AT_artificial:
+    case DW_AT_declaration:
+    case DW_AT_external:
+    case DW_AT_variable_parameter:
+    case DW_AT_use_UTF8:
+    case DW_AT_mutable:
+    case DW_AT_threads_scaled:
+    case DW_AT_explicit:
+    case DW_AT_elemental:
+    case DW_AT_pure:
+    case DW_AT_recursive:
+      return VS(flag);
+
+    case DW_AT_producer:
+      return VS(string);
+
+    case DW_AT_start_scope:
+      return VS(constant);
+
+    case DW_AT_bit_stride:
+    case DW_AT_binary_scale:
+    case DW_AT_decimal_scale:
+    case DW_AT_decimal_sign:
+    case DW_AT_digit_count:
+      return VS(constant);
+
+    case DW_AT_decl_file:
+    case DW_AT_call_file:
+      return VS(source_file);
+    case DW_AT_decl_line:
+    case DW_AT_call_line:
+      return VS(source_line);
+    case DW_AT_decl_column:
+    case DW_AT_call_column:
+      return VS(source_column);
+
+    case DW_AT_trampoline:
+      return VS(address) | VS(flag) | VS(reference) | VS(string);
+
+    case DW_AT_description:
+    case DW_AT_picture_string:
+      return VS(string);
+
+    case DW_AT_MIPS_linkage_name:
+      return VS(identifier);
+    }
+
+  return 0;
+}
diff --git a/libdw/c++/known.cc b/libdw/c++/known.cc
new file mode 100644 (file)
index 0000000..18ca629
--- /dev/null
@@ -0,0 +1,31 @@
+#include <config.h>
+#include "dwarf"
+#include "known-dwarf.h"
+
+using namespace elfutils;
+using namespace std;
+
+
+const char *
+dwarf::known_tag (int tag)
+{
+  switch (tag)
+    {
+#define ONE_KNOWN_DW_TAG(name, id)             case id: return #name;
+#define ONE_KNOWN_DW_TAG_DESC(name, id, desc)  ONE_KNOWN_DW_TAG (name, id)
+      ALL_KNOWN_DW_TAG
+    }
+  return NULL;
+}
+
+const char *
+dwarf::known_attribute (int name)
+{
+  switch (name)
+    {
+#define ONE_KNOWN_DW_AT(name, id)              case id: return #name;
+#define ONE_KNOWN_DW_AT_DESC(name, id, desc)   ONE_KNOWN_DW_AT (name, id)
+      ALL_KNOWN_DW_AT
+    }
+  return NULL;
+}
diff --git a/libdw/c++/values.cc b/libdw/c++/values.cc
new file mode 100644 (file)
index 0000000..0879f58
--- /dev/null
@@ -0,0 +1,535 @@
+/* -*- C++ -*- interfaces for libdw.
+   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
+   <http://www.openinventionnetwork.com>.  */
+
+#include <config.h>
+#include "dwarf"
+
+extern "C"
+{
+#include "libdwP.h"
+}
+
+using namespace elfutils;
+using namespace std;
+
+#include "dwarf-knowledge.cc"
+
+\f
+// dwarf::attr_value disambiguation and dispatch.
+
+/* For ambiguous the forms, we need to look up the expected
+   value spaces for this attribute to disambiguate.
+*/
+dwarf::value_space
+dwarf::attr_value::what_space () const
+{
+  unsigned int possible = 0;
+
+  switch (dwarf_whatform (thisattr ()))
+    {
+    case DW_FORM_flag:
+      return VS_flag;
+
+    case DW_FORM_addr:
+      return VS_address;
+
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      /* Location expression or target constant.  */
+      possible = VS(location) | VS(constant);
+      break;
+
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_udata:
+    case DW_FORM_sdata:
+      /* Target constant, known DWARF constant, or *ptr.  */
+      possible = (VS(dwarf_constant) | VS(constant)
+                 | VS(source_file) | VS(source_line) | VS(source_column)
+                 | VS(location) // loclistptr
+                 | VS(lineptr) | VS(macptr) | VS(rangelistptr));
+      break;
+
+    case DW_FORM_string:
+    case DW_FORM_strp:
+      /* Identifier, file name, or string.  */
+      possible = VS(identifier) | VS(source_file) | VS(string);
+      break;
+
+    case DW_FORM_ref_addr:
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_udata:
+      possible = VS(unit_reference) | VS(reference);
+      break;
+
+    default:
+      throw std::runtime_error ("XXX bad form");
+    }
+
+  unsigned int expected = expected_value_space
+    (dwarf_whatattr (thisattr ()), 0); // XXX need tag!
+
+  if (unlikely ((expected & possible) == 0))
+    {
+      if (expected == 0 && possible == (VS(unit_reference) | VS(reference)))
+       // An unknown reference is a reference, not a unit_reference.
+       return VS_reference;
+
+      // Otherwise we don't know enough to treat it robustly.
+      throw std::runtime_error ("XXX ambiguous form in unexpected attribute");
+    }
+
+  const int first = ffs (expected & possible) - 1;
+  if (likely ((expected & possible) == (1U << first)))
+    return static_cast<value_space> (first);
+
+  throw std::runtime_error ("XXX ambiguous form");
+}
+
+static string
+hex_string (Dwarf_Word value)
+{
+  std::ostringstream os;
+  os.setf(std::ios::hex, std::ios::basefield);
+  os << value;
+  return os.str ();
+}
+
+static string
+dec_string (Dwarf_Word value)
+{
+  std::ostringstream os;
+  os << value;
+  return os.str ();
+}
+
+static string
+addr_string (Dwarf_Addr value)
+{
+  // XXX some hook for symbol resolver??
+  return hex_string (value);
+}
+
+static inline string
+plain_string (const char *filename)
+{
+  return string ("\"") + filename + "\"";
+}
+
+string
+dwarf::attr_value::to_string () const
+{
+  switch (what_space ())
+    {
+    case VS_flag:
+      return flag () ? "1" : "0";
+
+    case VS_rangelistptr:
+      return ranges ().to_string ();
+
+    case VS_lineptr:   // XXX punt for now, treat as constant
+    case VS_macptr:    // XXX punt for now, treat as constant
+    case VS_constant:
+    case VS_dwarf_constant:
+      return hex_string (constant ());
+
+    case VS_source_line:
+    case VS_source_column:
+      return dec_string (constant ());
+
+    case VS_identifier:
+      return plain_string (identifier ());
+
+    case VS_string:
+      return plain_string (string ());
+
+    case VS_address:
+      return addr_string (address ());
+
+    case VS_reference:
+    case VS_unit_reference:
+      return "XXX";
+
+    case VS_source_file:
+      return source_file ().to_string ();
+
+    case VS_location:
+      return location ().to_string ();
+
+    case VS_discr_list:
+      break;           // XXX
+    }
+
+  throw std::runtime_error ("XXX unsupported value space");
+}
+
+// A few cases are trivial.
+#define SIMPLE(type, name, form)                               \
+  type                                                         \
+  dwarf::attr_value::name () const                             \
+  {                                                            \
+    type result;                                               \
+    xif (dwarf_form##form (thisattr (), &result) < 0); \
+    return result;                                             \
+  }
+
+SIMPLE (bool, flag, flag)
+
+// XXX check value_space is really constantish?? vs *ptr
+SIMPLE (Dwarf_Word, constant, udata)
+SIMPLE (Dwarf_Sword, signed_constant, sdata)
+
+SIMPLE (Dwarf_Addr, address, addr)
+
+const char *
+dwarf::attr_value::string () const
+{
+  const char *result = dwarf_formstring (thisattr ());
+  xif (result == NULL);
+  return result;
+}
+
+string
+dwarf::attr_value::constant_block () const
+{
+  Dwarf_Block block;
+
+  switch (dwarf_whatform (thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      xif (dwarf_formblock (thisattr (), &block) < 0);
+      break;
+
+    case DW_FORM_data1:
+      block.length = 1;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_data2:
+      block.length = 2;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_data4:
+      block.length = 4;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_data8:
+      block.length = 8;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_udata:
+    case DW_FORM_sdata:
+      // XXX ?
+
+    default:
+      throw std::runtime_error ("XXX wrong form");
+    }
+
+  return std::string (reinterpret_cast<const char *> (block.data),
+                     block.length);
+}
+\f
+// dwarf::source_file
+
+const class dwarf::source_file
+dwarf::attr_value::source_file () const
+{
+  switch (what_space ())
+    {
+    case VS_string:
+    case VS_source_file:
+      break;
+    default:
+      throw std::runtime_error ("XXX not a file name");
+    }
+  return source_file::source_file (_m_attr);
+}
+
+static bool
+stringform (Dwarf_Attribute *attr)
+{
+  switch (dwarf_whatform (attr))
+    {
+    case DW_FORM_string:
+    case DW_FORM_strp:
+      return true;
+    }
+  return false;
+}
+
+static bool
+get_files (Dwarf_Attribute *attr, Dwarf_Files **files, size_t *idx)
+{
+  Dwarf_Word result;
+  CUDIE (cudie, attr->cu);
+  if (dwarf_formudata (attr, &result) < 0
+      || dwarf_getsrcfiles (&cudie, files, NULL) < 0)
+    return true;
+  *idx = result;
+  return false;
+}
+
+Dwarf_Word
+dwarf::source_file::mtime () const
+{
+  if (stringform (thisattr ()))
+    return 0;
+
+  Dwarf_Files *files;
+  size_t idx;
+  xif (get_files (thisattr (), &files, &idx));
+
+  Dwarf_Word result;
+  xif (dwarf_filesrc (files, idx, &result, NULL) == NULL);
+  return result;
+}
+
+Dwarf_Word
+dwarf::source_file::size () const
+{
+  if (stringform (thisattr ()))
+    return 0;
+
+  Dwarf_Files *files;
+  size_t idx;
+  xif (get_files (thisattr (), &files, &idx));
+
+  Dwarf_Word result;
+  xif (dwarf_filesrc (files, idx, NULL, &result) == NULL);
+  return result;
+}
+
+const char *
+dwarf::source_file::name () const
+{
+  if (stringform (thisattr ()))
+    return dwarf_formstring (thisattr ());
+
+  Dwarf_Files *files;
+  size_t idx;
+  xif (get_files (thisattr (), &files, &idx));
+
+  const char *result = dwarf_filesrc (files, idx, NULL, NULL);
+  xif (result == NULL);
+  return result;
+}
+
+string
+dwarf::source_file::to_string () const
+{
+  if (stringform (thisattr ()))
+    return plain_string (dwarf_formstring (thisattr ()));
+
+  Dwarf_Files *files;
+  size_t idx;
+  xif (get_files (thisattr (), &files, &idx));
+
+  Dwarf_Word file_mtime;
+  Dwarf_Word file_size;
+  const char *result = dwarf_filesrc (files, idx, &file_mtime, &file_size);
+  xif (result == NULL);
+
+  if (likely (file_mtime == 0) && likely (file_size == 0))
+    return plain_string (result);
+
+  std::ostringstream os;
+  os << "{\"" << result << "," << file_mtime << "," << file_size << "}";
+  return os.str ();
+}
+\f
+// dwarf::location_attr
+
+const dwarf::location_attr
+dwarf::attr_value::location () const
+{
+  if (what_space () != VS_location)
+    throw std::runtime_error ("XXX not a location");
+
+  return location_attr (*this);
+}
+
+bool
+dwarf::location_attr::singleton () const
+{
+  switch (dwarf_whatform (_m_attr.thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      return true;
+    }
+
+  return false;
+}
+
+string
+dwarf::location_attr::to_string () const
+{
+  if (singleton ())
+    return "XXX";
+  return hex_string (_m_attr.constant ());
+}
+\f
+// dwarf::range_list
+
+dwarf::range_list::const_iterator::const_iterator (Dwarf_Attribute *attr)
+  : _m_base (-1), _m_cu (attr->cu), _m_offset (0)
+{
+  ++*this;
+}
+
+dwarf::range_list::const_iterator &
+dwarf::range_list::const_iterator::operator++ ()
+{
+  const Elf_Data *d = _m_cu->dbg->sectiondata[IDX_debug_ranges];
+  if (unlikely (d == NULL))
+    throw std::runtime_error ("XXX no ranges");
+
+  if (unlikely (_m_offset < 0) || unlikely ((size_t) _m_offset >= d->d_size))
+    throw std::runtime_error ("XXX bad offset in ranges iterator");
+
+  unsigned char *readp = (reinterpret_cast<unsigned char *> (d->d_buf)
+                         + _m_offset);
+
+  while (true)
+    {
+      if ((unsigned char *) d->d_buf + d->d_size - readp
+         < _m_cu->address_size * 2)
+       throw std::runtime_error ("XXX bad ranges");
+
+      if (_m_cu->address_size == 8)
+       {
+         _m_begin = read_8ubyte_unaligned_inc (_m_cu->dbg, readp);
+         _m_end = read_8ubyte_unaligned_inc (_m_cu->dbg, readp);
+         if (_m_begin == (uint64_t) -1l) /* Base address entry.  */
+           {
+             _m_base = _m_end;
+             continue;
+           }
+       }
+      else
+       {
+         _m_begin = read_4ubyte_unaligned_inc (_m_cu->dbg, readp);
+         _m_end = read_4ubyte_unaligned_inc (_m_cu->dbg, readp);
+         if (_m_begin == (uint32_t) -1) /* Base address entry.  */
+           {
+             _m_base = _m_end;
+             continue;
+           }
+       }
+
+      break;
+    }
+
+  if (_m_begin == 0 && _m_end == 0) /* End of list entry.  */
+    _m_offset = 1;
+  else
+    {
+      _m_offset = readp - reinterpret_cast<unsigned char *> (d->d_buf);
+
+      if (_m_base == (Dwarf_Addr) -1)
+       {
+         CUDIE (cudie, _m_cu);
+
+         /* Find the base address of the compilation unit.  It will
+            normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
+            the base address could be overridden by DW_AT_entry_pc.  It's
+            been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+            for compilation units with discontinuous ranges.  */
+         Dwarf_Attribute attr_mem;
+         if (unlikely (dwarf_lowpc (&cudie, &_m_base) != 0)
+             && dwarf_formaddr (dwarf_attr (&cudie,
+                                            DW_AT_entry_pc,
+                                            &attr_mem),
+                                &_m_base) != 0)
+           {
+             xif (true);               // XXX
+           }
+       }
+    }
+
+  return *this;
+}
+
+string
+dwarf::range_list::to_string () const
+{
+  std::ostringstream os;
+  os.setf(std::ios::hex, std::ios::basefield);
+
+  os << "<";
+
+  bool first = true;
+  for (const_iterator i = begin (); i != end (); ++i)
+    {
+      value_type range = *i;
+      if (!first)
+       os << ",";
+      os << range.first << "-" << range.second;
+      first = false;
+    }
+
+  os << ">";
+
+  return os.str ();
+}
index 867ad89b4a711dd9e0b9f61473d14f1df18da575..4ccae9e9c99aee0c7883b5be127ef1d289d5ecc9 100644 (file)
@@ -299,14 +299,21 @@ struct Dwarf_CU
 #define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size) \
   ((cu_offset) + 3 * (offset_size) - 4 + 3)
 
-#define CUDIE(fromcu) \
-  ((Dwarf_Die)                                                               \
-   {                                                                         \
-     .cu = (fromcu),                                                         \
-     .addr = ((char *) (fromcu)->dbg->sectiondata[IDX_debug_info]->d_buf      \
-             + (fromcu)->start + 3 * (fromcu)->offset_size - 4 + 3),         \
+#define CUDIE_ADDR(fromcu)                                             \
+  ((char *) (fromcu)->dbg->sectiondata[IDX_debug_info]->d_buf          \
+   + DIE_OFFSET_FROM_CU_OFFSET ((fromcu)->start, (fromcu)->offset_size))
+
+#ifdef __cplusplus
+# define CUDIE(name, fromcu)                   \
+  Dwarf_Die name = { CUDIE_ADDR (fromcu), (fromcu), NULL, 0l }
+#else
+# define CUDIE(fromcu)                         \
+  ((Dwarf_Die)                                 \
+   {                                           \
+    .cu = (fromcu),                            \
+    .addr = CUDIE_ADDR (fromcu),               \
    })
-
+#endif
 
 /* Macro information.  */
 struct Dwarf_Macro_s
index 96c9f9ada60707d29f00a43431e2e6da1b50c711..be8989e368c3cee10a5fbee68b62477fd8496352 100644 (file)
@@ -82,6 +82,8 @@ ld_SOURCES = ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhash.c \
 libar_a_SOURCES = arlib.c arlib2.c
 
 dwarfcmp_SOURCES = dwarfcmp.cc
+# XXX need to figure out C++ dso crapola
+dwarfcmp_SOURCES += ../libdw/c++/values.cc ../libdw/c++/known.cc
 
 noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \
                 ldscript.h xelf.h unaligned.h
index c4205828a2e8640dfa5e0c8e2ac48d921ae14d40..1bf342a90b23cc5a45b4d4836138913f95f22fad 100644 (file)
@@ -164,9 +164,9 @@ struct context
     location () << "different attributes" << endl;
   }
 
-  void values (int name) const
+  void values (const string &a, const string &b) const
   {
-    location () << "different values for attribute 0x" << hex << name << endl;
+    location () << "attribute " << a << " vs " << b << endl;
   }
 };
 
@@ -249,7 +249,7 @@ describe_mismatch (const dwarf::attribute &a, const dwarf::attribute &b,
     {
       result = a.second != b.second;
       if (result != 0)
-       say.values (a.first);
+       say.values (a.to_string (), b.to_string ());
     }
   return result;
 }