1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,656 @@ 1.4 +// Copyright (c) 2010 Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// The ExceptionHandler object installs signal handlers for a number of 1.34 +// signals. We rely on the signal handler running on the thread which crashed 1.35 +// in order to identify it. This is true of the synchronous signals (SEGV etc), 1.36 +// but not true of ABRT. Thus, if you send ABRT to yourself in a program which 1.37 +// uses ExceptionHandler, you need to use tgkill to direct it to the current 1.38 +// thread. 1.39 +// 1.40 +// The signal flow looks like this: 1.41 +// 1.42 +// SignalHandler (uses a global stack of ExceptionHandler objects to find 1.43 +// | one to handle the signal. If the first rejects it, try 1.44 +// | the second etc...) 1.45 +// V 1.46 +// HandleSignal ----------------------------| (clones a new process which 1.47 +// | | shares an address space with 1.48 +// (wait for cloned | the crashed process. This 1.49 +// process) | allows us to ptrace the crashed 1.50 +// | | process) 1.51 +// V V 1.52 +// (set signal handler to ThreadEntry (static function to bounce 1.53 +// SIG_DFL and rethrow, | back into the object) 1.54 +// killing the crashed | 1.55 +// process) V 1.56 +// DoDump (writes minidump) 1.57 +// | 1.58 +// V 1.59 +// sys_exit 1.60 +// 1.61 + 1.62 +// This code is a little fragmented. Different functions of the ExceptionHandler 1.63 +// class run in a number of different contexts. Some of them run in a normal 1.64 +// context and are easy to code, others run in a compromised context and the 1.65 +// restrictions at the top of minidump_writer.cc apply: no libc and use the 1.66 +// alternative malloc. Each function should have comment above it detailing the 1.67 +// context which it runs in. 1.68 + 1.69 +#include "client/linux/handler/exception_handler.h" 1.70 + 1.71 +#include <errno.h> 1.72 +#include <fcntl.h> 1.73 +#include <linux/limits.h> 1.74 +#include <sched.h> 1.75 +#include <signal.h> 1.76 +#include <stdio.h> 1.77 +#include <sys/mman.h> 1.78 +#include <sys/prctl.h> 1.79 +#include <sys/syscall.h> 1.80 +#include <sys/wait.h> 1.81 +#include <unistd.h> 1.82 + 1.83 +#include <sys/signal.h> 1.84 +#include <sys/ucontext.h> 1.85 +#include <sys/user.h> 1.86 +#include <ucontext.h> 1.87 + 1.88 +#include <algorithm> 1.89 +#include <utility> 1.90 +#include <vector> 1.91 + 1.92 +#include "common/linux/linux_libc_support.h" 1.93 +#include "common/memory.h" 1.94 +#include "client/linux/log/log.h" 1.95 +#include "client/linux/minidump_writer/linux_dumper.h" 1.96 +#include "client/linux/minidump_writer/minidump_writer.h" 1.97 +#include "common/linux/eintr_wrapper.h" 1.98 +#include "third_party/lss/linux_syscall_support.h" 1.99 + 1.100 +#include "linux/sched.h" 1.101 + 1.102 +#ifndef PR_SET_PTRACER 1.103 +#define PR_SET_PTRACER 0x59616d61 1.104 +#endif 1.105 + 1.106 +// A wrapper for the tgkill syscall: send a signal to a specific thread. 1.107 +static int tgkill(pid_t tgid, pid_t tid, int sig) { 1.108 + return syscall(__NR_tgkill, tgid, tid, sig); 1.109 + return 0; 1.110 +} 1.111 + 1.112 +namespace google_breakpad { 1.113 + 1.114 +namespace { 1.115 +// The list of signals which we consider to be crashes. The default action for 1.116 +// all these signals must be Core (see man 7 signal) because we rethrow the 1.117 +// signal after handling it and expect that it'll be fatal. 1.118 +const int kExceptionSignals[] = { 1.119 + SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS 1.120 +}; 1.121 +const int kNumHandledSignals = 1.122 + sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]); 1.123 +struct sigaction old_handlers[kNumHandledSignals]; 1.124 +bool handlers_installed = false; 1.125 + 1.126 +// InstallAlternateStackLocked will store the newly installed stack in new_stack 1.127 +// and (if it exists) the previously installed stack in old_stack. 1.128 +stack_t old_stack; 1.129 +stack_t new_stack; 1.130 +bool stack_installed = false; 1.131 + 1.132 +// Create an alternative stack to run the signal handlers on. This is done since 1.133 +// the signal might have been caused by a stack overflow. 1.134 +// Runs before crashing: normal context. 1.135 +void InstallAlternateStackLocked() { 1.136 + if (stack_installed) 1.137 + return; 1.138 + 1.139 + memset(&old_stack, 0, sizeof(old_stack)); 1.140 + memset(&new_stack, 0, sizeof(new_stack)); 1.141 + 1.142 + // SIGSTKSZ may be too small to prevent the signal handlers from overrunning 1.143 + // the alternative stack. Ensure that the size of the alternative stack is 1.144 + // large enough. 1.145 + static const unsigned kSigStackSize = std::max(8192, SIGSTKSZ); 1.146 + 1.147 + // Only set an alternative stack if there isn't already one, or if the current 1.148 + // one is too small. 1.149 + if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp || 1.150 + old_stack.ss_size < kSigStackSize) { 1.151 + new_stack.ss_sp = malloc(kSigStackSize); 1.152 + new_stack.ss_size = kSigStackSize; 1.153 + 1.154 + if (sys_sigaltstack(&new_stack, NULL) == -1) { 1.155 + free(new_stack.ss_sp); 1.156 + return; 1.157 + } 1.158 + stack_installed = true; 1.159 + } 1.160 +} 1.161 + 1.162 +// Runs before crashing: normal context. 1.163 +void RestoreAlternateStackLocked() { 1.164 + if (!stack_installed) 1.165 + return; 1.166 + 1.167 + stack_t current_stack; 1.168 + if (sys_sigaltstack(NULL, ¤t_stack) == -1) 1.169 + return; 1.170 + 1.171 + // Only restore the old_stack if the current alternative stack is the one 1.172 + // installed by the call to InstallAlternateStackLocked. 1.173 + if (current_stack.ss_sp == new_stack.ss_sp) { 1.174 + if (old_stack.ss_sp) { 1.175 + if (sys_sigaltstack(&old_stack, NULL) == -1) 1.176 + return; 1.177 + } else { 1.178 + stack_t disable_stack; 1.179 + disable_stack.ss_flags = SS_DISABLE; 1.180 + if (sys_sigaltstack(&disable_stack, NULL) == -1) 1.181 + return; 1.182 + } 1.183 + } 1.184 + 1.185 + free(new_stack.ss_sp); 1.186 + stack_installed = false; 1.187 +} 1.188 + 1.189 +} // namespace 1.190 + 1.191 +// We can stack multiple exception handlers. In that case, this is the global 1.192 +// which holds the stack. 1.193 +std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; 1.194 +pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = 1.195 + PTHREAD_MUTEX_INITIALIZER; 1.196 + 1.197 +// Runs before crashing: normal context. 1.198 +ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, 1.199 + FilterCallback filter, 1.200 + MinidumpCallback callback, 1.201 + void* callback_context, 1.202 + bool install_handler, 1.203 + const int server_fd) 1.204 + : filter_(filter), 1.205 + callback_(callback), 1.206 + callback_context_(callback_context), 1.207 + minidump_descriptor_(descriptor), 1.208 + crash_handler_(NULL) { 1.209 + if (server_fd >= 0) 1.210 + crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd)); 1.211 + 1.212 + if (!IsOutOfProcess() && !minidump_descriptor_.IsFD()) 1.213 + minidump_descriptor_.UpdatePath(); 1.214 + 1.215 + pthread_mutex_lock(&handler_stack_mutex_); 1.216 + if (!handler_stack_) 1.217 + handler_stack_ = new std::vector<ExceptionHandler*>; 1.218 + if (install_handler) { 1.219 + InstallAlternateStackLocked(); 1.220 + InstallHandlersLocked(); 1.221 + } 1.222 + handler_stack_->push_back(this); 1.223 + pthread_mutex_unlock(&handler_stack_mutex_); 1.224 +} 1.225 + 1.226 +// Runs before crashing: normal context. 1.227 +ExceptionHandler::~ExceptionHandler() { 1.228 + pthread_mutex_lock(&handler_stack_mutex_); 1.229 + std::vector<ExceptionHandler*>::iterator handler = 1.230 + std::find(handler_stack_->begin(), handler_stack_->end(), this); 1.231 + handler_stack_->erase(handler); 1.232 + if (handler_stack_->empty()) { 1.233 + RestoreAlternateStackLocked(); 1.234 + RestoreHandlersLocked(); 1.235 + } 1.236 + pthread_mutex_unlock(&handler_stack_mutex_); 1.237 +} 1.238 + 1.239 +// Runs before crashing: normal context. 1.240 +// static 1.241 +bool ExceptionHandler::InstallHandlersLocked() { 1.242 + if (handlers_installed) 1.243 + return false; 1.244 + 1.245 + // Fail if unable to store all the old handlers. 1.246 + for (int i = 0; i < kNumHandledSignals; ++i) { 1.247 + if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1) 1.248 + return false; 1.249 + } 1.250 + 1.251 + struct sigaction sa; 1.252 + memset(&sa, 0, sizeof(sa)); 1.253 + sigemptyset(&sa.sa_mask); 1.254 + 1.255 + // Mask all exception signals when we're handling one of them. 1.256 + for (int i = 0; i < kNumHandledSignals; ++i) 1.257 + sigaddset(&sa.sa_mask, kExceptionSignals[i]); 1.258 + 1.259 + sa.sa_sigaction = SignalHandler; 1.260 + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; 1.261 + 1.262 + for (int i = 0; i < kNumHandledSignals; ++i) { 1.263 + if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) { 1.264 + // At this point it is impractical to back out changes, and so failure to 1.265 + // install a signal is intentionally ignored. 1.266 + } 1.267 + } 1.268 + handlers_installed = true; 1.269 + return true; 1.270 +} 1.271 + 1.272 +// This function runs in a compromised context: see the top of the file. 1.273 +// Runs on the crashing thread. 1.274 +// static 1.275 +void ExceptionHandler::RestoreHandlersLocked() { 1.276 + if (!handlers_installed) 1.277 + return; 1.278 + 1.279 + for (int i = 0; i < kNumHandledSignals; ++i) { 1.280 + if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) { 1.281 + signal(kExceptionSignals[i], SIG_DFL); 1.282 + } 1.283 + } 1.284 + handlers_installed = false; 1.285 +} 1.286 + 1.287 +// void ExceptionHandler::set_crash_handler(HandlerCallback callback) { 1.288 +// crash_handler_ = callback; 1.289 +// } 1.290 + 1.291 +// This function runs in a compromised context: see the top of the file. 1.292 +// Runs on the crashing thread. 1.293 +// static 1.294 +void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { 1.295 + // All the exception signals are blocked at this point. 1.296 + pthread_mutex_lock(&handler_stack_mutex_); 1.297 + 1.298 + // Sometimes, Breakpad runs inside a process where some other buggy code 1.299 + // saves and restores signal handlers temporarily with 'signal' 1.300 + // instead of 'sigaction'. This loses the SA_SIGINFO flag associated 1.301 + // with this function. As a consequence, the values of 'info' and 'uc' 1.302 + // become totally bogus, generally inducing a crash. 1.303 + // 1.304 + // The following code tries to detect this case. When it does, it 1.305 + // resets the signal handlers with sigaction + SA_SIGINFO and returns. 1.306 + // This forces the signal to be thrown again, but this time the kernel 1.307 + // will call the function with the right arguments. 1.308 + struct sigaction cur_handler; 1.309 + if (sigaction(sig, NULL, &cur_handler) == 0 && 1.310 + (cur_handler.sa_flags & SA_SIGINFO) == 0) { 1.311 + // Reset signal handler with the right flags. 1.312 + sigemptyset(&cur_handler.sa_mask); 1.313 + sigaddset(&cur_handler.sa_mask, sig); 1.314 + 1.315 + cur_handler.sa_sigaction = SignalHandler; 1.316 + cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO; 1.317 + 1.318 + if (sigaction(sig, &cur_handler, NULL) == -1) { 1.319 + // When resetting the handler fails, try to reset the 1.320 + // default one to avoid an infinite loop here. 1.321 + signal(sig, SIG_DFL); 1.322 + } 1.323 + pthread_mutex_unlock(&handler_stack_mutex_); 1.324 + return; 1.325 + } 1.326 + 1.327 + bool handled = false; 1.328 + for (int i = handler_stack_->size() - 1; !handled && i >= 0; --i) { 1.329 + handled = (*handler_stack_)[i]->HandleSignal(sig, info, uc); 1.330 + } 1.331 + 1.332 + // Upon returning from this signal handler, sig will become unmasked and then 1.333 + // it will be retriggered. If one of the ExceptionHandlers handled it 1.334 + // successfully, restore the default handler. Otherwise, restore the 1.335 + // previously installed handler. Then, when the signal is retriggered, it will 1.336 + // be delivered to the appropriate handler. 1.337 + if (handled) { 1.338 + signal(sig, SIG_DFL); 1.339 + } else { 1.340 + RestoreHandlersLocked(); 1.341 + } 1.342 + 1.343 + pthread_mutex_unlock(&handler_stack_mutex_); 1.344 + 1.345 + if (info->si_code <= 0) { 1.346 + // This signal was sent by another process. (Positive values of 1.347 + // si_code are reserved for kernel-originated signals.) In order 1.348 + // to retrigger it, we have to queue a new signal. 1.349 + if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) { 1.350 + // If we failed to kill ourselves (e.g. because a sandbox disallows us 1.351 + // to do so), we instead resort to terminating our process. This will 1.352 + // result in an incorrect exit code. 1.353 + _exit(1); 1.354 + } 1.355 + } else { 1.356 + // This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV). 1.357 + // No need to reissue the signal. It will automatically trigger again, 1.358 + // when we return from the signal handler. 1.359 + } 1.360 +} 1.361 + 1.362 +struct ThreadArgument { 1.363 + pid_t pid; // the crashing process 1.364 + const MinidumpDescriptor* minidump_descriptor; 1.365 + ExceptionHandler* handler; 1.366 + const void* context; // a CrashContext structure 1.367 + size_t context_size; 1.368 +}; 1.369 + 1.370 +// This is the entry function for the cloned process. We are in a compromised 1.371 +// context here: see the top of the file. 1.372 +// static 1.373 +int ExceptionHandler::ThreadEntry(void *arg) { 1.374 + const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg); 1.375 + 1.376 + // Block here until the crashing process unblocks us when 1.377 + // we're allowed to use ptrace 1.378 + thread_arg->handler->WaitForContinueSignal(); 1.379 + 1.380 + return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context, 1.381 + thread_arg->context_size) == false; 1.382 +} 1.383 + 1.384 +// This function runs in a compromised context: see the top of the file. 1.385 +// Runs on the crashing thread. 1.386 +bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) { 1.387 + if (filter_ && !filter_(callback_context_)) 1.388 + return false; 1.389 + 1.390 + // Allow ourselves to be dumped if the signal is trusted. 1.391 + bool signal_trusted = info->si_code > 0; 1.392 + bool signal_pid_trusted = info->si_code == SI_USER || 1.393 + info->si_code == SI_TKILL; 1.394 + if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) { 1.395 + sys_prctl(PR_SET_DUMPABLE, 1); 1.396 + } 1.397 + CrashContext context; 1.398 + memcpy(&context.siginfo, info, sizeof(siginfo_t)); 1.399 + memcpy(&context.context, uc, sizeof(struct ucontext)); 1.400 +#if !defined(__ARM_EABI__) 1.401 + // FP state is not part of user ABI on ARM Linux. 1.402 + struct ucontext *uc_ptr = (struct ucontext*)uc; 1.403 + if (uc_ptr->uc_mcontext.fpregs) { 1.404 + memcpy(&context.float_state, 1.405 + uc_ptr->uc_mcontext.fpregs, 1.406 + sizeof(context.float_state)); 1.407 + } 1.408 +#endif 1.409 + context.tid = syscall(__NR_gettid); 1.410 + if (crash_handler_ != NULL) { 1.411 + if (crash_handler_(&context, sizeof(context), callback_context_)) { 1.412 + return true; 1.413 + } 1.414 + } 1.415 + return GenerateDump(&context); 1.416 +} 1.417 + 1.418 +// This is a public interface to HandleSignal that allows the client to 1.419 +// generate a crash dump. This function may run in a compromised context. 1.420 +bool ExceptionHandler::SimulateSignalDelivery(int sig) { 1.421 + siginfo_t siginfo = {}; 1.422 + // Mimic a trusted signal to allow tracing the process (see 1.423 + // ExceptionHandler::HandleSignal(). 1.424 + siginfo.si_code = SI_USER; 1.425 + siginfo.si_pid = getpid(); 1.426 + struct ucontext context; 1.427 + getcontext(&context); 1.428 + return HandleSignal(sig, &siginfo, &context); 1.429 +} 1.430 + 1.431 +// This function may run in a compromised context: see the top of the file. 1.432 +bool ExceptionHandler::GenerateDump(CrashContext *context) { 1.433 + if (IsOutOfProcess()) 1.434 + return crash_generation_client_->RequestDump(context, sizeof(*context)); 1.435 + 1.436 + static const unsigned kChildStackSize = 8000; 1.437 + PageAllocator allocator; 1.438 + uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize); 1.439 + if (!stack) 1.440 + return false; 1.441 + // clone() needs the top-most address. (scrub just to be safe) 1.442 + stack += kChildStackSize; 1.443 + my_memset(stack - 16, 0, 16); 1.444 + 1.445 + ThreadArgument thread_arg; 1.446 + thread_arg.handler = this; 1.447 + thread_arg.minidump_descriptor = &minidump_descriptor_; 1.448 + thread_arg.pid = getpid(); 1.449 + thread_arg.context = context; 1.450 + thread_arg.context_size = sizeof(*context); 1.451 + 1.452 + // We need to explicitly enable ptrace of parent processes on some 1.453 + // kernels, but we need to know the PID of the cloned process before we 1.454 + // can do this. Create a pipe here which we can use to block the 1.455 + // cloned process after creating it, until we have explicitly enabled ptrace 1.456 + if(sys_pipe(fdes) == -1) { 1.457 + // Creating the pipe failed. We'll log an error but carry on anyway, 1.458 + // as we'll probably still get a useful crash report. All that will happen 1.459 + // is the write() and read() calls will fail with EBADF 1.460 + static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump \ 1.461 + sys_pipe failed:"; 1.462 + logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1); 1.463 + logger::write(strerror(errno), strlen(strerror(errno))); 1.464 + logger::write("\n", 1); 1.465 + } 1.466 + 1.467 + const pid_t child = sys_clone( 1.468 + ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, 1.469 + &thread_arg, NULL, NULL, NULL); 1.470 + 1.471 + int r, status; 1.472 + // Allow the child to ptrace us 1.473 + sys_prctl(PR_SET_PTRACER, child); 1.474 + SendContinueSignalToChild(); 1.475 + do { 1.476 + r = sys_waitpid(child, &status, __WALL); 1.477 + } while (r == -1 && errno == EINTR); 1.478 + 1.479 + sys_close(fdes[0]); 1.480 + sys_close(fdes[1]); 1.481 + 1.482 + if (r == -1) { 1.483 + static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:"; 1.484 + logger::write(msg, sizeof(msg) - 1); 1.485 + logger::write(strerror(errno), strlen(strerror(errno))); 1.486 + logger::write("\n", 1); 1.487 + } 1.488 + 1.489 + bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0; 1.490 + if (callback_) 1.491 + success = callback_(minidump_descriptor_, callback_context_, success); 1.492 + return success; 1.493 +} 1.494 + 1.495 +// This function runs in a compromised context: see the top of the file. 1.496 +void ExceptionHandler::SendContinueSignalToChild() { 1.497 + static const char okToContinueMessage = 'a'; 1.498 + int r; 1.499 + r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char))); 1.500 + if(r == -1) { 1.501 + static const char msg[] = "ExceptionHandler::SendContinueSignalToChild \ 1.502 + sys_write failed:"; 1.503 + logger::write(msg, sizeof(msg) - 1); 1.504 + logger::write(strerror(errno), strlen(strerror(errno))); 1.505 + logger::write("\n", 1); 1.506 + } 1.507 +} 1.508 + 1.509 +// This function runs in a compromised context: see the top of the file. 1.510 +// Runs on the cloned process. 1.511 +void ExceptionHandler::WaitForContinueSignal() { 1.512 + int r; 1.513 + char receivedMessage; 1.514 + r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char))); 1.515 + if(r == -1) { 1.516 + static const char msg[] = "ExceptionHandler::WaitForContinueSignal \ 1.517 + sys_read failed:"; 1.518 + logger::write(msg, sizeof(msg) - 1); 1.519 + logger::write(strerror(errno), strlen(strerror(errno))); 1.520 + logger::write("\n", 1); 1.521 + } 1.522 +} 1.523 + 1.524 +// This function runs in a compromised context: see the top of the file. 1.525 +// Runs on the cloned process. 1.526 +bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, 1.527 + size_t context_size) { 1.528 + if (minidump_descriptor_.IsFD()) { 1.529 + return google_breakpad::WriteMinidump(minidump_descriptor_.fd(), 1.530 + minidump_descriptor_.size_limit(), 1.531 + crashing_process, 1.532 + context, 1.533 + context_size, 1.534 + mapping_list_, 1.535 + app_memory_list_); 1.536 + } 1.537 + return google_breakpad::WriteMinidump(minidump_descriptor_.path(), 1.538 + minidump_descriptor_.size_limit(), 1.539 + crashing_process, 1.540 + context, 1.541 + context_size, 1.542 + mapping_list_, 1.543 + app_memory_list_); 1.544 +} 1.545 + 1.546 +// static 1.547 +bool ExceptionHandler::WriteMinidump(const string& dump_path, 1.548 + MinidumpCallback callback, 1.549 + void* callback_context) { 1.550 + MinidumpDescriptor descriptor(dump_path); 1.551 + ExceptionHandler eh(descriptor, NULL, callback, callback_context, false, -1); 1.552 + return eh.WriteMinidump(); 1.553 +} 1.554 + 1.555 +bool ExceptionHandler::WriteMinidump() { 1.556 + if (!IsOutOfProcess() && !minidump_descriptor_.IsFD()) { 1.557 + // Update the path of the minidump so that this can be called multiple times 1.558 + // and new files are created for each minidump. This is done before the 1.559 + // generation happens, as clients may want to access the MinidumpDescriptor 1.560 + // after this call to find the exact path to the minidump file. 1.561 + minidump_descriptor_.UpdatePath(); 1.562 + } else if (minidump_descriptor_.IsFD()) { 1.563 + // Reposition the FD to its beginning and resize it to get rid of the 1.564 + // previous minidump info. 1.565 + lseek(minidump_descriptor_.fd(), 0, SEEK_SET); 1.566 + static_cast<void>(ftruncate(minidump_descriptor_.fd(), 0)); 1.567 + } 1.568 + 1.569 + // Allow this process to be dumped. 1.570 + sys_prctl(PR_SET_DUMPABLE, 1); 1.571 + 1.572 + CrashContext context; 1.573 + int getcontext_result = getcontext(&context.context); 1.574 + if (getcontext_result) 1.575 + return false; 1.576 +#if !defined(__ARM_EABI__) 1.577 + // FPU state is not part of ARM EABI ucontext_t. 1.578 + memcpy(&context.float_state, context.context.uc_mcontext.fpregs, 1.579 + sizeof(context.float_state)); 1.580 +#endif 1.581 + context.tid = sys_gettid(); 1.582 + 1.583 + // Add an exception stream to the minidump for better reporting. 1.584 + memset(&context.siginfo, 0, sizeof(context.siginfo)); 1.585 + context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED; 1.586 +#if defined(__i386__) 1.587 + context.siginfo.si_addr = 1.588 + reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_EIP]); 1.589 +#elif defined(__x86_64__) 1.590 + context.siginfo.si_addr = 1.591 + reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_RIP]); 1.592 +#elif defined(__arm__) 1.593 + context.siginfo.si_addr = 1.594 + reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc); 1.595 +#else 1.596 +#error "This code has not been ported to your platform yet." 1.597 +#endif 1.598 + 1.599 + return GenerateDump(&context); 1.600 +} 1.601 + 1.602 +void ExceptionHandler::AddMappingInfo(const string& name, 1.603 + const uint8_t identifier[sizeof(MDGUID)], 1.604 + uintptr_t start_address, 1.605 + size_t mapping_size, 1.606 + size_t file_offset) { 1.607 + MappingInfo info; 1.608 + info.start_addr = start_address; 1.609 + info.size = mapping_size; 1.610 + info.offset = file_offset; 1.611 + strncpy(info.name, name.c_str(), sizeof(info.name) - 1); 1.612 + info.name[sizeof(info.name) - 1] = '\0'; 1.613 + 1.614 + MappingEntry mapping; 1.615 + mapping.first = info; 1.616 + memcpy(mapping.second, identifier, sizeof(MDGUID)); 1.617 + mapping_list_.push_back(mapping); 1.618 +} 1.619 + 1.620 +void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { 1.621 + AppMemoryList::iterator iter = 1.622 + std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr); 1.623 + if (iter != app_memory_list_.end()) { 1.624 + // Don't allow registering the same pointer twice. 1.625 + return; 1.626 + } 1.627 + 1.628 + AppMemory app_memory; 1.629 + app_memory.ptr = ptr; 1.630 + app_memory.length = length; 1.631 + app_memory_list_.push_back(app_memory); 1.632 +} 1.633 + 1.634 +void ExceptionHandler::UnregisterAppMemory(void* ptr) { 1.635 + AppMemoryList::iterator iter = 1.636 + std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr); 1.637 + if (iter != app_memory_list_.end()) { 1.638 + app_memory_list_.erase(iter); 1.639 + } 1.640 +} 1.641 + 1.642 +// static 1.643 +bool ExceptionHandler::WriteMinidumpForChild(pid_t child, 1.644 + pid_t child_blamed_thread, 1.645 + const string& dump_path, 1.646 + MinidumpCallback callback, 1.647 + void* callback_context) { 1.648 + // This function is not run in a compromised context. 1.649 + MinidumpDescriptor descriptor(dump_path); 1.650 + descriptor.UpdatePath(); 1.651 + if (!google_breakpad::WriteMinidump(descriptor.path(), 1.652 + child, 1.653 + child_blamed_thread)) 1.654 + return false; 1.655 + 1.656 + return callback ? callback(descriptor, callback_context, true) : true; 1.657 +} 1.658 + 1.659 +} // namespace google_breakpad