aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/b.cxx24
-rw-r--r--build2/buildfile7
-rw-r--r--build2/scheduler.cxx6
-rw-r--r--build2/scheduler.hxx2
4 files changed, 35 insertions, 4 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index 882b469..022df9d 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -13,12 +13,14 @@
#endif
#include <sstream>
-#include <cstring> // strcmp(), strchr()
+#include <cstring> // strcmp(), strchr()
#include <typeinfo>
-#include <iostream> // cout
+#include <iostream> // cout
+#include <exception> // set_terminate(), terminate_handler
#include <libbutl/pager.mxx>
-#include <libbutl/fdstream.mxx> // stderr_fd(), fdterm()
+#include <libbutl/fdstream.mxx> // stderr_fd(), fdterm()
+#include <libbutl/backtrace.mxx> // backtrace()
#include <build2/types.hxx>
#include <build2/utility.hxx>
@@ -131,9 +133,25 @@ namespace build2
}
}
+// Print backtrace if terminating due to an unhandled exception. Note that
+// custom_terminate is non-static and not a lambda to reduce the noise.
+//
+static terminate_handler default_terminate;
+
+void
+custom_terminate ()
+{
+ *diag_stream << backtrace ();
+
+ if (default_terminate != nullptr)
+ default_terminate ();
+}
+
int build2::
main (int argc, char* argv[])
{
+ default_terminate = set_terminate (custom_terminate);
+
tracer trace ("main");
int r (0);
diff --git a/build2/buildfile b/build2/buildfile
index bf3f10b..ba8f25c 100644
--- a/build2/buildfile
+++ b/build2/buildfile
@@ -51,7 +51,14 @@ if ($cxx.target == $build.host)
}
if ($cxx.target.class != "windows")
+{
+ # Make sure backtrace includes function names.
+ #
+ if ($cxx.target.class == 'linux')
+ cxx.loptions += -rdynamic
+
cxx.libs += -lpthread
+}
else
{
# Adjust stack size (affects all threads).
diff --git a/build2/scheduler.cxx b/build2/scheduler.cxx
index 790f2f6..ad3a640 100644
--- a/build2/scheduler.cxx
+++ b/build2/scheduler.cxx
@@ -588,6 +588,12 @@ namespace build2
// inherit the main thread's stack size (since the first helper is always
// created by the main thread).
//
+ // Note also the interaction with our backtrace functionality: in order to
+ // get the complete stack trace we let unhandled exceptions escape the
+ // thread function expecting the runtime to still call std::terminate. In
+ // particular, having a noexcept function anywhere on the exception's path
+ // causes the stack trace to be truncated, at least on Linux.
+ //
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
#ifndef BUILD2_DEFAULT_STACK_SIZE
diff --git a/build2/scheduler.hxx b/build2/scheduler.hxx
index cd3693b..3aa1dc5 100644
--- a/build2/scheduler.hxx
+++ b/build2/scheduler.hxx
@@ -370,7 +370,7 @@ namespace build2
template <size_t... i>
void
- thunk (std::index_sequence<i...>) noexcept
+ thunk (std::index_sequence<i...>)
{
move (func) (std::get<i> (move (args))...);
}