Add x64 version of getcontext.
Assembly code is derived in part from code in libunwind. Code tested on desktop linux (Android testing pending emulation support). BUG=346626 R=dannyb@google.com, thestig@chromium.org Review URL: https://breakpad.appspot.com/1454002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1311 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
a2245d6744
commit
6594ac922c
5 changed files with 275 additions and 0 deletions
|
@ -305,6 +305,87 @@ NESTED (breakpad_getcontext, FRAME_SIZE, ra)
|
|||
|
||||
END (breakpad_getcontext)
|
||||
|
||||
#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 <ppluzhnikov@google.com>
|
||||
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
|
||||
|
||||
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!"
|
||||
|
|
|
@ -27,11 +27,26 @@
|
|||
// (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 <asm/sigcontext.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/android/ucontext_constants.h"
|
||||
|
||||
template <int left, int right>
|
||||
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<left, right> tag;
|
||||
|
||||
TEST(AndroidUContext, GRegsOffset) {
|
||||
#if defined(__arm__)
|
||||
// There is no gregs[] array on ARM, so compare to the offset of
|
||||
|
@ -95,6 +110,70 @@ TEST(AndroidUContext, GRegsOffset) {
|
|||
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR),
|
||||
offsetof(ucontext_t,uc_mcontext.fpc_csr));
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.gregs),
|
||||
mcontext_gregs_offset);
|
||||
#define CHECK_REG(x) \
|
||||
COMPILE_ASSERT_EQ(static_cast<size_t>(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<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.gregs));
|
||||
|
|
|
@ -175,6 +175,73 @@ typedef struct ucontext {
|
|||
// Other fields are not used by Google Breakpad. Don't define them.
|
||||
} ucontext_t;
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
enum {
|
||||
REG_R8 = 0,
|
||||
REG_R9,
|
||||
REG_R10,
|
||||
REG_R11,
|
||||
REG_R12,
|
||||
REG_R13,
|
||||
REG_R14,
|
||||
REG_R15,
|
||||
REG_RDI,
|
||||
REG_RSI,
|
||||
REG_RBP,
|
||||
REG_RBX,
|
||||
REG_RDX,
|
||||
REG_RAX,
|
||||
REG_RCX,
|
||||
REG_RSP,
|
||||
REG_RIP,
|
||||
REG_EFL,
|
||||
REG_CSGSFS,
|
||||
REG_ERR,
|
||||
REG_TRAPNO,
|
||||
REG_OLDMASK,
|
||||
REG_CR2,
|
||||
NGREG
|
||||
};
|
||||
|
||||
// This struct is essentially the same as _fpstate in asm/sigcontext.h
|
||||
// except that the individual field names are chosen here to match the
|
||||
// ones used in breakpad for other x86_64 platforms.
|
||||
struct _libc_fpstate {
|
||||
/* 64-bit FXSAVE format. */
|
||||
uint16_t cwd;
|
||||
uint16_t swd;
|
||||
uint16_t ftw;
|
||||
uint16_t fop;
|
||||
uint64_t rip;
|
||||
uint64_t rdp;
|
||||
uint32_t mxcsr;
|
||||
uint32_t mxcr_mask;
|
||||
uint32_t _st[32]; // 128 bytes for the ST/MM registers 0-7
|
||||
uint32_t _xmm[64]; // 256 bytes for the XMM registers 0-7
|
||||
uint32_t padding[24]; // 96 bytes
|
||||
};
|
||||
|
||||
typedef long greg_t;
|
||||
typedef greg_t gregset_t[NGREG];
|
||||
|
||||
typedef struct _libc_fpstate* fpregset_t;
|
||||
|
||||
typedef struct {
|
||||
gregset_t gregs;
|
||||
fpregset_t fpregs;
|
||||
uint64_t __reserved1[8];
|
||||
} mcontext_t;
|
||||
|
||||
typedef struct ucontext {
|
||||
unsigned long uc_flags;
|
||||
struct ucontext* uc_link;
|
||||
stack_t uc_stack;
|
||||
mcontext_t uc_mcontext;
|
||||
sigset_t uc_sigmask;
|
||||
uint64_t __padding[15];
|
||||
_libc_fpstate __fpregs_mem;
|
||||
} ucontext_t;
|
||||
|
||||
#else
|
||||
# error "Unsupported Android CPU ABI!"
|
||||
#endif
|
||||
|
|
|
@ -143,6 +143,28 @@ struct user_fpregs_struct {
|
|||
unsigned int fir;
|
||||
};
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
#include <sys/types.h>
|
||||
#include_next <sys/user.h>
|
||||
|
||||
// This struct is essentially the same as user_i387_struct in sys/user.h
|
||||
// except that the struct name and individual field names are chosen here
|
||||
// to match the ones used in breakpad for other x86_64 platforms.
|
||||
|
||||
struct user_fpregs_struct {
|
||||
__u16 cwd;
|
||||
__u16 swd;
|
||||
__u16 ftw;
|
||||
__u16 fop;
|
||||
__u64 rip;
|
||||
__u64 rdp;
|
||||
__u32 mxcsr;
|
||||
__u32 mxcr_mask;
|
||||
__u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
|
||||
__u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
|
||||
__u32 padding[24];
|
||||
};
|
||||
|
||||
#else
|
||||
# error "Unsupported Android CPU ABI"
|
||||
#endif
|
||||
|
|
|
@ -103,6 +103,32 @@
|
|||
#define MCONTEXT_FPC_CSR 556
|
||||
#define UCONTEXT_SIGMASK_OFFSET 616
|
||||
|
||||
#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 424
|
||||
#define FPREGS_OFFSET_MXCSR 24
|
||||
|
||||
#else
|
||||
#error "This header has not been ported for your CPU"
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue