mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-02-02 21:22:09 +00:00
Added operators for frame_view class, libunwind backend now stores addresses
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(...) {}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user