From: Roland McGrath Date: Tue, 27 Jan 2009 02:37:36 +0000 (-0800) Subject: dwarf_ranges C++ wrapper X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=14ae5f5555ca55d6bc9549060811c9617191b9c0;p=thirdparty%2Felfutils.git dwarf_ranges C++ wrapper --- diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf index d4aa9b888..92fe17248 100644 --- a/libdw/c++/dwarf +++ b/libdw/c++/dwarf @@ -360,6 +360,7 @@ namespace elfutils class attr_value; class location_attr; class range_list; + class ranges; class debug_info_entry { @@ -432,6 +433,11 @@ namespace elfutils { return ::dwarf_dieoffset (thisdie ()); } + + inline const dwarf::ranges ranges () const + { + return dwarf::ranges (*this); + } }; // Container for raw list of child DIEs, intended to be a compatible with @@ -856,8 +862,8 @@ namespace elfutils /* containers/iterators: - lines - macros + XXX lines + XXX macros abbrevs (punt) @@ -1168,7 +1174,7 @@ namespace elfutils return const_iterator (); } - const_iterator find (const key_type &match) + const_iterator find (const key_type &match) const { return std::find (begin (), end (), match); } @@ -1277,6 +1283,151 @@ namespace elfutils } }; + /* This works like range_list, but is based on a debug_info_entry using + dwarf_ranges. If the entry has DW_AT_low_pc and DW_AT_high_pc, this + will present a singleton list; if it has a DW_AT_ranges, it will be + the same as the range_list presentation. If neither, an empty list. */ + class ranges + { + friend class debug_info_entry; + private: + debug_info_entry _m_die; + + ranges (const debug_info_entry &die) : _m_die (die) {} + + public: + typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type; + typedef key_type value_type; + + ranges (const ranges &other) : _m_die (other._m_die) {} + + std::string to_string () const; + + class const_iterator + : public std::iterator + { + friend class ranges; + private: + debug_info_entry _m_die; + ::Dwarf_Addr _m_base; + ::Dwarf_Addr _m_begin; + ::Dwarf_Addr _m_end; + ptrdiff_t _m_offset; + + inline const_iterator () : _m_die (), _m_offset (0) {} // end () value + inline const_iterator (const debug_info_entry &die) + : _m_die (die), _m_offset (0) + { + ++*this; + } + + public: + inline const_iterator (const const_iterator &i) + : _m_die (i._m_die), _m_base (i._m_base), + _m_begin (i._m_begin), _m_end (i._m_begin), + _m_offset (i._m_offset) {} + + inline value_type operator* () const + { + return std::make_pair (_m_begin, _m_end); + } + + inline const_iterator &operator= (const const_iterator &other) + { + _m_die = other._m_die; + _m_base = other._m_base; + _m_begin = other._m_begin; + _m_end = other._m_end; + _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 + { + do + _m_offset = dwarf_ranges (_m_die.thisdie (), _m_offset, + &_m_base, &_m_begin, &_m_end); + // Skip over empty ranges. + while (_m_offset != 0 && _m_begin == _m_end); + return *this; + } + inline const_iterator operator++ (int) // postfix + { + const_iterator prev = *this; + ++*this; + return prev; + } + }; + + const_iterator begin () const + { + return const_iterator (_m_die); + } + const_iterator end () const + { + return const_iterator (); + } + + inline bool empty () const + { + return begin () == end (); + } + + const_iterator find (const key_type &match) const + { + return std::find (begin (), end (), match); + } + + private: + struct entry_contains + : public std::binary_function + { + 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 () const + { + return std::set (begin (), end ()); + } + + template + inline bool operator== (const ranges &other) const + { + /* 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 mine = *this; + const std::set his = other; + return mine == his; + } + template + inline bool operator!= (const ranges &other) const + { + return !(*this == other); + } + }; + // Container for raw CUs in file order, intended to be compatible // with a read-only subset of std::list. class raw_compile_units @@ -1415,8 +1566,9 @@ namespace elfutils containers/iterators: raw CU in file order - pubnames: list of (CU, DIE, FQ name string) - aranges: list of (start, len, CU file offset) + XXX pubnames: list of (CU, DIE, FQ name string) + XXX aranges: list of (start, len, CU file offset) + XXX or aranges: list of (CU, range_list) raw CU by addr (getarange_addr) logical CU in file order diff --git a/libdw/c++/values.cc b/libdw/c++/values.cc index 22bee1354..c0a0cbd13 100644 --- a/libdw/c++/values.cc +++ b/libdw/c++/values.cc @@ -518,8 +518,9 @@ dwarf::range_list::const_iterator::operator++ () return *this; } +template string -dwarf::range_list::to_string () const +__libdw_ranges_to_string (const container &c) { std::ostringstream os; os.setf(std::ios::hex, std::ios::basefield); @@ -527,9 +528,9 @@ dwarf::range_list::to_string () const os << "<"; bool first = true; - for (const_iterator i = begin (); i != end (); ++i) + for (typename container::const_iterator i = c.begin (); i != c.end (); ++i) { - value_type range = *i; + typename container::value_type range = *i; if (!first) os << ","; os << range.first << "-" << range.second; @@ -540,3 +541,15 @@ dwarf::range_list::to_string () const return os.str (); } + +string +dwarf::range_list::to_string () const +{ + return __libdw_ranges_to_string (*this); +} + +string +dwarf::ranges::to_string () const +{ + return __libdw_ranges_to_string (*this); +}