2 /*--------------------------------------------------------------------*/
3 /*--- Platform-specific syscalls stuff. syswrap-arm64-freebsd.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2024 Paul Floyd
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 /* ---------------------------------------------------------------------
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
,
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 */
101 /* don't zero out x9 */
110 /* " mov x18, #0\n\t"*/
121 " mov x29, sp\n\t" /* FP = SP, in the absence of better suggestions */
123 /* " ret x30\n" */ // jump to f
124 " udf #0\n" // should never get here
127 /* ---------------------------------------------------------------------
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)
141 // int sysarch(int number, void *args);
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
152 // void *break(char *nsize);
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 )",
169 PRE_REG_READ3(int, "clock_getcpuclockid2", id_t
, id
, int, len
, clockid_t
*,
171 PRE_MEM_WRITE("clock_getcpuclockid2(clock_id)", ARG3
, sizeof(vki_clockid_t
));
175 // pid_t rfork(int flags);
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
186 SET_STATUS_Failure(VKI_EINVAL
);
188 SET_STATUS_Failure(VKI_ENOSYS
);
193 // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
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
);
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
);
228 struct vki_iovec
* vec
= (struct vki_iovec
*)(Addr
)ARG2
;
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
;
240 VG_(core_panic
)("preadv: remains < 0");
247 // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
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
);
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
);
278 // int sendfile(int fd, int s, off_t offset, size_t nbytes,
279 // struct sf_hdtr *hdtr, off_t *sbytes, int flags);
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
);
292 PRE_MEM_READ("sendfile(hdtr)", ARG5
, sizeof(struct vki_sf_hdtr
));
296 PRE_MEM_WRITE("sendfile(sbytes)", ARG6
, sizeof(vki_off_t
));
303 POST_MEM_WRITE(ARG6
, sizeof(vki_off_t
));
308 // int sigreturn(const ucontext_t *scp);
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
);
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);
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
);
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);
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
);
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);
468 struct vki_ucontext
* ucp
;
469 struct vki_ucontext
* oucp
;
472 PRINT("sys_swapcontext ( %#" FMT_REGWORD
"x, %#" FMT_REGWORD
"x )", ARG1
,
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
);
488 tst
= VG_(get_ThreadState
)(tid
);
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__
));
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
;
517 // int thr_new(struct thr_param *param, int param_size);
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
);
526 vki_sigset_t blockall
;
527 vki_sigset_t savedmask
;
528 struct vki_thr_param tp
;
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
);
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
558 The parent gets the child's new tid returned from clone, but the
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
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
);
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
);
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
);
628 if (sr_isError(res
)) {
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
);
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
641 *flags
|= SfYieldAfter
;
644 /* "Complete" the syscall so that the wrapper doesn't call the kernel again.
646 SET_STATUS_from_SysRes(res
);
650 // ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
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
);
663 PRE_MEM_WRITE("pread(buf)", ARG2
, ARG3
);
670 POST_MEM_WRITE(ARG2
, RES
);
674 // ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
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
)))
691 SET_STATUS_Failure(VKI_EBADF
);
693 PRE_MEM_READ("pwrite(buf)", ARG2
, ARG3
);
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
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
);
716 // off_t lseek(int fildes, off_t offset, int whence);
719 PRINT("sys_lseek ( %" FMT_REGWORD
"u, 0x%" FMT_REGWORD
"x, %" FMT_REGWORD
722 PRE_REG_READ3(long, "lseek", unsigned int, fd
, unsigned long, offset
,
723 unsigned int, whence
);
727 // int truncate(const char *path, off_t length);
730 *flags
|= SfMayBlock
;
731 PRINT("sys_truncate ( %#" FMT_REGWORD
"x(%s), %" FMT_REGWORD
"u )", ARG1
,
733 PRE_REG_READ2(long, "truncate", const char*, path
, unsigned long, length
);
734 PRE_MEM_RASCIIZ("truncate(path)", ARG1
);
738 // int ftruncate(int fd, off_t length);
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 )",
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*,
783 PRE_MEM_WRITE("cpuset_getaffinity", ARG5
, ARG4
);
786 POST(sys_cpuset_getaffinity
)
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*,
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 )",
815 PRE_REG_READ3(long, "posix_fallocate", int, fd
, vki_off_t
, offset
, vki_off_t
,
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,
828 // @todo PJF advice can be 0 to 5 inclusive
832 // pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
833 // struct __wrusage *wrusage, siginfo_t *infop);
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));
844 PRE_MEM_WRITE("wait6(wrusage)", ARG5
, sizeof(struct vki___wrusage
));
847 PRE_MEM_WRITE("wait6(infop)", ARG6
, sizeof(vki_siginfo_t
));
853 POST_MEM_WRITE(ARG3
, sizeof(int));
855 POST_MEM_WRITE(ARG5
, sizeof(struct vki___wrusage
));
859 POST_MEM_WRITE(ARG6
, sizeof(vki_siginfo_t
));
863 // the man page is inconsistent for the last argument
864 // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386
865 // will stick to 'arg' for simplicity
868 // int procctl(idtype_t idtype, id_t id, int cmd, void *arg);
871 PRINT("sys_procctl ( %" FMT_REGWORD
"d, %" FMT_REGWORD
"d, %" FMT_REGWORD
872 "d, %#" FMT_REGWORD
"x )",
873 SARG1
, SARG2
, SARG3
, ARG4
);
874 PRE_REG_READ4(int, "procctl", vki_idtype_t
, idtype
, vki_id_t
, id
, int, cmd
,
877 case VKI_PROC_ASLR_CTL
:
878 case VKI_PROC_SPROTECT
:
879 case VKI_PROC_TRACE_CTL
:
880 case VKI_PROC_TRAPCAP_CTL
:
881 case VKI_PROC_PDEATHSIG_CTL
:
882 case VKI_PROC_STACKGAP_CTL
:
883 case VKI_PROC_NO_NEW_PRIVS_CTL
:
884 case VKI_PROC_WXMAP_CTL
:
885 PRE_MEM_READ("procctl(arg)", ARG4
, sizeof(int));
887 case VKI_PROC_REAP_STATUS
:
888 PRE_MEM_READ("procctl(arg)", ARG4
,
889 sizeof(struct vki_procctl_reaper_status
));
891 case VKI_PROC_REAP_GETPIDS
:
892 PRE_MEM_READ("procctl(arg)", ARG4
,
893 sizeof(struct vki_procctl_reaper_pids
));
895 case VKI_PROC_REAP_KILL
:
896 /* The first three fields are reads
901 * The last two fields are writes
905 * There is also a pad field
907 PRE_MEM_READ("procctl(arg)", ARG4
,
908 sizeof(int) + sizeof(u_int
) + sizeof(vki_pid_t
));
909 PRE_MEM_WRITE("procctl(arg)",
910 ARG4
+ offsetof(struct vki_procctl_reaper_kill
, rk_killed
),
911 sizeof(u_int
) + sizeof(vki_pid_t
));
913 case VKI_PROC_ASLR_STATUS
:
914 case VKI_PROC_PDEATHSIG_STATUS
:
915 case VKI_PROC_STACKGAP_STATUS
:
916 case VKI_PROC_TRAPCAP_STATUS
:
917 case VKI_PROC_TRACE_STATUS
:
918 case VKI_PROC_NO_NEW_PRIVS_STATUS
:
919 case VKI_PROC_WXMAP_STATUS
:
920 PRE_MEM_WRITE("procctl(arg)", ARG4
, sizeof(int));
921 case VKI_PROC_REAP_ACQUIRE
:
922 case VKI_PROC_REAP_RELEASE
:
931 case VKI_PROC_REAP_KILL
:
932 POST_MEM_WRITE(ARG4
+ offsetof(struct vki_procctl_reaper_kill
, rk_killed
),
933 sizeof(u_int
) + sizeof(vki_pid_t
));
935 case VKI_PROC_ASLR_STATUS
:
936 case VKI_PROC_PDEATHSIG_STATUS
:
937 case VKI_PROC_STACKGAP_STATUS
:
938 case VKI_PROC_TRAPCAP_STATUS
:
939 case VKI_PROC_TRACE_STATUS
:
940 case VKI_PROC_NO_NEW_PRIVS_STATUS
:
941 case VKI_PROC_WXMAP_STATUS
:
942 POST_MEM_WRITE(ARG4
, sizeof(int));
949 // int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
952 PRINT("sys_mknodat ( %" FMT_REGWORD
"u, %#" FMT_REGWORD
953 "x(%s), 0x%" FMT_REGWORD
"x, 0x%" FMT_REGWORD
"x )",
954 ARG1
, ARG2
, (char*)ARG2
, ARG3
, ARG4
);
955 PRE_REG_READ4(long, "mknodat", int, fd
, const char*, path
, vki_mode_t
, mode
,
957 PRE_MEM_RASCIIZ("mknodat(pathname)", ARG2
);
960 #if (FREEBSD_VERS >= FREEBSD_12)
962 // SYS_cpuset_getdomain 561
963 // int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
964 // size_t setsize, domainset_t *mask, int *policy);
965 PRE(sys_cpuset_getdomain
)
967 PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD
"d, %" FMT_REGWORD
968 "d, %" FMT_REGWORD
"d, %" FMT_REGWORD
"u, %#" FMT_REGWORD
969 "x, %#" FMT_REGWORD
"x )",
970 SARG1
, SARG2
, SARG3
, ARG4
, ARG5
, ARG6
);
971 PRE_REG_READ6(int, "cpuset_getdomain", cpulevel_t
, level
, cpuwhich_t
, which
,
972 id_t
, id
, size_t, setsize
, vki_domainset_t
*, mask
, int*,
974 // man page says that setsize (ARG4) "is usually provided by calling
976 PRE_MEM_WRITE("cpuset_getdomain(mask)", ARG5
, ARG4
);
977 PRE_MEM_WRITE("cpuset_getdomain(policy)", ARG6
, sizeof(int));
980 POST(sys_cpuset_getdomain
)
982 POST_MEM_WRITE(ARG5
, ARG4
);
983 POST_MEM_WRITE(ARG6
, sizeof(int));
986 // SYS_cpuset_setdomain 562
987 // int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
988 // size_t setsize, const domainset_t *mask, int policy);
989 PRE(sys_cpuset_setdomain
)
991 PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD
"d, %" FMT_REGWORD
992 "d, %" FMT_REGWORD
"d, %" FMT_REGWORD
"u, %#" FMT_REGWORD
993 "x, %" FMT_REGWORD
"d )",
994 SARG1
, SARG2
, SARG3
, ARG4
, ARG5
, SARG6
);
995 PRE_REG_READ6(int, "cpuset_getdomain", cpulevel_t
, level
, cpuwhich_t
, which
,
996 id_t
, id
, size_t, setsize
, vki_domainset_t
*, mask
, int,
998 // man page says that setsize (ARG4) "is usually provided by calling
1000 PRE_MEM_READ("cpuset_getdomain(mask)", ARG5
, ARG4
);
1005 PRE(sys_fake_sigreturn
)
1008 struct vki_ucontext
* uc
;
1011 PRINT("sys_sigreturn ( %#" FMT_REGWORD
"x )", ARG1
);
1012 PRE_REG_READ1(long, "sigreturn", struct vki_ucontext
*, scp
);
1014 PRE_MEM_READ("sigreturn(scp)", ARG1
, sizeof(struct vki_ucontext
));
1015 PRE_MEM_WRITE("sigreturn(scp)", ARG1
, sizeof(struct vki_ucontext
));
1017 vg_assert(VG_(is_valid_tid
)(tid
));
1018 vg_assert(tid
>= 1 && tid
< VG_N_THREADS
);
1019 vg_assert(VG_(is_running_thread
)(tid
));
1021 tst
= VG_(get_ThreadState
)(tid
);
1023 uc
= (struct vki_ucontext
*)ARG1
;
1025 SET_STATUS_Failure(VKI_EINVAL
);
1029 /* This is only so that the EIP is (might be) useful to report if
1030 something goes wrong in the sigreturn */
1031 ML_(fixup_guest_state_to_restart_syscall
)(&tst
->arch
);
1033 VG_(sigframe_destroy
)(tid
);
1035 /* For unclear reasons, it appears we need the syscall to return
1036 without changing %RAX. Since %RAX is the return value, and can
1037 denote either success or failure, we must set up so that the
1038 driver logic copies it back unchanged. Also, note %RAX is of
1039 the guest registers written by VG_(sigframe_destroy). */
1040 rflags
= LibVEX_GuestARM64_get_nzcv(&tst
->arch
.vex
);
1041 SET_STATUS_from_SysRes(VG_(mk_SysRes_amd64_freebsd
)(
1042 tst
->arch
.vex
.guest_X0
, tst
->arch
.vex
.guest_X1
,
1043 (rflags
& VKI_PSR_C
) != 0U ? True
: False
));
1046 * Signal handler might have changed the signal mask. Respect that.
1048 tst
->sig_mask
= uc
->uc_sigmask
;
1049 tst
->tmp_sig_mask
= uc
->uc_sigmask
;
1051 /* Tell the driver not to update the guest state with the "result",
1052 and set a bogus result to keep it happy. */
1053 *flags
|= SfNoWriteResult
;
1054 SET_STATUS_Success(0);
1056 /* Check to see if some any signals arose as a result of this. */
1057 *flags
|= SfPollAfter
;
1063 #endif /* defined(VGP_arm64_freebsd) */
1065 /*--------------------------------------------------------------------*/
1067 /*--------------------------------------------------------------------*/