aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrmcilroy@chromium.org <rmcilroy@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2014-04-03 13:15:37 +0000
committerrmcilroy@chromium.org <rmcilroy@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2014-04-03 13:15:37 +0000
commit410b7024e3b66863af88e624536bebbbb7873252 (patch)
treee025780f530fd5ed4986333b97ed34c44d92c0a8
parentFirst cut at adding arm64 Linux / Android support to Breakpad. (diff)
downloadbreakpad-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.cc11
-rw-r--r--src/client/linux/handler/exception_handler.h8
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc21
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.h7
-rw-r--r--src/common/android/breakpad_getcontext.S94
-rw-r--r--src/common/android/ucontext_constants.h24
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__)