2 /*--------------------------------------------------------------------*/
3 /*--- Platform-specific syscalls stuff. syswrap-x86-freebsd.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2008 Nicholas Nethercote
12 Copyright (C) 2018-2021 Paul Floyd
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, see <http://www.gnu.org/licenses/>.
28 The GNU General Public License is contained in the file COPYING.
31 #if defined(VGP_x86_freebsd)
33 /* TODO/FIXME jrs 20050207: assignments to the syscall return result
34 in interrupted_syscall() need to be reviewed. They don't seem
35 to assign the shadow state.
38 #include "pub_core_basics.h"
39 #include "pub_core_vki.h"
40 #include "pub_core_vkiscnums.h"
41 #include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
42 #include "pub_core_threadstate.h"
43 #include "pub_core_aspacemgr.h"
44 #include "pub_core_debuglog.h"
45 #include "pub_core_libcbase.h"
46 #include "pub_core_libcassert.h"
47 #include "pub_core_libcprint.h"
48 #include "pub_core_libcproc.h"
49 #include "pub_core_libcsignal.h"
50 #include "pub_core_machine.h"
51 #include "pub_core_mallocfree.h"
52 #include "pub_core_options.h"
53 #include "pub_core_scheduler.h"
54 #include "pub_core_sigframe.h" // For VG_(sigframe_destroy)()
55 #include "pub_core_signals.h"
56 #include "pub_core_syscall.h"
57 #include "pub_core_syswrap.h"
58 #include "pub_core_tooliface.h"
59 #include "pub_core_stacks.h" // VG_(register_stack)
61 #include "priv_types_n_macros.h"
62 #include "priv_syswrap-generic.h" /* for decls of generic wrappers */
63 #include "priv_syswrap-freebsd.h" /* for decls of linux-ish wrappers */
64 #include "priv_syswrap-main.h"
66 /* ---------------------------------------------------------------------
68 ------------------------------------------------------------------ */
70 /* Call f(arg1), but first switch stacks, using 'stack' as the new
71 stack, and use 'retaddr' as f's return-to address. Also, clear all
72 the integer registers before entering f.*/
73 __attribute__((noreturn
))
74 void ML_(call_on_new_stack_0_1
) ( Addr stack
,
84 ".globl vgModuleLocal_call_on_new_stack_0_1\n"
85 "vgModuleLocal_call_on_new_stack_0_1:\n"
86 " movl %esp, %esi\n" // remember old stack pointer
87 " movl 4(%esi), %esp\n" // set stack
88 " pushl 16(%esi)\n" // arg1 to stack
89 " pushl 8(%esi)\n" // retaddr to stack
90 " pushl 12(%esi)\n" // f to stack
91 " movl $0, %eax\n" // zero all GP regs
99 " ud2\n" // should never get here
106 Perform a rfork system call. rfork is strange because it has
107 fork()-like return-twice semantics, so it needs special
112 int (fn)(void*) in 0+FSZ(%esp)
113 void* child_stack in 4+FSZ(%esp)
114 int flags in 8+FSZ(%esp)
115 void* arg in 12+FSZ(%esp)
116 pid_t* child_tid in 16+FSZ(%esp)
117 pid_t* parent_tid in 20+FSZ(%esp)
118 void* tls_ptr in 24+FSZ(%esp)
120 System call requires:
122 int $__NR_clone in %eax
124 void* child_stack in %ecx
125 pid_t* parent_tid in %edx
126 pid_t* child_tid in %edi
127 void* tls_ptr in %esi
129 Returns an Int encoded in the linux-x86 way, not a SysRes.
131 #define FSZ "4+4+4+4" /* frame size = retaddr+ebx+edi+esi */
132 #define __NR_CLONE VG_STRINGIFY(__NR_clone)
133 #define __NR_EXIT VG_STRINGIFY(__NR_exit)
136 Int
do_syscall_clone_x86_freebsd ( Word (*fn
)(void *),
142 vki_modify_ldt_t
* );
145 "do_syscall_clone_x86_freebsd:\n"
150 /* set up child stack with function and arg */
151 " movl 4+"FSZ
"(%esp), %ecx\n" /* syscall arg2: child stack */
152 " movl 12+"FSZ
"(%esp), %ebx\n" /* fn arg */
153 " movl 0+"FSZ
"(%esp), %eax\n" /* fn */
154 " lea -8(%ecx), %ecx\n" /* make space on stack */
155 " movl %ebx, 4(%ecx)\n" /* fn arg */
156 " movl %eax, 0(%ecx)\n" /* fn */
158 /* get other args to clone */
159 " movl 8+"FSZ
"(%esp), %ebx\n" /* syscall arg1: flags */
160 " movl 20+"FSZ
"(%esp), %edx\n" /* syscall arg3: parent tid * */
161 " movl 16+"FSZ
"(%esp), %edi\n" /* syscall arg5: child tid * */
162 " movl 24+"FSZ
"(%esp), %esi\n" /* syscall arg4: tls_ptr * */
163 " movl $"__NR_CLONE
", %eax\n"
164 " int $0x80\n" /* clone() */
165 " testl %eax, %eax\n" /* child if retval == 0 */
168 /* CHILD - call thread function */
170 " call *%eax\n" /* call fn */
172 /* exit with result */
173 " movl %eax, %ebx\n" /* arg1: return value from fn */
174 " movl $"__NR_EXIT
", %eax\n"
177 /* Hm, exit returned */
180 "1:\n" /* PARENT or ERROR */
193 // forward declarations
194 static void setup_child ( ThreadArchState
*, ThreadArchState
*, Bool
);
197 When a client clones, we need to keep track of the new thread. This means:
198 1. allocate a ThreadId+ThreadState+stack for the the thread
200 2. initialize the thread's new VCPU state
202 3. create the thread using the same args as the client requested,
203 but using the scheduler entrypoint for EIP, and a separate stack
206 static SysRes
do_rfork ( ThreadId ptid
,
209 static const Bool debug
= False
;
212 ThreadId ctid
= VG_(alloc_ThreadState
)();
213 ThreadState
* ptst
= VG_(get_ThreadState
)(ptid
);
214 ThreadState
* ctst
= VG_(get_ThreadState
)(ctid
);
219 vki_sigset_t blockall
, savedmask
;
221 VG_(sigfillset
)(&blockall
);
223 vg_assert(VG_(is_running_thread
)(ptid
));
224 vg_assert(VG_(is_valid_tid
)(ctid
));
226 stack
= (UWord
*)ML_(allocstack
)(ctid
);
228 res
= VG_(mk_SysRes_Error
)( VKI_ENOMEM
);
232 /* Copy register state
234 Both parent and child return to the same place, and the code
235 following the clone syscall works out which is which, so we
236 don't need to worry about it.
238 The parent gets the child's new tid returned from clone, but the
241 If the clone call specifies a NULL esp for the new thread, then
242 it actually gets a copy of the parent's esp.
244 /* Note: the clone call done by the Quadrics Elan3 driver specifies
245 clone flags of 0xF00, and it seems to rely on the assumption
246 that the child inherits a copy of the parent's GDT.
247 setup_child takes care of setting that up. */
248 setup_child( &ctst
->arch
, &ptst
->arch
, True
);
250 /* Make sys_clone appear to have returned Success(0) in the
252 ctst
->arch
.vex
.guest_EAX
= 0;
254 /* Assume linuxthreads port storing its intended stack in %esi */
255 esp
= ctst
->arch
.vex
.guest_ESI
;
257 ctst
->os_state
.parent
= ptid
;
259 /* inherit signal mask */
260 ctst
->sig_mask
= ptst
->sig_mask
;
261 ctst
->tmp_sig_mask
= ptst
->sig_mask
;
263 /* We don't really know where the client stack is, because its
264 allocated by the client. The best we can do is look at the
265 memory mappings and try to derive some useful information. We
266 assume that esp starts near its highest possible value, and can
267 only go down to the start of the mmaped segment. */
268 seg
= VG_(am_find_nsegment
)((Addr
)esp
);
269 if (seg
&& seg
->kind
!= SkResvn
) {
270 ctst
->client_stack_highest_byte
= (Addr
)VG_PGROUNDUP(esp
);
271 ctst
->client_stack_szB
= ctst
->client_stack_highest_byte
- seg
->start
;
273 ctst
->os_state
.stk_id
= VG_(register_stack
)(seg
->start
, ctst
->client_stack_highest_byte
);
276 VG_(printf
)("tid %d: guessed client stack range %#lx-%#lx\n",
277 ctid
, seg
->start
, VG_PGROUNDUP(esp
));
279 VG_(message
)(Vg_UserMsg
, "!? New thread %d starts with ESP(%#lx) unmapped\n",
281 ctst
->client_stack_szB
= 0;
284 /* Assume the clone will succeed, and tell any tool that wants to
285 know that this thread has come into existence. We cannot defer
286 it beyond this point because sys_set_thread_area, just below,
287 causes tCheck to assert by making references to the new ThreadId
288 if we don't state the new thread exists prior to that point.
289 If the clone fails, we'll send out a ll_exit notification for it
290 at the out: label below, to clean up. */
291 VG_TRACK ( pre_thread_ll_create
, ptid
, ctid
);
293 /* start the thread with everything blocked */
294 VG_(sigprocmask
)(VKI_SIG_SETMASK
, &blockall
, &savedmask
);
296 /* Create the new thread */
297 /* XXX need to see what happens with tids etc with rfork */
298 eax
= do_syscall_clone_x86_freebsd(
299 ML_(start_thread_NORETURN
), stack
, flags
/*, &VG_(threads)[ctid], NULL*/ );
300 res
= VG_(mk_SysRes_x86_freebsd
)( eax
); /* XXX edx returns too! */
302 VG_(sigprocmask
)(VKI_SIG_SETMASK
, &savedmask
, NULL
);
307 VG_(cleanup_thread
)(&ctst
->arch
);
308 ctst
->status
= VgTs_Empty
;
309 /* oops. Better tell the tool the thread exited in a hurry :-) */
310 VG_TRACK( pre_thread_ll_exit
, ctid
);
317 /* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr */
320 void translate_to_hw_format ( /* IN */ void* base
,
321 /* OUT */ VexGuestX86SegDescr
* out
)
323 UInt entry_1
, entry_2
;
324 UInt base_addr
= (UInt
) base
;
325 vg_assert(8 == sizeof(VexGuestX86SegDescr
));
328 VG_(printf
)("translate_to_hw_format: base %p\n", base
);
330 /* Allow LDTs to be cleared by the user. */
336 /* base as specified, no limit, read/write/accessed etc */
337 entry_1
= ((base_addr
& 0x0000ffff) << 16) | 0x0ffff;
338 entry_2
= (base_addr
& 0xff000000) |
339 ((base_addr
& 0x00ff0000) >> 16) | 0x00cff300;
341 /* Install the new entry ... */
343 out
->LdtEnt
.Words
.word1
= entry_1
;
344 out
->LdtEnt
.Words
.word2
= entry_2
;
347 /* Create a zeroed-out GDT. */
348 static VexGuestX86SegDescr
* alloc_zeroed_x86_GDT ( void )
350 Int nbytes
= VEX_GUEST_X86_GDT_NENT
* sizeof(VexGuestX86SegDescr
);
351 return VG_(arena_calloc
)(VG_AR_CORE
, "di.syswrap-x86.azxG.1", nbytes
, 1);
354 /* Create a zeroed-out LDT. */
355 static VexGuestX86SegDescr
* alloc_zeroed_x86_LDT ( void )
357 Int nbytes
= VEX_GUEST_X86_LDT_NENT
* sizeof(VexGuestX86SegDescr
);
358 return VG_(arena_calloc
)(VG_AR_CORE
, "di.syswrap-x86.azxL.1", nbytes
, 1);
361 /* Free up an LDT or GDT allocated by the above fns. */
362 static void free_LDT_or_GDT ( VexGuestX86SegDescr
* dt
)
365 VG_(arena_free
)(VG_AR_CORE
, (void*)dt
);
368 /* Copy contents between two existing LDTs. */
369 static void copy_LDT_from_to ( VexGuestX86SegDescr
* src
,
370 VexGuestX86SegDescr
* dst
)
375 for (i
= 0; i
< VEX_GUEST_X86_LDT_NENT
; i
++)
379 /* Copy contents between two existing GDTs. */
380 static void copy_GDT_from_to ( VexGuestX86SegDescr
* src
,
381 VexGuestX86SegDescr
* dst
)
386 for (i
= 0; i
< VEX_GUEST_X86_GDT_NENT
; i
++)
390 /* Free this thread's DTs, if it has any. */
391 static void deallocate_LGDTs_for_thread ( VexGuestX86State
* vex
)
393 vg_assert(sizeof(HWord
) == sizeof(void*));
396 VG_(printf
)("deallocate_LGDTs_for_thread: "
397 "ldt = 0x%llx, gdt = 0x%llx\n",
398 vex
->guest_LDT
, vex
->guest_GDT
);
400 if (vex
->guest_LDT
!= (HWord
)NULL
) {
401 free_LDT_or_GDT( (VexGuestX86SegDescr
*)vex
->guest_LDT
);
402 vex
->guest_LDT
= (HWord
)NULL
;
405 if (vex
->guest_GDT
!= (HWord
)NULL
) {
406 free_LDT_or_GDT( (VexGuestX86SegDescr
*)vex
->guest_GDT
);
407 vex
->guest_GDT
= (HWord
)NULL
;
411 static SysRes
sys_set_thread_area ( ThreadId tid
, Int
*idxptr
, void *base
)
413 VexGuestX86SegDescr
* gdt
;
416 vg_assert(8 == sizeof(VexGuestX86SegDescr
));
417 vg_assert(sizeof(HWord
) == sizeof(VexGuestX86SegDescr
*));
419 gdt
= (VexGuestX86SegDescr
*)VG_(threads
)[tid
].arch
.vex
.guest_GDT
;
421 /* If the thread doesn't have a GDT, allocate it now. */
423 gdt
= alloc_zeroed_x86_GDT();
424 VG_(threads
)[tid
].arch
.vex
.guest_GDT
= (HWord
)gdt
;
429 /* Find and use the first free entry. Don't allocate entry
430 zero, because the hardware will never do that, and apparently
431 doing so confuses some code (perhaps stuff running on
433 for (idx
= 1; idx
< VEX_GUEST_X86_GDT_NENT
; idx
++) {
434 if (gdt
[idx
].LdtEnt
.Words
.word1
== 0
435 && gdt
[idx
].LdtEnt
.Words
.word2
== 0)
439 if (idx
== VEX_GUEST_X86_GDT_NENT
)
440 return VG_(mk_SysRes_Error
)( VKI_ESRCH
);
441 } else if (idx
< 0 || idx
== 0 || idx
>= VEX_GUEST_X86_GDT_NENT
) {
442 /* Similarly, reject attempts to use GDT[0]. */
443 return VG_(mk_SysRes_Error
)( VKI_EINVAL
);
446 translate_to_hw_format(base
, &gdt
[idx
]);
449 return VG_(mk_SysRes_Success
)( 0 );
452 static SysRes
sys_get_thread_area ( ThreadId tid
, Int idx
, void ** basep
)
454 VexGuestX86SegDescr
* gdt
;
457 vg_assert(sizeof(HWord
) == sizeof(VexGuestX86SegDescr
*));
458 vg_assert(8 == sizeof(VexGuestX86SegDescr
));
460 gdt
= (VexGuestX86SegDescr
*)VG_(threads
)[tid
].arch
.vex
.guest_GDT
;
462 /* If the thread doesn't have a GDT, allocate it now. */
464 gdt
= alloc_zeroed_x86_GDT();
465 VG_(threads
)[tid
].arch
.vex
.guest_GDT
= (HWord
)gdt
;
468 base
= ( gdt
[idx
].LdtEnt
.Bits
.BaseHi
<< 24 ) |
469 ( gdt
[idx
].LdtEnt
.Bits
.BaseMid
<< 16 ) |
470 gdt
[idx
].LdtEnt
.Bits
.BaseLow
;
471 *basep
= (void *)base
;
473 return VG_(mk_SysRes_Success
)( 0 );
477 void x86_setup_LDT_GDT ( /*OUT*/ ThreadArchState
*child
,
478 /*IN*/ ThreadArchState
*parent
)
480 /* We inherit our parent's LDT. */
481 if (parent
->vex
.guest_LDT
== (HWord
)NULL
) {
482 /* We hope this is the common case. */
483 child
->vex
.guest_LDT
= (HWord
)NULL
;
485 /* No luck .. we have to take a copy of the parent's. */
486 child
->vex
.guest_LDT
= (HWord
)alloc_zeroed_x86_LDT();
487 copy_LDT_from_to( (VexGuestX86SegDescr
*)(HWord
)parent
->vex
.guest_LDT
,
488 (VexGuestX86SegDescr
*)(HWord
)child
->vex
.guest_LDT
);
491 /* Either we start with an empty GDT (the usual case) or inherit a
492 copy of our parents' one (Quadrics Elan3 driver -style clone
494 child
->vex
.guest_GDT
= (HWord
)NULL
;
496 if (parent
->vex
.guest_GDT
!= (HWord
)NULL
) {
497 //child->vex.guest_GDT = (HWord)alloc_system_x86_GDT();
498 child
->vex
.guest_GDT
= (HWord
)alloc_zeroed_x86_GDT();
499 copy_GDT_from_to( (VexGuestX86SegDescr
*)(HWord
)parent
->vex
.guest_GDT
,
500 (VexGuestX86SegDescr
*)(HWord
)child
->vex
.guest_GDT
);
506 /* ---------------------------------------------------------------------
508 ------------------------------------------------------------------ */
510 void VG_(cleanup_thread
) ( ThreadArchState
* arch
)
513 * This is what x86 Linux does but it doesn't work off the bat for x86 FreeBSD
514 * My suspicion is that the rtld code uses the TCB stored in the GDT after the
516 * Alternatively the rtld use is after the start of the next thread and we haven't
517 * reallocated this memory
519 deallocate_LGDTs_for_thread( &arch
->vex
);
523 /* ---------------------------------------------------------------------
524 PRE/POST wrappers for x86/FreeBSD-specific syscalls
525 ------------------------------------------------------------------ */
527 #define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name)
528 #define POST(name) DEFN_POST_TEMPLATE(freebsd, name)
531 // int sysarch(int number, void *args);
538 PRINT("sys_sysarch ( %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x )", ARG1
, ARG2
);
539 PRE_REG_READ2(int, "sysarch", int, number
, void *, args
);
541 case VKI_I386_SET_GSBASE
:
542 PRINT("sys_i386_set_gsbase ( %#lx )", ARG2
);
544 if (ML_(safe_to_deref
)((void**)ARG2
, sizeof(void*))) {
545 /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */
546 tst
= VG_(get_ThreadState
)(tid
);
548 tst
->arch
.vex
.guest_GS
= (1 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */
549 /* "do" the syscall ourselves; the kernel never sees it */
551 SET_STATUS_from_SysRes( sys_set_thread_area( tid
, &idx
, *p
) );
554 SET_STATUS_Failure( VKI_EINVAL
);
558 case VKI_I386_GET_GSBASE
:
559 PRINT("sys_i386_get_gsbase ( %#lx )", ARG2
);
560 PRE_MEM_WRITE( "i386_get_gsbase(basep)", ARG2
, sizeof(void *) );
561 if (ML_(safe_to_deref
)((void**)ARG2
, sizeof(void*))) {
562 /* "do" the syscall ourselves; the kernel never sees it */
563 SET_STATUS_from_SysRes( sys_get_thread_area( tid
, 2, (void **)ARG2
) );
565 SET_STATUS_Failure( VKI_EINVAL
);
568 case VKI_I386_GET_XFPUSTATE
:
569 PRINT("sys_i386_get_xfpustate ( %#lx )", ARG2
);
570 PRE_MEM_WRITE( "i386_get_xfpustate(basep)", ARG2
, sizeof(void *) );
571 /* "do" the syscall ourselves; the kernel never sees it */
572 tst
= VG_(get_ThreadState
)(tid
);
573 SET_STATUS_Success2( tst
->arch
.vex
.guest_FPTAG
[0], tst
->arch
.vex
.guest_FPTAG
[0] );
576 VG_(message
) (Vg_UserMsg
, "unhandled sysarch cmd %lu", ARG1
);
577 VG_(unimplemented
) ("unhandled sysarch cmd");
585 case VKI_AMD64_SET_FSBASE
:
587 case VKI_AMD64_GET_FSBASE
:
588 POST_MEM_WRITE( ARG2
, sizeof(void *) );
590 case VKI_AMD64_GET_XFPUSTATE
:
591 POST_MEM_WRITE( ARG2
, sizeof(void *) );
598 // freebsd6_pread 173
599 #if (FREEBSD_VERS <= FREEBSD_10)
600 PRE(sys_freebsd6_pread
)
602 *flags
|= SfMayBlock
;
603 PRINT("sys_freebsd6_pread ( %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u )", ARG1
, ARG2
, ARG3
, ARG5
, ARG6
);
604 PRE_REG_READ6(ssize_t
, "pread",
605 unsigned int, fd
, char *, buf
, vki_size_t
, count
,
606 int, pad
, unsigned int, off_low
, unsigned int, off_high
);
608 if (!ML_(fd_allowed
)(ARG1
, "freebsd6_pread", tid
, False
))
609 SET_STATUS_Failure( VKI_EBADF
);
611 PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2
, ARG3
);
614 POST(sys_freebsd6_pread
)
617 POST_MEM_WRITE( ARG2
, RES
);
621 // freebsd6_pwrite 174
622 #if (FREEBSD_VERS <= FREEBSD_10)
623 PRE(sys_freebsd6_pwrite
)
626 *flags
|= SfMayBlock
;
627 PRINT("sys_freebsd6_pwrite ( %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u )", ARG1
, ARG2
, ARG3
, ARG5
, ARG6
);
628 PRE_REG_READ6(ssize_t
, "freebsd6_pwrite",
629 unsigned int, fd
, const char *, buf
, vki_size_t
, count
,
630 int, pad
, unsigned int, off_low
, unsigned int, off_high
);
631 /* check to see if it is allowed. If not, try for an exemption from
632 --sim-hints=enable-outer (used for self hosting). */
633 ok
= ML_(fd_allowed
)(ARG1
, "freebsd6_pwrite", tid
, False
);
634 if (!ok
&& ARG1
== 2/*stderr*/
635 && SimHintiS(SimHint_enable_outer
, VG_(clo_sim_hints
)))
638 SET_STATUS_Failure( VKI_EBADF
);
640 PRE_MEM_READ( "freebsd6_write(buf)", ARG2
, ARG3
);
644 // SYS_freebsd6_mmap 197
645 #if (FREEBSD_VERS <= FREEBSD_10)
646 /* This is here because on x86 the off_t is passed in 2 regs. Don't ask about pad. */
648 /* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); */
649 /* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7+ARG8 */
651 PRE(sys_freebsd6_mmap
)
655 PRINT("sys_freebsd6_mmap ( %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, pad%" FMT_REGWORD
"u, lo0x%" FMT_REGWORD
"x hi0x%" FMT_REGWORD
"x)",
656 ARG1
, (UWord
)ARG2
, ARG3
, ARG4
, ARG5
, ARG6
, ARG7
, ARG8
);
657 PRE_REG_READ8(long, "mmap",
658 char *, addr
, unsigned long, len
, int, prot
, int, flags
,
659 int, fd
, int, pad
, unsigned long, lo
, unsigned long, hi
);
661 r
= ML_(generic_PRE_sys_mmap
)( tid
, ARG1
, ARG2
, ARG3
, ARG4
, ARG5
, MERGE64(ARG7
,ARG8
) );
662 SET_STATUS_from_SysRes(r
);
666 // freebsd6_lseek 199
667 #if (FREEBSD_VERS <= FREEBSD_10)
668 PRE(sys_freebsd6_lseek
)
670 PRINT("sys_freebsd6_lseek ( %" FMT_REGWORD
"u, 0x%" FMT_REGWORD
"x, 0x%" FMT_REGWORD
"x, %" FMT_REGWORD
"u )", ARG1
,ARG3
,ARG4
,ARG5
);
671 PRE_REG_READ5(long, "lseek",
672 unsigned int, fd
, int, pad
, unsigned int, offset_low
,
673 unsigned int, offset_high
, unsigned int, whence
);
677 // freebsd6_truncate 200
678 #if (FREEBSD_VERS <= FREEBSD_10)
679 PRE(sys_freebsd6_truncate
)
681 *flags
|= SfMayBlock
;
682 PRINT("sys_truncate ( %#" FMT_REGWORD
"x(%s), %" FMT_REGWORD
"u, %" FMT_REGWORD
"u )", ARG1
,(char *)ARG1
,ARG3
,ARG4
);
683 PRE_REG_READ4(long, "truncate",
684 const char *, path
, int, pad
,
685 unsigned int, length_low
, unsigned int, length_high
);
686 PRE_MEM_RASCIIZ( "truncate(path)", ARG1
);
690 // freebsd6_ftruncate 201
691 #if (FREEBSD_VERS <= FREEBSD_10)
692 PRE(sys_freebsd6_ftruncate
)
694 *flags
|= SfMayBlock
;
695 PRINT("sys_ftruncate ( %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u )", ARG1
,ARG3
,ARG4
);
696 PRE_REG_READ4(long, "ftruncate", unsigned int, fd
, int, pad
,
697 unsigned int, length_low
, unsigned int, length_high
);
701 // SYS_clock_getcpuclockid2 247
702 // no manpage for this, from syscalls.master
703 // int clock_getcpuclockid2(id_t id, int which, _Out_ clockid_t *clock_id);
704 PRE(sys_clock_getcpuclockid2
)
706 PRINT("sys_clock_getcpuclockid2( %lld, %" FMT_REGWORD
"d, %#" FMT_REGWORD
"x )",
707 (vki_id_t
)MERGE64(ARG1
,ARG2
),SARG3
,ARG4
);
708 PRE_REG_READ4(int, "clock_getcpuclockid2",
709 vki_uint32_t
, MERGE64_FIRST(offset
),
710 vki_uint32_t
, MERGE64_SECOND(offset
),
711 int, len
, clockid_t
*, clock_id
);
712 PRE_MEM_WRITE("clock_getcpuclockid2(clock_id)", ARG3
, sizeof(vki_clockid_t
));
716 // pid_t rfork(int flags);
719 PRINT("sys_rfork ( %" FMT_REGWORD
"x )",ARG1
);
720 PRE_REG_READ1(int, "rfork",
721 unsigned int, flags
);
726 if (!ML_(client_signal_OK
)(ARG1
& VKI_CSIGNAL
)) {
727 SET_STATUS_Failure( VKI_EINVAL
);
731 SET_STATUS_from_SysRes( do_clone(tid
, ARG1
));
734 *flags
|= SfYieldAfter
;
737 VG_(message
)(Vg_UserMsg
, "rfork() not implemented");
738 VG_(unimplemented
)("Valgrind does not support rfork() yet.");
739 SET_STATUS_Failure( VKI_ENOSYS
);
744 // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
748 struct vki_iovec
* vec
;
749 *flags
|= SfMayBlock
;
750 PRINT("sys_preadv ( %" FMT_REGWORD
"d, %#" FMT_REGWORD
"x, %"
751 FMT_REGWORD
"d, %llu )", SARG1
, ARG2
, SARG3
, MERGE64(ARG4
,ARG5
));
752 PRE_REG_READ5(ssize_t
, "preadv",
753 int, fd
, const struct iovec
*, iov
,
754 int, iovcnt
, vki_uint32_t
, MERGE64_FIRST(offset
),
755 vki_uint32_t
, MERGE64_SECOND(offset
));
756 if (!ML_(fd_allowed
)(ARG1
, "preadv", tid
, False
)) {
757 SET_STATUS_Failure( VKI_EBADF
);
760 PRE_MEM_READ( "preadv(iov)", ARG2
, ARG3
* sizeof(struct vki_iovec
) );
762 if (ML_(safe_to_deref
)((struct vki_iovec
*)ARG2
, ARG3
* sizeof(struct vki_iovec
))) {
763 vec
= (struct vki_iovec
*)(Addr
)ARG2
;
764 for (i
= 0; i
< (Int
)ARG3
; i
++)
765 PRE_MEM_WRITE( "preadv(iov[...])",
766 (Addr
)vec
[i
].iov_base
, vec
[i
].iov_len
);
776 struct vki_iovec
* vec
= (struct vki_iovec
*)(Addr
)ARG2
;
779 /* RES holds the number of bytes read. */
780 for (i
= 0; i
< (Int
)ARG3
; i
++) {
781 Int nReadThisBuf
= vec
[i
].iov_len
;
782 if (nReadThisBuf
> remains
) nReadThisBuf
= remains
;
783 POST_MEM_WRITE( (Addr
)vec
[i
].iov_base
, nReadThisBuf
);
784 remains
-= nReadThisBuf
;
785 if (remains
< 0) VG_(core_panic
)("preadv: remains < 0");
791 // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
795 struct vki_iovec
* vec
;
796 *flags
|= SfMayBlock
;
797 PRINT("sys_pwritev ( %" FMT_REGWORD
"d, %#" FMT_REGWORD
"x, %"
798 FMT_REGWORD
"d, %llu )", SARG1
, ARG2
, SARG3
, MERGE64(ARG4
,ARG5
));
800 PRE_REG_READ5(ssize_t
, "pwritev",
801 int, fd
, const struct iovec
*, iov
,
803 vki_uint32_t
, MERGE64_FIRST(offset
),
804 vki_uint32_t
, MERGE64_SECOND(offset
));
805 if (!ML_(fd_allowed
)(ARG1
, "pwritev", tid
, False
)) {
806 SET_STATUS_Failure( VKI_EBADF
);
809 PRE_MEM_READ( "pwritev(vector)", ARG2
, ARG3
* sizeof(struct vki_iovec
) );
810 if (ML_(safe_to_deref
)((struct vki_iovec
*)ARG2
, ARG3
* sizeof(struct vki_iovec
))) {
811 vec
= (struct vki_iovec
*)(Addr
)ARG2
;
812 for (i
= 0; i
< (Int
)ARG3
; i
++)
813 PRE_MEM_READ( "pwritev(iov[...])",
814 (Addr
)vec
[i
].iov_base
, vec
[i
].iov_len
);
820 // int sendfile(int fd, int s, off_t offset, size_t nbytes,
821 // struct sf_hdtr *hdtr, off_t *sbytes, int flags);
824 *flags
|= SfMayBlock
;
825 PRINT("sys_sendfile ( %" FMT_REGWORD
"d, %" FMT_REGWORD
"d, %llu, %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"d )",
826 SARG1
,SARG2
,LOHI64(ARG3
,ARG4
),ARG5
,ARG6
,ARG7
,SARG8
);
827 PRE_REG_READ8(int, "sendfile",
828 int, fd
, int, s
, unsigned int, offset_low
,
829 unsigned int, offset_high
, size_t, nbytes
,
830 void *, hdtr
, vki_off_t
*, sbytes
, int, flags
);
833 PRE_MEM_READ("sendfile(hdtr)", ARG6
, sizeof(struct vki_sf_hdtr
));
836 PRE_MEM_WRITE( "sendfile(sbytes)", ARG7
, sizeof(vki_off_t
) );
842 POST_MEM_WRITE( ARG7
, sizeof( vki_off_t
) );
847 // int sigreturn(const ucontext_t *scp);
850 PRINT("sys_sigreturn ( %#" FMT_REGWORD
"x )", ARG1
);
851 PRE_REG_READ1(int, "sigreturn",
852 struct vki_ucontext
*, scp
);
854 PRE_MEM_READ( "sigreturn(scp)", ARG1
, sizeof(struct vki_ucontext
) );
855 PRE_MEM_WRITE( "sigreturn(scp)", ARG1
, sizeof(struct vki_ucontext
) );
859 static void restore_mcontext(ThreadState
*tst
, struct vki_mcontext
*sc
)
861 tst
->arch
.vex
.guest_EAX
= sc
->eax
;
862 tst
->arch
.vex
.guest_ECX
= sc
->ecx
;
863 tst
->arch
.vex
.guest_EDX
= sc
->edx
;
864 tst
->arch
.vex
.guest_EBX
= sc
->ebx
;
865 tst
->arch
.vex
.guest_EBP
= sc
->ebp
;
866 tst
->arch
.vex
.guest_ESP
= sc
->esp
;
867 tst
->arch
.vex
.guest_ESI
= sc
->esi
;
868 tst
->arch
.vex
.guest_EDI
= sc
->edi
;
869 tst
->arch
.vex
.guest_EIP
= sc
->eip
;
870 tst
->arch
.vex
.guest_CS
= sc
->cs
;
871 tst
->arch
.vex
.guest_SS
= sc
->ss
;
872 tst
->arch
.vex
.guest_DS
= sc
->ds
;
873 tst
->arch
.vex
.guest_ES
= sc
->es
;
874 tst
->arch
.vex
.guest_FS
= sc
->fs
;
875 tst
->arch
.vex
.guest_GS
= sc
->gs
;
877 * XXX: missing support for other flags.
879 if (sc
->eflags
& 0x0001)
880 LibVEX_GuestX86_put_eflag_c(1, &tst
->arch
.vex
);
882 LibVEX_GuestX86_put_eflag_c(0, &tst
->arch
.vex
);
885 static void fill_mcontext(ThreadState
*tst
, struct vki_mcontext
*sc
)
887 sc
->eax
= tst
->arch
.vex
.guest_EAX
;
888 sc
->ecx
= tst
->arch
.vex
.guest_ECX
;
889 sc
->edx
= tst
->arch
.vex
.guest_EDX
;
890 sc
->ebx
= tst
->arch
.vex
.guest_EBX
;
891 sc
->ebp
= tst
->arch
.vex
.guest_EBP
;
892 sc
->esp
= tst
->arch
.vex
.guest_ESP
;
893 sc
->esi
= tst
->arch
.vex
.guest_ESI
;
894 sc
->edi
= tst
->arch
.vex
.guest_EDI
;
895 sc
->eip
= tst
->arch
.vex
.guest_EIP
;
896 sc
->cs
= tst
->arch
.vex
.guest_CS
;
897 sc
->ss
= tst
->arch
.vex
.guest_SS
;
898 sc
->ds
= tst
->arch
.vex
.guest_DS
;
899 sc
->es
= tst
->arch
.vex
.guest_ES
;
900 sc
->fs
= tst
->arch
.vex
.guest_FS
;
901 sc
->gs
= tst
->arch
.vex
.guest_GS
;
902 sc
->eflags
= LibVEX_GuestX86_get_eflags(&tst
->arch
.vex
);
905 VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate));
907 sc
->fpformat
= VKI_FPFMT_NODEV
;
908 sc
->ownedfp
= VKI_FPOWNED_NONE
;
909 sc
->len
= sizeof(*sc
);
910 VG_(memset
)(sc
->spare2
, 0, sizeof(sc
->spare2
));
913 // SYS_getcontext 421
914 // int getcontext(ucontext_t *ucp);
918 struct vki_ucontext
*uc
;
920 PRINT("sys_getcontext ( %#" FMT_REGWORD
"x )", ARG1
);
921 PRE_REG_READ1(int, "getcontext",
922 struct vki_ucontext
*, ucp
);
923 PRE_MEM_WRITE( "getcontext(ucp)", ARG1
, sizeof(struct vki_ucontext
) );
924 uc
= (struct vki_ucontext
*)ARG1
;
925 if (!ML_(safe_to_deref
)(uc
, sizeof(struct vki_ucontext
))) {
926 SET_STATUS_Failure(VKI_EINVAL
);
929 tst
= VG_(get_ThreadState
)(tid
);
930 fill_mcontext(tst
, &uc
->uc_mcontext
);
931 uc
->uc_mcontext
.eax
= 0;
932 uc
->uc_mcontext
.edx
= 0;
933 uc
->uc_mcontext
.eflags
&= ~0x0001; /* PSL_C */
934 uc
->uc_sigmask
= tst
->sig_mask
;
935 VG_(memset
)(uc
->__spare__
, 0, sizeof(uc
->__spare__
));
936 SET_STATUS_Success(0);
939 // SYS_setcontext 422
940 // int setcontext(const ucontext_t *ucp);
944 struct vki_ucontext
*uc
;
946 PRINT("sys_setcontext ( %#" FMT_REGWORD
"x )", ARG1
);
947 PRE_REG_READ1(long, "setcontext",
948 struct vki_ucontext
*, ucp
);
950 PRE_MEM_READ( "setcontext(ucp)", ARG1
, sizeof(struct vki_ucontext
) );
951 PRE_MEM_WRITE( "setcontext(ucp)", ARG1
, sizeof(struct vki_ucontext
) );
953 vg_assert(VG_(is_valid_tid
)(tid
));
954 vg_assert(tid
>= 1 && tid
< VG_N_THREADS
);
955 vg_assert(VG_(is_running_thread
)(tid
));
957 tst
= VG_(get_ThreadState
)(tid
);
958 uc
= (struct vki_ucontext
*)ARG1
;
959 if (!ML_(safe_to_deref
)(uc
, sizeof(struct vki_ucontext
)) || uc
->uc_mcontext
.len
!= sizeof(uc
->uc_mcontext
)) {
960 SET_STATUS_Failure(VKI_EINVAL
);
964 restore_mcontext(tst
, &uc
->uc_mcontext
);
965 tst
->sig_mask
= uc
->uc_sigmask
;
966 tst
->tmp_sig_mask
= uc
->uc_sigmask
;
968 /* Tell the driver not to update the guest state with the "result",
969 and set a bogus result to keep it happy. */
970 *flags
|= SfNoWriteResult
;
971 SET_STATUS_Success(0);
973 /* Check to see if some any signals arose as a result of this. */
974 *flags
|= SfPollAfter
;
977 // SYS_swapcontext 423
978 // int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
981 struct vki_ucontext
*ucp
, *oucp
;
984 PRINT("sys_swapcontext ( %#" FMT_REGWORD
"x, %#" FMT_REGWORD
"x )", ARG1
, ARG2
);
985 PRE_REG_READ2(long, "swapcontext",
986 struct vki_ucontext
*, oucp
, struct vki_ucontext
*, ucp
);
988 PRE_MEM_READ( "swapcontext(ucp)", ARG2
, sizeof(struct vki_ucontext
) );
989 PRE_MEM_WRITE( "swapcontext(oucp)", ARG1
, sizeof(struct vki_ucontext
) );
991 oucp
= (struct vki_ucontext
*)ARG1
;
992 ucp
= (struct vki_ucontext
*)ARG2
;
993 if (!ML_(safe_to_deref
)(oucp
, sizeof(struct vki_ucontext
)) ||
994 !ML_(safe_to_deref
)(ucp
, sizeof(struct vki_ucontext
)) ||
995 ucp
->uc_mcontext
.len
!= sizeof(ucp
->uc_mcontext
)) {
996 SET_STATUS_Failure(VKI_EINVAL
);
999 tst
= VG_(get_ThreadState
)(tid
);
1004 fill_mcontext(tst
, &oucp
->uc_mcontext
);
1005 oucp
->uc_mcontext
.eax
= 0;
1006 oucp
->uc_mcontext
.edx
= 0;
1007 oucp
->uc_mcontext
.eflags
&= ~0x0001; /* PSL_C */
1008 oucp
->uc_sigmask
= tst
->sig_mask
;
1009 VG_(memset
)(oucp
->__spare__
, 0, sizeof(oucp
->__spare__
));
1012 * Switch to new one.
1014 restore_mcontext(tst
, &ucp
->uc_mcontext
);
1015 tst
->sig_mask
= ucp
->uc_sigmask
;
1016 tst
->tmp_sig_mask
= ucp
->uc_sigmask
;
1018 /* Tell the driver not to update the guest state with the "result",
1019 and set a bogus result to keep it happy. */
1020 *flags
|= SfNoWriteResult
;
1021 SET_STATUS_Success(0);
1023 /* Check to see if some any signals arose as a result of this. */
1024 *flags
|= SfPollAfter
;
1028 // int thr_new(struct thr_param *param, int param_size);
1031 static const Bool debug
= False
;
1033 ThreadId ctid
= VG_(alloc_ThreadState
)();
1034 ThreadState
* ptst
= VG_(get_ThreadState
)(tid
);
1035 ThreadState
* ctst
= VG_(get_ThreadState
)(ctid
);
1037 vki_sigset_t blockall
, savedmask
;
1038 struct vki_thr_param tp
;
1042 PRINT("thr_new ( %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u )",ARG1
,ARG2
);
1043 PRE_REG_READ2(int, "thr_new",
1044 struct thr_param
*, param
,
1047 PRE_MEM_READ( "thr_new(param)", ARG1
, offsetof(struct vki_thr_param
, spare
));
1048 if (!ML_(safe_to_deref
)( (void*)ARG1
, offsetof(struct vki_thr_param
, spare
))) {
1049 SET_STATUS_Failure( VKI_EFAULT
);
1052 VG_(memset
)(&tp
, 0, sizeof(tp
));
1053 VG_(memcpy
)(&tp
, (void *)ARG1
, offsetof(struct vki_thr_param
, spare
));
1054 PRE_MEM_WRITE("clone(parent_tidptr)", (Addr
)tp
.parent_tid
, sizeof(long));
1055 PRE_MEM_WRITE("clone(child_tidptr)", (Addr
)tp
.child_tid
, sizeof(long));
1057 VG_(sigfillset
)(&blockall
);
1059 vg_assert(VG_(is_running_thread
)(tid
));
1060 vg_assert(VG_(is_valid_tid
)(ctid
));
1062 /* Copy register state
1064 On linux, both parent and child return to the same place, and the code
1065 following the clone syscall works out which is which, so we
1066 don't need to worry about it.
1067 On FreeBSD, thr_new arranges a direct call. We don't actually need any
1070 The parent gets the child's new tid returned from clone, but the
1073 If the clone call specifies a NULL rsp for the new thread, then
1074 it actually gets a copy of the parent's rsp.
1076 /* We inherit our parent's guest state. */
1077 ctst
->arch
.vex
= ptst
->arch
.vex
;
1078 ctst
->arch
.vex_shadow1
= ptst
->arch
.vex_shadow1
;
1079 ctst
->arch
.vex_shadow2
= ptst
->arch
.vex_shadow2
;
1081 /* Make sys_clone appear to have returned Success(0) in the
1083 ctst
->arch
.vex
.guest_EAX
= 0;
1084 ctst
->arch
.vex
.guest_EDX
= 0;
1085 LibVEX_GuestX86_put_eflag_c(0, &ctst
->arch
.vex
);
1087 x86_setup_LDT_GDT(&ctst
->arch
, &ptst
->arch
);
1089 ctst
->os_state
.parent
= tid
;
1091 /* inherit signal mask */
1092 ctst
->sig_mask
= ptst
->sig_mask
;
1093 ctst
->tmp_sig_mask
= ptst
->sig_mask
;
1095 /* Linux has to guess, we don't */
1096 ctst
->client_stack_highest_byte
= (Addr
)tp
.stack_base
+ tp
.stack_size
;
1097 ctst
->client_stack_szB
= tp
.stack_size
;
1098 ctst
->os_state
.stk_id
= VG_(register_stack
)((Addr
)tp
.stack_base
, (Addr
)tp
.stack_base
+ tp
.stack_size
);
1100 /* Assume the clone will succeed, and tell any tool that wants to
1101 know that this thread has come into existence. If the clone
1102 fails, we'll send out a ll_exit notification for it at the out:
1103 label below, to clean up. */
1104 VG_TRACK ( pre_thread_ll_create
, tid
, ctid
);
1107 VG_(printf
)("clone child has SETTLS: tls at %#lx\n", (Addr
)tp
.tls_base
);
1109 sys_set_thread_area( ctid
, &idx
, tp
.tls_base
);
1111 ctst
->arch
.vex
.guest_GS
= (idx
<< 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */
1112 tp
.tls_base
= 0; /* Don't have the kernel do it too */
1114 /* start the thread with everything blocked */
1115 VG_(sigprocmask
)(VKI_SIG_SETMASK
, &blockall
, &savedmask
);
1117 /* Set the client state for scheduler to run libthr's trampoline */
1118 ctst
->arch
.vex
.guest_ESP
= (Addr
)tp
.stack_base
+ tp
.stack_size
- 8;
1119 ctst
->arch
.vex
.guest_EIP
= (Addr
)tp
.start_func
;
1120 *(UWord
*)(ctst
->arch
.vex
.guest_ESP
+ 4) = (UWord
)tp
.arg
; /* Client arg */
1121 *(UWord
*)(ctst
->arch
.vex
.guest_ESP
+ 0) = 0; /* fake return addr */
1123 /* Set up valgrind's trampoline on its own stack */
1124 stk
= ML_(allocstack
)(ctid
);
1125 tp
.stack_base
= (void *)ctst
->os_state
.valgrind_stack_base
;
1126 tp
.stack_size
= (Addr
)stk
- (Addr
)tp
.stack_base
;
1127 /* This is for thr_new() to run valgrind's trampoline */
1128 tp
.start_func
= (void *)ML_(start_thread_NORETURN
);
1129 tp
.arg
= &VG_(threads
)[ctid
];
1131 /* Create the new thread */
1132 res
= VG_(do_syscall2
)(__NR_thr_new
, (UWord
)&tp
, sizeof(tp
));
1134 VG_(sigprocmask
)(VKI_SIG_SETMASK
, &savedmask
, NULL
);
1136 if (sr_isError(res
)) {
1138 VG_(cleanup_thread
)(&ctst
->arch
);
1139 ctst
->status
= VgTs_Empty
;
1140 /* oops. Better tell the tool the thread exited in a hurry :-) */
1141 VG_TRACK( pre_thread_ll_exit
, ctid
);
1144 POST_MEM_WRITE((Addr
)tp
.parent_tid
, sizeof(long));
1145 POST_MEM_WRITE((Addr
)tp
.child_tid
, sizeof(long));
1146 POST_MEM_WRITE((Addr
)ctst
->arch
.vex
.guest_ESP
, 8);
1148 /* Thread creation was successful; let the child have the chance
1150 *flags
|= SfYieldAfter
;
1153 /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */
1154 SET_STATUS_from_SysRes(res
);
1158 // ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
1161 *flags
|= SfMayBlock
;
1162 PRINT("sys_pread ( %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u )", ARG1
, ARG2
, ARG3
, ARG4
, ARG5
);
1163 PRE_REG_READ5(ssize_t
, "pread",
1164 unsigned int, fd
, char *, buf
, vki_size_t
, count
,
1165 unsigned int, off_low
, unsigned int, off_high
);
1167 if (!ML_(fd_allowed
)(ARG1
, "pread", tid
, False
))
1168 SET_STATUS_Failure( VKI_EBADF
);
1170 PRE_MEM_WRITE( "pread(buf)", ARG2
, ARG3
);
1176 POST_MEM_WRITE( ARG2
, RES
);
1180 // ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
1184 *flags
|= SfMayBlock
;
1185 PRINT("sys_pwrite ( %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u, %llu )", ARG1
, ARG2
, ARG3
, MERGE64(ARG4
, ARG5
));
1186 PRE_REG_READ5(ssize_t
, "pwrite",
1187 unsigned int, fd
, const char *, buf
, vki_size_t
, count
,
1188 vki_uint32_t
, MERGE64_FIRST(offset
),
1189 vki_uint32_t
, MERGE64_SECOND(offset
));
1190 /* check to see if it is allowed. If not, try for an exemption from
1191 --sim-hints=enable-outer (used for self hosting). */
1192 ok
= ML_(fd_allowed
)(ARG1
, "pwrite", tid
, False
);
1193 if (!ok
&& ARG1
== 2/*stderr*/
1194 && SimHintiS(SimHint_enable_outer
, VG_(clo_sim_hints
)))
1197 SET_STATUS_Failure( VKI_EBADF
);
1199 PRE_MEM_READ( "pwrite(buf)", ARG2
, ARG3
);
1203 // void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
1208 PRINT("sys_mmap ( %#" FMT_REGWORD
"x, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %llu )",
1209 ARG1
, (UWord
)ARG2
, ARG3
, ARG4
, ARG5
, MERGE64(ARG6
, ARG7
) );
1210 PRE_REG_READ7(void *, "mmap",
1211 void *, addr
, size_t, len
, int, prot
, int, flags
, int, fd
,
1212 vki_uint32_t
, MERGE64_FIRST(offset
),
1213 vki_uint32_t
, MERGE64_SECOND(offset
));
1215 r
= ML_(generic_PRE_sys_mmap
)( tid
, ARG1
, ARG2
, ARG3
, ARG4
, ARG5
, MERGE64(ARG6
,ARG7
) );
1216 SET_STATUS_from_SysRes(r
);
1220 // off_t lseek(int fildes, off_t offset, int whence);
1223 PRINT("sys_lseek ( %" FMT_REGWORD
"d, %llu, %" FMT_REGWORD
"d )", SARG1
,MERGE64(ARG2
,ARG3
),SARG4
);
1224 PRE_REG_READ4(long, "lseek",
1226 vki_uint32_t
, MERGE64_FIRST(offset
),
1227 vki_uint32_t
, MERGE64_SECOND(offset
),
1228 unsigned int, whence
);
1232 // int truncate(const char *path, off_t length);
1235 *flags
|= SfMayBlock
;
1236 PRINT("sys_truncate ( %#" FMT_REGWORD
"x(%s), %llu )", ARG1
,(char *)ARG1
,MERGE64(ARG2
,ARG3
));
1237 PRE_REG_READ3(long, "truncate",
1239 vki_uint32_t
, MERGE64_FIRST(length
),
1240 vki_uint32_t
, MERGE64_SECOND(length
));
1241 PRE_MEM_RASCIIZ( "truncate(path)", ARG1
);
1244 // SYS_ftruncate 480
1245 // int ftruncate(int fd, off_t length);
1248 *flags
|= SfMayBlock
;
1249 PRINT("sys_ftruncate ( %" FMT_REGWORD
"d, %" FMT_REGWORD
"u, %" FMT_REGWORD
"u )", SARG1
,ARG2
,ARG3
);
1250 PRE_REG_READ3(int, "ftruncate", int, fd
,
1251 vki_uint32_t
, MERGE64_FIRST(length
),
1252 vki_uint32_t
, MERGE64_SECOND(length
));
1255 // SYS_cpuset_setid 485
1256 // int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid);
1257 PRE(sys_cpuset_setid
)
1259 PRINT("sys_cpuset_setid ( %" FMT_REGWORD
"d, %llu, %#" FMT_REGWORD
"x )",
1260 SARG1
, MERGE64(ARG2
,ARG3
), ARG4
);
1261 PRE_REG_READ4(int, "cpuset_setid", vki_cpuwhich_t
, which
,
1262 vki_uint32_t
, MERGE64_FIRST(id
),
1263 vki_uint32_t
, MERGE64_SECOND(id
),
1264 vki_cpusetid_t
,setid
);
1267 // SYS_cpuset_getid 486
1268 // int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id,
1269 // cpusetid_t *setid);
1270 PRE(sys_cpuset_getid
)
1272 PRINT("sys_cpuset_getid ( %" FMT_REGWORD
"d, %" FMT_REGWORD
"d, %llu, %#" FMT_REGWORD
"x )",
1273 SARG1
, SARG2
, MERGE64(ARG3
, ARG4
), ARG5
);
1274 PRE_REG_READ5(int, "cpuset_getid", vki_cpulevel_t
, level
,
1275 vki_cpuwhich_t
, which
,
1276 vki_uint32_t
, MERGE64_FIRST(id
),
1277 vki_uint32_t
, MERGE64_SECOND(id
),
1278 vki_cpusetid_t
*,setid
);
1279 PRE_MEM_WRITE("cpuset_getid(setid)", ARG4
, sizeof(vki_cpusetid_t
));
1282 POST(sys_cpuset_getid
)
1284 POST_MEM_WRITE(ARG5
, sizeof(vki_cpusetid_t
));
1287 // SYS_cpuset_getaffinity 487
1288 // int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
1289 // size_t setsize, cpuset_t *mask);
1290 PRE(sys_cpuset_getaffinity
)
1292 PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %lld, %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x )",
1293 ARG1
, ARG2
, (vki_id_t
)MERGE64(ARG3
, ARG4
), ARG5
, ARG6
);
1294 PRE_REG_READ6(int, "cpuset_getaffinity",
1295 vki_cpulevel_t
, level
, vki_cpuwhich_t
, which
,
1296 vki_uint32_t
, MERGE64_FIRST(id
),
1297 vki_uint32_t
, MERGE64_SECOND(id
),
1298 size_t, setsize
, void *, mask
);
1299 PRE_MEM_WRITE("cpuset_getaffinity", ARG6
, ARG5
);
1302 POST(sys_cpuset_getaffinity
)
1306 POST_MEM_WRITE( ARG6
, ARG5
);
1309 // SYS_cpuset_setaffinity 488
1310 // int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
1311 // size_t setsize, const cpuset_t *mask);
1312 PRE(sys_cpuset_setaffinity
)
1315 PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD
"u, %" FMT_REGWORD
"u, %llu, %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x )",
1316 ARG1
, ARG2
, MERGE64(ARG3
, ARG4
), ARG5
, ARG6
);
1317 PRE_REG_READ6(int, "cpuset_setaffinity",
1318 vki_cpulevel_t
, level
, vki_cpuwhich_t
, which
,
1319 vki_uint32_t
, MERGE64_FIRST(id
),
1320 vki_uint32_t
, MERGE64_SECOND(id
),
1321 size_t, setsize
, void *, mask
);
1322 PRE_MEM_READ("cpuset_setaffinity", ARG6
, ARG5
);
1325 // SYS_posix_fallocate 530
1326 // int posix_fallocate(int fd, off_t offset, off_t len);
1327 PRE(sys_posix_fallocate
)
1329 PRINT("sys_posix_fallocate ( %" FMT_REGWORD
"d, %llu, %llu )",
1330 SARG1
, MERGE64(ARG2
,ARG3
), MERGE64(ARG4
, ARG5
));
1331 PRE_REG_READ5(long, "posix_fallocate",
1332 int, fd
, vki_uint32_t
, MERGE64_FIRST(offset
),
1333 vki_uint32_t
, MERGE64_SECOND(offset
),
1334 vki_uint32_t
, MERGE64_FIRST(len
),
1335 vki_uint32_t
, MERGE64_SECOND(len
));
1338 // SYS_posix_fadvise 531
1339 // int posix_fadvise(int fd, off_t offset, off_t len, int advice);
1340 PRE(sys_posix_fadvise
)
1342 PRINT("sys_posix_fadvise ( %" FMT_REGWORD
"d, %llu, %llu, %" FMT_REGWORD
"d )",
1343 SARG1
, MERGE64(ARG2
,ARG3
), MERGE64(ARG4
,ARG5
), SARG6
);
1344 PRE_REG_READ6(long, "posix_fadvise",
1345 int, fd
, vki_uint32_t
, MERGE64_FIRST(offset
),
1346 vki_uint32_t
, MERGE64_SECOND(offset
),
1347 vki_uint32_t
, MERGE64_FIRST(len
),
1348 vki_uint32_t
, MERGE64_SECOND(len
),
1353 // pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
1354 // struct __wrusage *wrusage, siginfo_t *infop);
1357 PRINT("sys_wait6 ( %" FMT_REGWORD
"d, %llu, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"d, %#" FMT_REGWORD
"x, %#" FMT_REGWORD
"x )",
1358 SARG1
, MERGE64(ARG2
, ARG3
), ARG4
, SARG5
, ARG6
, ARG7
);
1359 PRE_REG_READ7(pid_t
, "wait6", vki_idtype_t
, idtype
,
1360 vki_uint32_t
, MERGE64_FIRST(id
),
1361 vki_uint32_t
, MERGE64_SECOND(id
),
1362 int *, status
, int, options
,
1363 struct vki___wrusage
*, wrusage
, vki_siginfo_t
*,infop
);
1364 PRE_MEM_WRITE("wait6(status)", ARG4
, sizeof(int));
1366 PRE_MEM_WRITE("wait6(wrusage)", ARG6
, sizeof(struct vki___wrusage
));
1369 PRE_MEM_WRITE("wait6(infop)", ARG7
, sizeof(vki_siginfo_t
));
1375 POST_MEM_WRITE(ARG4
, sizeof(int));
1377 POST_MEM_WRITE(ARG6
, sizeof(struct vki___wrusage
));
1381 POST_MEM_WRITE(ARG7
, sizeof(vki_siginfo_t
));
1385 // the man page is inconsistent for the last argument
1386 // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386
1387 // will stick to 'arg' for simplicity
1390 // int procctl(idtype_t idtype, id_t id, int cmd, void *arg);
1393 PRINT("sys_procctl ( %" FMT_REGWORD
"d, %llu, %" FMT_REGWORD
"d, %#" FMT_REGWORD
"x )",
1394 SARG1
, MERGE64(ARG2
, ARG3
), SARG4
, ARG5
);
1395 PRE_REG_READ5(int, "procctl", vki_idtype_t
, idtype
,
1396 vki_uint32_t
, MERGE64_FIRST(id
),
1397 vki_uint32_t
, MERGE64_SECOND(id
),
1398 int, cmd
, void *, arg
);
1400 case VKI_PROC_ASLR_CTL
:
1401 case VKI_PROC_SPROTECT
:
1402 case VKI_PROC_TRACE_CTL
:
1403 case VKI_PROC_TRAPCAP_CTL
:
1404 case VKI_PROC_PDEATHSIG_CTL
:
1405 case VKI_PROC_STACKGAP_CTL
:
1406 case VKI_PROC_NO_NEW_PRIVS_CTL
:
1407 case VKI_PROC_WXMAP_CTL
:
1408 PRE_MEM_READ("procctl(arg)", ARG5
, sizeof(int));
1410 case VKI_PROC_REAP_STATUS
:
1411 PRE_MEM_READ("procctl(arg)", ARG5
, sizeof(struct vki_procctl_reaper_status
));
1413 case VKI_PROC_REAP_GETPIDS
:
1414 PRE_MEM_READ("procctl(arg)", ARG5
, sizeof(struct vki_procctl_reaper_pids
));
1416 case VKI_PROC_REAP_KILL
:
1417 /* The first three fields are reads
1422 * The last two fields are writes
1426 * There is also a pad field
1428 PRE_MEM_READ("procctl(arg)", ARG5
, sizeof(int) + sizeof(u_int
) + sizeof(vki_pid_t
));
1429 PRE_MEM_WRITE("procctl(arg)", ARG5
+offsetof(struct vki_procctl_reaper_kill
, rk_killed
), sizeof(u_int
) + sizeof(vki_pid_t
));
1431 case VKI_PROC_ASLR_STATUS
:
1432 case VKI_PROC_PDEATHSIG_STATUS
:
1433 case VKI_PROC_STACKGAP_STATUS
:
1434 case VKI_PROC_TRAPCAP_STATUS
:
1435 case VKI_PROC_TRACE_STATUS
:
1436 PRE_MEM_WRITE("procctl(arg)", ARG5
, sizeof(int));
1437 case VKI_PROC_REAP_ACQUIRE
:
1438 case VKI_PROC_REAP_RELEASE
:
1447 case VKI_PROC_REAP_KILL
:
1448 POST_MEM_WRITE(ARG5
+offsetof(struct vki_procctl_reaper_kill
, rk_killed
), sizeof(u_int
) + sizeof(vki_pid_t
));
1450 case VKI_PROC_ASLR_STATUS
:
1451 case VKI_PROC_PDEATHSIG_STATUS
:
1452 case VKI_PROC_STACKGAP_STATUS
:
1453 case VKI_PROC_TRAPCAP_STATUS
:
1454 case VKI_PROC_TRACE_STATUS
:
1455 case VKI_PROC_NO_NEW_PRIVS_STATUS
:
1456 case VKI_PROC_WXMAP_STATUS
:
1457 POST_MEM_WRITE(ARG5
, sizeof(int));
1463 #if (FREEBSD_VERS >= FREEBSD_12)
1465 // SYS_cpuset_getdomain 561
1466 // int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
1467 // size_t setsize, domainset_t *mask, int *policy);
1468 PRE(sys_cpuset_getdomain
)
1470 PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD
"d, %" FMT_REGWORD
"d, %llu, %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %#" FMT_REGWORD
"x )",
1471 SARG1
, SARG2
, MERGE64(ARG3
, ARG4
), ARG5
, ARG6
, ARG7
);
1472 PRE_REG_READ7(int, "cpuset_getdomain",
1473 cpulevel_t
, level
, cpuwhich_t
, which
,
1474 vki_uint32_t
, MERGE64_FIRST(id
),
1475 vki_uint32_t
, MERGE64_SECOND(id
),
1476 size_t, setsize
, vki_domainset_t
*, mask
, int *, policy
);
1477 // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
1478 PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG6
, ARG5
);
1479 PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG7
, sizeof(int) );
1482 POST(sys_cpuset_getdomain
)
1484 POST_MEM_WRITE(ARG5
, ARG4
);
1485 POST_MEM_WRITE(ARG6
, sizeof(int) );
1488 // SYS_cpuset_setdomain 562
1489 // int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
1490 // size_t setsize, const domainset_t *mask, int policy);
1491 PRE(sys_cpuset_setdomain
)
1493 PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD
"d, %" FMT_REGWORD
"d, %llu, %" FMT_REGWORD
"u, %#" FMT_REGWORD
"x, %" FMT_REGWORD
"d )",
1494 SARG1
, SARG2
, MERGE64(ARG3
, ARG4
), ARG5
, ARG6
, SARG7
);
1495 PRE_REG_READ7(int, "cpuset_getdomain",
1496 cpulevel_t
, level
, cpuwhich_t
, which
,
1497 vki_uint32_t
, MERGE64_FIRST(id
),
1498 vki_uint32_t
, MERGE64_SECOND(id
),
1499 size_t, setsize
, vki_domainset_t
*, mask
, int, policy
);
1500 // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
1501 PRE_MEM_READ( "cpuset_getdomain(mask)", ARG6
, ARG5
);
1506 PRE(sys_fake_sigreturn
)
1508 /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
1509 an explanation of what follows. */
1512 struct vki_ucontext
*uc
;
1513 PRINT("sys_sigreturn ( %#" FMT_REGWORD
"x )", ARG1
);
1514 PRE_REG_READ1(long, "sigreturn",
1515 struct vki_ucontext
*, scp
);
1517 PRE_MEM_READ( "sigreturn(scp)", ARG1
, sizeof(struct vki_ucontext
) );
1518 PRE_MEM_WRITE( "sigreturn(scp)", ARG1
, sizeof(struct vki_ucontext
) );
1520 vg_assert(VG_(is_valid_tid
)(tid
));
1521 vg_assert(tid
>= 1 && tid
< VG_N_THREADS
);
1522 vg_assert(VG_(is_running_thread
)(tid
));
1524 /* Adjust esp to point to start of frame; skip back up over handler
1526 tst
= VG_(get_ThreadState
)(tid
);
1527 tst
->arch
.vex
.guest_ESP
-= sizeof(Addr
); /* QQQ should be redundant */
1529 uc
= (struct vki_ucontext
*)ARG1
;
1530 if (uc
== NULL
|| uc
->uc_mcontext
.len
!= sizeof(uc
->uc_mcontext
)) {
1531 SET_STATUS_Failure(VKI_EINVAL
);
1535 /* This is only so that the EIP is (might be) useful to report if
1536 something goes wrong in the sigreturn */
1537 ML_(fixup_guest_state_to_restart_syscall
)(&tst
->arch
);
1539 /* Restore register state from frame and remove it */
1540 VG_(sigframe_destroy
)(tid
);
1542 /* For unclear reasons, it appears we need the syscall to return
1543 without changing %EAX. Since %EAX is the return value, and can
1544 denote either success or failure, we must set up so that the
1545 driver logic copies it back unchanged. Also, note %EAX is of
1546 the guest registers written by VG_(sigframe_destroy). */
1547 int eflags
= LibVEX_GuestX86_get_eflags(&tst
->arch
.vex
);
1548 SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_freebsd
)( tst
->arch
.vex
.guest_EAX
,
1549 tst
->arch
.vex
.guest_EDX
, (eflags
& 1) != 0 ? True
: False
) );
1552 * Signal handler might have changed the signal mask. Respect that.
1554 tst
->sig_mask
= uc
->uc_sigmask
;
1555 tst
->tmp_sig_mask
= uc
->uc_sigmask
;
1557 /* Tell the driver not to update the guest state with the "result",
1558 and set a bogus result to keep it happy. */
1559 *flags
|= SfNoWriteResult
;
1560 SET_STATUS_Success(0);
1562 /* Check to see if any signals arose as a result of this. */
1563 *flags
|= SfPollAfter
;
1570 #endif /* defined(VGP_x86_freebsd) */
1573 /*--------------------------------------------------------------------*/
1575 /*--------------------------------------------------------------------*/