]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/boost/stacktrace/detail/libbacktrace_impls.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / stacktrace / detail / libbacktrace_impls.hpp
index 121c41bffa3ba7b1faebd324738d75b9065b2a32..753234a5453b75d30825b1d9fe0e772d446037de 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright Antony Polukhin, 2016-2017.
+// Copyright Antony Polukhin, 2016-2019.
 //
 // Distributed under the Boost Software License, Version 1.0. (See
 // accompanying file LICENSE_1_0.txt or copy at
 #endif
 
 #include <boost/stacktrace/detail/to_hex_array.hpp>
+#include <boost/stacktrace/detail/to_dec_array.hpp>
 #include <boost/stacktrace/detail/location_from_symbol.hpp>
 #include <boost/core/demangle.hpp>
-#include <boost/lexical_cast.hpp>
 
-#include <backtrace.h>
+#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
+#   include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
+#else
+#   include <backtrace.h>
+#endif
 
 namespace boost { namespace stacktrace { namespace detail {
 
@@ -28,6 +32,18 @@ struct pc_data {
     std::size_t line;
 };
 
+inline void libbacktrace_syminfo_callback(void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
+    pc_data& d = *static_cast<pc_data*>(data);
+    if (d.function && symname) {
+        *d.function = symname;
+    }
+}
+
+// Old versions of libbacktrace have different signature for the callback
+inline void libbacktrace_syminfo_callback(void *data, uintptr_t pc, const char *symname, uintptr_t symval) {
+    boost::stacktrace::detail::libbacktrace_syminfo_callback(data, pc, symname, symval, 0);
+}
+
 inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
     pc_data& d = *static_cast<pc_data*>(data);
     if (d.filename && filename) {
@@ -44,30 +60,54 @@ inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int
     // Do nothing, just return.
 }
 
+// Not async-signal-safe, so this method is not called from async-safe functions.
+//
+// This function is not async signal safe because:
+// * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
+// * No guarantees on `backtrace_create_state` function.
+//
+// Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
+// That's why we provide a `prog_location` here.
+BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
+    // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
 
-inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
-    // Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
-    // That's why we provide a `prog_location` here.
-    return ::backtrace_create_state(
-        prog_location.name(), 0 /*thread-safe*/, boost::stacktrace::detail::libbacktrace_error_callback, 0
-    );
-
-    // TODO: this does not seem to work well when this function is in .so:
-    // Not async-signal-safe, so this method is not called from async-safe functions.
+    // TODO: The most obvious solution:
     //
-    // This function is not async signal safe because:
-    // * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
-    // * No guarantees on `backtrace_create_state` function.
+    //static ::backtrace_state* state = ::backtrace_create_state(
+    //    prog_location.name(),
+    //    1, // allow safe concurrent usage of the same state
+    //    boost::stacktrace::detail::libbacktrace_error_callback,
+    //    0 // pointer to data that will be passed to callback
+    //);
+    //
+    //
+    // Unfortunately, that solution segfaults when `construct_state()` function is in .so file
+    // and multiple threads concurrently work with state.
 
-    // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
 
-    /*  
-    static ::backtrace_state* state = ::backtrace_create_state(
-        0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
-    );
+#ifndef BOOST_HAS_THREADS
+    static
+#else
 
+    // Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
+    // gives a single `state` per thread and that state is not shared between threads in any way.
+
+#   ifndef BOOST_NO_CXX11_THREAD_LOCAL
+    thread_local
+#   elif defined(__GNUC__)
+    static __thread
+#   else
+    /* just a local variable */
+#   endif
+
+#endif
+      ::backtrace_state* state = ::backtrace_create_state(
+        prog_location.name(),
+        0,
+        boost::stacktrace::detail::libbacktrace_error_callback,
+        0
+    );
     return state;
-    */
 }
 
 struct to_string_using_backtrace {
@@ -86,6 +126,14 @@ struct to_string_using_backtrace {
                 boost::stacktrace::detail::libbacktrace_full_callback,
                 boost::stacktrace::detail::libbacktrace_error_callback,
                 &data
+            ) 
+            ||
+            ::backtrace_syminfo(
+                state,
+                reinterpret_cast<uintptr_t>(addr),
+                boost::stacktrace::detail::libbacktrace_syminfo_callback,
+                boost::stacktrace::detail::libbacktrace_error_callback,
+                &data
             );
         }
         line = data.line;
@@ -99,7 +147,7 @@ struct to_string_using_backtrace {
         res += " at ";
         res += filename;
         res += ':';
-        res += boost::lexical_cast<boost::array<char, 40> >(line).data();
+        res += boost::stacktrace::detail::to_dec_array(line).data();
         return true;
     }
 
@@ -125,6 +173,14 @@ inline std::string name_impl(const void* addr) {
             boost::stacktrace::detail::libbacktrace_full_callback,
             boost::stacktrace::detail::libbacktrace_error_callback,
             &data
+        )
+        ||
+        ::backtrace_syminfo(
+            state,
+            reinterpret_cast<uintptr_t>(addr),
+            boost::stacktrace::detail::libbacktrace_syminfo_callback,
+            boost::stacktrace::detail::libbacktrace_error_callback,
+            &data
         );
     }
     if (!res.empty()) {
@@ -139,6 +195,10 @@ inline std::string name_impl(const void* addr) {
 std::string frame::source_file() const {
     std::string res;
 
+    if (!addr_) {
+        return res;
+    }
+
     boost::stacktrace::detail::program_location prog_location;
     ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
 
@@ -157,6 +217,10 @@ std::string frame::source_file() const {
 }
 
 std::size_t frame::source_line() const {
+    if (!addr_) {
+        return 0;
+    }
+
     boost::stacktrace::detail::program_location prog_location;
     ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);