From e780d58fd7b6eda76065327a9921d6157e4a7964 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Mon, 16 Mar 2020 12:56:56 -0700 Subject: Use breakpad_getcontext on all Linux platforms missing getcontext getcontext is also not available on musl libc, so generalize breakpad_getcontext so it can be used as a fallback for non-Android platforms as well. On x86_64 and i386, ucontext_t uses an Android-specific offset for storage of FP registers, since its sigset_t differs in size. So, make the definition of MCONTEXT_FPREGS_MEM and UCONTEXT_FPREGS_MEM_OFFSET conditional on whether we are building for Android. On glibc and musl, signal.h and asm/sigcontext.h can't be included together, so in breakpad_context_unittest.cc, only compare the libc and kernel _fpstate when on Android. Bug: google-breakpad:631 Change-Id: If81d73c4101bae946e9a3655b8d1c40a34ab6c38 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2102135 Reviewed-by: Mike Frysinger --- src/common/android/breakpad_getcontext.S | 486 --------------------- src/common/android/breakpad_getcontext_unittest.cc | 186 -------- src/common/android/include/ucontext.h | 56 --- src/common/android/ucontext_constants.h | 144 ------ src/common/common.gyp | 14 +- src/common/linux/breakpad_getcontext.S | 486 +++++++++++++++++++++ src/common/linux/breakpad_getcontext.h | 56 +++ src/common/linux/breakpad_getcontext_unittest.cc | 194 ++++++++ src/common/linux/ucontext_constants.h | 153 +++++++ 9 files changed, 899 insertions(+), 876 deletions(-) delete mode 100644 src/common/android/breakpad_getcontext.S delete mode 100644 src/common/android/breakpad_getcontext_unittest.cc delete mode 100644 src/common/android/include/ucontext.h delete mode 100644 src/common/android/ucontext_constants.h create mode 100644 src/common/linux/breakpad_getcontext.S create mode 100644 src/common/linux/breakpad_getcontext.h create mode 100644 src/common/linux/breakpad_getcontext_unittest.cc create mode 100644 src/common/linux/ucontext_constants.h (limited to 'src/common') diff --git a/src/common/android/breakpad_getcontext.S b/src/common/android/breakpad_getcontext.S deleted file mode 100644 index 7f3a3b6f..00000000 --- a/src/common/android/breakpad_getcontext.S +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// A minimalistic implementation of getcontext() to be used by -// Google Breakpad on Android. - -#include "common/android/ucontext_constants.h" - -/* int getcontext (ucontext_t *ucp) */ - -#if defined(__arm__) - - .text - .global breakpad_getcontext - .hidden breakpad_getcontext - .type breakpad_getcontext, #function - .align 0 - .fnstart -breakpad_getcontext: - - /* First, save r4-r11 */ - add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4) - stm r1, {r4-r11} - - /* r12 is a scratch register, don't save it */ - - /* 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)] - str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] - - /* Save the caller's address in 'pc' */ - str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)] - - /* Save ucontext_t* pointer across next call */ - mov r4, r0 - - /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ - mov r0, #0 /* SIG_BLOCK */ - mov r1, #0 /* NULL */ - add r2, r4, #UCONTEXT_SIGMASK_OFFSET - bl sigprocmask(PLT) - - /* Intentionally do not save the FPU state here. This is because on - * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or - * ptrace(PTRACE_GETVFPREGS) to get it. - * - * Note that a real implementation of getcontext() would need to save - * this here to allow setcontext()/swapcontext() to work correctly. - */ - - /* Restore the values of r4 and lr */ - mov r0, r4 - ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] - ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)] - - /* Return 0 */ - mov r0, #0 - bx lr - - .fnend - .size breakpad_getcontext, . - breakpad_getcontext - -#elif defined(__aarch64__) - -#define _NSIG 64 -#define __NR_rt_sigprocmask 135 - - .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 - .global breakpad_getcontext - .hidden breakpad_getcontext - .align 4 - .type breakpad_getcontext, @function - -breakpad_getcontext: - - movl 4(%esp), %eax /* eax = uc */ - - /* Save register values */ - movl %ecx, MCONTEXT_ECX_OFFSET(%eax) - movl %edx, MCONTEXT_EDX_OFFSET(%eax) - movl %ebx, MCONTEXT_EBX_OFFSET(%eax) - movl %edi, MCONTEXT_EDI_OFFSET(%eax) - movl %esi, MCONTEXT_ESI_OFFSET(%eax) - movl %ebp, MCONTEXT_EBP_OFFSET(%eax) - - movl (%esp), %edx /* return address */ - lea 4(%esp), %ecx /* exclude return address from stack */ - mov %edx, MCONTEXT_EIP_OFFSET(%eax) - mov %ecx, MCONTEXT_ESP_OFFSET(%eax) - - xorl %ecx, %ecx - movw %fs, %cx - mov %ecx, MCONTEXT_FS_OFFSET(%eax) - - movl $0, MCONTEXT_EAX_OFFSET(%eax) - - /* Save floating point state to fpregstate, then update - * the fpregs pointer to point to it */ - leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx - fnstenv (%ecx) - fldenv (%ecx) - mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax) - - /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ - leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx - xorl %ecx, %ecx - push %edx /* &uc->uc_sigmask */ - push %ecx /* NULL */ - push %ecx /* SIGBLOCK == 0 on i386 */ - call sigprocmask@PLT - addl $12, %esp - - movl $0, %eax - ret - - .size breakpad_getcontext, . - breakpad_getcontext - -#elif defined(__mips__) - -// This implementation is inspired by implementation of getcontext in glibc. -#include -#include -#if _MIPS_SIM == _ABIO32 -#include -#endif - -// from asm-mips/asm.h -#if _MIPS_SIM == _ABIO32 -#define ALSZ 7 -#define ALMASK ~7 -#define SZREG 4 -#else // _MIPS_SIM != _ABIO32 -#define ALSZ 15 -#define ALMASK ~15 -#define SZREG 8 -#endif - -#include // for __NR_rt_sigprocmask - -#define _NSIG8 128 / 8 -#define SIG_BLOCK 1 - - - .text -LOCALS_NUM = 1 // save gp on stack -FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK - -GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG) -MCONTEXT_REG_SIZE = 8 - -#if _MIPS_SIM == _ABIO32 - -NESTED (breakpad_getcontext, FRAME_SIZE, ra) - .mask 0x00000000, 0 - .fmask 0x00000000, 0 - - .set noreorder - .cpload t9 - .set reorder - - move a2, sp -#define _SP a2 - - addiu sp, -FRAME_SIZE - .cprestore GP_FRAME_OFFSET - - sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sw ra, MCONTEXT_PC_OFFSET(a0) - -#ifdef __mips_hard_float - s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - - cfc1 v1, fcr31 - sw v1, MCONTEXT_FPC_CSR(a0) -#endif // __mips_hard_float - - /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ - li a3, _NSIG8 - addu a2, a0, UCONTEXT_SIGMASK_OFFSET - move a1, zero - li a0, SIG_BLOCK - li v0, __NR_rt_sigprocmask - syscall - - addiu sp, FRAME_SIZE - jr ra - -END (breakpad_getcontext) -#else - -#ifndef NESTED -/* - * NESTED - declare nested routine entry point - */ -#define NESTED(symbol, framesize, rpc) \ - .globl symbol; \ - .align 2; \ - .type symbol,@function; \ - .ent symbol,0; \ -symbol: .frame sp, framesize, rpc; -#endif - -/* - * END - mark end of function - */ -#ifndef END -# define END(function) \ - .end function; \ - .size function,.-function -#endif - -/* int getcontext (ucontext_t *ucp) */ - -NESTED (breakpad_getcontext, FRAME_SIZE, ra) - .mask 0x10000000, 0 - .fmask 0x00000000, 0 - - move a2, sp -#define _SP a2 - move a3, gp -#define _GP a3 - - daddiu sp, -FRAME_SIZE - .cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext - - /* Store a magic flag. */ - li v1, 1 - sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */ - - sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) - sd ra, MCONTEXT_PC_OFFSET(a0) - -#ifdef __mips_hard_float - s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) - - cfc1 v1, $31 - sw v1, MCONTEXT_FPC_CSR(a0) -#endif /* __mips_hard_float */ - -/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ - li a3, _NSIG8 - daddu a2, a0, UCONTEXT_SIGMASK_OFFSET - move a1, zero - li a0, SIG_BLOCK - - li v0, __NR_rt_sigprocmask - syscall - - .cpreturn - daddiu sp, FRAME_SIZE - move v0, zero - jr ra - -END (breakpad_getcontext) -#endif // _MIPS_SIM == _ABIO32 - -#elif defined(__x86_64__) -/* The x64 implementation of breakpad_getcontext was derived in part - from the implementation of libunwind which requires the following - notice. */ -/* libunwind - a platform-independent unwind library - Copyright (C) 2008 Google, Inc - Contributed by Paul Pluzhnikov - Copyright (C) 2010 Konstantin Belousov - -This file is part of libunwind. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - - .text - .global breakpad_getcontext - .hidden breakpad_getcontext - .align 4 - .type breakpad_getcontext, @function - -breakpad_getcontext: - .cfi_startproc - - /* Callee saved: RBX, RBP, R12-R15 */ - movq %r12, MCONTEXT_GREGS_R12(%rdi) - movq %r13, MCONTEXT_GREGS_R13(%rdi) - movq %r14, MCONTEXT_GREGS_R14(%rdi) - movq %r15, MCONTEXT_GREGS_R15(%rdi) - movq %rbp, MCONTEXT_GREGS_RBP(%rdi) - movq %rbx, MCONTEXT_GREGS_RBX(%rdi) - - /* Save argument registers (not strictly needed, but setcontext - restores them, so don't restore garbage). */ - movq %r8, MCONTEXT_GREGS_R8(%rdi) - movq %r9, MCONTEXT_GREGS_R9(%rdi) - movq %rdi, MCONTEXT_GREGS_RDI(%rdi) - movq %rsi, MCONTEXT_GREGS_RSI(%rdi) - movq %rdx, MCONTEXT_GREGS_RDX(%rdi) - movq %rax, MCONTEXT_GREGS_RAX(%rdi) - movq %rcx, MCONTEXT_GREGS_RCX(%rdi) - - /* Save fp state (not needed, except for setcontext not - restoring garbage). */ - leaq MCONTEXT_FPREGS_MEM(%rdi),%r8 - movq %r8, MCONTEXT_FPREGS_PTR(%rdi) - fnstenv (%r8) - stmxcsr FPREGS_OFFSET_MXCSR(%r8) - - leaq 8(%rsp), %rax /* exclude this call. */ - movq %rax, MCONTEXT_GREGS_RSP(%rdi) - - movq 0(%rsp), %rax - movq %rax, MCONTEXT_GREGS_RIP(%rdi) - - /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ - leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3 - xorq %rsi, %rsi // arg2 NULL - xorq %rdi, %rdi // arg1 SIGBLOCK == 0 - call sigprocmask@PLT - - /* Always return 0 for success, even if sigprocmask failed. */ - xorl %eax, %eax - ret - .cfi_endproc - .size breakpad_getcontext, . - breakpad_getcontext - -#else -#error "This file has not been ported for your CPU!" -#endif diff --git a/src/common/android/breakpad_getcontext_unittest.cc b/src/common/android/breakpad_getcontext_unittest.cc deleted file mode 100644 index 2c550bf2..00000000 --- a/src/common/android/breakpad_getcontext_unittest.cc +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#if defined(__x86_64__) -#include -#endif - -#include - -#include "breakpad_googletest_includes.h" -#include "common/android/ucontext_constants.h" - -template -struct CompileAssertEquals { - // a compilation error here indicates left and right are not equal. - char left_too_large[right - left]; - // a compilation error here indicates left and right are not equal. - char right_too_large[left - right]; -}; - -#define COMPILE_ASSERT_EQ(left, right, tag) \ - CompileAssertEquals tag; - -TEST(AndroidUContext, GRegsOffset) { -#if defined(__arm__) - // There is no gregs[] array on ARM, so compare to the offset of - // first register fields, since they're stored in order. - ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.arm_r0)); -#elif defined(__aarch64__) - // There is no gregs[] array on ARM, so compare to the offset of - // first register fields, since they're stored in order. - ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.regs[0])); - ASSERT_EQ(static_cast(MCONTEXT_SP_OFFSET), - offsetof(ucontext_t,uc_mcontext.sp)); - ASSERT_EQ(static_cast(MCONTEXT_PC_OFFSET), - offsetof(ucontext_t,uc_mcontext.pc)); - ASSERT_EQ(static_cast(MCONTEXT_PSTATE_OFFSET), - offsetof(ucontext_t,uc_mcontext.pstate)); - ASSERT_EQ(static_cast(MCONTEXT_EXTENSION_OFFSET), - offsetof(ucontext_t,uc_mcontext.__reserved)); -#elif defined(__i386__) - ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs)); -#define CHECK_REG(x) \ - ASSERT_EQ(static_cast(MCONTEXT_##x##_OFFSET), \ - offsetof(ucontext_t,uc_mcontext.gregs[REG_##x])) - CHECK_REG(GS); - CHECK_REG(FS); - CHECK_REG(ES); - CHECK_REG(DS); - CHECK_REG(EDI); - CHECK_REG(ESI); - CHECK_REG(EBP); - CHECK_REG(ESP); - CHECK_REG(EBX); - CHECK_REG(EDX); - CHECK_REG(ECX); - CHECK_REG(EAX); - CHECK_REG(TRAPNO); - CHECK_REG(ERR); - CHECK_REG(EIP); - CHECK_REG(CS); - CHECK_REG(EFL); - CHECK_REG(UESP); - CHECK_REG(SS); - - ASSERT_EQ(static_cast(UCONTEXT_FPREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.fpregs)); - - ASSERT_EQ(static_cast(UCONTEXT_FPREGS_MEM_OFFSET), - offsetof(ucontext_t,__fpregs_mem)); -#elif defined(__mips__) - ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs)); - - // PC for mips is not part of gregs. - ASSERT_EQ(static_cast(MCONTEXT_PC_OFFSET), - offsetof(ucontext_t,uc_mcontext.pc)); - - ASSERT_EQ(static_cast(MCONTEXT_FPREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.fpregs)); - - ASSERT_EQ(static_cast(MCONTEXT_FPC_CSR), - offsetof(ucontext_t,uc_mcontext.fpc_csr)); -#elif defined(__x86_64__) - - COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs), - mcontext_gregs_offset); -#define CHECK_REG(x) \ - COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_##x), \ - offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]), reg_##x) - CHECK_REG(R8); - CHECK_REG(R9); - CHECK_REG(R10); - CHECK_REG(R11); - CHECK_REG(R12); - CHECK_REG(R13); - CHECK_REG(R14); - CHECK_REG(R15); - CHECK_REG(RDI); - CHECK_REG(RSI); - CHECK_REG(RBP); - CHECK_REG(RBX); - CHECK_REG(RDX); - CHECK_REG(RAX); - CHECK_REG(RCX); - CHECK_REG(RSP); - CHECK_REG(RIP); - - // sigcontext is an analog to mcontext_t. The layout should be the same. - COMPILE_ASSERT_EQ(offsetof(mcontext_t,fpregs), - offsetof(sigcontext,fpstate), sigcontext_fpstate); - // Check that _fpstate from asm/sigcontext.h is essentially the same - // as _libc_fpstate. - COMPILE_ASSERT_EQ(sizeof(_libc_fpstate), sizeof(_fpstate), - sigcontext_fpstate_size); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,cwd),offsetof(_fpstate,cwd), - sigcontext_fpstate_cwd); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,swd),offsetof(_fpstate,swd), - sigcontext_fpstate_swd); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,ftw),offsetof(_fpstate,twd), - sigcontext_fpstate_twd); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,fop),offsetof(_fpstate,fop), - sigcontext_fpstate_fop); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rip),offsetof(_fpstate,rip), - sigcontext_fpstate_rip); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rdp),offsetof(_fpstate,rdp), - sigcontext_fpstate_rdp); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcsr),offsetof(_fpstate,mxcsr), - sigcontext_fpstate_mxcsr); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcr_mask), - offsetof(_fpstate,mxcsr_mask), - sigcontext_fpstate_mxcsr_mask); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_st), offsetof(_fpstate,st_space), - sigcontext_fpstate_stspace); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_xmm), offsetof(_fpstate,xmm_space), - sigcontext_fpstate_xmm_space); - - COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_PTR, - offsetof(ucontext_t,uc_mcontext.fpregs), - mcontext_fpregs_ptr); - COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_MEM, offsetof(ucontext_t,__fpregs_mem), - mcontext_fpregs_mem); - COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR, offsetof(_libc_fpstate,mxcsr), - fpregs_offset_mxcsr); - COMPILE_ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t, uc_sigmask), - ucontext_sigmask); -#else - ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs)); -#endif -} - -TEST(AndroidUContext, SigmakOffset) { - ASSERT_EQ(static_cast(UCONTEXT_SIGMASK_OFFSET), - offsetof(ucontext_t,uc_sigmask)); -} diff --git a/src/common/android/include/ucontext.h b/src/common/android/include/ucontext.h deleted file mode 100644 index 29db8ade..00000000 --- a/src/common/android/include/ucontext.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H - -#include - -#ifdef __BIONIC_UCONTEXT_H -#include -#else - -#include - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -// Provided by src/android/common/breakpad_getcontext.S -int breakpad_getcontext(ucontext_t* ucp); - -#define getcontext(x) breakpad_getcontext(x) - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // __BIONIC_UCONTEXT_H - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H diff --git a/src/common/android/ucontext_constants.h b/src/common/android/ucontext_constants.h deleted file mode 100644 index 1932d573..00000000 --- a/src/common/android/ucontext_constants.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This header can be included either from a C, C++ or Assembly file. -// Its purpose is to contain constants that must match the offsets of -// various fields in ucontext_t. -// -// They should match the definitions from -// src/common/android/include/sys/ucontext.h -// -// Used by src/common/android/breakpad_getcontext.S -// Tested by src/common/android/testing/breakpad_getcontext_unittest.cc - -#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H -#define GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H - -#if defined(__arm__) - -#define MCONTEXT_GREGS_OFFSET 32 -#define UCONTEXT_SIGMASK_OFFSET 104 - -#elif defined(__aarch64__) - -#define UCONTEXT_SIGMASK_OFFSET 40 - -#define MCONTEXT_GREGS_OFFSET 184 -#define MCONTEXT_SP_OFFSET 432 -#define MCONTEXT_PC_OFFSET 440 -#define MCONTEXT_PSTATE_OFFSET 448 -#define MCONTEXT_EXTENSION_OFFSET 464 - -#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 - -#elif defined(__i386__) - -#define MCONTEXT_GREGS_OFFSET 20 -#define MCONTEXT_GS_OFFSET (MCONTEXT_GREGS_OFFSET + 0*4) -#define MCONTEXT_FS_OFFSET (MCONTEXT_GREGS_OFFSET + 1*4) -#define MCONTEXT_ES_OFFSET (MCONTEXT_GREGS_OFFSET + 2*4) -#define MCONTEXT_DS_OFFSET (MCONTEXT_GREGS_OFFSET + 3*4) -#define MCONTEXT_EDI_OFFSET (MCONTEXT_GREGS_OFFSET + 4*4) -#define MCONTEXT_ESI_OFFSET (MCONTEXT_GREGS_OFFSET + 5*4) -#define MCONTEXT_EBP_OFFSET (MCONTEXT_GREGS_OFFSET + 6*4) -#define MCONTEXT_ESP_OFFSET (MCONTEXT_GREGS_OFFSET + 7*4) -#define MCONTEXT_EBX_OFFSET (MCONTEXT_GREGS_OFFSET + 8*4) -#define MCONTEXT_EDX_OFFSET (MCONTEXT_GREGS_OFFSET + 9*4) -#define MCONTEXT_ECX_OFFSET (MCONTEXT_GREGS_OFFSET + 10*4) -#define MCONTEXT_EAX_OFFSET (MCONTEXT_GREGS_OFFSET + 11*4) -#define MCONTEXT_TRAPNO_OFFSET (MCONTEXT_GREGS_OFFSET + 12*4) -#define MCONTEXT_ERR_OFFSET (MCONTEXT_GREGS_OFFSET + 13*4) -#define MCONTEXT_EIP_OFFSET (MCONTEXT_GREGS_OFFSET + 14*4) -#define MCONTEXT_CS_OFFSET (MCONTEXT_GREGS_OFFSET + 15*4) -#define MCONTEXT_EFL_OFFSET (MCONTEXT_GREGS_OFFSET + 16*4) -#define MCONTEXT_UESP_OFFSET (MCONTEXT_GREGS_OFFSET + 17*4) -#define MCONTEXT_SS_OFFSET (MCONTEXT_GREGS_OFFSET + 18*4) - -#define UCONTEXT_SIGMASK_OFFSET 108 - -#define UCONTEXT_FPREGS_OFFSET 96 -#define UCONTEXT_FPREGS_MEM_OFFSET 116 - -#elif defined(__mips__) - -#if _MIPS_SIM == _ABIO32 -#define MCONTEXT_PC_OFFSET 32 -#define MCONTEXT_GREGS_OFFSET 40 -#define MCONTEXT_FPREGS_OFFSET 296 -#define MCONTEXT_FPC_CSR 556 -#define UCONTEXT_SIGMASK_OFFSET 616 -#else -#define MCONTEXT_GREGS_OFFSET 40 -#define MCONTEXT_FPREGS_OFFSET 296 -#define MCONTEXT_PC_OFFSET 616 -#define MCONTEXT_FPC_CSR 624 -#define UCONTEXT_SIGMASK_OFFSET 640 -#endif - -#elif defined(__x86_64__) - -#define MCONTEXT_GREGS_OFFSET 40 -#define UCONTEXT_SIGMASK_OFFSET 296 - -#define MCONTEXT_GREGS_R8 40 -#define MCONTEXT_GREGS_R9 48 -#define MCONTEXT_GREGS_R10 56 -#define MCONTEXT_GREGS_R11 64 -#define MCONTEXT_GREGS_R12 72 -#define MCONTEXT_GREGS_R13 80 -#define MCONTEXT_GREGS_R14 88 -#define MCONTEXT_GREGS_R15 96 -#define MCONTEXT_GREGS_RDI 104 -#define MCONTEXT_GREGS_RSI 112 -#define MCONTEXT_GREGS_RBP 120 -#define MCONTEXT_GREGS_RBX 128 -#define MCONTEXT_GREGS_RDX 136 -#define MCONTEXT_GREGS_RAX 144 -#define MCONTEXT_GREGS_RCX 152 -#define MCONTEXT_GREGS_RSP 160 -#define MCONTEXT_GREGS_RIP 168 -#define MCONTEXT_FPREGS_PTR 224 -#define MCONTEXT_FPREGS_MEM 304 -#define FPREGS_OFFSET_MXCSR 24 - -#else -#error "This header has not been ported for your CPU" -#endif - -#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H diff --git a/src/common/common.gyp b/src/common/common.gyp index 103554ba..c1dbb0fe 100644 --- a/src/common/common.gyp +++ b/src/common/common.gyp @@ -33,7 +33,13 @@ 'defines': ['HAVE_MACH_O_NLIST_H'], }], ['OS=="linux"', { - 'defines': ['HAVE_A_OUT_H'], + # Assume glibc. + 'defines': ['HAVE_A_OUT_H', 'HAVE_GETCONTEXT'], + 'sources!': [ + 'linux/breakpad_getcontext.S', + 'linux/breakpad_getcontext.h', + 'linux/breakpad_getcontext_unittest.cc', + ], }], ['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}], ['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}], @@ -47,13 +53,11 @@ 'target_name': 'common', 'type': 'static_library', 'sources': [ - 'android/breakpad_getcontext.S', 'android/include/elf.h', 'android/include/link.h', 'android/include/stab.h', 'android/include/sys/procfs.h', 'android/include/sys/user.h', - 'android/include/ucontext.h', 'android/testing/include/wchar.h', 'android/testing/mkdtemp.h', 'android/testing/pthread_fixes.h', @@ -87,6 +91,8 @@ 'dwarf_line_to_module.h', 'language.cc', 'language.h', + 'linux/breakpad_getcontext.S', + 'linux/breakpad_getcontext.h', 'linux/crc32.cc', 'linux/crc32.h', 'linux/dump_symbols.cc', @@ -201,7 +207,6 @@ 'target_name': 'common_unittests', 'type': 'executable', 'sources': [ - 'android/breakpad_getcontext_unittest.cc', 'byte_cursor_unittest.cc', 'dwarf/bytereader_unittest.cc', 'dwarf/dwarf2diehandler_unittest.cc', @@ -210,6 +215,7 @@ 'dwarf_cfi_to_module_unittest.cc', 'dwarf_cu_to_module_unittest.cc', 'dwarf_line_to_module_unittest.cc', + 'linux/breakpad_getcontext_unittest.cc', 'linux/dump_symbols_unittest.cc', 'linux/elf_core_dump_unittest.cc', 'linux/elf_symbols_to_module_unittest.cc', diff --git a/src/common/linux/breakpad_getcontext.S b/src/common/linux/breakpad_getcontext.S new file mode 100644 index 00000000..fea0109d --- /dev/null +++ b/src/common/linux/breakpad_getcontext.S @@ -0,0 +1,486 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A minimalistic implementation of getcontext() to be used by +// Google Breakpad when getcontext() is not available in libc. + +#include "common/linux/ucontext_constants.h" + +/* int getcontext (ucontext_t *ucp) */ + +#if defined(__arm__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 0 + .fnstart +breakpad_getcontext: + + /* First, save r4-r11 */ + add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4) + stm r1, {r4-r11} + + /* r12 is a scratch register, don't save it */ + + /* 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)] + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + + /* Save the caller's address in 'pc' */ + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)] + + /* Save ucontext_t* pointer across next call */ + mov r4, r0 + + /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ + mov r0, #0 /* SIG_BLOCK */ + mov r1, #0 /* NULL */ + add r2, r4, #UCONTEXT_SIGMASK_OFFSET + bl sigprocmask(PLT) + + /* Intentionally do not save the FPU state here. This is because on + * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or + * ptrace(PTRACE_GETVFPREGS) to get it. + * + * Note that a real implementation of getcontext() would need to save + * this here to allow setcontext()/swapcontext() to work correctly. + */ + + /* Restore the values of r4 and lr */ + mov r0, r4 + ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)] + + /* Return 0 */ + mov r0, #0 + bx lr + + .fnend + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__aarch64__) + +#define _NSIG 64 +#define __NR_rt_sigprocmask 135 + + .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 + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + + movl 4(%esp), %eax /* eax = uc */ + + /* Save register values */ + movl %ecx, MCONTEXT_ECX_OFFSET(%eax) + movl %edx, MCONTEXT_EDX_OFFSET(%eax) + movl %ebx, MCONTEXT_EBX_OFFSET(%eax) + movl %edi, MCONTEXT_EDI_OFFSET(%eax) + movl %esi, MCONTEXT_ESI_OFFSET(%eax) + movl %ebp, MCONTEXT_EBP_OFFSET(%eax) + + movl (%esp), %edx /* return address */ + lea 4(%esp), %ecx /* exclude return address from stack */ + mov %edx, MCONTEXT_EIP_OFFSET(%eax) + mov %ecx, MCONTEXT_ESP_OFFSET(%eax) + + xorl %ecx, %ecx + movw %fs, %cx + mov %ecx, MCONTEXT_FS_OFFSET(%eax) + + movl $0, MCONTEXT_EAX_OFFSET(%eax) + + /* Save floating point state to fpregstate, then update + * the fpregs pointer to point to it */ + leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx + fnstenv (%ecx) + fldenv (%ecx) + mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx + xorl %ecx, %ecx + push %edx /* &uc->uc_sigmask */ + push %ecx /* NULL */ + push %ecx /* SIGBLOCK == 0 on i386 */ + call sigprocmask@PLT + addl $12, %esp + + movl $0, %eax + ret + + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__mips__) + +// This implementation is inspired by implementation of getcontext in glibc. +#include +#include +#if _MIPS_SIM == _ABIO32 +#include +#endif + +// from asm-mips/asm.h +#if _MIPS_SIM == _ABIO32 +#define ALSZ 7 +#define ALMASK ~7 +#define SZREG 4 +#else // _MIPS_SIM != _ABIO32 +#define ALSZ 15 +#define ALMASK ~15 +#define SZREG 8 +#endif + +#include // for __NR_rt_sigprocmask + +#define _NSIG8 128 / 8 +#define SIG_BLOCK 1 + + + .text +LOCALS_NUM = 1 // save gp on stack +FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK + +GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG) +MCONTEXT_REG_SIZE = 8 + +#if _MIPS_SIM == _ABIO32 + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x00000000, 0 + .fmask 0x00000000, 0 + + .set noreorder + .cpload t9 + .set reorder + + move a2, sp +#define _SP a2 + + addiu sp, -FRAME_SIZE + .cprestore GP_FRAME_OFFSET + + sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, fcr31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif // __mips_hard_float + + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + addu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + li v0, __NR_rt_sigprocmask + syscall + + addiu sp, FRAME_SIZE + jr ra + +END (breakpad_getcontext) +#else + +#ifndef NESTED +/* + * NESTED - declare nested routine entry point + */ +#define NESTED(symbol, framesize, rpc) \ + .globl symbol; \ + .align 2; \ + .type symbol,@function; \ + .ent symbol,0; \ +symbol: .frame sp, framesize, rpc; +#endif + +/* + * END - mark end of function + */ +#ifndef END +# define END(function) \ + .end function; \ + .size function,.-function +#endif + +/* int getcontext (ucontext_t *ucp) */ + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x10000000, 0 + .fmask 0x00000000, 0 + + move a2, sp +#define _SP a2 + move a3, gp +#define _GP a3 + + daddiu sp, -FRAME_SIZE + .cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext + + /* Store a magic flag. */ + li v1, 1 + sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */ + + sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, $31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif /* __mips_hard_float */ + +/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + daddu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + + li v0, __NR_rt_sigprocmask + syscall + + .cpreturn + daddiu sp, FRAME_SIZE + move v0, zero + jr ra + +END (breakpad_getcontext) +#endif // _MIPS_SIM == _ABIO32 + +#elif defined(__x86_64__) +/* The x64 implementation of breakpad_getcontext was derived in part + from the implementation of libunwind which requires the following + notice. */ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 Google, Inc + Contributed by Paul Pluzhnikov + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + .cfi_startproc + + /* Callee saved: RBX, RBP, R12-R15 */ + movq %r12, MCONTEXT_GREGS_R12(%rdi) + movq %r13, MCONTEXT_GREGS_R13(%rdi) + movq %r14, MCONTEXT_GREGS_R14(%rdi) + movq %r15, MCONTEXT_GREGS_R15(%rdi) + movq %rbp, MCONTEXT_GREGS_RBP(%rdi) + movq %rbx, MCONTEXT_GREGS_RBX(%rdi) + + /* Save argument registers (not strictly needed, but setcontext + restores them, so don't restore garbage). */ + movq %r8, MCONTEXT_GREGS_R8(%rdi) + movq %r9, MCONTEXT_GREGS_R9(%rdi) + movq %rdi, MCONTEXT_GREGS_RDI(%rdi) + movq %rsi, MCONTEXT_GREGS_RSI(%rdi) + movq %rdx, MCONTEXT_GREGS_RDX(%rdi) + movq %rax, MCONTEXT_GREGS_RAX(%rdi) + movq %rcx, MCONTEXT_GREGS_RCX(%rdi) + + /* Save fp state (not needed, except for setcontext not + restoring garbage). */ + leaq MCONTEXT_FPREGS_MEM(%rdi),%r8 + movq %r8, MCONTEXT_FPREGS_PTR(%rdi) + fnstenv (%r8) + stmxcsr FPREGS_OFFSET_MXCSR(%r8) + + leaq 8(%rsp), %rax /* exclude this call. */ + movq %rax, MCONTEXT_GREGS_RSP(%rdi) + + movq 0(%rsp), %rax + movq %rax, MCONTEXT_GREGS_RIP(%rdi) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3 + xorq %rsi, %rsi // arg2 NULL + xorq %rdi, %rdi // arg1 SIGBLOCK == 0 + call sigprocmask@PLT + + /* Always return 0 for success, even if sigprocmask failed. */ + xorl %eax, %eax + ret + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#else +#error "This file has not been ported for your CPU!" +#endif diff --git a/src/common/linux/breakpad_getcontext.h b/src/common/linux/breakpad_getcontext.h new file mode 100644 index 00000000..1418cde6 --- /dev/null +++ b/src/common/linux/breakpad_getcontext.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H +#define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_GETCONTEXT + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Provided by src/common/linux/breakpad_getcontext.S +int breakpad_getcontext(ucontext_t* ucp); + +#define getcontext(x) breakpad_getcontext(x) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // HAVE_GETCONTEXT + +#endif // GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H diff --git a/src/common/linux/breakpad_getcontext_unittest.cc b/src/common/linux/breakpad_getcontext_unittest.cc new file mode 100644 index 00000000..a57bfedf --- /dev/null +++ b/src/common/linux/breakpad_getcontext_unittest.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// asm/sigcontext.h can't be included with signal.h on glibc or +// musl, so only compare _libc_fpstate and _fpstate on Android. +#if defined(__ANDROID__) && defined(__x86_64__) +#include +#endif + +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/ucontext_constants.h" + +template +struct CompileAssertEquals { + // a compilation error here indicates left and right are not equal. + char left_too_large[right - left]; + // a compilation error here indicates left and right are not equal. + char right_too_large[left - right]; +}; + +#define COMPILE_ASSERT_EQ(left, right, tag) \ + CompileAssertEquals tag; + +TEST(AndroidUContext, GRegsOffset) { +#if defined(__arm__) + // There is no gregs[] array on ARM, so compare to the offset of + // first register fields, since they're stored in order. + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.arm_r0)); +#elif defined(__aarch64__) + // There is no gregs[] array on ARM, so compare to the offset of + // first register fields, since they're stored in order. + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.regs[0])); + ASSERT_EQ(static_cast(MCONTEXT_SP_OFFSET), + offsetof(ucontext_t,uc_mcontext.sp)); + ASSERT_EQ(static_cast(MCONTEXT_PC_OFFSET), + offsetof(ucontext_t,uc_mcontext.pc)); + ASSERT_EQ(static_cast(MCONTEXT_PSTATE_OFFSET), + offsetof(ucontext_t,uc_mcontext.pstate)); + ASSERT_EQ(static_cast(MCONTEXT_EXTENSION_OFFSET), + offsetof(ucontext_t,uc_mcontext.__reserved)); +#elif defined(__i386__) + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs)); +#define CHECK_REG(x) \ + ASSERT_EQ(static_cast(MCONTEXT_##x##_OFFSET), \ + offsetof(ucontext_t,uc_mcontext.gregs[REG_##x])) + CHECK_REG(GS); + CHECK_REG(FS); + CHECK_REG(ES); + CHECK_REG(DS); + CHECK_REG(EDI); + CHECK_REG(ESI); + CHECK_REG(EBP); + CHECK_REG(ESP); + CHECK_REG(EBX); + CHECK_REG(EDX); + CHECK_REG(ECX); + CHECK_REG(EAX); + CHECK_REG(TRAPNO); + CHECK_REG(ERR); + CHECK_REG(EIP); + CHECK_REG(CS); + CHECK_REG(EFL); + CHECK_REG(UESP); + CHECK_REG(SS); + + ASSERT_EQ(static_cast(UCONTEXT_FPREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.fpregs)); + + ASSERT_EQ(static_cast(UCONTEXT_FPREGS_MEM_OFFSET), + offsetof(ucontext_t,__fpregs_mem)); +#elif defined(__mips__) + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs)); + + // PC for mips is not part of gregs. + ASSERT_EQ(static_cast(MCONTEXT_PC_OFFSET), + offsetof(ucontext_t,uc_mcontext.pc)); + + ASSERT_EQ(static_cast(MCONTEXT_FPREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.fpregs)); + + ASSERT_EQ(static_cast(MCONTEXT_FPC_CSR), + offsetof(ucontext_t,uc_mcontext.fpc_csr)); +#elif defined(__x86_64__) + + COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs), + mcontext_gregs_offset); +#define CHECK_REG(x) \ + COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_##x), \ + offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]), reg_##x) + CHECK_REG(R8); + CHECK_REG(R9); + CHECK_REG(R10); + CHECK_REG(R11); + CHECK_REG(R12); + CHECK_REG(R13); + CHECK_REG(R14); + CHECK_REG(R15); + CHECK_REG(RDI); + CHECK_REG(RSI); + CHECK_REG(RBP); + CHECK_REG(RBX); + CHECK_REG(RDX); + CHECK_REG(RAX); + CHECK_REG(RCX); + CHECK_REG(RSP); + CHECK_REG(RIP); + + // sigcontext is an analog to mcontext_t. The layout should be the same. + COMPILE_ASSERT_EQ(offsetof(mcontext_t,fpregs), + offsetof(sigcontext,fpstate), sigcontext_fpstate); + +#if defined(__ANDROID__) + // Check that _fpstate from asm/sigcontext.h is essentially the same + // as _libc_fpstate. + COMPILE_ASSERT_EQ(sizeof(_libc_fpstate), sizeof(_fpstate), + sigcontext_fpstate_size); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,cwd),offsetof(_fpstate,cwd), + sigcontext_fpstate_cwd); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,swd),offsetof(_fpstate,swd), + sigcontext_fpstate_swd); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,ftw),offsetof(_fpstate,twd), + sigcontext_fpstate_twd); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,fop),offsetof(_fpstate,fop), + sigcontext_fpstate_fop); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rip),offsetof(_fpstate,rip), + sigcontext_fpstate_rip); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rdp),offsetof(_fpstate,rdp), + sigcontext_fpstate_rdp); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcsr),offsetof(_fpstate,mxcsr), + sigcontext_fpstate_mxcsr); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcr_mask), + offsetof(_fpstate,mxcsr_mask), + sigcontext_fpstate_mxcsr_mask); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_st), offsetof(_fpstate,st_space), + sigcontext_fpstate_stspace); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_xmm), offsetof(_fpstate,xmm_space), + sigcontext_fpstate_xmm_space); +#endif + + COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_PTR, + offsetof(ucontext_t,uc_mcontext.fpregs), + mcontext_fpregs_ptr); + COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_MEM, offsetof(ucontext_t,__fpregs_mem), + mcontext_fpregs_mem); + COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR, + offsetof(std::remove_pointer::type,mxcsr), + fpregs_offset_mxcsr); + COMPILE_ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t, uc_sigmask), + ucontext_sigmask); +#else + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs)); +#endif +} + +TEST(AndroidUContext, SigmakOffset) { + ASSERT_EQ(static_cast(UCONTEXT_SIGMASK_OFFSET), + offsetof(ucontext_t,uc_sigmask)); +} diff --git a/src/common/linux/ucontext_constants.h b/src/common/linux/ucontext_constants.h new file mode 100644 index 00000000..c390508a --- /dev/null +++ b/src/common/linux/ucontext_constants.h @@ -0,0 +1,153 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This header can be included either from a C, C++ or Assembly file. +// Its purpose is to contain constants that must match the offsets of +// various fields in ucontext_t. +// +// They should match the definitions from signal.h. +// +// Used by src/common/linux/breakpad_getcontext.S +// Tested by src/common/linux/breakpad_getcontext_unittest.cc +// +// This header should not be used by anything else. + +#ifndef GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H +#define GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H + +#if defined(__arm__) + +#define MCONTEXT_GREGS_OFFSET 32 +#define UCONTEXT_SIGMASK_OFFSET 104 + +#elif defined(__aarch64__) + +#define UCONTEXT_SIGMASK_OFFSET 40 + +#define MCONTEXT_GREGS_OFFSET 184 +#define MCONTEXT_SP_OFFSET 432 +#define MCONTEXT_PC_OFFSET 440 +#define MCONTEXT_PSTATE_OFFSET 448 +#define MCONTEXT_EXTENSION_OFFSET 464 + +#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 + +#elif defined(__i386__) + +#define MCONTEXT_GREGS_OFFSET 20 +#define MCONTEXT_GS_OFFSET (MCONTEXT_GREGS_OFFSET + 0*4) +#define MCONTEXT_FS_OFFSET (MCONTEXT_GREGS_OFFSET + 1*4) +#define MCONTEXT_ES_OFFSET (MCONTEXT_GREGS_OFFSET + 2*4) +#define MCONTEXT_DS_OFFSET (MCONTEXT_GREGS_OFFSET + 3*4) +#define MCONTEXT_EDI_OFFSET (MCONTEXT_GREGS_OFFSET + 4*4) +#define MCONTEXT_ESI_OFFSET (MCONTEXT_GREGS_OFFSET + 5*4) +#define MCONTEXT_EBP_OFFSET (MCONTEXT_GREGS_OFFSET + 6*4) +#define MCONTEXT_ESP_OFFSET (MCONTEXT_GREGS_OFFSET + 7*4) +#define MCONTEXT_EBX_OFFSET (MCONTEXT_GREGS_OFFSET + 8*4) +#define MCONTEXT_EDX_OFFSET (MCONTEXT_GREGS_OFFSET + 9*4) +#define MCONTEXT_ECX_OFFSET (MCONTEXT_GREGS_OFFSET + 10*4) +#define MCONTEXT_EAX_OFFSET (MCONTEXT_GREGS_OFFSET + 11*4) +#define MCONTEXT_TRAPNO_OFFSET (MCONTEXT_GREGS_OFFSET + 12*4) +#define MCONTEXT_ERR_OFFSET (MCONTEXT_GREGS_OFFSET + 13*4) +#define MCONTEXT_EIP_OFFSET (MCONTEXT_GREGS_OFFSET + 14*4) +#define MCONTEXT_CS_OFFSET (MCONTEXT_GREGS_OFFSET + 15*4) +#define MCONTEXT_EFL_OFFSET (MCONTEXT_GREGS_OFFSET + 16*4) +#define MCONTEXT_UESP_OFFSET (MCONTEXT_GREGS_OFFSET + 17*4) +#define MCONTEXT_SS_OFFSET (MCONTEXT_GREGS_OFFSET + 18*4) + +#define UCONTEXT_SIGMASK_OFFSET 108 + +#define UCONTEXT_FPREGS_OFFSET 96 +#if defined(__BIONIC__) +#define UCONTEXT_FPREGS_MEM_OFFSET 116 +#else +#define UCONTEXT_FPREGS_MEM_OFFSET 236 +#endif + +#elif defined(__mips__) + +#if _MIPS_SIM == _ABIO32 +#define MCONTEXT_PC_OFFSET 32 +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_FPC_CSR 556 +#define UCONTEXT_SIGMASK_OFFSET 616 +#else +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_PC_OFFSET 616 +#define MCONTEXT_FPC_CSR 624 +#define UCONTEXT_SIGMASK_OFFSET 640 +#endif + +#elif defined(__x86_64__) + +#define MCONTEXT_GREGS_OFFSET 40 +#define UCONTEXT_SIGMASK_OFFSET 296 + +#define MCONTEXT_GREGS_R8 40 +#define MCONTEXT_GREGS_R9 48 +#define MCONTEXT_GREGS_R10 56 +#define MCONTEXT_GREGS_R11 64 +#define MCONTEXT_GREGS_R12 72 +#define MCONTEXT_GREGS_R13 80 +#define MCONTEXT_GREGS_R14 88 +#define MCONTEXT_GREGS_R15 96 +#define MCONTEXT_GREGS_RDI 104 +#define MCONTEXT_GREGS_RSI 112 +#define MCONTEXT_GREGS_RBP 120 +#define MCONTEXT_GREGS_RBX 128 +#define MCONTEXT_GREGS_RDX 136 +#define MCONTEXT_GREGS_RAX 144 +#define MCONTEXT_GREGS_RCX 152 +#define MCONTEXT_GREGS_RSP 160 +#define MCONTEXT_GREGS_RIP 168 +#define MCONTEXT_FPREGS_PTR 224 +#if defined(__BIONIC__) +#define MCONTEXT_FPREGS_MEM 304 +#else +#define MCONTEXT_FPREGS_MEM 424 +#endif +#define FPREGS_OFFSET_MXCSR 24 + +#else +#error "This header has not been ported for your CPU" +#endif + +#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H -- cgit v1.2.1