diff options
-rw-r--r-- | build2/b.cxx | 24 | ||||
-rw-r--r-- | build2/buildfile | 7 | ||||
-rw-r--r-- | build2/scheduler.cxx | 6 | ||||
-rw-r--r-- | build2/scheduler.hxx | 2 |
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))...); } |