// Copyright 2010 Google LLC // // 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 Google LLC 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. // The ExceptionHandler object installs signal handlers for a number of // signals. We rely on the signal handler running on the thread which crashed // in order to identify it. This is true of the synchronous signals (SEGV etc), // but not true of ABRT. Thus, if you send ABRT to yourself in a program which // uses ExceptionHandler, you need to use tgkill to direct it to the current // thread. // // The signal flow looks like this: // // SignalHandler (uses a global stack of ExceptionHandler objects to find // | one to handle the signal. If the first rejects it, try // | the second etc...) // V // HandleSignal ----------------------------| (clones a new process which // | | shares an address space with // (wait for cloned | the crashed process. This // process) | allows us to ptrace the crashed // | | process) // V V // (set signal handler to ThreadEntry (static function to bounce // SIG_DFL and rethrow, | back into the object) // killing the crashed | // process) V // DoDump (writes minidump) // | // V // sys_exit // // This code is a little fragmented. Different functions of the ExceptionHandler // class run in a number of different contexts. Some of them run in a normal // context and are easy to code, others run in a compromised context and the // restrictions at the top of minidump_writer.cc apply: no libc and use the // alternative malloc. Each function should have comment above it detailing the // context which it runs in. #ifdef HAVE_CONFIG_H #include <config.h> // Must come first #endif #include "client/linux/handler/exception_handler.h" #include <errno.h> #include <fcntl.h> #include <linux/limits.h> #include <pthread.h> #include <sched.h> #include <signal.h> #include <stdio.h> #include <sys/mman.h> #include <sys/prctl.h> #include <sys/syscall.h> #include <sys/wait.h> #include <unistd.h> #include <sys/ucontext.h> #include <sys/user.h> #include <ucontext.h> #include <algorithm> #include <utility> #include <vector> #include "common/basictypes.h" #include "common/linux/breakpad_getcontext.h" #include "common/linux/linux_libc_support.h" #include "common/memory_allocator.h" #include "client/linux/log/log.h" #include "client/linux/microdump_writer/microdump_writer.h" #include "client/linux/minidump_writer/linux_dumper.h" #include "client/linux/minidump_writer/minidump_writer.h" #include "common/linux/eintr_wrapper.h" #include "third_party/lss/linux_syscall_support.h" #if defined(__ANDROID__) #include "linux/sched.h" #endif #ifndef PR_SET_PTRACER #define PR_SET_PTRACER … #endif namespace google_breakpad { namespace { // The list of signals which we consider to be crashes. The default action for // all these signals must be Core (see man 7 signal) because we rethrow the // signal after handling it and expect that it'll be fatal. const int kExceptionSignals[] = …; const int kNumHandledSignals = …; struct sigaction old_handlers[kNumHandledSignals]; bool handlers_installed = …; // InstallAlternateStackLocked will store the newly installed stack in new_stack // and (if it exists) the previously installed stack in old_stack. stack_t old_stack; stack_t new_stack; bool stack_installed = …; // Create an alternative stack to run the signal handlers on. This is done since // the signal might have been caused by a stack overflow. // Runs before crashing: normal context. void InstallAlternateStackLocked() { … } // Runs before crashing: normal context. void RestoreAlternateStackLocked() { … } void InstallDefaultHandler(int sig) { … } // The global exception handler stack. This is needed because there may exist // multiple ExceptionHandler instances in a process. Each will have itself // registered in this stack. std::vector<ExceptionHandler*>* g_handler_stack_ = …; pthread_mutex_t g_handler_stack_mutex_ = …; // sizeof(CrashContext) can be too big w.r.t the size of alternatate stack // for SignalHandler(). Keep the crash context as a .bss field. Exception // handlers are serialized by the |g_handler_stack_mutex_| and at most one at a // time can use |g_crash_context_|. ExceptionHandler::CrashContext g_crash_context_; FirstChanceHandler g_first_chance_handler_ = …; } // namespace // Runs before crashing: normal context. ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, FilterCallback filter, MinidumpCallback callback, void* callback_context, bool install_handler, const int server_fd) : … { … } // Runs before crashing: normal context. ExceptionHandler::~ExceptionHandler() { … } // Runs before crashing: normal context. // static bool ExceptionHandler::InstallHandlersLocked() { … } // This function runs in a compromised context: see the top of the file. // Runs on the crashing thread. // static void ExceptionHandler::RestoreHandlersLocked() { … } // void ExceptionHandler::set_crash_handler(HandlerCallback callback) { // crash_handler_ = callback; // } // This function runs in a compromised context: see the top of the file. // Runs on the crashing thread. // static void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { … } struct ThreadArgument { … }; // This is the entry function for the cloned process. We are in a compromised // context here: see the top of the file. // static int ExceptionHandler::ThreadEntry(void* arg) { … } // This function runs in a compromised context: see the top of the file. // Runs on the crashing thread. bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) { … } // This is a public interface to HandleSignal that allows the client to // generate a crash dump. This function may run in a compromised context. bool ExceptionHandler::SimulateSignalDelivery(int sig) { … } // This function may run in a compromised context: see the top of the file. bool ExceptionHandler::GenerateDump(CrashContext* context) { … } // This function runs in a compromised context: see the top of the file. void ExceptionHandler::SendContinueSignalToChild() { … } // This function runs in a compromised context: see the top of the file. // Runs on the cloned process. void ExceptionHandler::WaitForContinueSignal() { … } // This function runs in a compromised context: see the top of the file. // Runs on the cloned process. bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, size_t context_size) { … } // static bool ExceptionHandler::WriteMinidump(const string& dump_path, MinidumpCallback callback, void* callback_context) { … } // In order to making using EBP to calculate the desired value for ESP // a valid operation, ensure that this function is compiled with a // frame pointer using the following attribute. This attribute // is supported on GCC but not on clang. #if defined(__i386__) && defined(__GNUC__) && !defined(__clang__) __attribute__((optimize("no-omit-frame-pointer"))) #endif bool ExceptionHandler::WriteMinidump() { … } void ExceptionHandler::AddMappingInfo(const string& name, const uint8_t identifier[sizeof(MDGUID)], uintptr_t start_address, size_t mapping_size, size_t file_offset) { … } void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { … } void ExceptionHandler::UnregisterAppMemory(void* ptr) { … } // static bool ExceptionHandler::WriteMinidumpForChild(pid_t child, pid_t child_blamed_thread, const string& dump_path, MinidumpCallback callback, void* callback_context) { … } void SetFirstChanceExceptionHandler(FirstChanceHandler callback) { … } } // namespace google_breakpad