Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- A minimal setjmp/longjmp implementation.      m_libcsetjmp.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2010-2013 Mozilla Inc
     11 
     12    This program is free software; you can redistribute it and/or
     13    modify it under the terms of the GNU General Public License as
     14    published by the Free Software Foundation; either version 2 of the
     15    License, or (at your option) any later version.
     16 
     17    This program is distributed in the hope that it will be useful, but
     18    WITHOUT ANY WARRANTY; without even the implied warranty of
     19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     20    General Public License for more details.
     21 
     22    You should have received a copy of the GNU General Public License
     23    along with this program; if not, write to the Free Software
     24    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     25    02111-1307, USA.
     26 
     27    The GNU General Public License is contained in the file COPYING.
     28 */
     29 
     30 /* Contributed by Julian Seward <jseward (at) acm.org> */
     31 
     32 
     33 #include "pub_core_basics.h"
     34 #include "pub_core_libcsetjmp.h"    /* self */
     35 
     36 
     37 /* See include/pub_tool_libcsetjmp.h for background and rationale. */
     38 
     39 /* The alternative implementations are for ppc{32,64}-linux and
     40    {amd64,x86}-{linux,darwin}.  See #259977.  That leaves only
     41    {arm,s390x}-linux using the gcc builtins now.
     42 */
     43 
     44 /* ------------ ppc32-linux ------------ */
     45 
     46 #if defined(VGP_ppc32_linux)
     47 
     48 __asm__(
     49 ".text"  "\n"
     50 ""       "\n"
     51 ".global VG_MINIMAL_SETJMP"  "\n"  // r3 = jmp_buf
     52 "VG_MINIMAL_SETJMP:"  "\n"
     53 "        stw     0, 0(3)"  "\n"
     54 "        stw     1, 4(3)"  "\n"
     55 "        stw     2, 8(3)"  "\n"
     56 "        stw     3, 12(3)"  "\n"
     57 "        stw     4, 16(3)"  "\n"
     58 "        stw     5, 20(3)"  "\n"
     59 "        stw     6, 24(3)"  "\n"
     60 "        stw     7, 28(3)"  "\n"
     61 "        stw     8, 32(3)"  "\n"
     62 "        stw     9, 36(3)"  "\n"
     63 "        stw     10, 40(3)"  "\n"
     64 "        stw     11, 44(3)"  "\n"
     65 "        stw     12, 48(3)"  "\n"
     66 "        stw     13, 52(3)"  "\n"
     67 "        stw     14, 56(3)"  "\n"
     68 "        stw     15, 60(3)"  "\n"
     69 "        stw     16, 64(3)"  "\n"
     70 "        stw     17, 68(3)"  "\n"
     71 "        stw     18, 72(3)"  "\n"
     72 "        stw     19, 76(3)"  "\n"
     73 "        stw     20, 80(3)"  "\n"
     74 "        stw     21, 84(3)"  "\n"
     75 "        stw     22, 88(3)"  "\n"
     76 "        stw     23, 92(3)"  "\n"
     77 "        stw     24, 96(3)"  "\n"
     78 "        stw     25, 100(3)"  "\n"
     79 "        stw     26, 104(3)"  "\n"
     80 "        stw     27, 108(3)"  "\n"
     81 "        stw     28, 112(3)"  "\n"
     82 "        stw     29, 116(3)"  "\n"
     83 "        stw     30, 120(3)"  "\n"
     84 "        stw     31, 124(3)"  "\n"
     85          // must use a caller-save register here as scratch, hence r4
     86 "        mflr    4"  "\n"
     87 "        stw     4, 128(3)"  "\n"
     88 "        mfcr    4"  "\n"
     89 "        stw     4, 132(3)"  "\n"
     90 "        li      3, 0"  "\n"
     91 "        blr"  "\n"
     92 ""       "\n"
     93 
     94 
     95 ".global VG_MINIMAL_LONGJMP"  "\n"
     96 "VG_MINIMAL_LONGJMP:"  "\n"    // r3 = jmp_buf
     97          // do r4 = 1
     98          // and park it in the restore slot for r3 (the ret reg)
     99 "        li      4, 1"  "\n"
    100 "        stw     4, 12(3)"  "\n"
    101          // restore everything except r3
    102          // then r3 last of all
    103          // then blr
    104 "        lwz     0, 128(3)"  "\n"
    105 "        mtlr    0"  "\n"
    106 "        lwz     0, 132(3)"  "\n"
    107 "        mtcr    0"  "\n"
    108 "        lwz     0, 0(3)"  "\n"
    109 "        lwz     1, 4(3)"  "\n"
    110 "        lwz     2, 8(3)"  "\n"
    111          // r3 is done at the end
    112 "        lwz     4, 16(3)"  "\n"
    113 "        lwz     5, 20(3)"  "\n"
    114 "        lwz     6, 24(3)"  "\n"
    115 "        lwz     7, 28(3)"  "\n"
    116 "        lwz     8, 32(3)"  "\n"
    117 "        lwz     9, 36(3)"  "\n"
    118 "        lwz     10, 40(3)"  "\n"
    119 "        lwz     11, 44(3)"  "\n"
    120 "        lwz     12, 48(3)"  "\n"
    121 "        lwz     13, 52(3)"  "\n"
    122 "        lwz     14, 56(3)"  "\n"
    123 "        lwz     15, 60(3)"  "\n"
    124 "        lwz     16, 64(3)"  "\n"
    125 "        lwz     17, 68(3)"  "\n"
    126 "        lwz     18, 72(3)"  "\n"
    127 "        lwz     19, 76(3)"  "\n"
    128 "        lwz     20, 80(3)"  "\n"
    129 "        lwz     21, 84(3)"  "\n"
    130 "        lwz     22, 88(3)"  "\n"
    131 "        lwz     23, 92(3)"  "\n"
    132 "        lwz     24, 96(3)"  "\n"
    133 "        lwz     25, 100(3)"  "\n"
    134 "        lwz     26, 104(3)"  "\n"
    135 "        lwz     27, 108(3)"  "\n"
    136 "        lwz     28, 112(3)"  "\n"
    137 "        lwz     29, 116(3)"  "\n"
    138 "        lwz     30, 120(3)"  "\n"
    139 "        lwz     31, 124(3)"  "\n"
    140 "        lwz     3, 12(3)"  "\n"
    141 "        blr"  "\n"
    142 ""       "\n"
    143 
    144 ".previous"  "\n"
    145 );
    146 
    147 #endif /* VGP_ppc32_linux */
    148 
    149 
    150 /* ------------ ppc64-linux ------------ */
    151 
    152 #if defined(VGP_ppc64_linux)
    153 
    154 __asm__(
    155 ".section \".toc\",\"aw\""          "\n"
    156 
    157 ".section \".text\""                "\n"
    158 ".align 2"                          "\n"
    159 ".p2align 4,,15"                    "\n"
    160 ".globl VG_MINIMAL_SETJMP"          "\n"
    161 
    162 ".section \".opd\",\"aw\""          "\n"
    163 ".align 3"                          "\n"
    164 "VG_MINIMAL_SETJMP:"                "\n"
    165 ".quad .L.VG_MINIMAL_SETJMP,.TOC.@tocbase,0"   "\n"
    166 ".previous"                         "\n"
    167 
    168 ".type VG_MINIMAL_SETJMP, @function"   "\n"
    169 ".L.VG_MINIMAL_SETJMP:"   "\n"
    170 "        std     0, 0(3)"  "\n"
    171 "        std     1, 8(3)"  "\n"
    172 "        std     2, 16(3)"  "\n"
    173 "        std     3, 24(3)"  "\n"
    174 "        std     4, 32(3)"  "\n"
    175 "        std     5, 40(3)"  "\n"
    176 "        std     6, 48(3)"  "\n"
    177 "        std     7, 56(3)"  "\n"
    178 "        std     8, 64(3)"  "\n"
    179 "        std     9, 72(3)"  "\n"
    180 "        std     10, 80(3)"  "\n"
    181 "        std     11, 88(3)"  "\n"
    182 "        std     12, 96(3)"  "\n"
    183 "        std     13, 104(3)"  "\n"
    184 "        std     14, 112(3)"  "\n"
    185 "        std     15, 120(3)"  "\n"
    186 "        std     16, 128(3)"  "\n"
    187 "        std     17, 136(3)"  "\n"
    188 "        std     18, 144(3)"  "\n"
    189 "        std     19, 152(3)"  "\n"
    190 "        std     20, 160(3)"  "\n"
    191 "        std     21, 168(3)"  "\n"
    192 "        std     22, 176(3)"  "\n"
    193 "        std     23, 184(3)"  "\n"
    194 "        std     24, 192(3)"  "\n"
    195 "        std     25, 200(3)"  "\n"
    196 "        std     26, 208(3)"  "\n"
    197 "        std     27, 216(3)"  "\n"
    198 "        std     28, 224(3)"  "\n"
    199 "        std     29, 232(3)"  "\n"
    200 "        std     30, 240(3)"  "\n"
    201 "        std     31, 248(3)"  "\n"
    202          // must use a caller-save register here as scratch, hence r4
    203 "        mflr    4"  "\n"
    204 "        std     4, 256(3)"  "\n"
    205 "        mfcr    4"  "\n"
    206 "        std     4, 264(3)"  "\n"
    207 "        li      3, 0"  "\n"
    208 "        blr"  "\n"
    209 ""       "\n"
    210 
    211 
    212 ".globl VG_MINIMAL_LONGJMP"         "\n"
    213 
    214 ".section \".opd\",\"aw\""          "\n"
    215 ".align 3"                          "\n"
    216 "VG_MINIMAL_LONGJMP:"               "\n"
    217 ".quad .L.VG_MINIMAL_LONGJMP,.TOC.@tocbase,0"   "\n"
    218 ".previous" "\n"
    219 
    220 ".type   VG_MINIMAL_LONGJMP, @function"    "\n"
    221 ".L.VG_MINIMAL_LONGJMP:"            "\n"
    222          // do r4 = 1
    223          // and park it in the restore slot for r3 (the ret reg)
    224 "        li      4, 1"  "\n"
    225 "        std     4, 24(3)"  "\n"
    226          // restore everything except r3
    227          // then r3 last of all
    228          // then blr
    229 "        ld      0, 256(3)"  "\n"
    230 "        mtlr    0"  "\n"
    231 "        ld      0, 264(3)"  "\n"
    232 "        mtcr    0"  "\n"
    233 "        ld      0, 0(3)"  "\n"
    234 "        ld      1, 8(3)"  "\n"
    235 "        ld      2, 16(3)"  "\n"
    236          // r3 is done at the end
    237 "        ld      4, 32(3)"  "\n"
    238 "        ld      5, 40(3)"  "\n"
    239 "        ld      6, 48(3)"  "\n"
    240 "        ld      7, 56(3)"  "\n"
    241 "        ld      8, 64(3)"  "\n"
    242 "        ld      9, 72(3)"  "\n"
    243 "        ld      10, 80(3)"  "\n"
    244 "        ld      11, 88(3)"  "\n"
    245 "        ld      12, 96(3)"  "\n"
    246 "        ld      13, 104(3)"  "\n"
    247 "        ld      14, 112(3)"  "\n"
    248 "        ld      15, 120(3)"  "\n"
    249 "        ld      16, 128(3)"  "\n"
    250 "        ld      17, 136(3)"  "\n"
    251 "        ld      18, 144(3)"  "\n"
    252 "        ld      19, 152(3)"  "\n"
    253 "        ld      20, 160(3)"  "\n"
    254 "        ld      21, 168(3)"  "\n"
    255 "        ld      22, 176(3)"  "\n"
    256 "        ld      23, 184(3)"  "\n"
    257 "        ld      24, 192(3)"  "\n"
    258 "        ld      25, 200(3)"  "\n"
    259 "        ld      26, 208(3)"  "\n"
    260 "        ld      27, 216(3)"  "\n"
    261 "        ld      28, 224(3)"  "\n"
    262 "        ld      29, 232(3)"  "\n"
    263 "        ld      30, 240(3)"  "\n"
    264 "        ld      31, 248(3)"  "\n"
    265 "        ld      3, 24(3)"  "\n"
    266 "        blr"               "\n"
    267 ""       "\n"
    268 
    269 ".previous"  "\n"
    270 ".previous"  "\n"
    271 );
    272 
    273 #endif /* VGP_ppc64_linux */
    274 
    275 
    276 /* ------------ amd64-{linux,darwin} ------------ */
    277 
    278 #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
    279 
    280 __asm__(
    281 ".text"  "\n"
    282 ""       "\n"
    283 
    284 #if defined(VGP_amd64_linux)
    285 ".global VG_MINIMAL_SETJMP"  "\n"  // rdi = jmp_buf
    286 "VG_MINIMAL_SETJMP:"  "\n"
    287 
    288 #elif defined(VGP_amd64_darwin)
    289 ".globl _VG_MINIMAL_SETJMP"  "\n"  // rdi = jmp_buf
    290 "_VG_MINIMAL_SETJMP:"  "\n"
    291 
    292 #else
    293 #   error "Huh?"
    294 #endif
    295 
    296 "        movq   %rax,   0(%rdi)"   "\n"
    297 "        movq   %rbx,   8(%rdi)"   "\n"
    298 "        movq   %rcx,  16(%rdi)"   "\n"
    299 "        movq   %rdx,  24(%rdi)"   "\n"
    300 "        movq   %rdi,  32(%rdi)"   "\n"
    301 "        movq   %rsi,  40(%rdi)"   "\n"
    302 "        movq   %rbp,  48(%rdi)"   "\n"
    303 "        movq   %rsp,  56(%rdi)"   "\n"
    304 "        movq   %r8,   64(%rdi)"   "\n"
    305 "        movq   %r9,   72(%rdi)"   "\n"
    306 "        movq   %r10,  80(%rdi)"   "\n"
    307 "        movq   %r11,  88(%rdi)"   "\n"
    308 "        movq   %r12,  96(%rdi)"   "\n"
    309 "        movq   %r13, 104(%rdi)"   "\n"
    310 "        movq   %r14, 112(%rdi)"   "\n"
    311 "        movq   %r15, 120(%rdi)"   "\n"
    312          // store the return address
    313 "        movq   0(%rsp), %rax"     "\n"
    314 "        movq   %rax, 128(%rdi)"   "\n"
    315          // and return zero
    316 "        movq   $0, %rax"          "\n"
    317 "        ret"                      "\n"
    318 ""       "\n"
    319 
    320 
    321 #if defined(VGP_amd64_linux)
    322 ".global VG_MINIMAL_LONGJMP"  "\n"
    323 "VG_MINIMAL_LONGJMP:"  "\n"    // rdi = jmp_buf
    324 
    325 #elif defined(VGP_amd64_darwin)
    326 ".globl _VG_MINIMAL_LONGJMP"  "\n"
    327 "_VG_MINIMAL_LONGJMP:"  "\n"    // rdi = jmp_buf
    328 
    329 #else
    330 #   error "Huh?"
    331 #endif
    332          // skip restoring rax; it's pointless
    333 "        movq     8(%rdi),  %rbx"    "\n"
    334 "        movq    16(%rdi),  %rcx"    "\n"
    335 "        movq    24(%rdi),  %rdx"    "\n"
    336          // defer restoring rdi; we still need it
    337 "        movq    40(%rdi),  %rsi"    "\n"
    338 "        movq    48(%rdi),  %rbp"    "\n"
    339 "        movq    56(%rdi),  %rsp"    "\n"
    340 "        movq    64(%rdi),  %r8"     "\n"
    341 "        movq    72(%rdi),  %r9"     "\n"
    342 "        movq    80(%rdi),  %r10"    "\n"
    343 "        movq    88(%rdi),  %r11"    "\n"
    344 "        movq    96(%rdi),  %r12"    "\n"
    345 "        movq   104(%rdi),  %r13"    "\n"
    346 "        movq   112(%rdi),  %r14"    "\n"
    347 "        movq   120(%rdi),  %r15"    "\n"
    348          // restore the return address
    349 "        movq   128(%rdi), %rax"     "\n"
    350          // restore rdi; this is the last use
    351 "        movq   32(%rdi), %rdi"      "\n"
    352          // make %rsp look like we really did a return
    353 "        addq   $8, %rsp"            "\n"
    354          // continue at RA of original call.  Note: this is a
    355          // nasty trick.  We assume that %rax is nonzero, and so the
    356          // caller can differentiate this case from the normal _SETJMP
    357          // return case.  If the return address ever is zero, then
    358          // we're hosed; but that seems pretty unlikely given that it
    359          // would mean we'd be executing at the wraparound point of the
    360          // address space.
    361 "        jmp *%rax"                  "\n"
    362 ""       "\n"
    363 
    364 #if !defined(VGP_amd64_darwin)
    365 ".previous"       "\n"
    366 #endif
    367 );
    368 
    369 #endif /* VGP_amd64_linux || VGP_amd64_darwin */
    370 
    371 
    372 /* ------------ x86-{linux,darwin} ------------ */
    373 
    374 #if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
    375 
    376 __asm__(
    377 ".text"  "\n"
    378 ""       "\n"
    379 
    380 #if defined(VGP_x86_linux)
    381 ".global VG_MINIMAL_SETJMP"  "\n"  // eax = jmp_buf
    382 "VG_MINIMAL_SETJMP:"  "\n"
    383 
    384 #elif defined(VGP_x86_darwin)
    385 ".globl _VG_MINIMAL_SETJMP"  "\n"  // eax = jmp_buf
    386 "_VG_MINIMAL_SETJMP:"  "\n"
    387 
    388 #else
    389 #   error "Huh?"
    390 #endif
    391 
    392 "        movl   %eax,   0(%eax)"   "\n"
    393 "        movl   %ebx,   4(%eax)"   "\n"
    394 "        movl   %ecx,   8(%eax)"   "\n"
    395 "        movl   %edx,  12(%eax)"   "\n"
    396 "        movl   %edi,  16(%eax)"   "\n"
    397 "        movl   %esi,  20(%eax)"   "\n"
    398 "        movl   %ebp,  24(%eax)"   "\n"
    399 "        movl   %esp,  28(%eax)"   "\n"
    400          // store the return address
    401 "        movl   0(%esp), %ebx"     "\n"
    402 "        movl   %ebx, 32(%eax)"    "\n"
    403          // un-trash ebx (necessary?  i don't know)
    404 "        movl   4(%eax), %ebx"     "\n"
    405          // and return zero
    406 "        movl   $0, %eax"          "\n"
    407 "        ret"                      "\n"
    408 ""       "\n"
    409 
    410 
    411 #if defined(VGP_x86_linux)
    412 ".global VG_MINIMAL_LONGJMP"  "\n"
    413 "VG_MINIMAL_LONGJMP:"  "\n"    // eax = jmp_buf
    414 
    415 #elif defined(VGP_x86_darwin)
    416 ".globl _VG_MINIMAL_LONGJMP"  "\n"
    417 "_VG_MINIMAL_LONGJMP:"  "\n"    // eax = jmp_buf
    418 
    419 #else
    420 #   error "Huh?"
    421 #endif
    422 
    423          // skip restoring eax; it's pointless
    424 "        movl     4(%eax),  %ebx"    "\n"
    425 "        movl     8(%eax),  %ecx"    "\n"
    426 "        movl    12(%eax),  %edx"    "\n"
    427 "        movl    16(%eax),  %edi"    "\n"
    428 "        movl    20(%eax),  %esi"    "\n"
    429 "        movl    24(%eax),  %ebp"    "\n"
    430 "        movl    28(%eax),  %esp"    "\n"
    431          // restore the return address
    432 "        movl    32(%eax), %eax"     "\n"
    433          // make %esp look like we really did a return
    434 "        addl    $4, %esp"           "\n"
    435          // continue at RA of original call.  Same zero-vs-nonzero
    436          // trick/assumption as documented for the amd64-linux case.
    437 "        jmp *%eax"                  "\n"
    438 ""       "\n"
    439 
    440 #if !defined(VGP_x86_darwin)
    441 ".previous"       "\n"
    442 #endif
    443 );
    444 
    445 #endif /* VGP_x86_linux || VGP_x86_darwin */
    446 
    447 #if defined(VGP_mips32_linux)
    448 
    449 __asm__(
    450 ".text                          \n\t"
    451 ".globl VG_MINIMAL_SETJMP;      \n\t"
    452 ".align 2;                      \n\t"
    453 "VG_MINIMAL_SETJMP:             \n\t"  /* a0 = jmp_buf */
    454 "   sw   $s0,  0($a0)           \n\t"  /* Save registers s0-s7. */
    455 "   sw   $s1,  4($a0)           \n\t"
    456 "   sw   $s2,  8($a0)           \n\t"
    457 "   sw   $s3, 12($a0)           \n\t"
    458 "   sw   $s4, 16($a0)           \n\t"
    459 "   sw   $s5, 20($a0)           \n\t"
    460 "   sw   $s6, 24($a0)           \n\t"
    461 "   sw   $s7, 28($a0)           \n\t"
    462 "   sw   $s8, 32($a0)           \n\t"  /* Frame pointer. */
    463 "   sw   $ra, 36($a0)           \n\t"  /* Return address. */
    464 "   sw   $gp, 40($a0)           \n\t"  /* Global data pointer. */
    465 "   sw   $sp, 44($a0)           \n\t"  /* Stack pointer. */
    466 
    467 "   move $v0, $zero             \n\t"  /* Return zero. */
    468 "   j    $ra                    \n\t"
    469 "   nop                         \n\t"
    470 ".previous                      \n\t"
    471 "                               \n\t"
    472 ".globl VG_MINIMAL_LONGJMP;     \n\t"
    473 ".align 2;                      \n\t"
    474 "VG_MINIMAL_LONGJMP:            \n\t"  /* a0 = jmp_buf */
    475 "   lw   $s0,  0($a0)           \n\t"  /* Restore registers s0-s7. */
    476 "   lw   $s1,  4($a0)           \n\t"
    477 "   lw   $s2,  8($a0)           \n\t"
    478 "   lw   $s3, 12($a0)           \n\t"
    479 "   lw   $s4, 16($a0)           \n\t"
    480 "   lw   $s5, 20($a0)           \n\t"
    481 "   lw   $s6, 24($a0)           \n\t"
    482 "   lw   $s7, 28($a0)           \n\t"
    483 "   lw   $s8, 32($a0)           \n\t"  /* Frame pointer. */
    484 "   lw   $ra, 36($a0)           \n\t"  /* Return address. */
    485 "   lw   $gp, 40($a0)           \n\t"  /* Global data pointer. */
    486 "   lw   $sp, 44($a0)           \n\t"  /* Stack pointer. */
    487 
    488 /* Checking whether second argument is zero. */
    489 "   bnez $a1, 1f                \n\t"
    490 "   nop                         \n\t"
    491 "   addi $a1, $a1, 1            \n\t"  /* We must return 1 if val=0. */
    492 "1:                             \n\t"
    493 "   move $v0, $a1               \n\t"  /* Return value of second argument. */
    494 "   j    $ra                    \n\t"
    495 "   nop                         \n\t"
    496 ".previous                      \n\t"
    497 );
    498 #endif  /* VGP_mips32_linux */
    499 
    500 /*--------------------------------------------------------------------*/
    501 /*--- end                                                          ---*/
    502 /*--------------------------------------------------------------------*/
    503