mirror of
https://github.com/boostorg/stacktrace.git
synced 2026-01-28 07:42:11 +00:00
Added noop backend. Do not skip frames in backends anymore, because it is impossible to guess the inlining heuristics on different compilers. Fixed tests, added more tests, simplified code, improved docs
This commit is contained in:
@@ -33,6 +33,18 @@ explicit backtrace ;
|
||||
mp-run-simple has_windbg.cpp : : : : WinDbg ;
|
||||
explicit WinDbg ;
|
||||
|
||||
lib boost_stacktrace_noop
|
||||
: # sources
|
||||
../src/noop.cpp
|
||||
: # requirements
|
||||
<warnings>all
|
||||
: # default build
|
||||
: # usage-requirements
|
||||
<link>shared:<define>BOOST_TEST_DYN_LINK=1
|
||||
;
|
||||
|
||||
boost-install boost_stacktrace_noop ;
|
||||
|
||||
lib boost_stacktrace_libunwind
|
||||
: # sources
|
||||
../src/libunwind.cpp
|
||||
|
||||
@@ -33,7 +33,7 @@ class stacktrace {
|
||||
public:
|
||||
/// @brief Stores the current function call sequence inside the class.
|
||||
///
|
||||
/// @b Complexity: O(N) where N is call seaquence length
|
||||
/// @b Complexity: O(N) where N is call seaquence length, O(1) for noop backend.
|
||||
BOOST_STACKTRACE_FUNCTION stacktrace() BOOST_NOEXCEPT;
|
||||
|
||||
/// @b Complexity: O(1)
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
/// @returns Function name in a human readable form.
|
||||
/// @throws std::bad_alloc if not enough memory to construct resulting string.
|
||||
///
|
||||
/// @b Complexity: Amortized O(1)
|
||||
/// @b Complexity: Amortized O(1), O(1) for noop backend.
|
||||
BOOST_STACKTRACE_FUNCTION std::string operator[](std::size_t frame) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS) || defined(BOOST_STACKTRACE_USE_WINDBG)
|
||||
#if defined(BOOST_STACKTRACE_USE_NOOP)
|
||||
# include <boost/stacktrace/detail/stacktrace_noop.hpp>
|
||||
#elif defined(BOOST_WINDOWS) || defined(BOOST_STACKTRACE_USE_WINDBG)
|
||||
# include <boost/stacktrace/detail/stacktrace_windows.hpp>
|
||||
#elif defined(BOOST_STACKTRACE_USE_LIBUNWIND)
|
||||
# include <boost/stacktrace/detail/stacktrace_libunwind.hpp>
|
||||
|
||||
@@ -24,11 +24,10 @@
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct backtrace_holder {
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 1u;
|
||||
std::size_t frames_count;
|
||||
boost::shared_ptr<std::string[]> frames;
|
||||
|
||||
backtrace_holder() BOOST_NOEXCEPT
|
||||
BOOST_FORCEINLINE backtrace_holder() BOOST_NOEXCEPT
|
||||
: frames_count(0)
|
||||
{
|
||||
unw_context_t uc;
|
||||
@@ -44,11 +43,6 @@ struct backtrace_holder {
|
||||
while (unw_step(&cursor) > 0) {
|
||||
++ frames_count;
|
||||
}
|
||||
if (frames_count <= skip_frames) {
|
||||
frames_count = 0;
|
||||
return;
|
||||
}
|
||||
frames_count -= skip_frames;
|
||||
}
|
||||
|
||||
unw_cursor_t cursor;
|
||||
@@ -57,13 +51,6 @@ struct backtrace_holder {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < skip_frames; ++i) {
|
||||
if (unw_step(&cursor) <= 0) {
|
||||
frames_count = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TRY {
|
||||
frames = boost::make_shared<std::string[]>(frames_count);
|
||||
std::size_t i = 0;
|
||||
@@ -75,11 +62,11 @@ struct backtrace_holder {
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
std::size_t size() const BOOST_NOEXCEPT {
|
||||
inline std::size_t size() const BOOST_NOEXCEPT {
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
std::string get_frame(std::size_t frame) const {
|
||||
inline std::string get_frame(std::size_t frame) const {
|
||||
if (frame < frames_count) {
|
||||
return frames[frame];
|
||||
} else {
|
||||
@@ -87,7 +74,7 @@ struct backtrace_holder {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string get_frame_impl(unw_cursor_t& cursor) {
|
||||
static inline std::string get_frame_impl(unw_cursor_t& cursor) {
|
||||
std::string res;
|
||||
unw_word_t offp;
|
||||
char data[256];
|
||||
|
||||
@@ -26,23 +26,16 @@ struct backtrace_holder {
|
||||
BOOST_STATIC_CONSTEXPR std::size_t max_size = 100u;
|
||||
void* buffer[max_size];
|
||||
|
||||
#ifdef BOOST_STACKTRACE_HEADER_ONLY
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 0u;
|
||||
#else
|
||||
BOOST_STATIC_CONSTEXPR std::size_t skip_frames = 2u;
|
||||
#endif
|
||||
|
||||
inline backtrace_holder() BOOST_NOEXCEPT {
|
||||
BOOST_FORCEINLINE backtrace_holder() BOOST_NOEXCEPT {
|
||||
frames_count = ::backtrace(buffer, max_size);
|
||||
}
|
||||
|
||||
inline std::size_t size() const BOOST_NOEXCEPT {
|
||||
return frames_count > skip_frames ? frames_count - skip_frames : 1u;
|
||||
return frames_count;
|
||||
}
|
||||
|
||||
inline std::string get_frame(std::size_t frame) const {
|
||||
std::string res;
|
||||
frame += skip_frames;
|
||||
if (frame >= frames_count) {
|
||||
return res;
|
||||
}
|
||||
|
||||
29
include/boost/stacktrace/detail/stacktrace_noop.hpp
Normal file
29
include/boost/stacktrace/detail/stacktrace_noop.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright Antony Polukhin, 2016.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_STACKTRACE_DETAIL_STACKTRACE_NOOP_HPP
|
||||
#define BOOST_STACKTRACE_DETAIL_STACKTRACE_NOOP_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
struct backtrace_holder {
|
||||
inline std::size_t size() const BOOST_NOEXCEPT {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
inline std::string get_frame(std::size_t /*frame*/) const {
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace boost::stacktrace::detail
|
||||
|
||||
#endif // BOOST_STACKTRACE_DETAIL_STACKTRACE_NOOP_HPP
|
||||
@@ -34,7 +34,7 @@ struct backtrace_holder {
|
||||
void* buffer[max_size];
|
||||
HANDLE process;
|
||||
|
||||
inline backtrace_holder() BOOST_NOEXCEPT
|
||||
BOOST_FORCEINLINE backtrace_holder() BOOST_NOEXCEPT
|
||||
: frames_count(0)
|
||||
, process(GetCurrentProcess())
|
||||
{
|
||||
|
||||
8
src/noop.cpp
Normal file
8
src/noop.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright Antony Polukhin, 2016.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_STACKTRACE_USE_NOOP
|
||||
#include <boost/stacktrace/detail/stacktrace.ipp>
|
||||
@@ -20,20 +20,24 @@ project
|
||||
lib test_unwind_lib : test_impl.cpp : <link>shared : : <library>/boost/stacktrace//boost_stacktrace_libunwind [ check-target-builds ../build//libunwind : : <build>no ] ;
|
||||
lib test_backtrace_lib : test_impl.cpp : <link>shared : : <library>/boost/stacktrace//boost_stacktrace_backtrace [ check-target-builds ../build//backtrace : : <build>no ] ;
|
||||
lib test_windbg_lib : test_impl.cpp : <link>shared : : <library>/boost/stacktrace//boost_stacktrace_windbg [ check-target-builds ../build//WinDbg : : <build>no ] ;
|
||||
lib test_noop_lib : test_impl.cpp : <link>shared : : <library>/boost/stacktrace//boost_stacktrace_noop ;
|
||||
|
||||
local HONLY_UNW = <define>BOOST_STACKTRACE_HEADER_ONLY <define>BOOST_STACKTRACE_USE_LIBUNWIND <library>unwind [ check-target-builds ../build//libunwind : : <build>no ] ;
|
||||
local HONLY_BT = <define>BOOST_STACKTRACE_HEADER_ONLY <define>BOOST_STACKTRACE_USE_BACKTRACE <library>dl [ check-target-builds ../build//backtrace : : <build>no ] ;
|
||||
local HONLY_WIND = <define>BOOST_STACKTRACE_HEADER_ONLY <define>BOOST_STACKTRACE_USE_WINDBG <library>Dbghelp [ check-target-builds ../build//WinDbg : : <build>no ] ;
|
||||
local HONLY_NOOP = <define>BOOST_STACKTRACE_HEADER_ONLY <define>BOOST_STACKTRACE_USE_NOOP ;
|
||||
|
||||
test-suite stacktrace
|
||||
:
|
||||
[ run test.cpp test_impl.cpp : : : $(HONLY_UNW) : libunwind_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : $(HONLY_BT) : backtrace_ho ]
|
||||
[ run test.cpp test_impl.cpp : : : $(HONLY_WIND) : windbg_ho ]
|
||||
[ run test_noop.cpp test_impl.cpp : : : $(HONLY_NOOP) : noop_ho ]
|
||||
|
||||
[ run test.cpp : : : <library>.//test_unwind_lib [ check-target-builds ../build//libunwind : : <build>no ] : libunwind_lib ]
|
||||
[ run test.cpp : : : <library>.//test_backtrace_lib [ check-target-builds ../build//backtrace : : <build>no ] : backtrace_lib ]
|
||||
[ run test.cpp : : : <library>.//test_windbg_lib [ check-target-builds ../build//WinDbg : : <build>no ] : windbg_lib ]
|
||||
[ run test_noop.cpp : : : <library>.//test_noop_lib : noop_lib ]
|
||||
|
||||
[ run ../example/getting_started.cpp : : : $(HONLY_UNW) : libunwind_getting_started ]
|
||||
[ run ../example/getting_started.cpp : : : $(HONLY_BT) : backtrace_getting_started ]
|
||||
|
||||
@@ -9,13 +9,23 @@
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using boost::stacktrace::stacktrace;
|
||||
BOOST_SYMBOL_IMPORT std::pair<stacktrace, stacktrace> foo2(int i);
|
||||
BOOST_SYMBOL_IMPORT std::pair<stacktrace, stacktrace> foo1(int i);
|
||||
BOOST_SYMBOL_IMPORT stacktrace return_from_nested_namespaces();
|
||||
|
||||
void test_deeply_nested_namespaces() {
|
||||
std::stringstream ss;
|
||||
ss << return_from_nested_namespaces();
|
||||
std::cout << ss.str() << '\n';
|
||||
BOOST_TEST(ss.str().find("main") != std::string::npos);
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_HEADER_ONLY) || !defined(BOOST_STACKTRACE_USE_BACKTRACE)
|
||||
BOOST_TEST(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_nested() {
|
||||
std::pair<stacktrace, stacktrace> res = foo2(15);
|
||||
@@ -24,43 +34,30 @@ void test_nested() {
|
||||
ss1 << res.first;
|
||||
ss2 << res.second;
|
||||
std::cout << "'" << ss1.str() << "'\n\n" << ss2.str() << std::endl;
|
||||
assert(!ss1.str().empty());
|
||||
assert(!ss2.str().empty());
|
||||
BOOST_TEST(!ss1.str().empty());
|
||||
BOOST_TEST(!ss2.str().empty());
|
||||
|
||||
assert(ss1.str().find(" 0# ") != std::string::npos);
|
||||
assert(ss2.str().find(" 0# ") != std::string::npos);
|
||||
BOOST_TEST(ss1.str().find(" 0# ") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find(" 0# ") != std::string::npos);
|
||||
|
||||
assert(ss1.str().find(" 1# ") != std::string::npos);
|
||||
assert(ss2.str().find(" 1# ") != std::string::npos);
|
||||
BOOST_TEST(ss1.str().find(" 1# ") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find(" 1# ") != std::string::npos);
|
||||
|
||||
assert(ss1.str().find("main") != std::string::npos);
|
||||
assert(ss2.str().find("main") != std::string::npos);
|
||||
|
||||
|
||||
assert(ss2.str().find("stacktrace") == std::string::npos);
|
||||
BOOST_TEST(ss1.str().find("main") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find("main") != std::string::npos);
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_HEADER_ONLY) || !defined(BOOST_STACKTRACE_USE_BACKTRACE)
|
||||
assert(ss1.str().find("stacktrace") != std::string::npos);
|
||||
assert(ss1.str().find("pair") != std::string::npos);
|
||||
|
||||
assert(ss1.str().find("foo1") != std::string::npos);
|
||||
assert(ss1.str().find("foo2") != std::string::npos);
|
||||
assert(ss2.str().find("foo1") != std::string::npos);
|
||||
assert(ss2.str().find("foo2") != std::string::npos);
|
||||
BOOST_TEST(ss1.str().find("foo1") != std::string::npos);
|
||||
BOOST_TEST(ss1.str().find("foo2") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find("foo1") != std::string::npos);
|
||||
BOOST_TEST(ss2.str().find("foo2") != std::string::npos);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
std::stringstream ss;
|
||||
ss << return_from_nested_namespaces();
|
||||
std::cout << ss.str() << '\n';
|
||||
assert(ss.str().find("main") != std::string::npos);
|
||||
assert(ss.str().find("stacktrace") == std::string::npos);
|
||||
|
||||
#if !defined(BOOST_STACKTRACE_HEADER_ONLY) || !defined(BOOST_STACKTRACE_USE_BACKTRACE)
|
||||
assert(ss.str().find("get_backtrace_from_nested_namespaces") != std::string::npos);
|
||||
#endif
|
||||
|
||||
test_deeply_nested_namespaces();
|
||||
test_nested();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace boost::stacktrace;
|
||||
BOOST_SYMBOL_EXPORT std::pair<stacktrace, stacktrace> foo1(int i);
|
||||
BOOST_SYMBOL_EXPORT std::pair<stacktrace, stacktrace> foo2(int i);
|
||||
BOOST_SYMBOL_EXPORT BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo1(int i);
|
||||
BOOST_SYMBOL_EXPORT BOOST_NOINLINE std::pair<stacktrace, stacktrace> foo2(int i);
|
||||
|
||||
std::pair<stacktrace, stacktrace> foo1(int i) {
|
||||
if (i) {
|
||||
@@ -45,12 +45,12 @@ namespace very_very_very_very_very_very_long_namespace {
|
||||
namespace very_very_very_very_very_very_long_namespace {
|
||||
namespace very_very_very_very_very_very_long_namespace {
|
||||
namespace very_very_very_very_very_very_long_namespace {
|
||||
BOOST_SYMBOL_EXPORT stacktrace get_backtrace_from_nested_namespaces() {
|
||||
BOOST_SYMBOL_EXPORT BOOST_NOINLINE stacktrace get_backtrace_from_nested_namespaces() {
|
||||
return stacktrace();
|
||||
}
|
||||
}}}}}}}}}}
|
||||
|
||||
BOOST_SYMBOL_EXPORT stacktrace return_from_nested_namespaces() {
|
||||
BOOST_SYMBOL_EXPORT BOOST_NOINLINE stacktrace return_from_nested_namespaces() {
|
||||
using very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
|
||||
::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
|
||||
::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace::very_very_very_very_very_very_long_namespace
|
||||
|
||||
36
test/test_noop.cpp
Normal file
36
test/test_noop.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright Antony Polukhin, 2016.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/stacktrace.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using boost::stacktrace::stacktrace;
|
||||
BOOST_SYMBOL_IMPORT std::pair<stacktrace, stacktrace> foo2(int i);
|
||||
BOOST_SYMBOL_IMPORT std::pair<stacktrace, stacktrace> foo1(int i);
|
||||
BOOST_SYMBOL_IMPORT stacktrace return_from_nested_namespaces();
|
||||
|
||||
void test_deeply_nested_namespaces() {
|
||||
BOOST_TEST(return_from_nested_namespaces().size() == 0);
|
||||
BOOST_TEST(return_from_nested_namespaces()[0] == "");
|
||||
}
|
||||
|
||||
void test_nested() {
|
||||
std::pair<stacktrace, stacktrace> res = foo2(15);
|
||||
|
||||
BOOST_TEST(res.first.size() == 0);
|
||||
BOOST_TEST(res.first[0] == "");
|
||||
BOOST_TEST(res.second.size() == 0);
|
||||
BOOST_TEST(res.second[0] == "");
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
test_deeply_nested_namespaces();
|
||||
test_nested();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user