From 1d805807e9932923d2e695ca49a49c190f38ddcc Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Tue, 8 Nov 2022 17:13:36 +0100 Subject: [PATCH] Allow setting a default debug action Helps avoiding user interaction when running a batch of unit tests. --- src/util/debug.cpp | 67 +++++++++++++++++++++++++++++++++------------- src/util/debug.h | 11 ++++++++ 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 4380a0548..2dd12ef21 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -75,32 +75,62 @@ bool is_debug_enabled(const char * tag) { return g_enabled_debug_tags->contains(tag); } +atomic g_default_debug_action(debug_action::ask); + +debug_action get_default_debug_action() { + return g_default_debug_action; +} + +void set_default_debug_action(debug_action a) { + g_default_debug_action = a; +} + +debug_action ask_debug_action(std::istream& in) { + std::cerr << "(C)ontinue, (A)bort, (S)top, (T)hrow exception, Invoke (G)DB\n"; + char result; + bool ok = bool(in >> result); + if (!ok) + exit(ERR_INTERNAL_FATAL); // happens if std::cin is eof or unattached. + switch(result) { + case 'C': + case 'c': + return debug_action::cont; + case 'A': + case 'a': + return debug_action::abort; + case 'S': + case 's': + return debug_action::stop; + case 't': + case 'T': + return debug_action::throw_exception; + case 'G': + case 'g': + return debug_action::invoke_debugger; + default: + std::cerr << "INVALID COMMAND\n"; + return debug_action::ask; + } +} + #if !defined(_WINDOWS) && !defined(NO_Z3_DEBUGGER) void invoke_gdb() { char buffer[1024]; - int * x = nullptr; + int *x = nullptr; + debug_action a = get_default_debug_action(); for (;;) { - std::cerr << "(C)ontinue, (A)bort, (S)top, (T)hrow exception, Invoke (G)DB\n"; - char result; - bool ok = bool(std::cin >> result); - if (!ok) exit(ERR_INTERNAL_FATAL); // happens if std::cin is eof or unattached. - switch(result) { - case 'C': - case 'c': + switch (a) { + case debug_action::cont: return; - case 'A': - case 'a': + case debug_action::abort: exit(1); - case 'S': - case 's': + case debug_action::stop: // force seg fault... *x = 0; return; - case 't': - case 'T': + case debug_action::throw_exception: throw default_exception("assertion violation"); - case 'G': - case 'g': + case debug_action::invoke_debugger: sprintf(buffer, "gdb -nw /proc/%d/exe %d", getpid(), getpid()); std::cerr << "invoking GDB...\n"; if (system(buffer) == 0) { @@ -109,12 +139,13 @@ void invoke_gdb() { else { std::cerr << "error starting GDB...\n"; // forcing seg fault. - int * x = nullptr; + int *x = nullptr; *x = 0; } return; + case debug_action::ask: default: - std::cerr << "INVALID COMMAND\n"; + a = ask_debug_action(std::cin); } } } diff --git a/src/util/debug.h b/src/util/debug.h index cd4634ae2..5f092b181 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -24,6 +24,17 @@ Revision History: void enable_assertions(bool f); bool assertions_enabled(); +enum class debug_action { + ask, + cont, + abort, + stop, + throw_exception, + invoke_debugger, +}; +debug_action get_default_debug_action(); +void set_default_debug_action(debug_action a); + #include "util/error_codes.h" #include "util/warning.h"