Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 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 copyright |
| 11 | * notice, this list of conditions and the following disclaimer in |
| 12 | * the documentation and/or other materials provided with the |
| 13 | * distribution. |
| 14 | * |
| 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 26 | * SUCH DAMAGE. |
| 27 | */ |
| 28 | |
| 29 | #include <private/bionic_asm.h> |
| 30 | #include <private/bionic_constants.h> |
| 31 | |
| 32 | // The internal structure of a jmp_buf is totally private. |
| 33 | // Current layout (changes from release to release): |
| 34 | // |
| 35 | // word name description |
| 36 | // 0 sigflag/cookie setjmp cookie in top 31 bits, signal mask flag in low bit |
| 37 | // 1 sigmask 64-bit signal mask |
| 38 | // 2 ra |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 39 | // 3 sp |
| 40 | // 4 gp |
| 41 | // 5 s0 |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 42 | // ...... |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 43 | // 16 s11 |
| 44 | // 17 fs0 |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 45 | // ...... |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 46 | // 28 fs11 |
| 47 | // 29 checksum |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 48 | // _JBLEN: defined in bionic/libc/include/setjmp.h |
| 49 | |
| 50 | #define _JB_SIGFLAG 0 |
| 51 | #define _JB_SIGMASK 1 * 8 |
| 52 | #define _JB_RA 2 * 8 |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 53 | #define _JB_SP 3 * 8 |
| 54 | #define _JB_GP 4 * 8 |
| 55 | #define _JB_S0 5 * 8 |
| 56 | #define _JB_S1 6 * 8 |
| 57 | #define _JB_S2 7 * 8 |
| 58 | #define _JB_S3 8 * 8 |
| 59 | #define _JB_S4 9 * 8 |
| 60 | #define _JB_S5 10 * 8 |
| 61 | #define _JB_S6 11 * 8 |
| 62 | #define _JB_S7 12 * 8 |
| 63 | #define _JB_S8 13 * 8 |
| 64 | #define _JB_S9 14 * 8 |
| 65 | #define _JB_S10 15 * 8 |
| 66 | #define _JB_S11 16 * 8 |
| 67 | #define _JB_FS0 17 * 8 |
| 68 | #define _JB_FS1 18 * 8 |
| 69 | #define _JB_FS2 19 * 8 |
| 70 | #define _JB_FS3 20 * 8 |
| 71 | #define _JB_FS4 21 * 8 |
| 72 | #define _JB_FS5 22 * 8 |
| 73 | #define _JB_FS6 23 * 8 |
| 74 | #define _JB_FS7 24 * 8 |
| 75 | #define _JB_FS8 25 * 8 |
| 76 | #define _JB_FS9 26 * 8 |
| 77 | #define _JB_FS10 27 * 8 |
| 78 | #define _JB_FS11 28 * 8 |
| 79 | #define _JB_CHECKSUM 29 * 8 |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 80 | |
| 81 | .macro m_mangle_registers reg, sp_reg |
| 82 | xor s0, s0, \reg |
| 83 | xor s1, s1, \reg |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 84 | xor s2, s2, \reg |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 85 | xor s3, s3, \reg |
| 86 | xor s4, s4, \reg |
| 87 | xor s5, s5, \reg |
| 88 | xor s6, s6, \reg |
| 89 | xor s7, s7, \reg |
| 90 | xor s8, s8, \reg |
| 91 | xor s9, s9, \reg |
| 92 | xor s10, s10, \reg |
| 93 | xor s11, s11, \reg |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 94 | xor a4, a4, \reg // a4 is the masked gp (x3) for SCS. |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 95 | xor \sp_reg, \sp_reg, \reg |
| 96 | .endm |
| 97 | |
| 98 | .macro m_calculate_checksum dst, src, scratch |
| 99 | li \dst, 0 |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 100 | .irp i,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 101 | ld \scratch, (\i * 8)(\src) |
| 102 | xor \dst, \dst, \scratch |
| 103 | .endr |
| 104 | .endm |
| 105 | |
| 106 | .macro m_unmangle_registers reg, sp_reg |
| 107 | m_mangle_registers \reg, sp_reg=\sp_reg |
| 108 | .endm |
| 109 | |
Elliott Hughes | d783120 | 2024-01-19 20:55:31 +0000 | [diff] [blame] | 110 | ENTRY_WEAK_FOR_NATIVE_BRIDGE(setjmp) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 111 | li a1, 1 |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 112 | tail sigsetjmp |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 113 | END(setjmp) |
| 114 | |
Elliott Hughes | d783120 | 2024-01-19 20:55:31 +0000 | [diff] [blame] | 115 | ENTRY_WEAK_FOR_NATIVE_BRIDGE(_setjmp) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 116 | li a1, 0 |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 117 | tail sigsetjmp |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 118 | END(_setjmp) |
| 119 | |
| 120 | // int sigsetjmp(sigjmp_buf env, int save_signal_mask); |
Elliott Hughes | d783120 | 2024-01-19 20:55:31 +0000 | [diff] [blame] | 121 | ENTRY_WEAK_FOR_NATIVE_BRIDGE(sigsetjmp) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 122 | addi sp, sp, -24 |
| 123 | sd a0, 0(sp) |
| 124 | sd a1, 8(sp) |
| 125 | sd ra, 16(sp) |
| 126 | |
| 127 | // Get the cookie and store it along with the signal flag. |
| 128 | mv a0, a1 |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 129 | call __bionic_setjmp_cookie_get |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 130 | mv a1, a0 |
| 131 | ld a0, 0(sp) |
| 132 | sd a1, _JB_SIGFLAG(a0) |
| 133 | |
| 134 | // Do we need to save the signal mask? |
| 135 | andi a1, a1, 1 |
| 136 | beqz a1, 1f |
| 137 | |
| 138 | // Save current signal mask. |
| 139 | // The 'how'/a0 argument is ignored if set is NULL. |
| 140 | li a1, 0 // NULL |
| 141 | addi a2, a0, _JB_SIGMASK // old_mask. |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 142 | call sigprocmask |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 143 | |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 144 | 1: |
Elliott Hughes | 45a8486 | 2022-10-18 23:04:12 +0000 | [diff] [blame] | 145 | // Restore original a0/ra. |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 146 | ld a0, 0(sp) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 147 | ld ra, 16(sp) |
| 148 | addi sp, sp, 24 |
| 149 | |
Elliott Hughes | 45a8486 | 2022-10-18 23:04:12 +0000 | [diff] [blame] | 150 | // Get the cookie. |
| 151 | ld a1, _JB_SIGFLAG(a0) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 152 | andi a1, a1, -2 |
| 153 | |
Elliott Hughes | 9a7155d | 2023-02-10 02:00:03 +0000 | [diff] [blame] | 154 | // Mask off the high bits of the shadow call stack pointer. |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 155 | // We only store the low bits of gp to avoid leaking the |
Elliott Hughes | 9a7155d | 2023-02-10 02:00:03 +0000 | [diff] [blame] | 156 | // shadow call stack address into memory. |
| 157 | // See the SCS commentary in pthread_internal.h for more detail. |
| 158 | li a4, SCS_MASK |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 159 | and a4, a4, gp |
Elliott Hughes | 9a7155d | 2023-02-10 02:00:03 +0000 | [diff] [blame] | 160 | |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 161 | // Save core registers. |
| 162 | mv a2, sp |
| 163 | m_mangle_registers a1, sp_reg=a2 |
| 164 | sd ra, _JB_RA(a0) |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 165 | sd a4, _JB_GP(a0) // a4 is the masked gp (x3) for SCS. |
| 166 | sd a2, _JB_SP(a0) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 167 | sd s0, _JB_S0(a0) |
| 168 | sd s1, _JB_S1(a0) |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 169 | sd s2, _JB_S2(a0) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 170 | sd s3, _JB_S3(a0) |
| 171 | sd s4, _JB_S4(a0) |
| 172 | sd s5, _JB_S5(a0) |
| 173 | sd s6, _JB_S6(a0) |
| 174 | sd s7, _JB_S7(a0) |
| 175 | sd s8, _JB_S8(a0) |
| 176 | sd s9, _JB_S9(a0) |
| 177 | sd s10, _JB_S10(a0) |
| 178 | sd s11, _JB_S11(a0) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 179 | m_unmangle_registers a1, sp_reg=a2 |
| 180 | |
| 181 | // Save floating point registers. |
| 182 | fsd fs0, _JB_FS0(a0) |
| 183 | fsd fs1, _JB_FS1(a0) |
| 184 | fsd fs2, _JB_FS2(a0) |
| 185 | fsd fs3, _JB_FS3(a0) |
| 186 | fsd fs4, _JB_FS4(a0) |
| 187 | fsd fs5, _JB_FS5(a0) |
| 188 | fsd fs6, _JB_FS6(a0) |
| 189 | fsd fs7, _JB_FS7(a0) |
| 190 | fsd fs8, _JB_FS8(a0) |
| 191 | fsd fs9, _JB_FS9(a0) |
| 192 | fsd fs10, _JB_FS10(a0) |
| 193 | fsd fs11, _JB_FS11(a0) |
| 194 | |
| 195 | // Calculate the checksum and save it. |
| 196 | m_calculate_checksum t0, a0, t1 |
| 197 | sd t0, _JB_CHECKSUM(a0) |
| 198 | |
| 199 | li a0, 0 |
| 200 | ret |
| 201 | END(sigsetjmp) |
| 202 | |
| 203 | // void siglongjmp(sigjmp_buf env, int value); |
Elliott Hughes | d783120 | 2024-01-19 20:55:31 +0000 | [diff] [blame] | 204 | ENTRY_WEAK_FOR_NATIVE_BRIDGE(siglongjmp) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 205 | // Check the checksum before doing anything. |
| 206 | m_calculate_checksum t0, a0, t1 |
| 207 | ld t1, _JB_CHECKSUM(a0) |
Elliott Hughes | 9e89249 | 2024-04-08 16:32:25 +0000 | [diff] [blame] | 208 | bne t0, t1, L(checksum_failure) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 209 | |
| 210 | // Do we need to restore the signal mask? |
| 211 | ld a2, _JB_SIGFLAG(a0) |
| 212 | andi a3, a2, 1 |
| 213 | beqz a3, 1f |
| 214 | |
| 215 | addi sp, sp, -16 |
| 216 | sd a0, 0(sp) |
| 217 | sd ra, 8(sp) |
| 218 | |
| 219 | // Restore the signal mask. |
| 220 | mv t0, a1 // Save 'value'. |
| 221 | |
| 222 | mv a2, a0 |
| 223 | li a0, 2 // SIG_SETMASK |
| 224 | addi a1, a2, _JB_SIGMASK // new_mask |
| 225 | li a2, 0 // NULL |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 226 | call sigprocmask |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 227 | mv a1, t0 // Restore 'value'. |
| 228 | |
| 229 | // Restore original a0 and ra. |
| 230 | ld a0, 0(sp) |
| 231 | ld ra, 8(sp) |
| 232 | addi sp, sp, 16 |
| 233 | |
| 234 | ld a2, _JB_SIGFLAG(a0) |
| 235 | 1: |
| 236 | // Restore core registers. |
| 237 | andi a2, a2, -2 |
| 238 | ld ra, _JB_RA(a0) |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 239 | ld a4, _JB_GP(a0) // Don't clobber the upper bits of gp (x3) used for SCS yet. |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 240 | ld s0, _JB_S0(a0) |
| 241 | ld s1, _JB_S1(a0) |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 242 | ld s2, _JB_S2(a0) |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 243 | ld s3, _JB_S3(a0) |
| 244 | ld s4, _JB_S4(a0) |
| 245 | ld s5, _JB_S5(a0) |
| 246 | ld s6, _JB_S6(a0) |
| 247 | ld s7, _JB_S7(a0) |
| 248 | ld s8, _JB_S8(a0) |
| 249 | ld s9, _JB_S9(a0) |
| 250 | ld s10, _JB_S10(a0) |
| 251 | ld s11, _JB_S11(a0) |
| 252 | ld a3, _JB_SP(a0) |
| 253 | m_unmangle_registers a2, sp_reg=a3 |
| 254 | mv sp, a3 |
| 255 | |
Elliott Hughes | 9a7155d | 2023-02-10 02:00:03 +0000 | [diff] [blame] | 256 | // Restore the low bits of the shadow call stack pointer. |
| 257 | li a5, ~SCS_MASK |
Elliott Hughes | 7dd3896 | 2023-04-06 14:50:31 -0700 | [diff] [blame] | 258 | and gp, gp, a5 |
| 259 | or gp, gp, a4 |
Elliott Hughes | 9a7155d | 2023-02-10 02:00:03 +0000 | [diff] [blame] | 260 | |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 261 | addi sp, sp, -24 |
| 262 | sd ra, 0(sp) |
| 263 | sd a0, 8(sp) |
| 264 | sd a1, 16(sp) |
| 265 | ld a0, _JB_SIGFLAG(a0) |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 266 | call __bionic_setjmp_cookie_check |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 267 | ld ra, 0(sp) |
| 268 | ld a0, 8(sp) |
| 269 | ld a1, 16(sp) |
| 270 | addi sp, sp, 24 |
| 271 | |
| 272 | // Restore floating point registers. |
| 273 | fld fs0, _JB_FS0(a0) |
| 274 | fld fs1, _JB_FS1(a0) |
| 275 | fld fs2, _JB_FS2(a0) |
| 276 | fld fs3, _JB_FS3(a0) |
| 277 | fld fs4, _JB_FS4(a0) |
| 278 | fld fs5, _JB_FS5(a0) |
| 279 | fld fs6, _JB_FS6(a0) |
| 280 | fld fs7, _JB_FS7(a0) |
| 281 | fld fs8, _JB_FS8(a0) |
| 282 | fld fs9, _JB_FS9(a0) |
| 283 | fld fs10, _JB_FS10(a0) |
| 284 | fld fs11, _JB_FS11(a0) |
| 285 | |
| 286 | // Set return value. |
| 287 | beqz a1, 2f |
| 288 | li a0, 1 |
| 289 | 2: |
| 290 | mv a0, a1 |
| 291 | ret |
| 292 | |
Elliott Hughes | 9e89249 | 2024-04-08 16:32:25 +0000 | [diff] [blame] | 293 | L(checksum_failure): |
Elliott Hughes | 6a1dc51 | 2022-10-26 19:53:35 +0000 | [diff] [blame] | 294 | call __bionic_setjmp_checksum_mismatch |
Elliott Hughes | e1905ed | 2022-10-17 23:23:36 +0000 | [diff] [blame] | 295 | END(siglongjmp) |
| 296 | |
Elliott Hughes | d783120 | 2024-01-19 20:55:31 +0000 | [diff] [blame] | 297 | ALIAS_SYMBOL_WEAK_FOR_NATIVE_BRIDGE(longjmp, siglongjmp) |
| 298 | ALIAS_SYMBOL_WEAK_FOR_NATIVE_BRIDGE(_longjmp, siglongjmp) |