#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
+#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
// SIGSTKSZ may be too small to prevent the signal handlers from overrunning
// the alternative stack. Ensure that the size of the alternative stack is
// large enough.
- static const unsigned kSigStackSize = std::max(8192, SIGSTKSZ);
+ static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ);
// Only set an alternative stack if there isn't already one, or if the current
// one is too small.
if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp ||
old_stack.ss_size < kSigStackSize) {
- new_stack.ss_sp = malloc(kSigStackSize);
+ new_stack.ss_sp = calloc(1, kSigStackSize);
new_stack.ss_size = kSigStackSize;
if (sys_sigaltstack(&new_stack, NULL) == -1) {
stack_installed = false;
}
-} // namespace
+// 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_ = NULL;
+pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-// We can stack multiple exception handlers. In that case, this is the global
-// which holds the stack.
-std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
-pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
- PTHREAD_MUTEX_INITIALIZER;
+} // namespace
// Runs before crashing: normal context.
ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
if (!IsOutOfProcess() && !minidump_descriptor_.IsFD())
minidump_descriptor_.UpdatePath();
- pthread_mutex_lock(&handler_stack_mutex_);
- if (!handler_stack_)
- handler_stack_ = new std::vector<ExceptionHandler*>;
+ pthread_mutex_lock(&g_handler_stack_mutex_);
+ if (!g_handler_stack_)
+ g_handler_stack_ = new std::vector<ExceptionHandler*>;
if (install_handler) {
InstallAlternateStackLocked();
InstallHandlersLocked();
}
- handler_stack_->push_back(this);
- pthread_mutex_unlock(&handler_stack_mutex_);
+ g_handler_stack_->push_back(this);
+ pthread_mutex_unlock(&g_handler_stack_mutex_);
}
// Runs before crashing: normal context.
ExceptionHandler::~ExceptionHandler() {
- pthread_mutex_lock(&handler_stack_mutex_);
+ pthread_mutex_lock(&g_handler_stack_mutex_);
std::vector<ExceptionHandler*>::iterator handler =
- std::find(handler_stack_->begin(), handler_stack_->end(), this);
- handler_stack_->erase(handler);
- if (handler_stack_->empty()) {
+ std::find(g_handler_stack_->begin(), g_handler_stack_->end(), this);
+ g_handler_stack_->erase(handler);
+ if (g_handler_stack_->empty()) {
+ delete g_handler_stack_;
+ g_handler_stack_ = NULL;
RestoreAlternateStackLocked();
RestoreHandlersLocked();
}
- pthread_mutex_unlock(&handler_stack_mutex_);
+ pthread_mutex_unlock(&g_handler_stack_mutex_);
}
// Runs before crashing: normal context.
// 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_);
+ pthread_mutex_lock(&g_handler_stack_mutex_);
// Sometimes, Breakpad runs inside a process where some other buggy code
// saves and restores signal handlers temporarily with 'signal'
// default one to avoid an infinite loop here.
signal(sig, SIG_DFL);
}
- pthread_mutex_unlock(&handler_stack_mutex_);
+ pthread_mutex_unlock(&g_handler_stack_mutex_);
return;
}
bool handled = false;
- for (int i = handler_stack_->size() - 1; !handled && i >= 0; --i) {
- handled = (*handler_stack_)[i]->HandleSignal(sig, info, uc);
+ for (int i = g_handler_stack_->size() - 1; !handled && i >= 0; --i) {
+ handled = (*g_handler_stack_)[i]->HandleSignal(sig, info, uc);
}
// Upon returning from this signal handler, sig will become unmasked and then
RestoreHandlersLocked();
}
- pthread_mutex_unlock(&handler_stack_mutex_);
+ pthread_mutex_unlock(&g_handler_stack_mutex_);
if (info->si_pid || sig == SIGABRT) {
// This signal was triggered by somebody sending us the signal with kill().
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
CrashContext context;
+ // Fill in all the holes in the struct to make Valgrind happy.
+ memset(&context, 0, sizeof(context));
memcpy(&context.siginfo, info, sizeof(siginfo_t));
memcpy(&context.context, uc, sizeof(struct ucontext));
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if defined(__aarch64__)
+ struct ucontext *uc_ptr = (struct ucontext*)uc;
+ struct fpsimd_context *fp_ptr =
+ (struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved;
+ if (fp_ptr->head.magic == FPSIMD_MAGIC) {
+ memcpy(&context.float_state, fp_ptr, sizeof(context.float_state));
+ }
+#elif !defined(__ARM_EABI__) && !defined(__mips__)
// FP state is not part of user ABI on ARM Linux.
// In case of MIPS Linux FP state is already part of struct ucontext
// and 'float_state' is not a member of CrashContext.
// of caution than smash it into random locations.
static const unsigned kChildStackSize = 16000;
PageAllocator allocator;
- uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize);
+ uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize));
if (!stack)
return false;
// clone() needs the top-most address. (scrub just to be safe)
// kernels, but we need to know the PID of the cloned process before we
// can do this. Create a pipe here which we can use to block the
// cloned process after creating it, until we have explicitly enabled ptrace
- if(sys_pipe(fdes) == -1) {
+ if (sys_pipe(fdes) == -1) {
// Creating the pipe failed. We'll log an error but carry on anyway,
// as we'll probably still get a useful crash report. All that will happen
// is the write() and read() calls will fail with EBADF
- static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump \
- sys_pipe failed:";
+ static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump "
+ "sys_pipe failed:";
logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1);
logger::write(strerror(errno), strlen(strerror(errno)));
logger::write("\n", 1);
+
+ // Ensure fdes[0] and fdes[1] are invalid file descriptors.
+ fdes[0] = fdes[1] = -1;
}
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
&thread_arg, NULL, NULL, NULL);
+ if (child == -1) {
+ sys_close(fdes[0]);
+ sys_close(fdes[1]);
+ return false;
+ }
- int r, status;
// Allow the child to ptrace us
sys_prctl(PR_SET_PTRACER, child, 0, 0, 0);
SendContinueSignalToChild();
- do {
- r = sys_waitpid(child, &status, __WALL);
- } while (r == -1 && errno == EINTR);
+ int status;
+ const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL));
sys_close(fdes[0]);
sys_close(fdes[1]);
static const char okToContinueMessage = 'a';
int r;
r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char)));
- if(r == -1) {
- static const char msg[] = "ExceptionHandler::SendContinueSignalToChild \
- sys_write failed:";
+ if (r == -1) {
+ static const char msg[] = "ExceptionHandler::SendContinueSignalToChild "
+ "sys_write failed:";
logger::write(msg, sizeof(msg) - 1);
logger::write(strerror(errno), strlen(strerror(errno)));
logger::write("\n", 1);
int r;
char receivedMessage;
r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char)));
- if(r == -1) {
- static const char msg[] = "ExceptionHandler::WaitForContinueSignal \
- sys_read failed:";
+ if (r == -1) {
+ static const char msg[] = "ExceptionHandler::WaitForContinueSignal "
+ "sys_read failed:";
logger::write(msg, sizeof(msg) - 1);
logger::write(strerror(errno), strlen(strerror(errno)));
logger::write("\n", 1);
}
#endif
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__)
// FPU state is not part of ARM EABI ucontext_t.
memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
sizeof(context.float_state));
#elif defined(__arm__)
context.siginfo.si_addr =
reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc);
+#elif defined(__aarch64__)
+ context.siginfo.si_addr =
+ reinterpret_cast<void*>(context.context.uc_mcontext.pc);
#elif defined(__mips__)
context.siginfo.si_addr =
reinterpret_cast<void*>(context.context.uc_mcontext.pc);