From daa53da594d04925d10e792df804110d6a7bf2a2 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Fri, 4 Dec 2015 00:12:58 +0000 Subject: sim: Add support for generating back traces on errors Add functionality to generate a back trace if gem5 crashes (SIGABRT or SIGSEGV). The current implementation uses glibc's stack traversal support if available and stubs out the call to print_backtrace() otherwise. --- SConstruct | 17 ++++++++ src/base/atomicio.hh | 24 +++++++++++ src/sim/SConscript | 1 + src/sim/backtrace.hh | 50 ++++++++++++++++++++++ src/sim/backtrace_glibc.cc | 66 +++++++++++++++++++++++++++++ src/sim/backtrace_none.cc | 45 ++++++++++++++++++++ src/sim/init_signals.cc | 102 ++++++++++++++++++++++++++++++++++++--------- 7 files changed, 286 insertions(+), 19 deletions(-) create mode 100644 src/sim/backtrace.hh create mode 100644 src/sim/backtrace_glibc.cc create mode 100644 src/sim/backtrace_none.cc diff --git a/SConstruct b/SConstruct index 45cfb0b89..b8db543b8 100755 --- a/SConstruct +++ b/SConstruct @@ -983,6 +983,21 @@ if not GetOption('without_tcmalloc'): "installing tcmalloc (libgoogle-perftools-dev package "\ "on Ubuntu or RedHat)." + termcap.Normal + +# Detect back trace implementations. The last implementation in the +# list will be used by default. +backtrace_impls = [ "none" ] + +if conf.CheckLibWithHeader(None, 'execinfo.h', 'C', + 'backtrace_symbols_fd((void*)0, 0, 0);'): + backtrace_impls.append("glibc") + +if backtrace_impls[-1] == "none": + default_backtrace_impl = "none" + print termcap.Yellow + termcap.Bold + \ + "No suitable back trace implementation found." + \ + termcap.Normal + if not have_posix_clock: print "Can't find library for POSIX clocks." @@ -1131,6 +1146,8 @@ sticky_vars.AddVariables( BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm), EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None', all_protocols), + EnumVariable('BACKTRACE_IMPL', 'Post-mortem dump implementation', + backtrace_impls[-1], backtrace_impls) ) # These variables get exported to #defines in config/*.hh (see src/SConscript). diff --git a/src/base/atomicio.hh b/src/base/atomicio.hh index 5e703f315..bfd1e35e5 100644 --- a/src/base/atomicio.hh +++ b/src/base/atomicio.hh @@ -41,4 +41,28 @@ ssize_t atomic_read(int fd, void *s, size_t n); ssize_t atomic_write(int fd, const void *s, size_t n); +/** + * Statically allocate a string and write it to a file descriptor. + * + * @warning The return value will from atomic_write will be ignored + * which means that errors will be ignored. This is normally fine as + * this macro is intended to be used in fatal signal handlers where + * error handling might not be feasible. + */ +#define STATIC_MSG(fd, m) \ + do { \ + static const char msg[] = m; \ + atomic_write(fd, msg, sizeof(msg) - 1); \ + } while(0) + +/** + * Statically allocate a string and write it to STDERR. + * + * @warning The return value will from atomic_write will be ignored + * which means that errors will be ignored. This is normally fine as + * this macro is intended to be used in fatal signal handlers where + * error handling might not be feasible. + */ +#define STATIC_ERR(m) STATIC_MSG(STDERR_FILENO, m) + #endif // __BASE_ATOMICIO_HH__ diff --git a/src/sim/SConscript b/src/sim/SConscript index 204bfca3b..93fc30fbc 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -41,6 +41,7 @@ SimObject('SubSystem.py') Source('arguments.cc') Source('async.cc') +Source('backtrace_%s.cc' % env['BACKTRACE_IMPL']) Source('core.cc') Source('tags.cc') Source('cxx_config.cc') diff --git a/src/sim/backtrace.hh b/src/sim/backtrace.hh new file mode 100644 index 000000000..9d538727f --- /dev/null +++ b/src/sim/backtrace.hh @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ +#ifndef __SIM_BACKTRACE_HH__ +#define __SIM_BACKTRACE_HH__ + +/** + * Print a gem5 post-mortem report + * + * @note This is usually called from a signal handler. Implementations + * must support this use case. + */ +void print_backtrace(); + +#endif // __SIM_BACKTRACE_HH__ diff --git a/src/sim/backtrace_glibc.cc b/src/sim/backtrace_glibc.cc new file mode 100644 index 000000000..93badc134 --- /dev/null +++ b/src/sim/backtrace_glibc.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#include "sim/backtrace.hh" + +#include +#include + +#include "base/atomicio.hh" + +#define SAFE_MSG(m) \ + do { \ + static const char msg[] = m; \ + atomic_write(STDERR_FILENO, msg, sizeof(msg) - 1); \ + } while(0) + +void +print_backtrace() +{ + void *buffer[32]; + int size; + + size = backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); + + STATIC_ERR("--- BEGIN LIBC BACKTRACE ---\n"); + backtrace_symbols_fd(buffer, size, STDERR_FILENO); + if (size == sizeof(buffer)) + STATIC_ERR("Warning: Backtrace may have been truncated.\n"); + STATIC_ERR("--- END LIBC BACKTRACE ---\n"); +} diff --git a/src/sim/backtrace_none.cc b/src/sim/backtrace_none.cc new file mode 100644 index 000000000..5c833d2aa --- /dev/null +++ b/src/sim/backtrace_none.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#include "sim/backtrace.hh" + +void +print_backtrace() +{ +} diff --git a/src/sim/init_signals.cc b/src/sim/init_signals.cc index 7efbaea61..6fe196a67 100644 --- a/src/sim/init_signals.cc +++ b/src/sim/init_signals.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 ARM Limited + * Copyright (c) 2012, 2015 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -41,18 +41,67 @@ * Authors: Nathan Binkert */ +#include "sim/init_signals.hh" + +#include +#include + #include #include #include +#include "base/atomicio.hh" #include "base/cprintf.hh" #include "sim/async.hh" +#include "sim/backtrace.hh" #include "sim/core.hh" #include "sim/eventq.hh" -#include "sim/init_signals.hh" using namespace std; +// Use an separate stack for fatal signal handlers +static uint8_t fatalSigStack[2 * SIGSTKSZ]; + +static bool +setupAltStack() +{ + stack_t stack; + stack.ss_sp = fatalSigStack; + stack.ss_size = sizeof(fatalSigStack); + stack.ss_flags = 0; + + return sigaltstack(&stack, NULL) == 0; +} + +static void +installSignalHandler(int signal, void (*handler)(int sigtype), + int flags = SA_RESTART) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = handler; + sa.sa_flags = flags; + + if (sigaction(signal, &sa, NULL) == -1) + panic("Failed to setup handler for signal %i\n", signal); +} + +static void +raiseFatalSignal(int signo) +{ + // The signal handler should have been reset and unmasked (it was + // registered with SA_RESETHAND | SA_NODEFER), just raise the + // signal again to invoke the default handler. + pthread_kill(pthread_self(), signo); + + // Something is really wrong if the process is alive at this + // point, manually try to exit it. + STATIC_ERR("Failed to execute default signal handler!\n"); + _exit(127); +} + /// Stats signal handler. void dumpStatsHandler(int sigtype) @@ -87,7 +136,25 @@ exitNowHandler(int sigtype) void abortHandler(int sigtype) { - ccprintf(cerr, "Program aborted at tick %llu\n", curTick()); + const EventQueue *const eq(curEventQueue()); + if (eq) { + ccprintf(cerr, "Program aborted at tick %llu\n", eq->getCurTick()); + } else { + STATIC_ERR("Program aborted\n\n"); + } + + print_backtrace(); + raiseFatalSignal(sigtype); +} + +/// Segmentation fault signal handler. +static void +segvHandler(int sigtype) +{ + STATIC_ERR("gem5 has encountered a segmentation fault!\n\n"); + + print_backtrace(); + raiseFatalSignal(SIGSEGV); } // Handle SIGIO @@ -100,20 +167,6 @@ ioHandler(int sigtype) getEventQueue(0)->wakeup(); } -static void -installSignalHandler(int signal, void (*handler)(int sigtype)) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_handler = handler; - sa.sa_flags = SA_RESTART; - - if (sigaction(signal, &sa, NULL) == -1) - panic("Failed to setup handler for signal %i\n", signal); -} - /* * M5 can do several special things when various signals are sent. * None are mandatory. @@ -137,8 +190,19 @@ initSignals() // Exit cleanly on Interrupt (Ctrl-C) installSignalHandler(SIGINT, exitNowHandler); - // Print out cycle number on abort - installSignalHandler(SIGABRT, abortHandler); + // Print the current cycle number and a backtrace on abort. Make + // sure the signal is unmasked and the handler reset when a signal + // is delivered to be able to invoke the default handler. + installSignalHandler(SIGABRT, abortHandler, SA_RESETHAND | SA_NODEFER); + + // Setup a SIGSEGV handler with a private stack + if (setupAltStack()) { + installSignalHandler(SIGSEGV, segvHandler, + SA_RESETHAND | SA_NODEFER | SA_ONSTACK); + } else { + warn("Failed to setup stack for SIGSEGV handler, " + "using default signal handler.\n"); + } // Install a SIGIO handler to handle asynchronous file IO. See the // PollQueue class. -- cgit v1.2.3