vgdb: Handle EAGAIN in read_buf
[valgrind.git] / coregrind / m_syswrap / syswrap-x86-freebsd.c
blob61803a37b8e9d684e26ae0b1088ce71f81f39786
2 /*--------------------------------------------------------------------*/
3 /*--- Platform-specific syscalls stuff. syswrap-x86-freebsd.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2000-2008 Nicholas Nethercote
11 njn@valgrind.org
12 Copyright (C) 2018-2021 Paul Floyd
13 pjfloyd@wanadoo.fr
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 /* ---------------------------------------------------------------------
67 clone() handling
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,
75 Addr retaddr,
76 void (*f)(Word),
77 Word arg1 );
78 // 4(%esp) == stack
79 // 8(%esp) == retaddr
80 // 12(%esp) == f
81 // 16(%esp) == arg1
82 __asm__(
83 ".text\n"
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
92 " movl $0, %ebx\n"
93 " movl $0, %ecx\n"
94 " movl $0, %edx\n"
95 " movl $0, %esi\n"
96 " movl $0, %edi\n"
97 " movl $0, %ebp\n"
98 " ret\n" // jump to f
99 " ud2\n" // should never get here
100 ".previous\n"
104 #if 0
106 Perform a rfork system call. rfork is strange because it has
107 fork()-like return-twice semantics, so it needs special
108 handling here.
110 Upon entry, we have:
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
123 int flags in %ebx
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)
135 extern
136 Int do_syscall_clone_x86_freebsd ( Word (*fn)(void *),
137 void* stack,
138 Int flags,
139 void* arg,
140 Int* child_tid,
141 Int* parent_tid,
142 vki_modify_ldt_t * );
143 asm(
144 ".text\n"
145 "do_syscall_clone_x86_freebsd:\n"
146 " push %ebx\n"
147 " push %edi\n"
148 " push %esi\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 */
166 " jnz 1f\n"
168 /* CHILD - call thread function */
169 " popl %eax\n"
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"
175 " int $0x80\n"
177 /* Hm, exit returned */
178 " ud2\n"
180 "1:\n" /* PARENT or ERROR */
181 " pop %esi\n"
182 " pop %edi\n"
183 " pop %ebx\n"
184 " ret\n"
185 ".previous\n"
188 #undef FSZ
189 #undef __NR_CLONE
190 #undef __NR_EXIT
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
204 for ESP.
206 static SysRes do_rfork ( ThreadId ptid,
207 UInt flags)
209 static const Bool debug = False;
211 Addr esp;
212 ThreadId ctid = VG_(alloc_ThreadState)();
213 ThreadState* ptst = VG_(get_ThreadState)(ptid);
214 ThreadState* ctst = VG_(get_ThreadState)(ctid);
215 UWord* stack;
216 NSegment const* seg;
217 SysRes res;
218 Int eax;
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);
227 if (stack == NULL) {
228 res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
229 goto out;
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
239 child gets 0.
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
251 child. */
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);
275 if (debug)
276 VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
277 ctid, seg->start, VG_PGROUNDUP(esp));
278 } else {
279 VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%#lx) unmapped\n",
280 ctid, esp);
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);
304 out:
305 if (res.isError) {
306 /* clone failed */
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 );
313 return res;
315 #endif
317 /* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr */
319 static
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));
327 if (0) {
328 VG_(printf)("translate_to_hw_format: base %p\n", base );
331 /* Allow LDTs to be cleared by the user. */
332 if (base == 0) {
333 entry_1 = 0;
334 entry_2 = 0;
335 goto install;
337 /* base as specified, no limit, read/write/accessed etc */
338 entry_1 = ((base_addr & 0x0000ffff) << 16) | 0x0ffff;
339 entry_2 = (base_addr & 0xff000000) |
340 ((base_addr & 0x00ff0000) >> 16) | 0x00cff300;
342 /* Install the new entry ... */
343 install:
344 out->LdtEnt.Words.word1 = entry_1;
345 out->LdtEnt.Words.word2 = entry_2;
348 /* Create a zeroed-out GDT. */
349 static VexGuestX86SegDescr* alloc_zeroed_x86_GDT ( void )
351 Int nbytes = VEX_GUEST_X86_GDT_NENT * sizeof(VexGuestX86SegDescr);
352 return VG_(arena_calloc)(VG_AR_CORE, "di.syswrap-x86.azxG.1", nbytes, 1);
355 /* Create a zeroed-out LDT. */
356 static VexGuestX86SegDescr* alloc_zeroed_x86_LDT ( void )
358 Int nbytes = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr);
359 return VG_(arena_calloc)(VG_AR_CORE, "di.syswrap-x86.azxL.1", nbytes, 1);
362 /* Free up an LDT or GDT allocated by the above fns. */
363 static void free_LDT_or_GDT ( VexGuestX86SegDescr* dt )
365 vg_assert(dt);
366 VG_(arena_free)(VG_AR_CORE, (void*)dt);
369 /* Copy contents between two existing LDTs. */
370 static void copy_LDT_from_to ( VexGuestX86SegDescr* src,
371 VexGuestX86SegDescr* dst )
373 Int i;
374 vg_assert(src);
375 vg_assert(dst);
376 for (i = 0; i < VEX_GUEST_X86_LDT_NENT; i++) {
377 dst[i] = src[i];
381 /* Copy contents between two existing GDTs. */
382 static void copy_GDT_from_to ( VexGuestX86SegDescr* src,
383 VexGuestX86SegDescr* dst )
385 Int i;
386 vg_assert(src);
387 vg_assert(dst);
388 for (i = 0; i < VEX_GUEST_X86_GDT_NENT; i++) {
389 dst[i] = src[i];
393 /* Free this thread's DTs, if it has any. */
394 static void deallocate_LGDTs_for_thread ( VexGuestX86State* vex )
396 vg_assert(sizeof(HWord) == sizeof(void*));
398 if (0) {
399 VG_(printf)("deallocate_LGDTs_for_thread: "
400 "ldt = 0x%llx, gdt = 0x%llx\n",
401 vex->guest_LDT, vex->guest_GDT );
404 if (vex->guest_LDT != (HWord)NULL) {
405 free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_LDT );
406 vex->guest_LDT = (HWord)NULL;
409 if (vex->guest_GDT != (HWord)NULL) {
410 free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_GDT );
411 vex->guest_GDT = (HWord)NULL;
415 static SysRes sys_set_thread_area ( ThreadId tid, Int *idxptr, void *base)
417 VexGuestX86SegDescr* gdt;
418 Int idx;
420 vg_assert(8 == sizeof(VexGuestX86SegDescr));
421 vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
423 gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT;
425 /* If the thread doesn't have a GDT, allocate it now. */
426 if (!gdt) {
427 gdt = alloc_zeroed_x86_GDT();
428 VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
431 idx = *idxptr;
432 if (idx == -1) {
433 /* Find and use the first free entry. Don't allocate entry
434 zero, because the hardware will never do that, and apparently
435 doing so confuses some code (perhaps stuff running on
436 Wine). */
437 for (idx = 1; idx < VEX_GUEST_X86_GDT_NENT; idx++) {
438 if (gdt[idx].LdtEnt.Words.word1 == 0
439 && gdt[idx].LdtEnt.Words.word2 == 0) {
440 break;
444 if (idx == VEX_GUEST_X86_GDT_NENT) {
445 return VG_(mk_SysRes_Error)( VKI_ESRCH );
447 } else if (idx < 0 || idx == 0 || idx >= VEX_GUEST_X86_GDT_NENT) {
448 /* Similarly, reject attempts to use GDT[0]. */
449 return VG_(mk_SysRes_Error)( VKI_EINVAL );
452 translate_to_hw_format(base, &gdt[idx]);
454 *idxptr = idx;
455 return VG_(mk_SysRes_Success)( 0 );
458 static SysRes sys_get_thread_area ( ThreadId tid, Int idx, void ** basep )
460 VexGuestX86SegDescr* gdt;
461 UInt base;
463 vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
464 vg_assert(8 == sizeof(VexGuestX86SegDescr));
466 gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT;
468 /* If the thread doesn't have a GDT, allocate it now. */
469 if (!gdt) {
470 gdt = alloc_zeroed_x86_GDT();
471 VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
474 base = ( gdt[idx].LdtEnt.Bits.BaseHi << 24 ) |
475 ( gdt[idx].LdtEnt.Bits.BaseMid << 16 ) |
476 gdt[idx].LdtEnt.Bits.BaseLow;
477 *basep = (void *)base;
479 return VG_(mk_SysRes_Success)( 0 );
482 static
483 void x86_setup_LDT_GDT ( /*OUT*/ ThreadArchState *child,
484 /*IN*/ ThreadArchState *parent )
486 /* We inherit our parent's LDT. */
487 if (parent->vex.guest_LDT == (HWord)NULL) {
488 /* We hope this is the common case. */
489 child->vex.guest_LDT = (HWord)NULL;
490 } else {
491 /* No luck .. we have to take a copy of the parent's. */
492 child->vex.guest_LDT = (HWord)alloc_zeroed_x86_LDT();
493 copy_LDT_from_to( (VexGuestX86SegDescr*)(HWord)parent->vex.guest_LDT,
494 (VexGuestX86SegDescr*)(HWord)child->vex.guest_LDT );
497 /* Either we start with an empty GDT (the usual case) or inherit a
498 copy of our parents' one (Quadrics Elan3 driver -style clone
499 only). */
500 child->vex.guest_GDT = (HWord)NULL;
502 if (parent->vex.guest_GDT != (HWord)NULL) {
503 //child->vex.guest_GDT = (HWord)alloc_system_x86_GDT();
504 child->vex.guest_GDT = (HWord)alloc_zeroed_x86_GDT();
505 copy_GDT_from_to( (VexGuestX86SegDescr*)(HWord)parent->vex.guest_GDT,
506 (VexGuestX86SegDescr*)(HWord)child->vex.guest_GDT );
512 /* ---------------------------------------------------------------------
513 More thread stuff
514 ------------------------------------------------------------------ */
516 void VG_(cleanup_thread) ( ThreadArchState* arch )
519 * This is what x86 Linux does but it doesn't work off the bat for x86 FreeBSD
520 * My suspicion is that the rtld code uses the TCB stored in the GDT after the
521 * end of thr_exit.
522 * Alternatively the rtld use is after the start of the next thread and we haven't
523 * reallocated this memory
525 deallocate_LGDTs_for_thread( &arch->vex );
529 /* ---------------------------------------------------------------------
530 PRE/POST wrappers for x86/FreeBSD-specific syscalls
531 ------------------------------------------------------------------ */
533 #define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name)
534 #define POST(name) DEFN_POST_TEMPLATE(freebsd, name)
536 // SYS_sysarch 165
537 // int sysarch(int number, void *args);
538 PRE(sys_sysarch)
540 ThreadState *tst;
541 Int idx;
542 void **p;
544 PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2);
545 PRE_REG_READ2(int, "sysarch", int, number, void *, args);
546 switch (ARG1) {
547 case VKI_I386_SET_GSBASE:
548 PRINT("sys_i386_set_gsbase ( %#lx )", ARG2);
550 if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) {
551 /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */
552 tst = VG_(get_ThreadState)(tid);
553 p = (void**)ARG2;
554 tst->arch.vex.guest_GS = (1 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */
555 /* "do" the syscall ourselves; the kernel never sees it */
556 idx = 1;
557 SET_STATUS_from_SysRes( sys_set_thread_area( tid, &idx, *p ) );
558 } else {
559 // ????
560 SET_STATUS_Failure( VKI_EINVAL );
563 break;
564 case VKI_I386_GET_GSBASE:
565 PRINT("sys_i386_get_gsbase ( %#lx )", ARG2);
566 PRE_MEM_WRITE( "i386_get_gsbase(basep)", ARG2, sizeof(void *) );
567 if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) {
568 /* "do" the syscall ourselves; the kernel never sees it */
569 SET_STATUS_from_SysRes( sys_get_thread_area( tid, 2, (void **)ARG2 ) );
570 } else {
571 SET_STATUS_Failure( VKI_EINVAL );
573 break;
574 case VKI_I386_GET_XFPUSTATE:
575 PRINT("sys_i386_get_xfpustate ( %#lx )", ARG2);
576 PRE_MEM_WRITE( "i386_get_xfpustate(basep)", ARG2, sizeof(void *) );
577 /* "do" the syscall ourselves; the kernel never sees it */
578 tst = VG_(get_ThreadState)(tid);
579 SET_STATUS_Success2( tst->arch.vex.guest_FPTAG[0], tst->arch.vex.guest_FPTAG[0] );
580 break;
581 default:
582 VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %lu", ARG1);
583 VG_(unimplemented) ("unhandled sysarch cmd");
584 break;
588 POST(sys_sysarch)
590 switch (ARG1) {
591 case VKI_AMD64_SET_FSBASE:
592 break;
593 case VKI_AMD64_GET_FSBASE:
594 POST_MEM_WRITE( ARG2, sizeof(void *) );
595 break;
596 case VKI_AMD64_GET_XFPUSTATE:
597 POST_MEM_WRITE( ARG2, sizeof(void *) );
598 break;
599 default:
600 break;
604 // freebsd6_pread 173
605 #if (FREEBSD_VERS <= FREEBSD_10)
606 PRE(sys_freebsd6_pread)
608 *flags |= SfMayBlock;
609 PRINT("sys_freebsd6_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG5, ARG6);
610 PRE_REG_READ6(ssize_t, "pread",
611 unsigned int, fd, char *, buf, vki_size_t, count,
612 int, pad, unsigned int, off_low, unsigned int, off_high);
614 if (!ML_(fd_allowed)(ARG1, "freebsd6_pread", tid, False))
615 SET_STATUS_Failure( VKI_EBADF );
616 else
617 PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2, ARG3 );
620 POST(sys_freebsd6_pread)
622 vg_assert(SUCCESS);
623 POST_MEM_WRITE( ARG2, RES );
625 #endif
627 // freebsd6_pwrite 174
628 #if (FREEBSD_VERS <= FREEBSD_10)
629 PRE(sys_freebsd6_pwrite)
631 Bool ok;
632 *flags |= SfMayBlock;
633 PRINT("sys_freebsd6_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG5, ARG6);
634 PRE_REG_READ6(ssize_t, "freebsd6_pwrite",
635 unsigned int, fd, const char *, buf, vki_size_t, count,
636 int, pad, unsigned int, off_low, unsigned int, off_high);
637 /* check to see if it is allowed. If not, try for an exemption from
638 --sim-hints=enable-outer (used for self hosting). */
639 ok = ML_(fd_allowed)(ARG1, "freebsd6_pwrite", tid, False);
640 if (!ok && ARG1 == 2/*stderr*/
641 && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints)))
642 ok = True;
643 if (!ok)
644 SET_STATUS_Failure( VKI_EBADF );
645 else
646 PRE_MEM_READ( "freebsd6_write(buf)", ARG2, ARG3 );
648 #endif
650 // SYS_freebsd6_mmap 197
651 #if (FREEBSD_VERS <= FREEBSD_10)
652 /* This is here because on x86 the off_t is passed in 2 regs. Don't ask about pad. */
654 /* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); */
655 /* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7+ARG8 */
657 PRE(sys_freebsd6_mmap)
659 SysRes r;
661 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)",
662 ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8 );
663 PRE_REG_READ8(long, "mmap",
664 char *, addr, unsigned long, len, int, prot, int, flags,
665 int, fd, int, pad, unsigned long, lo, unsigned long, hi);
667 r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, MERGE64(ARG7,ARG8) );
668 SET_STATUS_from_SysRes(r);
670 #endif
672 // freebsd6_lseek 199
673 #if (FREEBSD_VERS <= FREEBSD_10)
674 PRE(sys_freebsd6_lseek)
676 PRINT("sys_freebsd6_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG3,ARG4,ARG5);
677 PRE_REG_READ5(long, "lseek",
678 unsigned int, fd, int, pad, unsigned int, offset_low,
679 unsigned int, offset_high, unsigned int, whence);
681 #endif
683 // freebsd6_truncate 200
684 #if (FREEBSD_VERS <= FREEBSD_10)
685 PRE(sys_freebsd6_truncate)
687 *flags |= SfMayBlock;
688 PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG3,ARG4);
689 PRE_REG_READ4(long, "truncate",
690 const char *, path, int, pad,
691 unsigned int, length_low, unsigned int, length_high);
692 PRE_MEM_RASCIIZ( "truncate(path)", ARG1 );
694 #endif
696 // freebsd6_ftruncate 201
697 #if (FREEBSD_VERS <= FREEBSD_10)
698 PRE(sys_freebsd6_ftruncate)
700 *flags |= SfMayBlock;
701 PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG3,ARG4);
702 PRE_REG_READ4(long, "ftruncate", unsigned int, fd, int, pad,
703 unsigned int, length_low, unsigned int, length_high);
705 #endif
707 // SYS_clock_getcpuclockid2 247
708 // no manpage for this, from syscalls.master
709 // int clock_getcpuclockid2(id_t id, int which, _Out_ clockid_t *clock_id);
710 PRE(sys_clock_getcpuclockid2)
712 PRINT("sys_clock_getcpuclockid2( %lld, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
713 (vki_id_t)MERGE64(ARG1,ARG2),SARG3,ARG4);
714 PRE_REG_READ4(int, "clock_getcpuclockid2",
715 vki_uint32_t, MERGE64_FIRST(offset),
716 vki_uint32_t, MERGE64_SECOND(offset),
717 int, len, clockid_t *, clock_id);
718 PRE_MEM_WRITE("clock_getcpuclockid2(clock_id)", ARG3, sizeof(vki_clockid_t));
721 // SYS_rfork 251
722 // pid_t rfork(int flags);
723 PRE(sys_rfork)
725 PRINT("sys_rfork ( %" FMT_REGWORD "x )",ARG1);
726 PRE_REG_READ1(int, "rfork",
727 unsigned int, flags);
729 #if 0
730 cloneflags = ARG1;
732 if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
733 SET_STATUS_Failure( VKI_EINVAL );
734 return;
737 SET_STATUS_from_SysRes( do_clone(tid, ARG1));
739 if (SUCCESS) {
740 *flags |= SfYieldAfter;
742 #else
743 VG_(message)(Vg_UserMsg, "rfork() not implemented\n");
744 if ((UInt)ARG1 == VKI_RFSPAWN) {
745 // posix_spawn uses RFSPAWN and it will fall back to vfork
746 // if it sees EINVAL
747 SET_STATUS_Failure(VKI_EINVAL);
748 } else {
749 SET_STATUS_Failure(VKI_ENOSYS);
751 #endif
754 // SYS_preadv 289
755 // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
756 PRE(sys_preadv)
758 Int i;
759 struct vki_iovec * vec;
760 *flags |= SfMayBlock;
761 PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
762 FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5));
763 PRE_REG_READ5(ssize_t, "preadv",
764 int, fd, const struct iovec *, iov,
765 int, iovcnt, vki_uint32_t, MERGE64_FIRST(offset),
766 vki_uint32_t, MERGE64_SECOND(offset));
767 if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) {
768 SET_STATUS_Failure( VKI_EBADF );
769 } else {
770 if ((Int)ARG3 > 0)
771 PRE_MEM_READ( "preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec) );
773 if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
774 vec = (struct vki_iovec *)(Addr)ARG2;
775 for (i = 0; i < (Int)ARG3; i++)
776 PRE_MEM_WRITE( "preadv(iov[...])",
777 (Addr)vec[i].iov_base, vec[i].iov_len );
782 POST(sys_preadv)
784 vg_assert(SUCCESS);
785 if (RES > 0) {
786 Int i;
787 struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2;
788 Int remains = RES;
790 /* RES holds the number of bytes read. */
791 for (i = 0; i < (Int)ARG3; i++) {
792 Int nReadThisBuf = vec[i].iov_len;
793 if (nReadThisBuf > remains) nReadThisBuf = remains;
794 POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
795 remains -= nReadThisBuf;
796 if (remains < 0) VG_(core_panic)("preadv: remains < 0");
801 // SYS_pwritev 290
802 // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
803 PRE(sys_pwritev)
805 Int i;
806 struct vki_iovec * vec;
807 *flags |= SfMayBlock;
808 PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
809 FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5));
811 PRE_REG_READ5(ssize_t, "pwritev",
812 int, fd, const struct iovec *, iov,
813 int, iovcnt,
814 vki_uint32_t, MERGE64_FIRST(offset),
815 vki_uint32_t, MERGE64_SECOND(offset));
816 if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) {
817 SET_STATUS_Failure( VKI_EBADF );
818 } else {
819 if ((Int)ARG3 >= 0)
820 PRE_MEM_READ( "pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) );
821 if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
822 vec = (struct vki_iovec *)(Addr)ARG2;
823 for (i = 0; i < (Int)ARG3; i++)
824 PRE_MEM_READ( "pwritev(iov[...])",
825 (Addr)vec[i].iov_base, vec[i].iov_len );
830 // SYS_sendfile 393
831 // int sendfile(int fd, int s, off_t offset, size_t nbytes,
832 // struct sf_hdtr *hdtr, off_t *sbytes, int flags);
833 PRE(sys_sendfile)
835 *flags |= SfMayBlock;
836 PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
837 SARG1,SARG2,LOHI64(ARG3,ARG4),ARG5,ARG6,ARG7,SARG8);
838 PRE_REG_READ8(int, "sendfile",
839 int, fd, int, s, unsigned int, offset_low,
840 unsigned int, offset_high, size_t, nbytes,
841 void *, hdtr, vki_off_t *, sbytes, int, flags);
843 if (ARG6 != 0)
844 PRE_MEM_READ("sendfile(hdtr)", ARG6, sizeof(struct vki_sf_hdtr));
846 if (ARG7 != 0)
847 PRE_MEM_WRITE( "sendfile(sbytes)", ARG7, sizeof(vki_off_t) );
850 POST(sys_sendfile)
852 if (ARG7 != 0 ) {
853 POST_MEM_WRITE( ARG7, sizeof( vki_off_t ) );
857 // SYS_sigreturn 417
858 // int sigreturn(const ucontext_t *scp);
859 PRE(sys_sigreturn)
861 PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
862 PRE_REG_READ1(int, "sigreturn",
863 struct vki_ucontext *, scp);
865 PRE_MEM_READ( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
866 PRE_MEM_WRITE( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
870 static void restore_mcontext(ThreadState *tst, struct vki_mcontext *sc)
872 tst->arch.vex.guest_EAX = sc->eax;
873 tst->arch.vex.guest_ECX = sc->ecx;
874 tst->arch.vex.guest_EDX = sc->edx;
875 tst->arch.vex.guest_EBX = sc->ebx;
876 tst->arch.vex.guest_EBP = sc->ebp;
877 tst->arch.vex.guest_ESP = sc->esp;
878 tst->arch.vex.guest_ESI = sc->esi;
879 tst->arch.vex.guest_EDI = sc->edi;
880 tst->arch.vex.guest_EIP = sc->eip;
881 tst->arch.vex.guest_CS = sc->cs;
882 tst->arch.vex.guest_SS = sc->ss;
883 tst->arch.vex.guest_DS = sc->ds;
884 tst->arch.vex.guest_ES = sc->es;
885 tst->arch.vex.guest_FS = sc->fs;
886 tst->arch.vex.guest_GS = sc->gs;
888 * XXX: missing support for other flags.
890 if (sc->eflags & 0x0001)
891 LibVEX_GuestX86_put_eflag_c(1, &tst->arch.vex);
892 else
893 LibVEX_GuestX86_put_eflag_c(0, &tst->arch.vex);
896 static void fill_mcontext(ThreadState *tst, struct vki_mcontext *sc)
898 sc->eax = tst->arch.vex.guest_EAX;
899 sc->ecx = tst->arch.vex.guest_ECX;
900 sc->edx = tst->arch.vex.guest_EDX;
901 sc->ebx = tst->arch.vex.guest_EBX;
902 sc->ebp = tst->arch.vex.guest_EBP;
903 sc->esp = tst->arch.vex.guest_ESP;
904 sc->esi = tst->arch.vex.guest_ESI;
905 sc->edi = tst->arch.vex.guest_EDI;
906 sc->eip = tst->arch.vex.guest_EIP;
907 sc->cs = tst->arch.vex.guest_CS;
908 sc->ss = tst->arch.vex.guest_SS;
909 sc->ds = tst->arch.vex.guest_DS;
910 sc->es = tst->arch.vex.guest_ES;
911 sc->fs = tst->arch.vex.guest_FS;
912 sc->gs = tst->arch.vex.guest_GS;
913 sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
915 not yet.
916 VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate));
918 sc->fpformat = VKI_FPFMT_NODEV;
919 sc->ownedfp = VKI_FPOWNED_NONE;
920 sc->len = sizeof(*sc);
921 VG_(memset)(sc->spare2, 0, sizeof(sc->spare2));
924 // SYS_getcontext 421
925 // int getcontext(ucontext_t *ucp);
926 PRE(sys_getcontext)
928 ThreadState* tst;
929 struct vki_ucontext *uc;
931 PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1);
932 PRE_REG_READ1(int, "getcontext",
933 struct vki_ucontext *, ucp);
934 PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
935 uc = (struct vki_ucontext *)ARG1;
936 if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) {
937 SET_STATUS_Failure(VKI_EINVAL);
938 return;
940 tst = VG_(get_ThreadState)(tid);
941 fill_mcontext(tst, &uc->uc_mcontext);
942 uc->uc_mcontext.eax = 0;
943 uc->uc_mcontext.edx = 0;
944 uc->uc_mcontext.eflags &= ~0x0001; /* PSL_C */
945 uc->uc_sigmask = tst->sig_mask;
946 VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__));
947 SET_STATUS_Success(0);
950 // SYS_setcontext 422
951 // int setcontext(const ucontext_t *ucp);
952 PRE(sys_setcontext)
954 ThreadState* tst;
955 struct vki_ucontext *uc;
957 PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", ARG1);
958 PRE_REG_READ1(long, "setcontext",
959 struct vki_ucontext *, ucp);
961 PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
962 PRE_MEM_WRITE( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
964 vg_assert(VG_(is_valid_tid)(tid));
965 vg_assert(tid >= 1 && tid < VG_N_THREADS);
966 vg_assert(VG_(is_running_thread)(tid));
968 tst = VG_(get_ThreadState)(tid);
969 uc = (struct vki_ucontext *)ARG1;
970 if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) {
971 SET_STATUS_Failure(VKI_EINVAL);
972 return;
975 restore_mcontext(tst, &uc->uc_mcontext);
976 tst->sig_mask = uc->uc_sigmask;
977 tst->tmp_sig_mask = uc->uc_sigmask;
979 /* Tell the driver not to update the guest state with the "result",
980 and set a bogus result to keep it happy. */
981 *flags |= SfNoWriteResult;
982 SET_STATUS_Success(0);
984 /* Check to see if some any signals arose as a result of this. */
985 *flags |= SfPollAfter;
988 // SYS_swapcontext 423
989 // int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
990 PRE(sys_swapcontext)
992 struct vki_ucontext *ucp, *oucp;
993 ThreadState* tst;
995 PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2);
996 PRE_REG_READ2(long, "swapcontext",
997 struct vki_ucontext *, oucp, struct vki_ucontext *, ucp);
999 PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) );
1000 PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) );
1002 oucp = (struct vki_ucontext *)ARG1;
1003 ucp = (struct vki_ucontext *)ARG2;
1004 if (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) ||
1005 !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) ||
1006 ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)) {
1007 SET_STATUS_Failure(VKI_EINVAL);
1008 return;
1010 tst = VG_(get_ThreadState)(tid);
1013 * Save the context.
1015 fill_mcontext(tst, &oucp->uc_mcontext);
1016 oucp->uc_mcontext.eax = 0;
1017 oucp->uc_mcontext.edx = 0;
1018 oucp->uc_mcontext.eflags &= ~0x0001; /* PSL_C */
1019 oucp->uc_sigmask = tst->sig_mask;
1020 VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__));
1023 * Switch to new one.
1025 restore_mcontext(tst, &ucp->uc_mcontext);
1026 tst->sig_mask = ucp->uc_sigmask;
1027 tst->tmp_sig_mask = ucp->uc_sigmask;
1029 /* Tell the driver not to update the guest state with the "result",
1030 and set a bogus result to keep it happy. */
1031 *flags |= SfNoWriteResult;
1032 SET_STATUS_Success(0);
1034 /* Check to see if some any signals arose as a result of this. */
1035 *flags |= SfPollAfter;
1038 // SYS_thr_new 455
1039 // int thr_new(struct thr_param *param, int param_size);
1040 PRE(sys_thr_new)
1042 static const Bool debug = False;
1044 ThreadId ctid = VG_(alloc_ThreadState)();
1045 ThreadState* ptst = VG_(get_ThreadState)(tid);
1046 ThreadState* ctst = VG_(get_ThreadState)(ctid);
1047 SysRes res;
1048 vki_sigset_t blockall, savedmask;
1049 struct vki_thr_param tp;
1050 Int idx = -1;
1051 Addr stk;
1053 PRINT("thr_new ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2);
1054 PRE_REG_READ2(int, "thr_new",
1055 struct thr_param *, param,
1056 int, param_size);
1058 PRE_MEM_READ( "thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare));
1059 if (!ML_(safe_to_deref)( (void*)ARG1, offsetof(struct vki_thr_param, spare))) {
1060 SET_STATUS_Failure( VKI_EFAULT );
1061 return;
1063 VG_(memset)(&tp, 0, sizeof(tp));
1064 VG_(memcpy)(&tp, (void *)ARG1, offsetof(struct vki_thr_param, spare));
1065 PRE_MEM_WRITE("clone(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long));
1066 PRE_MEM_WRITE("clone(child_tidptr)", (Addr)tp.child_tid, sizeof(long));
1068 VG_(sigfillset)(&blockall);
1070 vg_assert(VG_(is_running_thread)(tid));
1071 vg_assert(VG_(is_valid_tid)(ctid));
1073 /* Copy register state
1075 On linux, both parent and child return to the same place, and the code
1076 following the clone syscall works out which is which, so we
1077 don't need to worry about it.
1078 On FreeBSD, thr_new arranges a direct call. We don't actually need any
1079 of this gunk.
1081 The parent gets the child's new tid returned from clone, but the
1082 child gets 0.
1084 If the clone call specifies a NULL rsp for the new thread, then
1085 it actually gets a copy of the parent's rsp.
1087 /* We inherit our parent's guest state. */
1088 ctst->arch.vex = ptst->arch.vex;
1089 ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1;
1090 ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2;
1092 /* Make sys_clone appear to have returned Success(0) in the
1093 child. */
1094 ctst->arch.vex.guest_EAX = 0;
1095 ctst->arch.vex.guest_EDX = 0;
1096 LibVEX_GuestX86_put_eflag_c(0, &ctst->arch.vex);
1098 x86_setup_LDT_GDT(&ctst->arch, &ptst->arch);
1100 ctst->os_state.parent = tid;
1102 /* inherit signal mask */
1103 ctst->sig_mask = ptst->sig_mask;
1104 ctst->tmp_sig_mask = ptst->sig_mask;
1106 /* Linux has to guess, we don't */
1107 ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size;
1108 ctst->client_stack_szB = tp.stack_size;
1109 ctst->os_state.stk_id = VG_(register_stack)((Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size);
1111 /* Assume the clone will succeed, and tell any tool that wants to
1112 know that this thread has come into existence. If the clone
1113 fails, we'll send out a ll_exit notification for it at the out:
1114 label below, to clean up. */
1115 VG_TRACK ( pre_thread_ll_create, tid, ctid );
1117 if (debug)
1118 VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base);
1120 sys_set_thread_area( ctid, &idx, tp.tls_base );
1122 ctst->arch.vex.guest_GS = (idx << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */
1123 tp.tls_base = 0; /* Don't have the kernel do it too */
1125 /* start the thread with everything blocked */
1126 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
1128 /* Set the client state for scheduler to run libthr's trampoline */
1129 ctst->arch.vex.guest_ESP = (Addr)tp.stack_base + tp.stack_size - 8;
1130 ctst->arch.vex.guest_EIP = (Addr)tp.start_func;
1131 *(UWord *)(ctst->arch.vex.guest_ESP + 4) = (UWord)tp.arg; /* Client arg */
1132 *(UWord *)(ctst->arch.vex.guest_ESP + 0) = 0; /* fake return addr */
1134 /* Set up valgrind's trampoline on its own stack */
1135 stk = ML_(allocstack)(ctid);
1136 tp.stack_base = (void *)ctst->os_state.valgrind_stack_base;
1137 tp.stack_size = (Addr)stk - (Addr)tp.stack_base;
1138 /* This is for thr_new() to run valgrind's trampoline */
1139 tp.start_func = (void *)ML_(start_thread_NORETURN);
1140 tp.arg = &VG_(threads)[ctid];
1142 /* Create the new thread */
1143 res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp));
1145 VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
1147 if (sr_isError(res)) {
1148 /* clone failed */
1149 VG_(cleanup_thread)(&ctst->arch);
1150 ctst->status = VgTs_Empty;
1151 /* oops. Better tell the tool the thread exited in a hurry :-) */
1152 VG_TRACK( pre_thread_ll_exit, ctid );
1153 } else {
1155 POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long));
1156 POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long));
1157 POST_MEM_WRITE((Addr)ctst->arch.vex.guest_ESP, 8);
1159 /* Thread creation was successful; let the child have the chance
1160 to run */
1161 *flags |= SfYieldAfter;
1164 /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */
1165 SET_STATUS_from_SysRes(res);
1168 // SYS_pread 475
1169 // ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
1170 PRE(sys_pread)
1172 *flags |= SfMayBlock;
1173 PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4, ARG5);
1174 PRE_REG_READ5(ssize_t, "pread",
1175 unsigned int, fd, char *, buf, vki_size_t, count,
1176 unsigned int, off_low, unsigned int, off_high);
1178 if (!ML_(fd_allowed)(ARG1, "pread", tid, False))
1179 SET_STATUS_Failure( VKI_EBADF );
1180 else
1181 PRE_MEM_WRITE( "pread(buf)", ARG2, ARG3 );
1184 POST(sys_pread)
1186 vg_assert(SUCCESS);
1187 POST_MEM_WRITE( ARG2, RES );
1190 // SYS_pwrite 476
1191 // ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
1192 PRE(sys_pwrite)
1194 Bool ok;
1195 *flags |= SfMayBlock;
1196 PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %llu )", ARG1, ARG2, ARG3, MERGE64(ARG4, ARG5));
1197 PRE_REG_READ5(ssize_t, "pwrite",
1198 unsigned int, fd, const char *, buf, vki_size_t, count,
1199 vki_uint32_t, MERGE64_FIRST(offset),
1200 vki_uint32_t, MERGE64_SECOND(offset));
1201 /* check to see if it is allowed. If not, try for an exemption from
1202 --sim-hints=enable-outer (used for self hosting). */
1203 ok = ML_(fd_allowed)(ARG1, "pwrite", tid, False);
1204 if (!ok && ARG1 == 2/*stderr*/
1205 && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints)))
1206 ok = True;
1207 if (!ok)
1208 SET_STATUS_Failure( VKI_EBADF );
1209 else
1210 PRE_MEM_READ( "pwrite(buf)", ARG2, ARG3 );
1213 // SYS_mmap 477
1214 // void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
1215 PRE(sys_mmap)
1217 SysRes r;
1219 PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu )",
1220 ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6, ARG7) );
1221 PRE_REG_READ7(void *, "mmap",
1222 void *, addr, size_t, len, int, prot, int, flags, int, fd,
1223 vki_uint32_t, MERGE64_FIRST(offset),
1224 vki_uint32_t, MERGE64_SECOND(offset));
1226 r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6,ARG7) );
1227 SET_STATUS_from_SysRes(r);
1230 // SYS_lseek 478
1231 // off_t lseek(int fildes, off_t offset, int whence);
1232 PRE(sys_lseek)
1234 PRINT("sys_lseek ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "d )", SARG1,MERGE64(ARG2,ARG3),SARG4);
1235 PRE_REG_READ4(long, "lseek",
1236 unsigned int, fd,
1237 vki_uint32_t, MERGE64_FIRST(offset),
1238 vki_uint32_t, MERGE64_SECOND(offset),
1239 unsigned int, whence);
1242 // SYS_truncate 479
1243 // int truncate(const char *path, off_t length);
1244 PRE(sys_truncate)
1246 *flags |= SfMayBlock;
1247 PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %llu )", ARG1,(char *)ARG1,MERGE64(ARG2,ARG3));
1248 PRE_REG_READ3(long, "truncate",
1249 const char *, path,
1250 vki_uint32_t, MERGE64_FIRST(length),
1251 vki_uint32_t, MERGE64_SECOND(length));
1252 PRE_MEM_RASCIIZ( "truncate(path)", ARG1 );
1255 // SYS_ftruncate 480
1256 // int ftruncate(int fd, off_t length);
1257 PRE(sys_ftruncate)
1259 *flags |= SfMayBlock;
1260 PRINT("sys_ftruncate ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", SARG1,ARG2,ARG3);
1261 PRE_REG_READ3(int, "ftruncate", int, fd,
1262 vki_uint32_t, MERGE64_FIRST(length),
1263 vki_uint32_t, MERGE64_SECOND(length));
1266 // SYS_cpuset_setid 485
1267 // int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid);
1268 PRE(sys_cpuset_setid)
1270 PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )",
1271 SARG1, MERGE64(ARG2,ARG3), ARG4);
1272 PRE_REG_READ4(int, "cpuset_setid", vki_cpuwhich_t, which,
1273 vki_uint32_t, MERGE64_FIRST(id),
1274 vki_uint32_t, MERGE64_SECOND(id),
1275 vki_cpusetid_t,setid);
1278 // SYS_cpuset_getid 486
1279 // int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id,
1280 // cpusetid_t *setid);
1281 PRE(sys_cpuset_getid)
1283 PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )",
1284 SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5);
1285 PRE_REG_READ5(int, "cpuset_getid", vki_cpulevel_t, level,
1286 vki_cpuwhich_t, which,
1287 vki_uint32_t, MERGE64_FIRST(id),
1288 vki_uint32_t, MERGE64_SECOND(id),
1289 vki_cpusetid_t *,setid);
1290 PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t));
1293 POST(sys_cpuset_getid)
1295 POST_MEM_WRITE(ARG5, sizeof(vki_cpusetid_t));
1298 // SYS_cpuset_getaffinity 487
1299 // int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
1300 // size_t setsize, cpuset_t *mask);
1301 PRE(sys_cpuset_getaffinity)
1303 PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %lld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
1304 ARG1, ARG2, (vki_id_t)MERGE64(ARG3, ARG4), ARG5, ARG6);
1305 PRE_REG_READ6(int, "cpuset_getaffinity",
1306 vki_cpulevel_t, level, vki_cpuwhich_t, which,
1307 vki_uint32_t, MERGE64_FIRST(id),
1308 vki_uint32_t, MERGE64_SECOND(id),
1309 size_t, setsize, void *, mask);
1310 PRE_MEM_WRITE("cpuset_getaffinity", ARG6, ARG5);
1313 POST(sys_cpuset_getaffinity)
1315 vg_assert(SUCCESS);
1316 if (RES == 0)
1317 POST_MEM_WRITE( ARG6, ARG5 );
1320 // SYS_cpuset_setaffinity 488
1321 // int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
1322 // size_t setsize, const cpuset_t *mask);
1323 PRE(sys_cpuset_setaffinity)
1326 PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
1327 ARG1, ARG2, MERGE64(ARG3, ARG4), ARG5, ARG6);
1328 PRE_REG_READ6(int, "cpuset_setaffinity",
1329 vki_cpulevel_t, level, vki_cpuwhich_t, which,
1330 vki_uint32_t, MERGE64_FIRST(id),
1331 vki_uint32_t, MERGE64_SECOND(id),
1332 size_t, setsize, void *, mask);
1333 PRE_MEM_READ("cpuset_setaffinity", ARG6, ARG5);
1336 // SYS_posix_fallocate 530
1337 // int posix_fallocate(int fd, off_t offset, off_t len);
1338 PRE(sys_posix_fallocate)
1340 PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %llu, %llu )",
1341 SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4, ARG5));
1342 PRE_REG_READ5(long, "posix_fallocate",
1343 int, fd, vki_uint32_t, MERGE64_FIRST(offset),
1344 vki_uint32_t, MERGE64_SECOND(offset),
1345 vki_uint32_t, MERGE64_FIRST(len),
1346 vki_uint32_t, MERGE64_SECOND(len));
1349 // SYS_posix_fadvise 531
1350 // int posix_fadvise(int fd, off_t offset, off_t len, int advice);
1351 PRE(sys_posix_fadvise)
1353 PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %llu, %llu, %" FMT_REGWORD "d )",
1354 SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4,ARG5), SARG6);
1355 PRE_REG_READ6(long, "posix_fadvise",
1356 int, fd, vki_uint32_t, MERGE64_FIRST(offset),
1357 vki_uint32_t, MERGE64_SECOND(offset),
1358 vki_uint32_t, MERGE64_FIRST(len),
1359 vki_uint32_t, MERGE64_SECOND(len),
1360 int, advice);
1363 // SYS_wait6 532
1364 // pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
1365 // struct __wrusage *wrusage, siginfo_t *infop);
1366 PRE(sys_wait6)
1368 PRINT("sys_wait6 ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
1369 SARG1, MERGE64(ARG2, ARG3), ARG4, SARG5, ARG6, ARG7);
1370 PRE_REG_READ7(pid_t, "wait6", vki_idtype_t, idtype,
1371 vki_uint32_t, MERGE64_FIRST(id),
1372 vki_uint32_t, MERGE64_SECOND(id),
1373 int *, status, int, options,
1374 struct vki___wrusage *, wrusage, vki_siginfo_t *,infop);
1375 PRE_MEM_WRITE("wait6(status)", ARG4, sizeof(int));
1376 if (ARG6) {
1377 PRE_MEM_WRITE("wait6(wrusage)", ARG6, sizeof(struct vki___wrusage));
1379 if (ARG7) {
1380 PRE_MEM_WRITE("wait6(infop)", ARG7, sizeof(vki_siginfo_t));
1384 POST(sys_wait6)
1386 POST_MEM_WRITE(ARG4, sizeof(int));
1387 if (ARG6) {
1388 POST_MEM_WRITE(ARG6, sizeof(struct vki___wrusage));
1391 if (ARG7) {
1392 POST_MEM_WRITE(ARG7, sizeof(vki_siginfo_t));
1396 // the man page is inconsistent for the last argument
1397 // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386
1398 // will stick to 'arg' for simplicity
1400 // SYS_procctl 544
1401 // int procctl(idtype_t idtype, id_t id, int cmd, void *arg);
1402 PRE(sys_procctl)
1404 PRINT("sys_procctl ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD"d, %#" FMT_REGWORD "x )",
1405 SARG1, MERGE64(ARG2, ARG3), SARG4, ARG5);
1406 PRE_REG_READ5(int, "procctl", vki_idtype_t, idtype,
1407 vki_uint32_t, MERGE64_FIRST(id),
1408 vki_uint32_t, MERGE64_SECOND(id),
1409 int, cmd, void *, arg);
1410 switch (ARG4) {
1411 case VKI_PROC_ASLR_CTL:
1412 case VKI_PROC_SPROTECT:
1413 case VKI_PROC_TRACE_CTL:
1414 case VKI_PROC_TRAPCAP_CTL:
1415 case VKI_PROC_PDEATHSIG_CTL:
1416 case VKI_PROC_STACKGAP_CTL:
1417 case VKI_PROC_NO_NEW_PRIVS_CTL:
1418 case VKI_PROC_WXMAP_CTL:
1419 PRE_MEM_READ("procctl(arg)", ARG5, sizeof(int));
1420 break;
1421 case VKI_PROC_REAP_STATUS:
1422 PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_status));
1423 break;
1424 case VKI_PROC_REAP_GETPIDS:
1425 PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_pids));
1426 break;
1427 case VKI_PROC_REAP_KILL:
1428 /* The first three fields are reads
1429 * int rk_sig;
1430 * u_int rk_flags;
1431 * pid_t rk_subtree;
1433 * The last two fields are writes
1434 * u_int rk_killed;
1435 * pid_t rk_fpid;
1437 * There is also a pad field
1439 PRE_MEM_READ("procctl(arg)", ARG5, sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t));
1440 PRE_MEM_WRITE("procctl(arg)", ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
1441 break;
1442 case VKI_PROC_ASLR_STATUS:
1443 case VKI_PROC_PDEATHSIG_STATUS:
1444 case VKI_PROC_STACKGAP_STATUS:
1445 case VKI_PROC_TRAPCAP_STATUS:
1446 case VKI_PROC_TRACE_STATUS:
1447 PRE_MEM_WRITE("procctl(arg)", ARG5, sizeof(int));
1448 case VKI_PROC_REAP_ACQUIRE:
1449 case VKI_PROC_REAP_RELEASE:
1450 default:
1451 break;
1455 POST(sys_procctl)
1457 switch (ARG4) {
1458 case VKI_PROC_REAP_KILL:
1459 POST_MEM_WRITE(ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
1460 break;
1461 case VKI_PROC_ASLR_STATUS:
1462 case VKI_PROC_PDEATHSIG_STATUS:
1463 case VKI_PROC_STACKGAP_STATUS:
1464 case VKI_PROC_TRAPCAP_STATUS:
1465 case VKI_PROC_TRACE_STATUS:
1466 case VKI_PROC_NO_NEW_PRIVS_STATUS:
1467 case VKI_PROC_WXMAP_STATUS:
1468 POST_MEM_WRITE(ARG5, sizeof(int));
1469 default:
1470 break;
1474 // SYS_mknodat 559
1475 // int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
1476 PRE(sys_mknodat)
1478 PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 );
1479 PRE_REG_READ5(long, "mknodat",
1480 int, fd, const char *, path, vki_mode_t, mode, vki_uint32_t, MERGE64_FIRST(dev), vki_uint32_t, MERGE64_SECOND(idev))
1481 PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 );
1484 #if (FREEBSD_VERS >= FREEBSD_12)
1486 // SYS_cpuset_getdomain 561
1487 // int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
1488 // size_t setsize, domainset_t *mask, int *policy);
1489 PRE(sys_cpuset_getdomain)
1491 PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
1492 SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, ARG7);
1493 PRE_REG_READ7(int, "cpuset_getdomain",
1494 cpulevel_t, level, cpuwhich_t, which,
1495 vki_uint32_t, MERGE64_FIRST(id),
1496 vki_uint32_t, MERGE64_SECOND(id),
1497 size_t, setsize, vki_domainset_t *, mask, int *, policy);
1498 // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
1499 PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG6, ARG5 );
1500 PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG7, sizeof(int) );
1503 POST(sys_cpuset_getdomain)
1505 POST_MEM_WRITE(ARG5, ARG4 );
1506 POST_MEM_WRITE(ARG6, sizeof(int) );
1509 // SYS_cpuset_setdomain 562
1510 // int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
1511 // size_t setsize, const domainset_t *mask, int policy);
1512 PRE(sys_cpuset_setdomain)
1514 PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
1515 SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, SARG7);
1516 PRE_REG_READ7(int, "cpuset_getdomain",
1517 cpulevel_t, level, cpuwhich_t, which,
1518 vki_uint32_t, MERGE64_FIRST(id),
1519 vki_uint32_t, MERGE64_SECOND(id),
1520 size_t, setsize, vki_domainset_t *, mask, int, policy);
1521 // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
1522 PRE_MEM_READ( "cpuset_getdomain(mask)", ARG6, ARG5 );
1525 #endif
1527 PRE(sys_fake_sigreturn)
1529 /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
1530 an explanation of what follows. */
1532 ThreadState* tst;
1533 struct vki_ucontext *uc;
1534 PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
1535 PRE_REG_READ1(long, "sigreturn",
1536 struct vki_ucontext *, scp);
1538 PRE_MEM_READ( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
1539 PRE_MEM_WRITE( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
1541 vg_assert(VG_(is_valid_tid)(tid));
1542 vg_assert(tid >= 1 && tid < VG_N_THREADS);
1543 vg_assert(VG_(is_running_thread)(tid));
1545 /* Adjust esp to point to start of frame; skip back up over handler
1546 ret addr */
1547 tst = VG_(get_ThreadState)(tid);
1548 tst->arch.vex.guest_ESP -= sizeof(Addr); /* QQQ should be redundant */
1550 uc = (struct vki_ucontext *)ARG1;
1551 if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) {
1552 SET_STATUS_Failure(VKI_EINVAL);
1553 return;
1556 /* This is only so that the EIP is (might be) useful to report if
1557 something goes wrong in the sigreturn */
1558 ML_(fixup_guest_state_to_restart_syscall)(&tst->arch);
1560 /* Restore register state from frame and remove it */
1561 VG_(sigframe_destroy)(tid);
1563 /* For unclear reasons, it appears we need the syscall to return
1564 without changing %EAX. Since %EAX is the return value, and can
1565 denote either success or failure, we must set up so that the
1566 driver logic copies it back unchanged. Also, note %EAX is of
1567 the guest registers written by VG_(sigframe_destroy). */
1568 int eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
1569 SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_freebsd)( tst->arch.vex.guest_EAX,
1570 tst->arch.vex.guest_EDX, (eflags & 1) != 0 ? True : False) );
1573 * Signal handler might have changed the signal mask. Respect that.
1575 tst->sig_mask = uc->uc_sigmask;
1576 tst->tmp_sig_mask = uc->uc_sigmask;
1578 /* Tell the driver not to update the guest state with the "result",
1579 and set a bogus result to keep it happy. */
1580 *flags |= SfNoWriteResult;
1581 SET_STATUS_Success(0);
1583 /* Check to see if any signals arose as a result of this. */
1584 *flags |= SfPollAfter;
1587 #undef PRE
1588 #undef POST
1591 #endif /* defined(VGP_x86_freebsd) */
1594 /*--------------------------------------------------------------------*/
1595 /*--- end ---*/
1596 /*--------------------------------------------------------------------*/