]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Various fixes; started location list reader interface.
authorRoland McGrath <roland@redhat.com>
Mon, 2 Feb 2009 02:34:04 +0000 (18:34 -0800)
committerRoland McGrath <roland@redhat.com>
Mon, 2 Feb 2009 02:34:04 +0000 (18:34 -0800)
libdw/c++/dwarf
libdw/c++/subr.hh
libdw/c++/values.cc

index 9ceb4b40a964fa8a151ceb3d762bcee87dc2e8a3..14f2947f0a08b10dcb473a30dd43f23df88ed954 100644 (file)
@@ -180,6 +180,8 @@ namespace elfutils
       : _m_size (v._m_size), _m_array (v._m_array) {}
     const_vector (const elt *start, const elt *stop)
       : _m_size (stop - start), _m_array (start) {}
+    const_vector (const ::Dwarf_Block &b)
+      : _m_size (b.length), _m_array (reinterpret_cast<const elt *> (b.data)) {}
 
     inline const_vector &operator= (const const_vector &v)
     {
@@ -241,6 +243,15 @@ namespace elfutils
       return os.str ();
     }
 
+    template<typename string>
+    struct name_equal : public std::binary_function<const char *, string, bool>
+    {
+      bool operator () (const char *me, const string &you)
+      {
+       return you == me;
+      }
+    };
+
   public:
     static const char *known_attribute (int);
     static const char *known_tag (int);
@@ -835,6 +846,8 @@ namespace elfutils
        : attributes_base (raw) {}
 
     public:
+      typedef int key_type;
+      typedef attr_value mapped_type;
       typedef attribute value_type;
 
       inline attributes (const class attributes &a)
@@ -884,12 +897,12 @@ namespace elfutils
       {
        /* Our container is unordered (i.e., in file order).  A set of
           attributes is conceptually equal if all the pairs match,
-          regardless of the order.  But the std::equal algorithm will
+          regardless of the order.  But the container_equal algorithm will
           compare corresponding elements in order.  So we need an ordered
           map of our attributes for the comparison.  */
        const std::map<int, attr_value> mine = *this;
-       const std::map<int, attr_value> his = other;
-       return mine == his;
+       const std::map<int, typename attrs::mapped_type> his = other;
+       return mine.size () == his.size () && subr::container_equal (mine, his);
       }
 
       template<typename attrs>
@@ -998,9 +1011,8 @@ namespace elfutils
            if (other_size != 0 && other_size != size ())
              return false;
          }
-       return !strcmp (name (), other.name ());
+       return name_equal<typeof (other.name ())> () (name (), other.name ());
       }
-
       template<typename other_file>
       inline bool operator!= (const other_file &other) const
       {
@@ -1015,7 +1027,7 @@ namespace elfutils
       friend class location_attr;
       friend class range_list;
     private:
-      const ::Dwarf_Attribute _m_attr;
+      ::Dwarf_Attribute _m_attr;
       inline ::Dwarf_Attribute *thisattr () const
       {
        return const_cast< ::Dwarf_Attribute *> (&_m_attr);
@@ -1023,6 +1035,11 @@ namespace elfutils
 
       attr_value (const ::Dwarf_Attribute &attr) : _m_attr (attr) {}
 
+      inline bool same (const attr_value &other) const
+      {
+       return _m_attr.valp == other._m_attr.valp;
+      }
+
     public:
       // not copyable, don't worry about ref lifetime(?)
       // attr_value (const attr_value &v) : _m_attr (v.attr) {}
@@ -1036,6 +1053,11 @@ namespace elfutils
       {
        return debug_info_entry::raw_children::const_iterator (thisattr ());
       }
+      inline debug_info_entry::raw_children::const_iterator
+      unit_reference () const
+      {
+       return reference ();
+      }
 
       // XXX reloc, dwfl
       ::Dwarf_Addr address () const;
@@ -1051,6 +1073,14 @@ namespace elfutils
       }
 
       const dwarf::source_file source_file () const;
+      inline unsigned int source_line () const
+      {
+       return constant ();
+      }
+      inline unsigned int source_column () const
+      {
+       return constant ();
+      }
 
       // XXX reloc
       ::Dwarf_Word constant () const;
@@ -1078,8 +1108,8 @@ namespace elfutils
            {
            case VS_reference:
            case VS_unit_reference:
-             // XXX Reference identity check (?)
-             return reference ()->offset () == other.reference ()->offset ();
+             return true; // XXX Reference identity check (?)
+             //return reference ()->offset () == other.reference ()->offset ();
 
            case VS_flag:
              return flag () == other.flag ();
@@ -1094,15 +1124,20 @@ namespace elfutils
              /*FALLTHRU*/
            case VS_constant:
            case VS_dwarf_constant:
+             return constant () == other.constant ();
+
            case VS_source_line:
+             return source_line () == other.source_line ();
            case VS_source_column:
-             return constant () == other.constant ();
+             return source_column () == other.source_column ();
 
            case VS_identifier:
-             return !strcmp (identifier (), other.identifier ());
+             return name_equal<typeof (other.identifier ())> ()
+               (identifier (), other.identifier ());
 
            case VS_string:
-             return !strcmp (string (), other.string ());
+             return name_equal<typeof (other.string ())> ()
+               (string (), other.string ());
 
            case VS_address:
              return address () == other.address ();
@@ -1111,14 +1146,15 @@ namespace elfutils
              return source_file () == other.source_file ();
 
            case VS_location:
-             return location () == other; // XXX will be other.location ()
+             return location () == other.location ();
 
            case VS_discr_list:
              throw std::runtime_error ("XXX unimplemented");
            }
        return false;
       }
-      inline bool operator!= (const attr_value &other) const
+      template<typename value>
+      inline bool operator!= (const value &other) const
       {
        return !(*this == other);
       }
@@ -1130,30 +1166,135 @@ namespace elfutils
     {
       friend class attr_value;
     private:
-      const attr_value _m_attr;
+      attr_value _m_attr;
 
       location_attr (const attr_value &attr) : _m_attr (attr) {}
 
-      bool singleton () const; // XXX temp hack
+      inline bool same (const location_attr &it) const
+      {
+       return _m_attr.same (it._m_attr);
+      }
+
+      template<typename pair>
+      struct nonempty : public std::unary_function<pair, bool>
+      {
+       inline bool operator () (const pair &x)
+       {
+         return !x.second.empty ();
+       }
+      };
+
+      template<typename pair>
+      struct any : public std::unary_function<pair, bool>
+      {
+       inline bool operator () (const pair &x)
+       {
+         return true;
+       }
+      };
 
     public:
+      typedef size_t size_type;
+      typedef ptrdiff_t difference_type;
+      // XXX need proper type for exprs
+      typedef const_vector<uint8_t> mapped_type;
+      typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type;
+      typedef std::pair<const key_type, mapped_type> value_type;
+      class const_iterator;    // below
+
       std::string to_string () const;
 
+      bool is_list () const;
+
+      inline mapped_type location () const
+      {
+       if (is_list ())
+         throw std::runtime_error ("location is list, not single location");
+       return _m_attr.constant_block ();
+      }
+
+      inline const_iterator begin () const;
+      inline const_iterator end () const;
+
+      inline bool empty () const
+      {
+       if (is_list ())
+         return std::find_if (begin (), end (),
+                              nonempty<value_type> ()) == end ();
+       return location ().empty ();
+      }
+      inline size_type size () const
+      {
+       if (is_list ())
+         return std::count_if (begin (), end (), any<value_type> ());
+       return location ().empty () ? 0 : 1;
+      }
+
       template<typename other_attr>
       bool operator== (const other_attr &other) const
       {
-       // XXX hack, real location interface later
-       if (singleton ())
-         return _m_attr.constant_block () == other.constant_block ();
-       // loclistptr XXX punt for now, treat as constant
-       return _m_attr.constant () == other.constant ();
-      }
+       if (empty ())
+         return (other.empty ()
+                 || std::find_if (other.begin (), other.end (),
+                                  nonempty<value_type> ()) == other.end ());
+       if (!is_list ())
+         return !other.is_list () && location () == other.location ();
 
+       return other.is_list () && subr::container_equal (*this, other);
+      }
       template<typename other_file>
       inline bool operator!= (const other_file &other) const
       {
        return !(*this == other);
       }
+
+      /*
+       XXX missing: find, at; by key_type or by PC
+       */
+    };
+
+    class location_attr::const_iterator
+      : public std::iterator<std::input_iterator_tag, location_attr::value_type>
+    {
+      friend class location_attr;
+    private:
+      ::Dwarf_Addr _m_base;
+      ::Dwarf_Addr _m_begin;
+      ::Dwarf_Addr _m_end;
+      location_attr _m_attr;
+      ptrdiff_t _m_offset;
+
+      const_iterator (const location_attr &loc, ptrdiff_t offset)
+       : _m_base (-1), _m_begin (1), _m_end (0),
+         _m_attr (loc), _m_offset (offset) {}
+
+    public:
+
+      inline bool operator== (const const_iterator &it) const
+      {
+       return _m_offset == it._m_offset && _m_attr.same (it._m_attr);
+      }
+      inline bool operator!= (const const_iterator &it) const
+      {
+       return !(*this == it);
+      };
+
+      const_iterator &operator++ (); // prefix
+      inline const_iterator operator++ (int) // postfix
+      {
+       const_iterator prev = *this;
+       ++*this;
+       return prev;
+      }
+
+      inline value_type operator* () const
+      {
+       if (unlikely (_m_offset == 1))
+         throw std::runtime_error ("dereferencing end iterator");
+
+       return value_type (key_type (_m_base + _m_begin, _m_base + _m_end),
+                          _m_attr.location ());
+      }
     };
 
     /* The DW_AT_ranges attribute yields a range list.
@@ -1291,15 +1432,6 @@ namespace elfutils
     private:
       ::Dwarf_Files *_m_files;
 
-      template<typename string>
-      struct name_equal
-       : public std::binary_function<const char *, string, bool>
-      {
-       bool operator () (const char *me, const string &you)
-       {
-         return you == me;
-       }
-      };
       template<typename table>
       inline bool table_equal (const table &other) const
       {
@@ -1537,7 +1669,7 @@ namespace elfutils
       template<typename table>
       inline bool operator== (const table &other) const
       {
-       return subr::container_equal (*this, other);
+       return size () == other.size () && subr::container_equal (*this, other);
       }
       template<typename table>
       inline bool operator!= (const table &other) const
@@ -1985,6 +2117,10 @@ namespace elfutils
     private:
       typedef std::set<std::pair< ::Dwarf_Addr, ::Dwarf_Addr> > _base;
 
+    protected:
+      template<typename iterator>
+      arange_list (iterator first, iterator last) : _base (first, last) {}
+
     public:
       typedef _base::key_type key_type;
       typedef _base::value_type value_type;
@@ -2041,7 +2177,7 @@ namespace elfutils
 
   // Explicit specialization used inside dwarf::directory_table::operator==.
   template<>
-  struct dwarf::directory_table::name_equal<const char *>
+  struct dwarf::name_equal<const char *>
     : public std::binary_function<const char *, const char *, bool>
   {
     bool operator () (const char *me, const char *you)
@@ -2073,6 +2209,19 @@ namespace elfutils
   {
     return attributes::attributes (raw_attributes ());
   }
+
+  inline dwarf::location_attr::const_iterator
+  dwarf::location_attr::begin () const
+  {
+    const_iterator it (*this, 0);
+    if (is_list ())
+      ++it;
+    return it;
+  }
+  inline dwarf::location_attr::const_iterator dwarf::location_attr::end () const
+  {
+    return const_iterator (*this, 1);
+  }
 };
 
 #endif // <elfutils/dwarf>
index a7ac42e98c820c26b8f6d0aada4556079e443535..d9392c35395fca006f30c3ee5a650326d243b742 100644 (file)
@@ -86,9 +86,15 @@ namespace elfutils
       {
        return indexed_iterator (_m_contents, _m_idx + i._m_idx);
       }
-      inline indexed_iterator operator- (const indexed_iterator &i)
+      inline indexed_iterator operator+ (const typename array::difference_type
+                                        &i)
       {
-       return indexed_iterator (_m_contents, _m_idx - i._m_idx);
+       return indexed_iterator (_m_contents, _m_idx + i);
+      }
+      inline typename array::difference_type
+      operator- (const indexed_iterator &i)
+      {
+       return _m_idx - i._m_idx;
       }
 
       inline bool operator== (const indexed_iterator &i)
index 45f2ce30c9d37400c0f4a3198cc6b043b2464e03..335b80d19abf09f8f5d9cb76d647d072b1e1f2e3 100644 (file)
@@ -292,43 +292,7 @@ dwarf::attr_value::constant_block () const
       throw std::runtime_error ("XXX wrong form");
     }
 
-  const uint8_t *const begin = reinterpret_cast<const uint8_t *> (block.data);
-  const uint8_t *const end = begin + block.length;
-  return const_vector<uint8_t> (begin, end);
-}
-\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 (), "#");
+  return const_vector<uint8_t> (block);
 }
 \f
 // dwarf::range_list
@@ -339,42 +303,48 @@ dwarf::range_list::const_iterator::const_iterator (Dwarf_Attribute *attr,
 {
 }
 
-dwarf::range_list::const_iterator &
-dwarf::range_list::const_iterator::operator++ ()
+static bool
+range_list_advance (int secndx,
+                   Dwarf_CU *cu,
+                   Dwarf_Addr &base,
+                   Dwarf_Addr &begin,
+                   Dwarf_Addr &end,
+                   ptrdiff_t &offset,
+                   unsigned char **valp)
 {
-  const Elf_Data *d = _m_cu->dbg->sectiondata[IDX_debug_ranges];
+  const Elf_Data *d = cu->dbg->sectiondata[secndx];
   if (unlikely (d == NULL))
     throw std::runtime_error ("XXX no ranges");
 
-  if (unlikely (_m_offset < 0) || unlikely ((size_t) _m_offset >= d->d_size))
+  if (unlikely (offset < 0) || unlikely ((size_t) 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);
+  unsigned char *readp = reinterpret_cast<unsigned char *> (d->d_buf) + offset;
+  unsigned char *const readendp
+    = reinterpret_cast<unsigned char *> (d->d_buf) + d->d_size;
 
   while (true)
     {
-      if ((unsigned char *) d->d_buf + d->d_size - readp
-         < _m_cu->address_size * 2)
+      if (readendp - readp < cu->address_size * 2)
        throw std::runtime_error ("XXX bad ranges");
 
-      if (_m_cu->address_size == 8)
+      if (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.  */
+         begin = read_8ubyte_unaligned_inc (cu->dbg, readp);
+         end = read_8ubyte_unaligned_inc (cu->dbg, readp);
+         if (begin == (uint64_t) -1l) /* Base address entry.  */
            {
-             _m_base = _m_end;
+             base = 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.  */
+         begin = read_4ubyte_unaligned_inc (cu->dbg, readp);
+         end = read_4ubyte_unaligned_inc (cu->dbg, readp);
+         if (begin == (uint32_t) -1) /* Base address entry.  */
            {
-             _m_base = _m_end;
+             base = end;
              continue;
            }
        }
@@ -382,15 +352,17 @@ dwarf::range_list::const_iterator::operator++ ()
       break;
     }
 
-  if (_m_begin == 0 && _m_end == 0) /* End of list entry.  */
-    _m_offset = 1;
+  if (begin == 0 && end == 0) /* End of list entry.  */
+    offset = 1;
   else
     {
-      _m_offset = readp - reinterpret_cast<unsigned char *> (d->d_buf);
+      if (valp)
+       *valp = readp;
+      offset = readp - reinterpret_cast<unsigned char *> (d->d_buf);
 
-      if (_m_base == (Dwarf_Addr) -1)
+      if (base == (Dwarf_Addr) -1)
        {
-         CUDIE (cudie, _m_cu);
+         CUDIE (cudie, cu);
 
          /* Find the base address of the compilation unit.  It will
             normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
@@ -398,20 +370,29 @@ dwarf::range_list::const_iterator::operator++ ()
             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)
+         if (unlikely (dwarf_lowpc (&cudie, &base) != 0)
              && dwarf_formaddr (dwarf_attr (&cudie,
                                             DW_AT_entry_pc,
                                             &attr_mem),
-                                &_m_base) != 0)
+                                &base) != 0)
            {
-             xif (true);               // XXX
+             return true;      // XXX
            }
        }
     }
 
+  return false;
+}
+
+dwarf::range_list::const_iterator &
+dwarf::range_list::const_iterator::operator++ ()
+{
+  xif (range_list_advance (IDX_debug_ranges, _m_cu, _m_base,
+                          _m_begin, _m_end, _m_offset, NULL));
   return *this;
 }
 
+
 template<typename container>
 string
 __libdw_ranges_to_string (const container &c)
@@ -473,3 +454,62 @@ dwarf::aranges () const
 
   return result;
 }
+\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::is_list () const
+{
+  switch (dwarf_whatform (_m_attr.thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      return false;
+    }
+
+  return true;
+}
+
+dwarf::location_attr::const_iterator &
+dwarf::location_attr::const_iterator::operator++ ()
+{
+  if (unlikely (_m_offset == 1))
+    throw std::runtime_error ("incrementing end iterator");
+  else if (_m_offset == 0)
+    // Singleton, now at end.
+    _m_offset = 1;
+  else
+    {
+      // Advance to next list entry.
+      xif (range_list_advance (IDX_debug_loc, _m_attr._m_attr._m_attr.cu,
+                              _m_base, _m_begin, _m_end, _m_offset,
+                              &_m_attr._m_attr._m_attr.valp));
+      if (_m_offset > 1)
+       {
+         _m_attr._m_attr._m_attr.form = DW_FORM_block2;
+         _m_offset += read_2ubyte_unaligned (_m_attr._m_attr._m_attr.cu->dbg,
+                                             _m_attr._m_attr._m_attr.valp);
+       }
+    }
+
+  return *this;
+}
+
+string
+dwarf::location_attr::to_string () const
+{
+  if (is_list ())
+    return hex_string (_m_attr.constant (), "#");
+  return "XXX";
+}