/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2010-2019 Danny Robson */ #include "./system.hpp" #include "./assert.hpp" #include "./debugger.hpp" #include "./except.hpp" #include "./crash.hpp" #include "../backtrace.hpp" #include "../log.hpp" #include //////////////////////////////////////////////////////////////////////////////// static std::terminate_handler old_handler = nullptr; //----------------------------------------------------------------------------- static void abort_with_trace (void) { // We used to trigger a breakpoint so that our debugger didn't just let the // child terminate (ie, the behaviour of CLion/Win32/GDB). // // But this might silently terminate the program instead of allowing us the // chance to dump a backtrace depending on the precise mechanism for // `breakpoint`; in particular SIGTRAP and SIGINT trigger this. #if 0 breakpoint (); #endif // If we're here because of an exception we may as well rethrow and hope // that the system will print exception data during the abort process. // // But we can at least try to print anything derived from std::exception // (which is a likely guess) before we self-destruct. if (auto ptr = std::current_exception (); ptr) { try { std::rethrow_exception (ptr); } catch (std::exception const &x) { LOG_EMERGENCY ("unhandled exception: {}\n{}", x.what (), ::cruft::backtrace {}); } catch (cruft::error const &x) { LOG_EMERGENCY ("unhandled exception: {}\n{}", x, ::cruft::backtrace {}); } catch (...) { LOG_EMERGENCY ("unhandled exception\n{}", ::cruft::backtrace {}); } } else { LOG_EMERGENCY ("aborting: {}", ::cruft::backtrace {}); } old_handler (); } /////////////////////////////////////////////////////////////////////////////// void cruft::debug::init (void) { init_crash_handler (); old_handler = std::set_terminate (abort_with_trace); CHECK_NEQ ( reinterpret_cast (old_handler), reinterpret_cast (abort_with_trace) ); if (!debug_enabled && !getenv ("DEBUG")) return; LOG_DEBUG ("setting debug environment"); enable_fpe (); force_console (); prepare_debugger (); if (getenv ("DEBUG_WAIT")) await_debugger (); }