Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Use addr2line as a fallback for stacktraces when backtrace is not available
[simgrid.git] / src / xbt / backtrace.cpp
1 /* Copyright (c) 2005-2019. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "src/internal_config.h"
7
8 #include "simgrid/simix.h" /* SIMIX_process_self_get_name() */
9 #include <xbt/backtrace.hpp>
10 #include <xbt/log.h>
11 #include <xbt/string.hpp>
12 #include <xbt/sysdep.h>
13
14 #include <cstddef>
15 #include <cstdlib>
16 #include <cstring>
17 #include <fstream>
18 #include <sstream>
19 #include <sys/stat.h>
20 #include <vector>
21
22 #include <boost/algorithm/string.hpp>
23
24 // Try to detect and use the C++ itanium ABI for name demangling:
25 #ifdef __GXX_ABI_VERSION
26 #include <cxxabi.h>
27 #endif
28
29 #if HAVE_BOOST_STACKTRACE_BACKTRACE
30 #define BOOST_STACKTRACE_USE_BACKTRACE
31 #include <boost/stacktrace.hpp>
32 #elif HAVE_BOOST_STACKTRACE_ADDR2LINE
33 #define BOOST_STACKTRACE_USE_ADDR2LINE
34 #include <boost/stacktrace.hpp>
35 #endif
36
37 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_backtrace, xbt, "Backtrace");
38
39 /** @brief show the backtrace of the current point (lovely while debugging) */
40 void xbt_backtrace_display_current()
41 {
42   simgrid::xbt::Backtrace().display();
43 }
44
45 namespace simgrid {
46 namespace xbt {
47
48 std::unique_ptr<char, std::function<void(char*)>> demangle(const char* name)
49 {
50 #ifdef __GXX_ABI_VERSION
51   int status;
52   std::unique_ptr<char, std::function<void(char*)>> res(abi::__cxa_demangle(name, nullptr, nullptr, &status),
53                                                         &std::free);
54   if (res != nullptr)
55     return res;
56   // We did not manage to resolve this. Probably because this is not a mangled symbol:
57 #endif
58   // Return the symbol:
59   return std::unique_ptr<char, std::function<void(char*)>>(xbt_strdup(name), &xbt_free_f);
60 }
61
62 class BacktraceImpl {
63   short refcount_ = 1;
64
65 public:
66   void ref() { refcount_++; }
67   bool unref()
68   {
69     refcount_--;
70     if (refcount_ == 0) {
71       delete this;
72       return true;
73     } else {
74       return false;
75     }
76   }
77 #if HAVE_BOOST_STACKTRACE_BACKTRACE || HAVE_BOOST_STACKTRACE_ADDR2LINE
78   boost::stacktrace::stacktrace st;
79 #endif
80 };
81
82 Backtrace::Backtrace()
83 {
84 #if HAVE_BOOST_STACKTRACE_BACKTRACE || HAVE_BOOST_STACKTRACE_ADDR2LINE
85   impl_     = new BacktraceImpl();
86   impl_->st = boost::stacktrace::stacktrace();
87 #endif
88 }
89 Backtrace::Backtrace(const Backtrace& bt)
90 {
91   impl_ = bt.impl_;
92   if (impl_)
93     impl_->ref();
94 }
95
96 Backtrace::Backtrace(Backtrace&& bt)
97 {
98   impl_    = bt.impl_;
99   bt.impl_ = nullptr;
100 }
101
102 Backtrace& Backtrace::operator=(const Backtrace& rhs)
103 {
104   if (this != &rhs) {
105     if (impl_)
106       impl_->unref();
107     impl_ = rhs.impl_;
108     if (impl_)
109       impl_->ref();
110   }
111   return *this;
112 }
113
114 Backtrace& Backtrace::operator=(Backtrace&& rhs)
115 {
116   if (this != &rhs) {
117     if (impl_)
118       impl_->unref();
119     impl_     = rhs.impl_;
120     rhs.impl_ = nullptr;
121   }
122   return *this;
123 }
124
125 Backtrace::~Backtrace()
126 {
127   if (impl_)
128     impl_->unref();
129 }
130
131 std::string const Backtrace::resolve() const
132 {
133   std::string result("");
134
135 #if HAVE_BOOST_STACKTRACE_BACKTRACE || HAVE_BOOST_STACKTRACE_ADDR2LINE
136   std::stringstream ss;
137   ss << impl_->st;
138   result.append(ss.str());
139 #endif
140   return result;
141 }
142
143 void Backtrace::display() const
144 {
145   std::string backtrace = resolve();
146   if (backtrace.empty()) {
147     fprintf(stderr, "(backtrace not set -- did you install Boost.Stacktrace?)\n");
148     return;
149   }
150   fprintf(stderr, "Backtrace (displayed in actor %s):\n", SIMIX_process_self_get_name());
151   std::fprintf(stderr, "%s\n", backtrace.c_str());
152 }
153
154 } // namespace xbt
155 } // namespace simgrid