Home | History | Annotate | Download | only in android
      1 // Copyright (c) 2012, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // A minimalistic implementation of getcontext() to be used by
     31 // Google Breakpad on Android.
     32 
     33 #include "common/android/ucontext_constants.h"
     34 
     35 /* int getcontext (ucontext_t *ucp) */
     36 
     37 #if defined(__arm__)
     38 
     39   .text
     40   .global breakpad_getcontext
     41   .hidden breakpad_getcontext
     42   .type breakpad_getcontext, #function
     43   .align 0
     44   .fnstart
     45 breakpad_getcontext:
     46 
     47   /* First, save r4-r11 */
     48   add   r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4)
     49   stm   r1, {r4-r11}
     50 
     51   /* r12 is a scratch register, don't save it */
     52 
     53   /* Save sp and lr explicitly. */
     54   /* - sp can't be stored with stmia in Thumb-2 */
     55   /* - STM instructions that store sp and pc are deprecated in ARM */
     56   str   sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)]
     57   str   lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)]
     58 
     59   /* Save the caller's address in 'pc' */
     60   str   lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)]
     61 
     62   /* Save ucontext_t* pointer across next call */
     63   mov   r4, r0
     64 
     65   /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
     66   mov   r0, #0  /* SIG_BLOCK */
     67   mov   r1, #0  /* NULL */
     68   add   r2, r4, #UCONTEXT_SIGMASK_OFFSET
     69   bl    sigprocmask(PLT)
     70 
     71   /* Intentionally do not save the FPU state here. This is because on
     72    * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or
     73    * ptrace(PTRACE_GETVFPREGS) to get it.
     74    *
     75    * Note that a real implementation of getcontext() would need to save
     76    * this here to allow setcontext()/swapcontext() to work correctly.
     77    */
     78 
     79   /* Restore the values of r4 and lr */
     80   mov   r0, r4
     81   ldr   lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)]
     82   ldr   r4, [r0, #(MCONTEXT_GREGS_OFFSET +  4*4)]
     83 
     84   /* Return 0 */
     85   mov   r0, #0
     86   bx    lr
     87 
     88   .fnend
     89   .size breakpad_getcontext, . - breakpad_getcontext
     90 
     91 #elif defined(__aarch64__)
     92 
     93 #define  _NSIG                       64
     94 #define  __NR_rt_sigprocmask         135
     95 
     96   .text
     97   .global breakpad_getcontext
     98   .hidden breakpad_getcontext
     99   .type breakpad_getcontext, #function
    100   .align 4
    101   .cfi_startproc
    102 breakpad_getcontext:
    103 
    104   /* The saved context will return to the getcontext() call point
    105      with a return value of 0 */
    106   str     xzr,      [x0, MCONTEXT_GREGS_OFFSET +  0 * REGISTER_SIZE]
    107 
    108   stp     x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE]
    109   stp     x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE]
    110   stp     x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE]
    111   stp     x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE]
    112   stp     x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE]
    113   stp     x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE]
    114   str     x30,      [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE]
    115 
    116   /* Place LR into the saved PC, this will ensure that when
    117      switching to this saved context with setcontext() control
    118      will pass back to the caller of getcontext(), we have
    119      already arranged to return the appropriate return value in x0
    120      above.  */
    121   str     x30, [x0, MCONTEXT_PC_OFFSET]
    122 
    123   /* Save the current SP */
    124   mov     x2, sp
    125   str     x2, [x0, MCONTEXT_SP_OFFSET]
    126 
    127   /* Initialize the pstate.  */
    128   str     xzr, [x0, MCONTEXT_PSTATE_OFFSET]
    129 
    130   /* Figure out where to place the first context extension
    131      block.  */
    132   add     x2, x0, #MCONTEXT_EXTENSION_OFFSET
    133 
    134   /* Write the context extension fpsimd header.  */
    135   mov     w3, #(FPSIMD_MAGIC & 0xffff)
    136   movk    w3, #(FPSIMD_MAGIC >> 16), lsl #16
    137   str     w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET]
    138   mov     w3, #FPSIMD_CONTEXT_SIZE
    139   str     w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET]
    140 
    141   /* Fill in the FP SIMD context.  */
    142   add     x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE)
    143   stp     d8,  d9, [x3], #(2 * SIMD_REGISTER_SIZE)
    144   stp     d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE)
    145   stp     d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE)
    146   stp     d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE)
    147 
    148   add     x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET
    149 
    150   mrs     x4, fpsr
    151   str     w4, [x3]
    152 
    153   mrs     x4, fpcr
    154   str     w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET]
    155 
    156   /* Write the termination context extension header.  */
    157   add     x2, x2, #FPSIMD_CONTEXT_SIZE
    158 
    159   str     xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET]
    160   str     xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET]
    161 
    162   /* Grab the signal mask */
    163   /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
    164   add     x2, x0, #UCONTEXT_SIGMASK_OFFSET
    165   mov     x0, #0  /* SIG_BLOCK */
    166   mov     x1, #0  /* NULL */
    167   mov     x3, #(_NSIG / 8)
    168   mov     x8, #__NR_rt_sigprocmask
    169   svc     0
    170 
    171   /* Return x0 for success */
    172   mov     x0, 0
    173   ret
    174 
    175   .cfi_endproc
    176   .size breakpad_getcontext, . - breakpad_getcontext
    177 
    178 #elif defined(__i386__)
    179 
    180   .text
    181   .global breakpad_getcontext
    182   .hidden breakpad_getcontext
    183   .align 4
    184   .type breakpad_getcontext, @function
    185 
    186 breakpad_getcontext:
    187 
    188   movl 4(%esp), %eax   /* eax = uc */
    189 
    190   /* Save register values */
    191   movl %ecx, MCONTEXT_ECX_OFFSET(%eax)
    192   movl %edx, MCONTEXT_EDX_OFFSET(%eax)
    193   movl %ebx, MCONTEXT_EBX_OFFSET(%eax)
    194   movl %edi, MCONTEXT_EDI_OFFSET(%eax)
    195   movl %esi, MCONTEXT_ESI_OFFSET(%eax)
    196   movl %ebp, MCONTEXT_EBP_OFFSET(%eax)
    197 
    198   movl (%esp), %edx   /* return address */
    199   lea  4(%esp), %ecx  /* exclude return address from stack */
    200   mov  %edx, MCONTEXT_EIP_OFFSET(%eax)
    201   mov  %ecx, MCONTEXT_ESP_OFFSET(%eax)
    202 
    203   xorl %ecx, %ecx
    204   movw %fs, %cx
    205   mov  %ecx, MCONTEXT_FS_OFFSET(%eax)
    206 
    207   movl $0, MCONTEXT_EAX_OFFSET(%eax)
    208 
    209   /* Save floating point state to fpregstate, then update
    210    * the fpregs pointer to point to it */
    211   leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx
    212   fnstenv (%ecx)
    213   fldenv  (%ecx)
    214   mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax)
    215 
    216   /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */
    217   leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx
    218   xorl %ecx, %ecx
    219   push %edx   /* &uc->uc_sigmask */
    220   push %ecx   /* NULL */
    221   push %ecx   /* SIGBLOCK == 0 on i386 */
    222   call sigprocmask@PLT
    223   addl $12, %esp
    224 
    225   movl $0, %eax
    226   ret
    227 
    228   .size breakpad_getcontext, . - breakpad_getcontext
    229 
    230 #elif defined(__mips__)
    231 
    232 // This implementation is inspired by implementation of getcontext in glibc.
    233 #if _MIPS_SIM == _ABIO32
    234 #include <asm/asm.h>
    235 #include <asm/regdef.h>
    236 #include <asm/fpregdef.h>
    237 #else
    238 #include <machine/asm.h>
    239 #include <machine/regdef.h>
    240 #endif
    241 
    242 // from asm/asm.h
    243 #if _MIPS_SIM == _ABIO32
    244 #define ALSZ 7
    245 #define ALMASK ~7
    246 #define SZREG 4
    247 #else // _MIPS_SIM != _ABIO32
    248 #define ALSZ 15
    249 #define ALMASK ~15
    250 #define SZREG 8
    251 #endif
    252 
    253 #include <asm/unistd.h> // for __NR_rt_sigprocmask
    254 
    255 #define _NSIG8 128 / 8
    256 #define SIG_BLOCK 1
    257 
    258 
    259   .text
    260 LOCALS_NUM = 1 // save gp on stack
    261 FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK
    262 
    263 GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
    264 MCONTEXT_REG_SIZE = 8
    265 
    266 #if _MIPS_SIM == _ABIO32
    267 
    268 NESTED (breakpad_getcontext, FRAME_SIZE, ra)
    269   .mask	0x00000000, 0
    270   .fmask 0x00000000, 0
    271 
    272   .set noreorder
    273   .cpload t9
    274   .set reorder
    275 
    276   move a2, sp
    277 #define _SP a2
    278 
    279   addiu sp, -FRAME_SIZE
    280   .cprestore GP_FRAME_OFFSET
    281 
    282   sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    283   sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    284   sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    285   sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    286   sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    287   sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    288   sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    289   sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    290   sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    291   sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    292   sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    293   sw ra, MCONTEXT_PC_OFFSET(a0)
    294 
    295 #ifdef __mips_hard_float
    296   s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    297   s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    298   s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    299   s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    300   s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    301   s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    302 
    303   cfc1 v1, fcr31
    304   sw v1, MCONTEXT_FPC_CSR(a0)
    305 #endif  // __mips_hard_float
    306 
    307   /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
    308   li a3, _NSIG8
    309   addu a2, a0, UCONTEXT_SIGMASK_OFFSET
    310   move a1, zero
    311   li a0, SIG_BLOCK
    312   li v0, __NR_rt_sigprocmask
    313   syscall
    314 
    315   addiu sp, FRAME_SIZE
    316   jr ra
    317 
    318 END (breakpad_getcontext)
    319 #else
    320 
    321 #ifndef NESTED
    322 /*
    323  * NESTED - declare nested routine entry point
    324  */
    325 #define NESTED(symbol, framesize, rpc)  \
    326     .globl  symbol;                     \
    327     .align  2;                          \
    328     .type symbol,@function;             \
    329     .ent  symbol,0;                     \
    330 symbol:   .frame  sp, framesize, rpc;
    331 #endif
    332 
    333 /*
    334  * END - mark end of function
    335  */
    336 #ifndef END
    337 # define END(function)                  \
    338     .end  function;                     \
    339     .size function,.-function
    340 #endif
    341 
    342 /* int getcontext (ucontext_t *ucp) */
    343 
    344 NESTED (breakpad_getcontext, FRAME_SIZE, ra)
    345   .mask   0x10000000, 0
    346   .fmask  0x00000000, 0
    347 
    348   move  a2, sp
    349 #define _SP a2
    350   move  a3, gp
    351 #define _GP a3
    352 
    353   daddiu sp, -FRAME_SIZE
    354   .cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext
    355 
    356   /* Store a magic flag.  */
    357   li  v1, 1
    358   sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)  /* zero */
    359 
    360   sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    361   sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    362   sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    363   sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    364   sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    365   sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    366   sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    367   sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    368   sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    369   sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    370   sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    371   sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
    372   sd ra, MCONTEXT_PC_OFFSET(a0)
    373 
    374 #ifdef __mips_hard_float
    375   s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    376   s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    377   s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    378   s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    379   s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    380   s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    381   s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    382   s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
    383 
    384   cfc1  v1, $31
    385   sw  v1, MCONTEXT_FPC_CSR(a0)
    386 #endif /* __mips_hard_float */
    387 
    388 /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
    389   li  a3, _NSIG8
    390   daddu a2, a0, UCONTEXT_SIGMASK_OFFSET
    391   move  a1, zero
    392   li  a0, SIG_BLOCK
    393 
    394   li  v0, __NR_rt_sigprocmask
    395   syscall
    396 
    397   .cpreturn
    398   daddiu sp, FRAME_SIZE
    399   move  v0, zero
    400   jr  ra
    401 
    402 END (breakpad_getcontext)
    403 #endif // _MIPS_SIM == _ABIO32
    404 
    405 #elif defined(__x86_64__)
    406 /* The x64 implementation of breakpad_getcontext was derived in part
    407    from the implementation of libunwind which requires the following
    408    notice. */
    409 /* libunwind - a platform-independent unwind library
    410    Copyright (C) 2008 Google, Inc
    411 	Contributed by Paul Pluzhnikov <ppluzhnikov (at) google.com>
    412    Copyright (C) 2010 Konstantin Belousov <kib (at) freebsd.org>
    413 
    414 This file is part of libunwind.
    415 
    416 Permission is hereby granted, free of charge, to any person obtaining
    417 a copy of this software and associated documentation files (the
    418 "Software"), to deal in the Software without restriction, including
    419 without limitation the rights to use, copy, modify, merge, publish,
    420 distribute, sublicense, and/or sell copies of the Software, and to
    421 permit persons to whom the Software is furnished to do so, subject to
    422 the following conditions:
    423 
    424 The above copyright notice and this permission notice shall be
    425 included in all copies or substantial portions of the Software.
    426 
    427 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    428 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    429 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    430 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    431 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    432 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    433 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    434 
    435   .text
    436   .global breakpad_getcontext
    437   .hidden breakpad_getcontext
    438   .align 4
    439   .type breakpad_getcontext, @function
    440 
    441 breakpad_getcontext:
    442   .cfi_startproc
    443 
    444   /* Callee saved: RBX, RBP, R12-R15  */
    445   movq %r12, MCONTEXT_GREGS_R12(%rdi)
    446   movq %r13, MCONTEXT_GREGS_R13(%rdi)
    447   movq %r14, MCONTEXT_GREGS_R14(%rdi)
    448   movq %r15, MCONTEXT_GREGS_R15(%rdi)
    449   movq %rbp, MCONTEXT_GREGS_RBP(%rdi)
    450   movq %rbx, MCONTEXT_GREGS_RBX(%rdi)
    451 
    452   /* Save argument registers (not strictly needed, but setcontext
    453      restores them, so don't restore garbage).  */
    454   movq %r8,  MCONTEXT_GREGS_R8(%rdi)
    455   movq %r9,  MCONTEXT_GREGS_R9(%rdi)
    456   movq %rdi, MCONTEXT_GREGS_RDI(%rdi)
    457   movq %rsi, MCONTEXT_GREGS_RSI(%rdi)
    458   movq %rdx, MCONTEXT_GREGS_RDX(%rdi)
    459   movq %rax, MCONTEXT_GREGS_RAX(%rdi)
    460   movq %rcx, MCONTEXT_GREGS_RCX(%rdi)
    461 
    462   /* Save fp state (not needed, except for setcontext not
    463      restoring garbage).  */
    464   leaq MCONTEXT_FPREGS_MEM(%rdi),%r8
    465   movq %r8, MCONTEXT_FPREGS_PTR(%rdi)
    466   fnstenv (%r8)
    467   stmxcsr FPREGS_OFFSET_MXCSR(%r8)
    468 
    469   leaq 8(%rsp), %rax /* exclude this call.  */
    470   movq %rax, MCONTEXT_GREGS_RSP(%rdi)
    471 
    472   movq 0(%rsp), %rax
    473   movq %rax, MCONTEXT_GREGS_RIP(%rdi)
    474 
    475   /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */
    476   leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx  // arg3
    477   xorq %rsi, %rsi  // arg2 NULL
    478   xorq %rdi, %rdi  // arg1 SIGBLOCK == 0
    479   call sigprocmask@PLT
    480 
    481   /* Always return 0 for success, even if sigprocmask failed. */
    482   xorl %eax, %eax
    483   ret
    484   .cfi_endproc
    485   .size breakpad_getcontext, . - breakpad_getcontext
    486 
    487 #else
    488 #error "This file has not been ported for your CPU!"
    489 #endif
    490