FreeBSD: add a suppression for reachable from __cxa_exit
[valgrind.git] / coregrind / m_syswrap / syswrap-arm64-freebsd.c
blobd90cf212ba6116e8e93a34c3084641dc891a938a
2 /*--------------------------------------------------------------------*/
3 /*--- Platform-specific syscalls stuff. syswrap-arm64-freebsd.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2024 Paul Floyd
11 pjfloyd@wanadoo.fr
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
30 * This port of Valgrind was done in the first quarter of 2024
31 * The FreeBSD platforms supported at that time were
32 * 13.3-RELEASE - not tested but should work
33 * 14.0-RELEASE - the platform used for porting
34 * 15.0-CURRENT - tested and should work
36 * Old syscalls that are specific releases are not handled. In the
37 * unlikely event that they are ever needed they can probably just be
38 * copied from the amd64 implementation. The first FreeBSD version with
39 * arm64 support was 11.0-RELEASE
42 #if defined(VGP_arm64_freebsd)
44 #include "pub_core_aspacemgr.h"
45 #include "pub_core_basics.h"
46 #include "pub_core_debuglog.h"
47 #include "pub_core_libcassert.h"
48 #include "pub_core_libcbase.h"
49 #include "pub_core_libcprint.h"
50 #include "pub_core_libcproc.h"
51 #include "pub_core_libcsignal.h"
52 #include "pub_core_machine.h"
53 #include "pub_core_options.h"
54 #include "pub_core_scheduler.h"
55 #include "pub_core_sigframe.h"
56 #include "pub_core_signals.h"
57 #include "pub_core_stacks.h" // VG_(register_stack)
58 #include "pub_core_syscall.h"
59 #include "pub_core_syswrap.h"
60 #include "pub_core_threadstate.h"
61 #include "pub_core_tooliface.h"
62 #include "pub_core_vki.h"
63 #include "pub_core_vkiscnums.h"
65 #include "priv_syswrap-freebsd.h" /* for decls of freebsd-ish wrappers */
66 #include "priv_syswrap-generic.h" /* for decls of generic wrappers */
67 #include "priv_syswrap-main.h"
68 #include "priv_types_n_macros.h"
70 /* ---------------------------------------------------------------------
71 clone() handling
72 ------------------------------------------------------------------ */
74 /* Call f(arg1), but first switch stacks, using 'stack' as the new
75 stack, and use 'retaddr' as f's return-to address. Also, clear all
76 the integer registers before entering f. */
77 __attribute__((noreturn)) void ML_(call_on_new_stack_0_1)(Addr stack,
78 Addr retaddr,
79 void (*f)(Word),
80 Word arg1);
81 // r0 = stack
82 // r1 = retaddr
83 // r2 = f
84 // r3 = arg1
85 asm(
86 ".text\n"
87 ".globl vgModuleLocal_call_on_new_stack_0_1\n"
88 "vgModuleLocal_call_on_new_stack_0_1:\n"
89 " mov sp, x0\n\t" /* Stack pointer */
90 " mov x30, x1\n\t" /* Return address (x30 is LR) */
91 " mov x0, x3\n\t" /* First argument */
92 " mov x9, x2\n\t" /* 'f': x9 won't be zeroed at start of f. Oh well. */
93 " mov x1, #0\n\t" /* Clear our GPRs */
94 " mov x2, #0\n\t"
95 " mov x3, #0\n\t"
96 " mov x4, #0\n\t"
97 " mov x5, #0\n\t"
98 " mov x6, #0\n\t"
99 " mov x7, #0\n\t"
100 " mov x8, #0\n\t"
101 /* don't zero out x9 */
102 " mov x10, #0\n\t"
103 " mov x11, #0\n\t"
104 " mov x12, #0\n\t"
105 " mov x13, #0\n\t"
106 " mov x14, #0\n\t"
107 " mov x15, #0\n\t"
108 " mov x16, #0\n\t"
109 " mov x17, #0\n\t"
110 /* " mov x18, #0\n\t"*/
111 " mov x19, #0\n\t"
112 " mov x20, #0\n\t"
113 " mov x21, #0\n\t"
114 " mov x22, #0\n\t"
115 " mov x23, #0\n\t"
116 " mov x24, #0\n\t"
117 " mov x25, #0\n\t"
118 " mov x26, #0\n\t"
119 " mov x27, #0\n\t"
120 " mov x28, #0\n\t"
121 " mov x29, sp\n\t" /* FP = SP, in the absence of better suggestions */
122 " br x9\n\t"
123 /* " ret x30\n" */ // jump to f
124 " udf #0\n" // should never get here
125 ".previous\n");
127 /* ---------------------------------------------------------------------
128 More thread stuff
129 ------------------------------------------------------------------ */
131 void VG_(cleanup_thread)(ThreadArchState* arch) {}
133 /* ---------------------------------------------------------------------
134 PRE/POST wrappers for amd64/FreeBSD-specific syscalls
135 ------------------------------------------------------------------ */
137 #define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name)
138 #define POST(name) DEFN_POST_TEMPLATE(freebsd, name)
140 // SYS_sysarch 165
141 // int sysarch(int number, void *args);
142 PRE(sys_sysarch)
144 PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2);
145 PRE_REG_READ2(int, "sysarch", int, number, void*, args);
146 // returns ENOTSUP on arm64
149 POST(sys_sysarch) {}
151 // SYS_brk 17
152 // void *break(char *nsize);
153 PRE(sys_brk)
155 PRINT("sys_brk ( %#" FMT_REGWORD "x )", ARG1);
156 // same name as generic rather than the same name as
157 // FreeBSD syscalls.master
158 PRE_REG_READ1(void*, "brk", char*, end_data_segment);
161 // SYS_clock_getcpuclockid2 247
162 // no manpage for this, from syscalls.master
163 // int clock_getcpuclockid2(id_t id, int which, _Out_ clockid_t *clock_id);
164 PRE(sys_clock_getcpuclockid2)
166 PRINT("sys_clock_getcpuclockid2( %" FMT_REGWORD "d, %" FMT_REGWORD
167 "d, %#" FMT_REGWORD "x )",
168 SARG1, SARG2, ARG3);
169 PRE_REG_READ3(int, "clock_getcpuclockid2", id_t, id, int, len, clockid_t*,
170 clock_id);
171 PRE_MEM_WRITE("clock_getcpuclockid2(clock_id)", ARG3, sizeof(vki_clockid_t));
174 // SYS_rfork 251
175 // pid_t rfork(int flags);
176 PRE(sys_rfork)
178 PRINT("sys_rfork ( %#" FMT_REGWORD "x )", ARG1);
179 PRE_REG_READ1(pid_t, "rfork", int, flags);
181 VG_(message)(Vg_UserMsg, "warning: rfork() not implemented\n");
183 if ((UInt)ARG1 == VKI_RFSPAWN) {
184 // posix_spawn uses RFSPAWN and it will fall back to vfork
185 // if it sees EINVAL
186 SET_STATUS_Failure(VKI_EINVAL);
187 } else {
188 SET_STATUS_Failure(VKI_ENOSYS);
192 // SYS_preadv 289
193 // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
194 PRE(sys_preadv)
196 Int i;
197 struct vki_iovec* vec;
198 char buf[sizeof("preadv(iov[])") + 11];
199 *flags |= SfMayBlock;
200 PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD
201 "d, %" FMT_REGWORD "d )",
202 SARG1, ARG2, SARG3, SARG4);
203 PRE_REG_READ4(ssize_t, "preadv", int, fd, const struct iovec*, iov, int,
204 iovcnt, vki_off_t, offset);
205 if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) {
206 SET_STATUS_Failure(VKI_EBADF);
207 } else {
208 if ((Int)ARG3 > 0) {
209 PRE_MEM_READ("preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec));
212 if (ML_(safe_to_deref)((struct vki_iovec*)ARG2,
213 ARG3 * sizeof(struct vki_iovec))) {
214 vec = (struct vki_iovec*)(Addr)ARG2;
215 for (i = 0; i < (Int)ARG3; i++) {
216 VG_(sprintf)(buf, "preadv(iov[%d])", i);
217 PRE_MEM_WRITE(buf, (Addr)vec[i].iov_base, vec[i].iov_len);
223 POST(sys_preadv)
225 vg_assert(SUCCESS);
226 if (RES > 0) {
227 Int i;
228 struct vki_iovec* vec = (struct vki_iovec*)(Addr)ARG2;
229 Int remains = RES;
231 /* RES holds the number of bytes read. */
232 for (i = 0; i < (Int)ARG3; i++) {
233 Int nReadThisBuf = vec[i].iov_len;
234 if (nReadThisBuf > remains) {
235 nReadThisBuf = remains;
237 POST_MEM_WRITE((Addr)vec[i].iov_base, nReadThisBuf);
238 remains -= nReadThisBuf;
239 if (remains < 0) {
240 VG_(core_panic)("preadv: remains < 0");
246 // SYS_pwritev 290
247 // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
248 PRE(sys_pwritev)
250 Int i;
251 struct vki_iovec* vec;
252 char buf[sizeof("pwritev(iov[])") + 11];
253 *flags |= SfMayBlock;
254 PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD
255 "d, %" FMT_REGWORD "d )",
256 SARG1, ARG2, SARG3, SARG4);
258 PRE_REG_READ4(ssize_t, "pwritev", int, fd, const struct iovec*, iov, int,
259 iovcnt, vki_off_t, offset);
260 if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) {
261 SET_STATUS_Failure(VKI_EBADF);
262 } else {
263 if ((Int)ARG3 >= 0) {
264 PRE_MEM_READ("pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec));
266 if (ML_(safe_to_deref)((struct vki_iovec*)ARG2,
267 ARG3 * sizeof(struct vki_iovec))) {
268 vec = (struct vki_iovec*)(Addr)ARG2;
269 for (i = 0; i < (Int)ARG3; i++) {
270 VG_(sprintf)(buf, "pwritev(iov[%d])", i);
271 PRE_MEM_READ(buf, (Addr)vec[i].iov_base, vec[i].iov_len);
277 // SYS_sendfile 393
278 // int sendfile(int fd, int s, off_t offset, size_t nbytes,
279 // struct sf_hdtr *hdtr, off_t *sbytes, int flags);
280 PRE(sys_sendfile)
282 *flags |= SfMayBlock;
284 PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD
285 "d, %lu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD
286 "x, %" FMT_REGWORD "d )",
287 SARG1, SARG2, ARG3, ARG4, ARG5, ARG6, SARG7);
288 PRE_REG_READ7(int, "sendfile", int, fd, int, s, vki_off_t, offset, size_t,
289 nbytes, void*, hdtr, vki_off_t*, sbytes, int, flags);
291 if (ARG5 != 0) {
292 PRE_MEM_READ("sendfile(hdtr)", ARG5, sizeof(struct vki_sf_hdtr));
295 if (ARG6 != 0) {
296 PRE_MEM_WRITE("sendfile(sbytes)", ARG6, sizeof(vki_off_t));
300 POST(sys_sendfile)
302 if (ARG6 != 0) {
303 POST_MEM_WRITE(ARG6, sizeof(vki_off_t));
307 // SYS_sigreturn 417
308 // int sigreturn(const ucontext_t *scp);
309 PRE(sys_sigreturn)
311 PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
312 PRE_REG_READ1(int, "sigreturn", struct vki_ucontext*, scp);
314 PRE_MEM_READ("sigreturn(scp)", ARG1, sizeof(struct vki_ucontext));
315 PRE_MEM_WRITE("sigreturn(scp)", ARG1, sizeof(struct vki_ucontext));
318 static void restore_mcontext(ThreadState* tst, struct vki_mcontext* sc)
320 tst->arch.vex.guest_X0 = sc->mc_gpregs.gp_x[0];
321 tst->arch.vex.guest_X1 = sc->mc_gpregs.gp_x[1];
322 tst->arch.vex.guest_X2 = sc->mc_gpregs.gp_x[2];
323 tst->arch.vex.guest_X3 = sc->mc_gpregs.gp_x[3];
324 tst->arch.vex.guest_X4 = sc->mc_gpregs.gp_x[4];
325 tst->arch.vex.guest_X5 = sc->mc_gpregs.gp_x[5];
326 tst->arch.vex.guest_X6 = sc->mc_gpregs.gp_x[6];
327 tst->arch.vex.guest_X7 = sc->mc_gpregs.gp_x[7];
328 tst->arch.vex.guest_X8 = sc->mc_gpregs.gp_x[8];
329 tst->arch.vex.guest_X9 = sc->mc_gpregs.gp_x[9];
330 tst->arch.vex.guest_X10 = sc->mc_gpregs.gp_x[10];
331 tst->arch.vex.guest_X11 = sc->mc_gpregs.gp_x[11];
332 tst->arch.vex.guest_X12 = sc->mc_gpregs.gp_x[12];
333 tst->arch.vex.guest_X13 = sc->mc_gpregs.gp_x[13];
334 tst->arch.vex.guest_X14 = sc->mc_gpregs.gp_x[14];
335 tst->arch.vex.guest_X15 = sc->mc_gpregs.gp_x[15];
336 tst->arch.vex.guest_X16 = sc->mc_gpregs.gp_x[16];
337 tst->arch.vex.guest_X17 = sc->mc_gpregs.gp_x[17];
338 tst->arch.vex.guest_X18 = sc->mc_gpregs.gp_x[18];
339 tst->arch.vex.guest_X19 = sc->mc_gpregs.gp_x[19];
340 tst->arch.vex.guest_X20 = sc->mc_gpregs.gp_x[20];
341 tst->arch.vex.guest_X21 = sc->mc_gpregs.gp_x[21];
342 tst->arch.vex.guest_X22 = sc->mc_gpregs.gp_x[22];
343 tst->arch.vex.guest_X23 = sc->mc_gpregs.gp_x[23];
344 tst->arch.vex.guest_X24 = sc->mc_gpregs.gp_x[24];
345 tst->arch.vex.guest_X25 = sc->mc_gpregs.gp_x[25];
346 tst->arch.vex.guest_X26 = sc->mc_gpregs.gp_x[26];
347 tst->arch.vex.guest_X27 = sc->mc_gpregs.gp_x[27];
348 tst->arch.vex.guest_X28 = sc->mc_gpregs.gp_x[28];
349 tst->arch.vex.guest_X29 = sc->mc_gpregs.gp_x[29];
350 tst->arch.vex.guest_X30 = sc->mc_gpregs.gp_lr;
351 tst->arch.vex.guest_XSP = sc->mc_gpregs.gp_sp;
352 tst->arch.vex.guest_PC = sc->mc_gpregs.gp_elr;
354 * XXX: missing support for other flags.
356 if (sc->mc_flags & VKI_PSR_C)
357 LibVEX_GuestARM64_put_nzcv_c(1, &tst->arch.vex);
358 else
359 LibVEX_GuestARM64_put_nzcv_c(0, &tst->arch.vex);
362 static void fill_mcontext(ThreadState* tst, struct vki_mcontext* sc)
364 sc->mc_gpregs.gp_x[0] = tst->arch.vex.guest_X0;
365 sc->mc_gpregs.gp_x[1] = tst->arch.vex.guest_X1;
366 sc->mc_gpregs.gp_x[2] = tst->arch.vex.guest_X2;
367 sc->mc_gpregs.gp_x[3] = tst->arch.vex.guest_X3;
368 sc->mc_gpregs.gp_x[4] = tst->arch.vex.guest_X4;
369 sc->mc_gpregs.gp_x[5] = tst->arch.vex.guest_X5;
370 sc->mc_gpregs.gp_x[6] = tst->arch.vex.guest_X6;
371 sc->mc_gpregs.gp_x[7] = tst->arch.vex.guest_X7;
372 sc->mc_gpregs.gp_x[8] = tst->arch.vex.guest_X8;
373 sc->mc_gpregs.gp_x[9] = tst->arch.vex.guest_X9;
374 sc->mc_gpregs.gp_x[10] = tst->arch.vex.guest_X10;
375 sc->mc_gpregs.gp_x[11] = tst->arch.vex.guest_X11;
376 sc->mc_gpregs.gp_x[12] = tst->arch.vex.guest_X12;
377 sc->mc_gpregs.gp_x[13] = tst->arch.vex.guest_X13;
378 sc->mc_gpregs.gp_x[14] = tst->arch.vex.guest_X14;
379 sc->mc_gpregs.gp_x[15] = tst->arch.vex.guest_X15;
380 sc->mc_gpregs.gp_x[16] = tst->arch.vex.guest_X16;
381 sc->mc_gpregs.gp_x[17] = tst->arch.vex.guest_X17;
382 sc->mc_gpregs.gp_x[18] = tst->arch.vex.guest_X18;
383 sc->mc_gpregs.gp_x[19] = tst->arch.vex.guest_X19;
384 sc->mc_gpregs.gp_x[20] = tst->arch.vex.guest_X20;
385 sc->mc_gpregs.gp_x[21] = tst->arch.vex.guest_X21;
386 sc->mc_gpregs.gp_x[22] = tst->arch.vex.guest_X22;
387 sc->mc_gpregs.gp_x[23] = tst->arch.vex.guest_X23;
388 sc->mc_gpregs.gp_x[24] = tst->arch.vex.guest_X24;
389 sc->mc_gpregs.gp_x[25] = tst->arch.vex.guest_X25;
390 sc->mc_gpregs.gp_x[26] = tst->arch.vex.guest_X26;
391 sc->mc_gpregs.gp_x[27] = tst->arch.vex.guest_X27;
392 sc->mc_gpregs.gp_x[28] = tst->arch.vex.guest_X28;
393 sc->mc_gpregs.gp_x[29] = tst->arch.vex.guest_X29;
394 sc->mc_gpregs.gp_lr = tst->arch.vex.guest_X30;
395 sc->mc_gpregs.gp_sp = tst->arch.vex.guest_XSP;
396 sc->mc_gpregs.gp_elr = tst->arch.vex.guest_PC;
397 sc->mc_gpregs.gp_spsr = LibVEX_GuestARM64_get_nzcv(&tst->arch.vex);
399 // @todo PJF ARM64 floating point
400 // https://github.com/freebsd/freebsd-src/blob/main/sys/arm64/arm64/exec_machdep.c#L511
403 // SYS_getcontext 421
404 // int getcontext(ucontext_t *ucp);
405 PRE(sys_getcontext)
407 ThreadState* tst;
408 struct vki_ucontext* uc;
410 PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1);
411 PRE_REG_READ1(int, "getcontext", struct vki_ucontext*, ucp);
412 PRE_MEM_WRITE("getcontext(ucp)", ARG1, sizeof(struct vki_ucontext));
413 uc = (struct vki_ucontext*)ARG1;
414 if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) {
415 SET_STATUS_Failure(VKI_EFAULT);
416 return;
418 tst = VG_(get_ThreadState)(tid);
419 fill_mcontext(tst, &uc->uc_mcontext);
420 uc->uc_mcontext.mc_gpregs.gp_x[0] = 0;
421 uc->uc_mcontext.mc_gpregs.gp_spsr &= ~VKI_PSR_C;
422 uc->uc_sigmask = tst->sig_mask;
423 VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__));
424 SET_STATUS_Success(0);
427 // SYS_setcontext 422
428 // int setcontext(const ucontext_t *ucp);
429 PRE(sys_setcontext)
431 ThreadState* tst;
432 struct vki_ucontext* uc;
434 PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", ARG1);
435 PRE_REG_READ1(long, "setcontext", struct vki_ucontext*, ucp);
437 PRE_MEM_READ("setcontext(ucp)", ARG1, sizeof(struct vki_ucontext));
438 PRE_MEM_WRITE("setcontext(ucp)", ARG1, sizeof(struct vki_ucontext));
440 vg_assert(VG_(is_valid_tid)(tid));
441 vg_assert(tid >= 1 && tid < VG_N_THREADS);
442 vg_assert(VG_(is_running_thread)(tid));
444 tst = VG_(get_ThreadState)(tid);
445 uc = (struct vki_ucontext*)ARG1;
446 if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) /*|| uc->uc_mcontext.len != sizeof(uc->uc_mcontext)*/) {
447 SET_STATUS_Failure(VKI_EFAULT);
448 return;
451 restore_mcontext(tst, &uc->uc_mcontext);
452 tst->sig_mask = uc->uc_sigmask;
453 tst->tmp_sig_mask = uc->uc_sigmask;
455 /* Tell the driver not to update the guest state with the "result",
456 and set a bogus result to keep it happy. */
457 *flags |= SfNoWriteResult;
458 SET_STATUS_Success(0);
460 /* Check to see if some any signals arose as a result of this. */
461 *flags |= SfPollAfter;
464 // SYS_swapcontext 423
465 // int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
466 PRE(sys_swapcontext)
468 struct vki_ucontext* ucp;
469 struct vki_ucontext* oucp;
470 ThreadState* tst;
472 PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,
473 ARG2);
474 PRE_REG_READ2(long, "swapcontext", struct vki_ucontext*, oucp,
475 struct vki_ucontext*, ucp);
477 PRE_MEM_READ("swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext));
478 PRE_MEM_WRITE("swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext));
480 oucp = (struct vki_ucontext*)ARG1;
481 ucp = (struct vki_ucontext*)ARG2;
482 if (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) ||
483 !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) /*||
484 ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)*/) {
485 SET_STATUS_Failure(VKI_EINVAL);
486 return;
488 tst = VG_(get_ThreadState)(tid);
491 * Save the context.
493 fill_mcontext(tst, &oucp->uc_mcontext);
494 oucp->uc_mcontext.mc_gpregs.gp_x[0] = 0;
495 oucp->uc_mcontext.mc_gpregs.gp_x[1] = 0;
496 oucp->uc_mcontext.mc_gpregs.gp_spsr &= ~VKI_PSR_C;
497 oucp->uc_sigmask = tst->sig_mask;
498 VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__));
501 * Switch to new one.
503 restore_mcontext(tst, &ucp->uc_mcontext);
504 tst->sig_mask = ucp->uc_sigmask;
505 tst->tmp_sig_mask = ucp->uc_sigmask;
507 /* Tell the driver not to update the guest state with the "result",
508 and set a bogus result to keep it happy. */
509 *flags |= SfNoWriteResult;
510 SET_STATUS_Success(0);
512 /* Check to see if some any signals arose as a result of this. */
513 *flags |= SfPollAfter;
516 // SYS_thr_new 455
517 // int thr_new(struct thr_param *param, int param_size);
518 PRE(sys_thr_new)
520 static const Bool debug = False;
522 ThreadId ctid = VG_(alloc_ThreadState)();
523 ThreadState* ptst = VG_(get_ThreadState)(tid);
524 ThreadState* ctst = VG_(get_ThreadState)(ctid);
525 SysRes res;
526 vki_sigset_t blockall;
527 vki_sigset_t savedmask;
528 struct vki_thr_param tp;
529 Addr stk;
531 PRINT("thr_new ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2);
532 PRE_REG_READ2(int, "thr_new", struct thr_param*, param, int, param_size);
534 PRE_MEM_READ("thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare));
535 if (!ML_(safe_to_deref)((void*)ARG1,
536 offsetof(struct vki_thr_param, spare))) {
537 SET_STATUS_Failure(VKI_EFAULT);
538 return;
540 VG_(memset)(&tp, 0, sizeof(tp));
541 VG_(memcpy)(&tp, (void*)ARG1, offsetof(struct vki_thr_param, spare));
542 PRE_MEM_WRITE("thr_new(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long));
543 PRE_MEM_WRITE("thr_new(child_tidptr)", (Addr)tp.child_tid, sizeof(long));
545 VG_(sigfillset)(&blockall);
547 vg_assert(VG_(is_running_thread)(tid));
548 vg_assert(VG_(is_valid_tid)(ctid));
550 /* Copy register state
552 On linux, both parent and child return to the same place, and the code
553 following the clone syscall works out which is which, so we
554 don't need to worry about it.
555 On FreeBSD, thr_new arranges a direct call. We don't actually need any
556 of this gunk.
558 The parent gets the child's new tid returned from clone, but the
559 child gets 0.
561 If the clone call specifies a NULL rsp for the new thread, then
562 it actually gets a copy of the parent's rsp.
564 /* We inherit our parent's guest state. */
565 ctst->arch.vex = ptst->arch.vex;
566 ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1;
567 ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2;
569 /* Make thr_new appear to have returned Success(0) in the
570 child. */
571 ctst->arch.vex.guest_X0 = 0;
572 ctst->arch.vex.guest_X1 = 0;
573 LibVEX_GuestARM64_put_nzcv_c(0, &ctst->arch.vex);
575 ctst->os_state.parent = tid;
577 /* inherit signal mask */
578 ctst->sig_mask = ptst->sig_mask;
579 ctst->tmp_sig_mask = ptst->sig_mask;
581 /* Linux has to guess, we don't */
582 ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size;
583 ctst->client_stack_szB = tp.stack_size;
584 ctst->os_state.stk_id = VG_(register_stack)(
585 (Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size);
587 /* Assume the thr_new will succeed, and tell any tool that wants to
588 know that this thread has come into existence. If the thr_new
589 fails, we'll send out a ll_exit notification for it at the out:
590 label below, to clean up. */
591 VG_TRACK(pre_thread_ll_create, tid, ctid);
593 if (debug) {
594 VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base);
597 ctst->arch.vex.guest_TPIDR_EL0 = (UWord)tp.tls_base;
598 tp.tls_base = 0; /* Don't have the kernel do it too */
600 /* start the thread with everything blocked */
601 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
603 /* Set the client state for scheduler to run libthr's trampoline */
604 ctst->arch.vex.guest_X0 = (Addr)tp.arg;
605 /* XXX: align on 16-byte boundary? */
606 ctst->arch.vex.guest_XSP = (Addr)tp.stack_base + tp.stack_size - 8;
607 ctst->arch.vex.guest_PC = (Addr)tp.start_func;
609 /* But this is for thr_new() to run valgrind's trampoline */
610 tp.start_func = (void*)ML_(start_thread_NORETURN);
611 tp.arg = &VG_(threads)[ctid];
613 /* And valgrind's trampoline on its own stack */
614 stk = ML_(allocstack)(ctid);
615 if (stk == (Addr)NULL) {
616 res = VG_(mk_SysRes_Error)(VKI_ENOMEM);
617 goto fail;
619 tp.stack_base = (void*)ctst->os_state.valgrind_stack_base;
620 tp.stack_size = (Addr)stk - (Addr)tp.stack_base;
622 /* Create the new thread */
623 res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp));
625 VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
627 fail:
628 if (sr_isError(res)) {
629 /* thr_new failed */
630 VG_(cleanup_thread)(&ctst->arch);
631 ctst->status = VgTs_Empty;
632 /* oops. Better tell the tool the thread exited in a hurry :-) */
633 VG_TRACK(pre_thread_ll_exit, ctid);
634 } else {
636 POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long));
637 POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long));
639 /* Thread creation was successful; let the child have the chance
640 to run */
641 *flags |= SfYieldAfter;
644 /* "Complete" the syscall so that the wrapper doesn't call the kernel again.
646 SET_STATUS_from_SysRes(res);
649 // SYS_pread 475
650 // ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
651 PRE(sys_pread)
653 *flags |= SfMayBlock;
654 PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
655 "u, %" FMT_REGWORD "u )",
656 ARG1, ARG2, ARG3, ARG4);
657 PRE_REG_READ4(ssize_t, "pread", unsigned int, fd, char*, buf, vki_size_t,
658 count, unsigned long, off);
660 if (!ML_(fd_allowed)(ARG1, "read", tid, False)) {
661 SET_STATUS_Failure(VKI_EBADF);
662 } else {
663 PRE_MEM_WRITE("pread(buf)", ARG2, ARG3);
667 POST(sys_pread)
669 vg_assert(SUCCESS);
670 POST_MEM_WRITE(ARG2, RES);
673 // SYS_pwrite 476
674 // ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
675 PRE(sys_pwrite)
677 Bool ok;
678 *flags |= SfMayBlock;
679 PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
680 "u, %" FMT_REGWORD "u )",
681 ARG1, ARG2, ARG3, ARG4);
682 PRE_REG_READ4(ssize_t, "pwrite", int, fd, const char*, buf, vki_size_t,
683 nbytes, vki_off_t, offset);
684 /* check to see if it is allowed. If not, try for an exemption from
685 --sim-hints=enable-outer (used for self hosting). */
686 ok = ML_(fd_allowed)(ARG1, "pwrite", tid, False);
687 if (!ok && ARG1 == 2 /*stderr*/
688 && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints)))
689 ok = True;
690 if (!ok) {
691 SET_STATUS_Failure(VKI_EBADF);
692 } else {
693 PRE_MEM_READ("pwrite(buf)", ARG2, ARG3);
697 // SYS_mmap 477
698 /* FreeBSD-7 introduces a "regular" version of mmap etc. */
699 // void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t
700 // offset);
701 PRE(sys_mmap)
703 SysRes r;
705 PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD
706 "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x)",
707 ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6);
708 PRE_REG_READ6(void*, "mmap", void*, addr, size_t, len, int, prot, int, flags,
709 int, fd, off_t, offset);
711 r = ML_(generic_PRE_sys_mmap)(tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
712 SET_STATUS_from_SysRes(r);
715 // SYS_lseek 478
716 // off_t lseek(int fildes, off_t offset, int whence);
717 PRE(sys_lseek)
719 PRINT("sys_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %" FMT_REGWORD
720 "u )",
721 ARG1, ARG2, ARG3);
722 PRE_REG_READ3(long, "lseek", unsigned int, fd, unsigned long, offset,
723 unsigned int, whence);
726 // SYS_truncate 479
727 // int truncate(const char *path, off_t length);
728 PRE(sys_truncate)
730 *flags |= SfMayBlock;
731 PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,
732 (char*)ARG1, ARG2);
733 PRE_REG_READ2(long, "truncate", const char*, path, unsigned long, length);
734 PRE_MEM_RASCIIZ("truncate(path)", ARG1);
737 // SYS_ftruncate 480
738 // int ftruncate(int fd, off_t length);
739 PRE(sys_ftruncate)
741 *flags |= SfMayBlock;
742 PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2);
743 PRE_REG_READ2(long, "ftruncate", unsigned int, fd, unsigned long, length);
746 // SYS_cpuset_setid 485
747 // int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid);
748 PRE(sys_cpuset_setid)
750 PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %" FMT_REGWORD
751 "d, %#" FMT_REGWORD "x )",
752 SARG1, SARG2, ARG3);
753 PRE_REG_READ3(int, "cpuset_setid", vki_cpuwhich_t, which, vki_id_t, id,
754 vki_cpusetid_t*, setid);
757 // SYS_cpuset_getid 486
758 // int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id,
759 // cpusetid_t *setid);
760 PRE(sys_cpuset_getid)
762 PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD
763 "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
764 SARG1, SARG2, SARG3, ARG4);
765 PRE_REG_READ4(int, "cpuset_getid", vki_cpulevel_t, level, vki_cpuwhich_t,
766 which, vki_id_t, id, vki_cpusetid_t, setid);
767 PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t));
770 POST(sys_cpuset_getid) { POST_MEM_WRITE(ARG4, sizeof(vki_cpusetid_t)); }
772 // SYS_cpuset_getaffinity 487
773 // int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
774 // size_t setsize, cpuset_t *mask);
775 PRE(sys_cpuset_getaffinity)
777 PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD
778 "u, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
779 ARG1, ARG2, SARG3, ARG4, ARG5);
780 PRE_REG_READ5(int, "cpuset_getaffinity", vki_cpulevel_t, level,
781 vki_cpuwhich_t, which, vki_id_t, id, size_t, setsize, void*,
782 mask);
783 PRE_MEM_WRITE("cpuset_getaffinity", ARG5, ARG4);
786 POST(sys_cpuset_getaffinity)
788 vg_assert(SUCCESS);
789 if (RES == 0)
790 POST_MEM_WRITE(ARG5, ARG4);
793 // SYS_cpuset_setaffinity 488
794 // int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
795 // size_t setsize, const cpuset_t *mask);
796 PRE(sys_cpuset_setaffinity)
799 PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD
800 "u, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
801 ARG1, ARG2, SARG3, ARG4, ARG5);
802 PRE_REG_READ5(int, "cpuset_setaffinity", vki_cpulevel_t, level,
803 vki_cpuwhich_t, which, vki_id_t, id, size_t, setsize, void*,
804 mask);
805 PRE_MEM_READ("cpuset_setaffinity", ARG5, ARG4);
808 // SYS_posix_fallocate 530
809 // int posix_fallocate(int fd, off_t offset, off_t len);
810 PRE(sys_posix_fallocate)
812 PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %" FMT_REGWORD
813 "u, %" FMT_REGWORD "u )",
814 SARG1, ARG2, ARG3);
815 PRE_REG_READ3(long, "posix_fallocate", int, fd, vki_off_t, offset, vki_off_t,
816 len);
819 // SYS_posix_fadvise 531
820 // int posix_fadvise(int fd, off_t offset, off_t len, int advice);
821 PRE(sys_posix_fadvise)
823 PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %" FMT_REGWORD
824 "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d )",
825 SARG1, ARG2, ARG3, SARG4);
826 PRE_REG_READ4(long, "posix_fadvise", int, fd, off_t, offset, off_t, len, int,
827 advice);
828 // @todo PJF advice can be 0 to 5 inclusive
831 // SYS_wait6 532
832 // pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
833 // struct __wrusage *wrusage, siginfo_t *infop);
834 PRE(sys_wait6)
836 PRINT("sys_wait6 ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD
837 "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
838 SARG1, SARG2, ARG3, SARG4, ARG5, ARG6);
839 PRE_REG_READ6(pid_t, "wait6", vki_idtype_t, idtype, vki_id_t, id, int*,
840 status, int, options, struct vki___wrusage*, wrusage,
841 vki_siginfo_t*, infop);
842 PRE_MEM_WRITE("wait6(status)", ARG3, sizeof(int));
843 if (ARG5) {
844 PRE_MEM_WRITE("wait6(wrusage)", ARG5, sizeof(struct vki___wrusage));
846 if (ARG6) {
847 PRE_MEM_WRITE("wait6(infop)", ARG6, sizeof(vki_siginfo_t));
851 POST(sys_wait6)
853 POST_MEM_WRITE(ARG3, sizeof(int));
854 if (ARG5) {
855 POST_MEM_WRITE(ARG5, sizeof(struct vki___wrusage));
858 if (ARG6) {
859 POST_MEM_WRITE(ARG6, sizeof(vki_siginfo_t));
863 // SYS_procctl 544
864 // int procctl(idtype_t idtype, id_t id, int cmd, void *data);
865 PRE(sys_procctl)
867 PRINT("sys_procctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD
868 "d, %#" FMT_REGWORD "x )",
869 SARG1, SARG2, SARG3, ARG4);
870 PRE_REG_READ4(int, "procctl", vki_idtype_t, idtype, vki_id_t, id, int, cmd,
871 void*, data);
872 switch (ARG3) {
873 case VKI_PROC_ASLR_CTL:
874 case VKI_PROC_SPROTECT:
875 case VKI_PROC_TRACE_CTL:
876 case VKI_PROC_TRAPCAP_CTL:
877 case VKI_PROC_PDEATHSIG_CTL:
878 case VKI_PROC_STACKGAP_CTL:
879 case VKI_PROC_NO_NEW_PRIVS_CTL:
880 case VKI_PROC_WXMAP_CTL:
881 PRE_MEM_READ("procctl(data)", ARG4, sizeof(int));
882 break;
883 case VKI_PROC_REAP_STATUS:
884 PRE_MEM_READ("procctl(data)", ARG4,
885 sizeof(struct vki_procctl_reaper_status));
886 break;
887 case VKI_PROC_REAP_GETPIDS:
888 PRE_MEM_READ("procctl(data)", ARG4,
889 sizeof(struct vki_procctl_reaper_pids));
890 break;
891 case VKI_PROC_REAP_KILL:
892 /* The first three fields are reads
893 * int rk_sig;
894 * u_int rk_flags;
895 * pid_t rk_subtree;
897 * The last two fields are writes
898 * u_int rk_killed;
899 * pid_t rk_fpid;
901 * There is also a pad field
903 PRE_MEM_READ("procctl(data)", ARG4,
904 sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t));
905 PRE_MEM_WRITE("procctl(data)",
906 ARG4 + offsetof(struct vki_procctl_reaper_kill, rk_killed),
907 sizeof(u_int) + sizeof(vki_pid_t));
908 break;
909 case VKI_PROC_ASLR_STATUS:
910 case VKI_PROC_PDEATHSIG_STATUS:
911 case VKI_PROC_STACKGAP_STATUS:
912 case VKI_PROC_TRAPCAP_STATUS:
913 case VKI_PROC_TRACE_STATUS:
914 case VKI_PROC_NO_NEW_PRIVS_STATUS:
915 case VKI_PROC_WXMAP_STATUS:
916 PRE_MEM_WRITE("procctl(data)", ARG4, sizeof(int));
917 case VKI_PROC_REAP_ACQUIRE:
918 case VKI_PROC_REAP_RELEASE:
919 default:
920 break;
924 POST(sys_procctl)
926 switch (ARG3) {
927 case VKI_PROC_REAP_KILL:
928 POST_MEM_WRITE(ARG4 + offsetof(struct vki_procctl_reaper_kill, rk_killed),
929 sizeof(u_int) + sizeof(vki_pid_t));
930 break;
931 case VKI_PROC_ASLR_STATUS:
932 case VKI_PROC_PDEATHSIG_STATUS:
933 case VKI_PROC_STACKGAP_STATUS:
934 case VKI_PROC_TRAPCAP_STATUS:
935 case VKI_PROC_TRACE_STATUS:
936 case VKI_PROC_NO_NEW_PRIVS_STATUS:
937 case VKI_PROC_WXMAP_STATUS:
938 POST_MEM_WRITE(ARG4, sizeof(int));
939 default:
940 break;
944 // SYS_mknodat 559
945 // int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
946 PRE(sys_mknodat)
948 PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD
949 "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )",
950 ARG1, ARG2, (char*)ARG2, ARG3, ARG4);
951 PRE_REG_READ4(long, "mknodat", int, fd, const char*, path, vki_mode_t, mode,
952 vki_dev_t, dev);
953 PRE_MEM_RASCIIZ("mknodat(pathname)", ARG2);
956 // SYS_cpuset_getdomain 561
957 // int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
958 // size_t setsize, domainset_t *mask, int *policy);
959 PRE(sys_cpuset_getdomain)
961 PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD
962 "d, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD
963 "x, %#" FMT_REGWORD "x )",
964 SARG1, SARG2, SARG3, ARG4, ARG5, ARG6);
965 PRE_REG_READ6(int, "cpuset_getdomain", cpulevel_t, level, cpuwhich_t, which,
966 id_t, id, size_t, setsize, vki_domainset_t*, mask, int*,
967 policy);
968 // man page says that setsize (ARG4) "is usually provided by calling
969 // sizeof(mask)"
970 PRE_MEM_WRITE("cpuset_getdomain(mask)", ARG5, ARG4);
971 PRE_MEM_WRITE("cpuset_getdomain(policy)", ARG6, sizeof(int));
974 POST(sys_cpuset_getdomain)
976 POST_MEM_WRITE(ARG5, ARG4);
977 POST_MEM_WRITE(ARG6, sizeof(int));
980 // SYS_cpuset_setdomain 562
981 // int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
982 // size_t setsize, const domainset_t *mask, int policy);
983 PRE(sys_cpuset_setdomain)
985 PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD
986 "d, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD
987 "x, %" FMT_REGWORD "d )",
988 SARG1, SARG2, SARG3, ARG4, ARG5, SARG6);
989 PRE_REG_READ6(int, "cpuset_getdomain", cpulevel_t, level, cpuwhich_t, which,
990 id_t, id, size_t, setsize, vki_domainset_t*, mask, int,
991 policy);
992 // man page says that setsize (ARG4) "is usually provided by calling
993 // sizeof(mask)"
994 PRE_MEM_READ("cpuset_getdomain(mask)", ARG5, ARG4);
997 PRE(sys_fake_sigreturn)
999 ThreadState* tst;
1000 struct vki_ucontext* uc;
1001 ULong rflags;
1003 PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
1004 PRE_REG_READ1(long, "sigreturn", struct vki_ucontext*, scp);
1006 PRE_MEM_READ("sigreturn(scp)", ARG1, sizeof(struct vki_ucontext));
1007 PRE_MEM_WRITE("sigreturn(scp)", ARG1, sizeof(struct vki_ucontext));
1009 vg_assert(VG_(is_valid_tid)(tid));
1010 vg_assert(tid >= 1 && tid < VG_N_THREADS);
1011 vg_assert(VG_(is_running_thread)(tid));
1013 tst = VG_(get_ThreadState)(tid);
1015 uc = (struct vki_ucontext*)ARG1;
1016 if (uc == NULL) {
1017 SET_STATUS_Failure(VKI_EINVAL);
1018 return;
1021 /* This is only so that the EIP is (might be) useful to report if
1022 something goes wrong in the sigreturn */
1023 ML_(fixup_guest_state_to_restart_syscall)(&tst->arch);
1025 VG_(sigframe_destroy)(tid);
1027 /* For unclear reasons, it appears we need the syscall to return
1028 without changing %RAX. Since %RAX is the return value, and can
1029 denote either success or failure, we must set up so that the
1030 driver logic copies it back unchanged. Also, note %RAX is of
1031 the guest registers written by VG_(sigframe_destroy). */
1032 rflags = LibVEX_GuestARM64_get_nzcv(&tst->arch.vex);
1033 SET_STATUS_from_SysRes(VG_(mk_SysRes_amd64_freebsd)(
1034 tst->arch.vex.guest_X0, tst->arch.vex.guest_X1,
1035 (rflags & VKI_PSR_C) != 0U ? True : False));
1038 * Signal handler might have changed the signal mask. Respect that.
1040 tst->sig_mask = uc->uc_sigmask;
1041 tst->tmp_sig_mask = uc->uc_sigmask;
1043 /* Tell the driver not to update the guest state with the "result",
1044 and set a bogus result to keep it happy. */
1045 *flags |= SfNoWriteResult;
1046 SET_STATUS_Success(0);
1048 /* Check to see if some any signals arose as a result of this. */
1049 *flags |= SfPollAfter;
1052 #undef PRE
1053 #undef POST
1055 #endif /* defined(VGP_arm64_freebsd) */
1057 /*--------------------------------------------------------------------*/
1058 /*--- end ---*/
1059 /*--------------------------------------------------------------------*/