Added operators for frame_view class, libunwind backend now stores addresses

This commit is contained in:
Antony Polukhin
2016-10-26 22:21:46 +03:00
parent 6c1fd6cba1
commit 8fa8c93fdb
4 changed files with 64 additions and 23 deletions

View File

@@ -12,8 +12,6 @@
# pragma once
#endif
#include <boost/core/noncopyable.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/assert.hpp>
@@ -101,8 +99,12 @@ class stacktrace {
/// @endcond
public:
#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
/// @brief Random access iterator that returns frame_view.
class iterator;
typedef implementation_specific iterator;
#else
class iterator; // forward declaration
#endif
class frame_view {
/// @cond
@@ -222,10 +224,9 @@ public:
/// is the function index where stacktrace was constructed and
/// index close to this->size() contains function `main()`.
/// @returns frame_view that references the actual frame info, stored inside *this.
/// @throws std::bad_alloc if not enough memory to construct resulting string.
///
/// @b Complexity: Amortized O(1), O(1) for noop backend.
frame_view operator[](std::size_t frame_no) const {
frame_view operator[](std::size_t frame_no) const BOOST_NOEXCEPT {
return *(cbegin() + frame_no);
}
@@ -277,27 +278,29 @@ public:
const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(this, size()) ); }
};
/// Comparison operators that order in a platform dependant order and have amortized O(1) complexity; O(size()) worst case conmlexity.
/// Comparison operators that order in a platform dependant order and have amortized O(1) complexity; O(size()) worst case complexity.
inline bool operator> (const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
inline bool operator<=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
inline bool operator>=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
inline bool operator!=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
/// Comparison operators that order in a platform dependant order and have O(1) complexity.
inline bool operator< (const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); }
inline bool operator> (const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return rhs < lhs; }
inline bool operator<=(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); }
inline bool operator>=(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); }
inline bool operator==(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); }
inline bool operator!=(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); }
/// Hashing support, O(1) complexity.
inline std::size_t hash_value(const stacktrace& st) BOOST_NOEXCEPT {
return st.hash_code();
}
/// Outputs stacktrace::frame in a human readable format to output stream.
template <class CharT, class TraitsT>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const stacktrace::frame_view& f) {
os << f.name();
if (f.source_line()) {
return os << '\t' << f.source_file() << ':' << f.source_line();
}
return os;
/// Hashing support, O(1) complexity.
inline std::size_t hash_value(const stacktrace::frame_view& f) BOOST_NOEXCEPT {
return reinterpret_cast<std::size_t>(f.address());
}
/// Outputs stacktrace in a human readable format to output stream.
@@ -317,6 +320,18 @@ std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT
return os;
}
/// Outputs stacktrace::frame in a human readable format to output stream.
template <class CharT, class TraitsT>
std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const stacktrace::frame_view& f) {
os << f.name();
if (f.source_line()) {
return os << '\t' << f.source_file() << ':' << f.source_line();
}
return os;
}
}} // namespace boost::stacktrace
/// @cond

View File

@@ -24,21 +24,34 @@
namespace boost { namespace stacktrace { namespace detail {
struct bt_pair {
std::string name;
const void* addr;
};
inline bool operator< (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT {
return lhs.addr < rhs.addr;
}
inline bool operator== (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT {
return lhs.addr == rhs.addr;
}
struct backtrace_holder {
std::size_t frames_count;
boost::shared_ptr<std::string[]> frames;
boost::shared_ptr<bt_pair[]> frames;
inline std::size_t size() const BOOST_NOEXCEPT {
return frames_count;
}
inline const void* get_address(std::size_t frame) const BOOST_NOEXCEPT {
return &frames[frame];
return frames[frame].addr;
}
inline std::string get_frame(std::size_t frame) const {
if (frame < frames_count) {
return frames[frame];
return frames[frame].name;
} else {
return std::string();
}
@@ -48,7 +61,7 @@ struct backtrace_holder {
std::string res;
unw_word_t offp;
char data[256];
const int ret = unw_get_proc_name (&cursor, data, sizeof(data) / sizeof(char), &offp);
const int ret = unw_get_proc_name(&cursor, data, sizeof(data) / sizeof(char), &offp);
if (ret == -UNW_ENOMEM) {
res.resize(sizeof(data) * 2);

View File

@@ -48,11 +48,15 @@ stacktrace::stacktrace() BOOST_NOEXCEPT
}
BOOST_TRY {
bt.frames = boost::make_shared<std::string[]>(bt.frames_count);
bt.frames = boost::make_shared<boost::stacktrace::detail::bt_pair[]>(bt.frames_count);
std::size_t i = 0;
while (unw_step(&cursor) > 0){
bt.frames[i] = boost::stacktrace::detail::backtrace_holder::get_frame_impl(cursor);
boost::hash_combine(hash_code_, bt.frames[i]);
bt.frames[i].name = boost::stacktrace::detail::backtrace_holder::get_frame_impl(cursor);
unw_proc_info_t inf;
const int res = unw_get_proc_info(&cursor, &inf);
(void)res;
bt.frames[i].addr = reinterpret_cast<void*>(inf.start_ip ? inf.start_ip : inf.gp);
boost::hash_combine(hash_code_, bt.frames[i].name);
++ i;
}
} BOOST_CATCH(...) {}

View File

@@ -168,6 +168,15 @@ void test_frame_view() {
stacktrace::frame_view fv = nst[1];
BOOST_TEST(st[1].name() != fv.name());
BOOST_TEST(st[1] != fv);
BOOST_TEST(st[1] == st[1]);
BOOST_TEST(st[1] <= st[1]);
BOOST_TEST(st[1] >= st[1]);
BOOST_TEST(st[1] < fv || st[1] > fv);
BOOST_TEST(hash_value(st[1]) != hash_value(fv));
fv = st[1];
BOOST_TEST(hash_value(st[1]) == hash_value(fv));
}
int main() {