diff options
author | rmcilroy@chromium.org <rmcilroy@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2014-04-03 13:15:37 +0000 |
---|---|---|
committer | rmcilroy@chromium.org <rmcilroy@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2014-04-03 13:15:37 +0000 |
commit | 410b7024e3b66863af88e624536bebbbb7873252 (patch) | |
tree | e025780f530fd5ed4986333b97ed34c44d92c0a8 | |
parent | First cut at adding arm64 Linux / Android support to Breakpad. (diff) | |
download | breakpad-410b7024e3b66863af88e624536bebbbb7873252.tar.xz |
Add Arm64 version of breakpad_getcontext for Android.
This CL adds breakpad_getcontext support for Arm64 to Android. The assembly
is based on getcontext.S in glibc.
BUG=354405,335641
R=mark@chromium.org
Review URL: https://breakpad.appspot.com/1384002
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1302 4c0a9323-5329-0410-9bdc-e9ce6186880e
-rw-r--r-- | src/client/linux/handler/exception_handler.cc | 11 | ||||
-rw-r--r-- | src/client/linux/handler/exception_handler.h | 8 | ||||
-rw-r--r-- | src/client/linux/minidump_writer/minidump_writer.cc | 21 | ||||
-rw-r--r-- | src/client/linux/minidump_writer/minidump_writer.h | 7 | ||||
-rw-r--r-- | src/common/android/breakpad_getcontext.S | 94 | ||||
-rw-r--r-- | src/common/android/ucontext_constants.h | 24 |
6 files changed, 140 insertions, 25 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index 9d081ca8..e5aaecd8 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -398,8 +398,15 @@ bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) { CrashContext context; memcpy(&context.siginfo, info, sizeof(siginfo_t)); memcpy(&context.context, uc, sizeof(struct ucontext)); -#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) - // FP state is not part of user ABI on ARM or ARM64 Linux. +#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. struct ucontext *uc_ptr = (struct ucontext*)uc; diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h index 2e842d83..e906e7a7 100644 --- a/src/client/linux/handler/exception_handler.h +++ b/src/client/linux/handler/exception_handler.h @@ -190,11 +190,11 @@ class ExceptionHandler { siginfo_t siginfo; pid_t tid; // the crashing thread. struct ucontext context; -#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) - // #ifdef this out because FP state is not part of user ABI for Linux ARM - // or ARM64. In case of MIPS Linux FP state is already part of struct +#if !defined(__ARM_EABI__) && !defined(__mips__) + // #ifdef this out because FP state is not part of user ABI for Linux ARM. + // In case of MIPS Linux FP state is already part of struct // ucontext so 'float_state' is not required. - struct _libc_fpstate float_state; + fpstate_t float_state; #endif }; diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index 50929f80..ce8503d2 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -344,8 +344,7 @@ void CPUFillFromThreadInfo(MDRawContextARM* out, #endif } -void CPUFillFromUContext(MDRawContextARM* out, const ucontext* uc, - const struct _libc_fpstate* fpregs) { +void CPUFillFromUContext(MDRawContextARM* out, const ucontext* uc) { out->context_flags = MD_CONTEXT_ARM_FULL; out->iregs[0] = uc->uc_mcontext.arm_r0; @@ -383,7 +382,7 @@ void CPUFillFromThreadInfo(MDRawContextARM64* out, } void CPUFillFromUContext(MDRawContextARM64* out, const ucontext* uc, - const struct _libc_fpstate* fpregs) { + const struct fpsimd_context* fpregs) { // TODO(rmcilroy): Implement for arm64. } @@ -418,8 +417,7 @@ static void CPUFillFromThreadInfo(MDRawContextMIPS* out, out->float_save.fir = info.fpregs.fir; } -static void CPUFillFromUContext(MDRawContextMIPS* out, const ucontext* uc, - const struct _libc_fpstate* fpregs) { +static void CPUFillFromUContext(MDRawContextMIPS* out, const ucontext* uc) { out->context_flags = MD_CONTEXT_MIPS_FULL; for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) @@ -483,11 +481,8 @@ class MinidumpWriter { : fd_(minidump_fd), path_(minidump_path), ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__aarch64__) +#if !defined(__ARM_EABI__) && !defined(__mips__) float_state_(context ? &context->float_state : NULL), -#else - // TODO: fix this after fixing ExceptionHandler - float_state_(NULL), #endif dumper_(dumper), minidump_size_limit_(-1), @@ -848,7 +843,11 @@ class MinidumpWriter { if (!cpu.Allocate()) return false; my_memset(cpu.get(), 0, sizeof(RawContextCPU)); +#if !defined(__ARM_EABI__) && !defined(__mips__) CPUFillFromUContext(cpu.get(), ucontext_, float_state_); +#else + CPUFillFromUContext(cpu.get(), ucontext_); +#endif if (stack_copy) PopSeccompStackFrame(cpu.get(), thread, stack_copy); thread.thread_context = cpu.location(); @@ -1756,7 +1755,9 @@ class MinidumpWriter { const char* path_; // Path to the file where the minidum should be written. const struct ucontext* const ucontext_; // also from the signal handler - const struct _libc_fpstate* const float_state_; // ditto +#if !defined(__ARM_EABI__) && !defined(__mips__) + const google_breakpad::fpstate_t* const float_state_; // ditto +#endif LinuxDumper* dumper_; MinidumpFileWriter minidump_writer_; off_t minidump_size_limit_; diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h index c9e150ae..e1afe69b 100644 --- a/src/client/linux/minidump_writer/minidump_writer.h +++ b/src/client/linux/minidump_writer/minidump_writer.h @@ -32,6 +32,7 @@ #include <stdint.h> #include <sys/types.h> +#include <sys/ucontext.h> #include <unistd.h> #include <list> @@ -52,6 +53,12 @@ struct MappingEntry { // A list of <MappingInfo, GUID> typedef std::list<MappingEntry> MappingList; +#if defined(__aarch64__) +typedef struct fpsimd_context fpstate_t; +#elif !defined(__ARM_EABI__) && !defined(__mips__) +typedef struct _libc_fpstate fpstate_t; +#endif + // These entries store a list of memory regions that the client wants included // in the minidump. struct AppMemory { diff --git a/src/common/android/breakpad_getcontext.S b/src/common/android/breakpad_getcontext.S index 849ffaf6..b41cb05c 100644 --- a/src/common/android/breakpad_getcontext.S +++ b/src/common/android/breakpad_getcontext.S @@ -34,7 +34,7 @@ /* int getcontext (ucontext_t *ucp) */ -#ifdef __arm__ +#if defined(__arm__) .text .global breakpad_getcontext @@ -50,7 +50,7 @@ breakpad_getcontext: /* r12 is a scratch register, don't save it */ - /* Save sp and lr explicitely. */ + /* Save sp and lr explicitly. */ /* - sp can't be stored with stmia in Thumb-2 */ /* - STM instructions that store sp and pc are deprecated in ARM */ str sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)] @@ -59,7 +59,7 @@ breakpad_getcontext: /* Save the caller's address in 'pc' */ str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)] - /* Save ucontext_t* pointer accross next call */ + /* Save ucontext_t* pointer across next call */ mov r4, r0 /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ @@ -88,6 +88,90 @@ breakpad_getcontext: .fnend .size breakpad_getcontext, . - breakpad_getcontext +#elif defined(__aarch64__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 4 + .cfi_startproc +breakpad_getcontext: + + /* The saved context will return to the getcontext() call point + with a return value of 0 */ + str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE] + + stp x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE] + stp x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE] + stp x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE] + stp x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE] + stp x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE] + stp x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE] + str x30, [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE] + + /* Place LR into the saved PC, this will ensure that when + switching to this saved context with setcontext() control + will pass back to the caller of getcontext(), we have + already arranged to return the appropriate return value in x0 + above. */ + str x30, [x0, MCONTEXT_PC_OFFSET] + + /* Save the current SP */ + mov x2, sp + str x2, [x0, MCONTEXT_SP_OFFSET] + + /* Initialize the pstate. */ + str xzr, [x0, MCONTEXT_PSTATE_OFFSET] + + /* Figure out where to place the first context extension + block. */ + add x2, x0, #MCONTEXT_EXTENSION_OFFSET + + /* Write the context extension fpsimd header. */ + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + str w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + mov w3, #FPSIMD_CONTEXT_SIZE + str w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Fill in the FP SIMD context. */ + add x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE) + stp d8, d9, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE) + + add x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET + + mrs x4, fpsr + str w4, [x3] + + mrs x4, fpcr + str w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET] + + /* Write the termination context extension header. */ + add x2, x2, #FPSIMD_CONTEXT_SIZE + + str xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + str xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Grab the signal mask */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + add x2, x0, #UCONTEXT_SIGMASK_OFFSET + mov x0, #0 /* SIG_BLOCK */ + mov x1, #0 /* NULL */ + mov x3, #(_NSIG / 8) + mov x8, #__NR_rt_sigprocmask + svc 0 + + /* Return x0 for success */ + mov x0, 0 + ret + + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + #elif defined(__i386__) .text @@ -140,10 +224,6 @@ breakpad_getcontext: .size breakpad_getcontext, . - breakpad_getcontext -#elif defined(__aarch64__) - - // TODO(rmcilroy): Implement for arm64. - #elif defined(__mips__) #if _MIPS_SIM != _ABIO32 diff --git a/src/common/android/ucontext_constants.h b/src/common/android/ucontext_constants.h index 87069517..4b00ae23 100644 --- a/src/common/android/ucontext_constants.h +++ b/src/common/android/ucontext_constants.h @@ -47,8 +47,28 @@ #elif defined(__aarch64__) -#define MCONTEXT_GREGS_OFFSET 56 -#define UCONTEXT_SIGMASK_OFFSET 40 +#define UCONTEXT_SIGMASK_OFFSET 40 + +#define MCONTEXT_GREGS_OFFSET 56 +#define MCONTEXT_SP_OFFSET 304 +#define MCONTEXT_PC_OFFSET 312 +#define MCONTEXT_PSTATE_OFFSET 320 +#define MCONTEXT_EXTENSION_OFFSET 336 + +#define FPSIMD_MAGIC 0x46508001 + +#define FPSIMD_CONTEXT_MAGIC_OFFSET 0 +#define FPSIMD_CONTEXT_SIZE_OFFSET 4 +#define FPSIMD_CONTEXT_FPSR_OFFSET 8 +#define FPSIMD_CONTEXT_FPCR_OFFSET 12 +#define FPSIMD_CONTEXT_VREGS_OFFSET 16 +#define FPSIMD_CONTEXT_SIZE 528 + +#define REGISTER_SIZE 8 +#define SIMD_REGISTER_SIZE 16 + +#define _NSIG 64 +#define __NR_rt_sigprocmask 135 #elif defined(__i386__) |