diff options
author | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-02 01:55:06 +0000 |
---|---|---|
committer | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-02 01:55:06 +0000 |
commit | b07fc5114ccce26011ec2312eee3397134739f9a (patch) | |
tree | 1570e3652386e2b314e1be8067e7e44a00f49b75 /breakpad/linux/exception_handler.cc | |
parent | 74f34b094a7b21f0c057f493abee5db30b988592 (diff) | |
download | chromium_src-b07fc5114ccce26011ec2312eee3397134739f9a.zip chromium_src-b07fc5114ccce26011ec2312eee3397134739f9a.tar.gz chromium_src-b07fc5114ccce26011ec2312eee3397134739f9a.tar.bz2 |
Linux: Use upstream google-breakpad instead of our fork.
BUG=28276
TEST=dump_syms works with ToT Chrome.
Review URL: http://codereview.chromium.org/414049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33534 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'breakpad/linux/exception_handler.cc')
-rw-r--r-- | breakpad/linux/exception_handler.cc | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/breakpad/linux/exception_handler.cc b/breakpad/linux/exception_handler.cc deleted file mode 100644 index 4a4955e..0000000 --- a/breakpad/linux/exception_handler.cc +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. -// -// 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 Inc. 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. - -#include "breakpad/linux/exception_handler.h" - -#include <errno.h> -#include <fcntl.h> -#include <linux/limits.h> -#include <sched.h> -#include <signal.h> -#include <stdio.h> -#include <sys/mman.h> -#include <sys/signal.h> -#include <sys/syscall.h> -#include <sys/ucontext.h> -#include <sys/user.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "breakpad/linux/linux_libc_support.h" -#include "breakpad/linux/linux_syscall_support.h" -#include "breakpad/linux/memory.h" -#include "breakpad/linux/minidump_writer.h" -#include "common/linux/guid_creator.h" - -// A wrapper for the tgkill syscall: send a signal to a specific thread. -static int tgkill(pid_t tgid, pid_t tid, int sig) { - syscall(__NR_tgkill, tgid, tid, sig); -} - -namespace google_breakpad { - -// 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. -static const int kExceptionSignals[] = { - SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1 -}; - -// We can stack multiple exception handlers. In that case, this is the global -// which holds the stack. -std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; -unsigned ExceptionHandler::handler_stack_index_ = 0; -pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = - PTHREAD_MUTEX_INITIALIZER; - -// Runs before crashing: normal context. -ExceptionHandler::ExceptionHandler(const std::string &dump_path, - FilterCallback filter, - MinidumpCallback callback, - void *callback_context, - bool install_handler) - : filter_(filter), - callback_(callback), - callback_context_(callback_context), - dump_path_(), - handler_installed_(install_handler), - crash_handler_(NULL) { - set_dump_path(dump_path); - - if (install_handler) { - InstallHandlers(); - - pthread_mutex_lock(&handler_stack_mutex_); - if (handler_stack_ == NULL) - handler_stack_ = new std::vector<ExceptionHandler *>; - handler_stack_->push_back(this); - pthread_mutex_unlock(&handler_stack_mutex_); - } -} - -// Runs before crashing: normal context. -ExceptionHandler::~ExceptionHandler() { - UninstallHandlers(); -} - -// Runs before crashing: normal context. -bool ExceptionHandler::InstallHandlers() { - // We run the signal handlers on an alternative stack because we might have - // crashed because of a stack overflow. - - // We use this value rather than SIGSTKSZ because we would end up overrunning - // such a small stack. - static const unsigned kSigStackSize = 8192; - - signal_stack = malloc(kSigStackSize); - stack_t stack; - memset(&stack, 0, sizeof(stack)); - stack.ss_sp = signal_stack; - stack.ss_size = kSigStackSize; - - if (sigaltstack(&stack, NULL) == -1) - return false; - - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - - // mask all exception signals when we're handling one of them. - for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) - sigaddset(&sa.sa_mask, kExceptionSignals[i]); - - sa.sa_sigaction = SignalHandler; - sa.sa_flags = SA_ONSTACK | SA_SIGINFO; - - for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) { - struct sigaction* old = new struct sigaction; - if (sigaction(kExceptionSignals[i], &sa, old) == -1) - return false; - old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old)); - } -} - -// Runs before crashing: normal context. -void ExceptionHandler::UninstallHandlers() { - for (unsigned i = 0; i < old_handlers_.size(); ++i) { - struct sigaction *action = - reinterpret_cast<struct sigaction*>(old_handlers_[i].second); - sigaction(old_handlers_[i].first, action, NULL); - delete action; - } - - old_handlers_.clear(); -} - -// Runs before crashing: normal context. -void ExceptionHandler::UpdateNextID() { - GUID guid; - char guid_str[kGUIDStringLength + 1]; - if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) { - next_minidump_id_ = guid_str; - next_minidump_id_c_ = next_minidump_id_.c_str(); - - char minidump_path[PATH_MAX]; - snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp", - dump_path_c_, - guid_str); - - next_minidump_path_ = minidump_path; - next_minidump_path_c_ = next_minidump_path_.c_str(); - } -} - -// 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) { - // All the exception signals are blocked at this point. - - pthread_mutex_lock(&handler_stack_mutex_); - - if (!handler_stack_->size()) { - pthread_mutex_unlock(&handler_stack_mutex_); - return; - } - - for (int i = handler_stack_->size() - 1; i >= 0; --i) { - if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) { - // successfully handled: We are in an invalid state since an exception - // signal has been delivered. We don't call the exit handlers because - // they could end up corrupting on-disk state. - break; - } - } - - pthread_mutex_unlock(&handler_stack_mutex_); - - // Terminate ourselves with the same signal so that our parent knows that we - // crashed. The default action for all the signals which we catch is Core, so - // this is the end of us. - signal(sig, SIG_DFL); - tgkill(getpid(), sys_gettid(), sig); - - // not reached. -} - -struct ThreadArgument { - pid_t pid; // the crashing process - ExceptionHandler* handler; - const void* context; // a CrashContext structure - size_t context_size; -}; - -// 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) { - const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg); - return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context, - thread_arg->context_size) == false; -} - -// 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) { - if (filter_ && !filter_(callback_context_)) - return false; - - // Allow ourselves to be dumped. - sys_prctl(PR_SET_DUMPABLE, 1); - - CrashContext context; - memcpy(&context.siginfo, info, sizeof(siginfo_t)); - memcpy(&context.context, uc, sizeof(struct ucontext)); - memcpy(&context.float_state, ((struct ucontext *)uc)->uc_mcontext.fpregs, - sizeof(context.float_state)); - context.tid = sys_gettid(); - - if (crash_handler_ && crash_handler_(&context, sizeof(context), - callback_context_)) - return true; - - static const unsigned kChildStackSize = 8000; - PageAllocator allocator; - uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize); - if (!stack) - return false; - // clone() needs the top-most address. (scrub just to be safe) - stack += kChildStackSize; - my_memset(stack - 16, 0, 16); - - ThreadArgument thread_arg; - thread_arg.handler = this; - thread_arg.pid = getpid(); - thread_arg.context = &context; - thread_arg.context_size = sizeof(context); - - const pid_t child = sys_clone( - ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, - &thread_arg, NULL, NULL, NULL); - int r, status; - do { - r = sys_waitpid(child, &status, __WALL); - } while (r == -1 && errno == EINTR); - - if (r == -1) { - static const char msg[] = "ExceptionHandler::HandleSignal: waitpid failed:"; - sys_write(2, msg, sizeof(msg) - 1); - sys_write(2, strerror(errno), strlen(strerror(errno))); - sys_write(2, "\n", 1); - } - - bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0; - - if (callback_) - success = callback_(dump_path_c_, next_minidump_id_c_, - callback_context_, success); - - return success; -} - -// 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) { - return google_breakpad::WriteMinidump( - next_minidump_path_c_, crashing_process, context, context_size); -} - -} // namespace google_breakpad |