From: Roland McGrath Date: Mon, 2 Feb 2009 02:34:04 +0000 (-0800) Subject: Various fixes; started location list reader interface. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2d6362f658b2ddedd03bf9530a8072bba0b3cc9e;p=thirdparty%2Felfutils.git Various fixes; started location list reader interface. --- diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf index 9ceb4b40a..14f2947f0 100644 --- a/libdw/c++/dwarf +++ b/libdw/c++/dwarf @@ -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 (b.data)) {} inline const_vector &operator= (const const_vector &v) { @@ -241,6 +243,15 @@ namespace elfutils return os.str (); } + template + struct name_equal : public std::binary_function + { + 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 mine = *this; - const std::map his = other; - return mine == his; + const std::map his = other; + return mine.size () == his.size () && subr::container_equal (mine, his); } template @@ -998,9 +1011,8 @@ namespace elfutils if (other_size != 0 && other_size != size ()) return false; } - return !strcmp (name (), other.name ()); + return name_equal () (name (), other.name ()); } - template 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 () + (identifier (), other.identifier ()); case VS_string: - return !strcmp (string (), other.string ()); + return name_equal () + (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 + 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 + struct nonempty : public std::unary_function + { + inline bool operator () (const pair &x) + { + return !x.second.empty (); + } + }; + + template + struct any : public std::unary_function + { + 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 mapped_type; + typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type; + typedef std::pair 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 ()) == end (); + return location ().empty (); + } + inline size_type size () const + { + if (is_list ()) + return std::count_if (begin (), end (), any ()); + return location ().empty () ? 0 : 1; + } + template 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 ()) == other.end ()); + if (!is_list ()) + return !other.is_list () && location () == other.location (); + return other.is_list () && subr::container_equal (*this, other); + } template 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 + { + 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 - struct name_equal - : public std::binary_function - { - bool operator () (const char *me, const string &you) - { - return you == me; - } - }; template inline bool table_equal (const table &other) const { @@ -1537,7 +1669,7 @@ namespace elfutils template inline bool operator== (const table &other) const { - return subr::container_equal (*this, other); + return size () == other.size () && subr::container_equal (*this, other); } template inline bool operator!= (const table &other) const @@ -1985,6 +2117,10 @@ namespace elfutils private: typedef std::set > _base; + protected: + template + 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 + struct dwarf::name_equal : public std::binary_function { 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 // diff --git a/libdw/c++/subr.hh b/libdw/c++/subr.hh index a7ac42e98..d9392c353 100644 --- a/libdw/c++/subr.hh +++ b/libdw/c++/subr.hh @@ -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) diff --git a/libdw/c++/values.cc b/libdw/c++/values.cc index 45f2ce30c..335b80d19 100644 --- a/libdw/c++/values.cc +++ b/libdw/c++/values.cc @@ -292,43 +292,7 @@ dwarf::attr_value::constant_block () const throw std::runtime_error ("XXX wrong form"); } - const uint8_t *const begin = reinterpret_cast (block.data); - const uint8_t *const end = begin + block.length; - return const_vector (begin, end); -} - -// 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 (block); } // 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 (d->d_buf) - + _m_offset); + unsigned char *readp = reinterpret_cast (d->d_buf) + offset; + unsigned char *const readendp + = reinterpret_cast (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 (d->d_buf); + if (valp) + *valp = readp; + offset = readp - reinterpret_cast (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 string __libdw_ranges_to_string (const container &c) @@ -473,3 +454,62 @@ dwarf::aranges () const return result; } + +// 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"; +}