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
This commit is contained in:
rmcilroy@chromium.org 2014-04-03 13:15:37 +00:00
parent 83b9a28cf9
commit 410b7024e3
6 changed files with 140 additions and 25 deletions

View file

@ -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;

View file

@ -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
};

View file

@ -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_;

View file

@ -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 {

View file

@ -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

View file

@ -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__)