1#if (defined(__riscv) && (__riscv_xlen == 64)) && defined(__linux__)
2
3#include "sanitizer_common/sanitizer_asm.h"
4
5ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
6
7.comm _ZN14__interception10real_vforkE,8,8
8.globl ASM_WRAPPER_NAME(vfork)
9ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
10ASM_WRAPPER_NAME(vfork):
11        // Save ra in the off-stack spill area.
12        // allocate space on stack
13        addi    sp, sp, -16
14        // store ra value
15        sd      ra, 8(sp)
16        call    COMMON_INTERCEPTOR_SPILL_AREA
17        // restore previous values from stack
18        ld      ra, 8(sp)
19        // adjust stack
20        addi    sp, sp, 16
21        // store ra by x10
22        sd      ra, 0(x10)
23
24        // Call real vfork. This may return twice. User code that runs between the first and the second return
25        // may clobber the stack frame of the interceptor; that's why it does not have a frame.
26        la x10, _ZN14__interception10real_vforkE
27        ld x10, 0(x10)
28        jalr x10
29
30        // adjust stack
31        addi    sp, sp, -16
32        // store x10 by adjusted stack
33        sd      x10, 8(sp)
34        // jump to exit label if x10 is 0
35        beqz    x10, .L_exit
36
37        // x0 != 0 => parent process. Clear stack shadow.
38        // put old sp to x10
39        addi   x10, sp, 16
40        call   COMMON_INTERCEPTOR_HANDLE_VFORK
41
42.L_exit:
43        // Restore ra
44        call   COMMON_INTERCEPTOR_SPILL_AREA
45        ld     ra, 0(x10)
46        // load value by stack
47        ld     x10, 8(sp)
48        // adjust stack
49        addi   sp, sp, 16
50        ret
51ASM_SIZE(vfork)
52
53.weak vfork
54.set vfork, ASM_WRAPPER_NAME(vfork)
55
56#endif
57