From f17b9a490a2fc481082483fce016d57605d429a0 Mon Sep 17 00:00:00 2001 From: Martin Quinson Date: Sun, 28 Oct 2018 22:30:38 +0100 Subject: [PATCH] Hide the backtrace implementation in a private pimpl This opens the path to an implementation with Boost.Stacktrace when found --- include/simgrid/Exception.hpp | 5 +-- include/xbt/backtrace.hpp | 24 +++++++------ src/xbt/backtrace.cpp | 68 ++++++++++++++++++++++------------- src/xbt/exception.cpp | 4 +-- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/include/simgrid/Exception.hpp b/include/simgrid/Exception.hpp index 9ea27ab704..0fe9a32615 100644 --- a/include/simgrid/Exception.hpp +++ b/include/simgrid/Exception.hpp @@ -34,7 +34,7 @@ class ThrowPoint { public: ThrowPoint() = default; explicit ThrowPoint(const char* file, int line, const char* function, Backtrace bt, std::string actor_name, int pid) - : file_(file), line_(line), function_(function), backtrace_(bt), procname_(actor_name), pid_(pid) + : file_(file), line_(line), function_(function), backtrace_(std::move(bt)), procname_(actor_name), pid_(pid) { } @@ -48,7 +48,8 @@ public: /** Create a ThrowPoint with (__FILE__, __LINE__, __func__) */ #define XBT_THROW_POINT \ - ::simgrid::xbt::ThrowPoint(__FILE__, __LINE__, __func__, simgrid::xbt::backtrace(), xbt_procname(), xbt_getpid()) + ::simgrid::xbt::ThrowPoint(__FILE__, __LINE__, __func__, std::move(simgrid::xbt::Backtrace()), xbt_procname(), \ + xbt_getpid()) } // namespace xbt /** Ancestor class of all SimGrid exception */ diff --git a/include/xbt/backtrace.hpp b/include/xbt/backtrace.hpp index dfde1bd7c9..55712c98d6 100644 --- a/include/xbt/backtrace.hpp +++ b/include/xbt/backtrace.hpp @@ -21,6 +21,13 @@ SG_END_DECL() namespace simgrid { namespace xbt { +/** Try to demangle a C++ name + * + * Return the origin string if this fails. + */ +XBT_PUBLIC std::unique_ptr demangle(const char* name); + +class BacktraceImpl; /** A backtrace * * This is used (among other things) in exceptions to store the associated @@ -28,16 +35,13 @@ namespace xbt { * * @ingroup XBT_ex */ -typedef std::vector Backtrace; - -/** Try to demangle a C++ name - * - * Return the origin string if this fails. - */ -XBT_PUBLIC std::unique_ptr demangle(const char* name); - -/** @brief Captures a backtrace for further use */ -XBT_PUBLIC Backtrace backtrace(); +class Backtrace { +public: + BacktraceImpl* impl_; + Backtrace(); + Backtrace(const Backtrace& bt); + ~Backtrace(); +}; /* Translate the backtrace in a human friendly form * diff --git a/src/xbt/backtrace.cpp b/src/xbt/backtrace.cpp index a74145f90a..baa1f647b7 100644 --- a/src/xbt/backtrace.cpp +++ b/src/xbt/backtrace.cpp @@ -58,19 +58,10 @@ void xbt_backtrace_display(const simgrid::xbt::Backtrace& bt) /** @brief show the backtrace of the current point (lovely while debugging) */ void xbt_backtrace_display_current() { - simgrid::xbt::Backtrace bt = simgrid::xbt::backtrace(); + simgrid::xbt::Backtrace bt = simgrid::xbt::Backtrace(); xbt_backtrace_display(bt); } -#if HAVE_BACKTRACE -// For some reason, if I try to use it directly, GCC thinks I try to use xbt::backtrace. -// I suspect that this symbol is not presented as a regular function in execinfo.h -static int gnu_backtrace(simgrid::xbt::Backtrace& bt) -{ - return backtrace(bt.data(), bt.size()); -} -#endif - namespace simgrid { namespace xbt { @@ -90,23 +81,50 @@ std::unique_ptr demangle(const char* name) return std::unique_ptr(xbt_strdup(name), std::free); } -Backtrace backtrace() +class BacktraceImpl { + short refcount_ = 1; + +public: + void ref() { refcount_++; } + bool unref() + { + refcount_--; + return refcount_ == 0; + } +#if HAVE_BACKTRACE + std::vector frames; +#endif +}; + +Backtrace::Backtrace() { - simgrid::xbt::Backtrace res; #if HAVE_BACKTRACE - res.resize(15); - int used = gnu_backtrace(res); + impl_ = new BacktraceImpl(); + impl_->frames.resize(15); + int used = backtrace(impl_->frames.data(), impl_->frames.size()); if (used == 0) { std::fprintf(stderr, "The backtrace() function failed, which probably means that the memory is exhausted\n."); std::fprintf(stderr, "Bailing out now since there is nothing I can do without a decent amount of memory\n."); std::fprintf(stderr, "Please go fix the memleaks\n"); std::exit(1); } - res.shrink_to_fit(); + impl_->frames.shrink_to_fit(); #endif - return res; +} +Backtrace::Backtrace(const Backtrace& bt) +{ + impl_ = bt.impl_; + impl_->ref(); } +Backtrace::~Backtrace() +{ + if (impl_->unref()) { +#if HAVE_BACKTRACE + delete impl_; +#endif + } +} } // namespace xbt } // namespace simgrid @@ -153,26 +171,26 @@ std::vector resolve_backtrace(const Backtrace& bt) #if HAVE_BACKTRACE && HAVE_EXECINFO_H && HAVE_POPEN && defined(ADDR2LINE) // FIXME: This code could be greatly improved/simplified with // http://cairo.sourcearchive.com/documentation/1.9.4/backtrace-symbols_8c-source.html - if (bt.size() == 0) + if (bt.impl_->frames.size() == 0) return result; if (xbt_binary_name == nullptr) XBT_WARN("XBT not initialized, the backtrace will not be resolved."); - char** backtrace_syms = backtrace_symbols(bt.data(), bt.size()); + char** backtrace_syms = backtrace_symbols(bt.impl_->frames.data(), bt.impl_->frames.size()); std::string binary_name = get_binary_path(); if (binary_name.empty()) { - for (std::size_t i = 1; i < bt.size(); i++) // the first one is not interesting - result.push_back(simgrid::xbt::string_printf("%p", bt[i])); + for (std::size_t i = 1; i < bt.impl_->frames.size(); i++) // the first one is not interesting + result.push_back(simgrid::xbt::string_printf("%p", bt.impl_->frames[i])); return result; } // Create the system command for add2line: std::ostringstream stream; stream << ADDR2LINE << " -f -e " << binary_name << ' '; - std::vector addrs(bt.size()); - for (std::size_t i = 1; i < bt.size(); i++) { // the first one is not interesting + std::vector addrs(bt.impl_->frames.size()); + for (std::size_t i = 1; i < bt.impl_->frames.size(); i++) { // the first one is not interesting /* retrieve this address */ XBT_DEBUG("Retrieving address number %zu from '%s'", i, backtrace_syms[i]); char buff[256]; @@ -199,7 +217,7 @@ std::vector resolve_backtrace(const Backtrace& bt) /* To read the output of addr2line */ char line_func[1024]; char line_pos[1024]; - for (std::size_t i = 1; i < bt.size(); i++) { // The first one is not interesting + for (std::size_t i = 1; i < bt.impl_->frames.size(); i++) { // The first one is not interesting XBT_DEBUG("Looking for symbol %zu, addr = '%s'", i, addrs[i].c_str()); if (fgets(line_func, 1024, pipe)) { line_func[strlen(line_func) - 1] = '\0'; @@ -217,7 +235,7 @@ std::vector resolve_backtrace(const Backtrace& bt) if (strcmp("??", line_func) != 0) { auto name = simgrid::xbt::demangle(line_func); XBT_DEBUG("Found static symbol %s at %s", name.get(), line_pos); - result.push_back(simgrid::xbt::string_printf("%s at %s, %p", name.get(), line_pos, bt[i])); + result.push_back(simgrid::xbt::string_printf("%s at %s, %p", name.get(), line_pos, bt.impl_->frames[i])); } else { /* Damn. The symbol is in a dynamic library. Let's get wild */ @@ -313,7 +331,7 @@ std::vector resolve_backtrace(const Backtrace& bt) if (strcmp("??", line_func)) { auto name = simgrid::xbt::demangle(line_func); XBT_DEBUG("Found dynamic symbol %s at %s", name.get(), line_pos); - result.push_back(simgrid::xbt::string_printf("%s at %s, %p", name.get(), line_pos, bt[i])); + result.push_back(simgrid::xbt::string_printf("%s at %s, %p", name.get(), line_pos, bt.impl_->frames[i])); } else { /* damn, nothing to do here. Let's print the raw address */ XBT_DEBUG("Dynamic symbol not found. Raw address = %s", backtrace_syms[i]); diff --git a/src/xbt/exception.cpp b/src/xbt/exception.cpp index 17c985042a..fe4c6b58a0 100644 --- a/src/xbt/exception.cpp +++ b/src/xbt/exception.cpp @@ -21,7 +21,7 @@ xbt_ex::~xbt_ex() = default; void _xbt_throw(char* message, xbt_errcat_t errcat, int value, const char* file, int line, const char* func) { - xbt_ex e(simgrid::xbt::ThrowPoint(file, line, func, simgrid::xbt::backtrace(), xbt_procname(), xbt_getpid()), + xbt_ex e(simgrid::xbt::ThrowPoint(file, line, func, simgrid::xbt::Backtrace(), xbt_procname(), xbt_getpid()), message); xbt_free(message); e.category = errcat; @@ -141,7 +141,7 @@ static void handler() // Get the current backtrace and exception auto e = std::current_exception(); - simgrid::xbt::Backtrace bt = simgrid::xbt::backtrace(); + simgrid::xbt::Backtrace bt = simgrid::xbt::Backtrace(); try { std::rethrow_exception(e); } -- 2.20.1