Bug 444488 - Use glibc.pthread.stack_cache_size tunable
[valgrind.git] / coregrind / m_syswrap / syswrap-x86-freebsd.c
blob0e9227014428f5e6aa955d706c2f808dc860c4eb
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 );
330 /* Allow LDTs to be cleared by the user. */
331 if (base == 0) {
332 entry_1 = 0;
333 entry_2 = 0;
334 goto install;
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 ... */
342 install:
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 )
364 vg_assert(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 )
372 Int i;
373 vg_assert(src);
374 vg_assert(dst);
375 for (i = 0; i < VEX_GUEST_X86_LDT_NENT; i++)
376 dst[i] = src[i];
379 /* Copy contents between two existing GDTs. */
380 static void copy_GDT_from_to ( VexGuestX86SegDescr* src,
381 VexGuestX86SegDescr* dst )
383 Int i;
384 vg_assert(src);
385 vg_assert(dst);
386 for (i = 0; i < VEX_GUEST_X86_GDT_NENT; i++)
387 dst[i] = src[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*));
395 if (0)
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;
414 Int idx;
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. */
422 if (!gdt) {
423 gdt = alloc_zeroed_x86_GDT();
424 VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
427 idx = *idxptr;
428 if (idx == -1) {
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
432 Wine). */
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)
436 break;
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]);
448 *idxptr = idx;
449 return VG_(mk_SysRes_Success)( 0 );
452 static SysRes sys_get_thread_area ( ThreadId tid, Int idx, void ** basep )
454 VexGuestX86SegDescr* gdt;
455 UInt base;
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. */
463 if (!gdt) {
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 );
476 static
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;
484 } else {
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
493 only). */
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 /* ---------------------------------------------------------------------
507 More thread stuff
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
515 * end of thr_exit.
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)
530 // SYS_sysarch 165
531 // int sysarch(int number, void *args);
532 PRE(sys_sysarch)
534 ThreadState *tst;
535 Int idx;
536 void **p;
538 PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2);
539 PRE_REG_READ2(int, "sysarch", int, number, void *, args);
540 switch (ARG1) {
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);
547 p = (void**)ARG2;
548 tst->arch.vex.guest_GS = (1 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */
549 /* "do" the syscall ourselves; the kernel never sees it */
550 idx = 1;
551 SET_STATUS_from_SysRes( sys_set_thread_area( tid, &idx, *p ) );
552 } else {
553 // ????
554 SET_STATUS_Failure( VKI_EINVAL );
557 break;
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 ) );
564 } else {
565 SET_STATUS_Failure( VKI_EINVAL );
567 break;
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] );
574 break;
575 default:
576 VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %lu", ARG1);
577 VG_(unimplemented) ("unhandled sysarch cmd");
578 break;
582 POST(sys_sysarch)
584 switch (ARG1) {
585 case VKI_AMD64_SET_FSBASE:
586 break;
587 case VKI_AMD64_GET_FSBASE:
588 POST_MEM_WRITE( ARG2, sizeof(void *) );
589 break;
590 case VKI_AMD64_GET_XFPUSTATE:
591 POST_MEM_WRITE( ARG2, sizeof(void *) );
592 break;
593 default:
594 break;
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 );
610 else
611 PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2, ARG3 );
614 POST(sys_freebsd6_pread)
616 vg_assert(SUCCESS);
617 POST_MEM_WRITE( ARG2, RES );
619 #endif
621 // freebsd6_pwrite 174
622 #if (FREEBSD_VERS <= FREEBSD_10)
623 PRE(sys_freebsd6_pwrite)
625 Bool ok;
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)))
636 ok = True;
637 if (!ok)
638 SET_STATUS_Failure( VKI_EBADF );
639 else
640 PRE_MEM_READ( "freebsd6_write(buf)", ARG2, ARG3 );
642 #endif
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)
653 SysRes r;
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);
664 #endif
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);
675 #endif
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 );
688 #endif
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);
699 #endif
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));
715 // SYS_rfork 251
716 // pid_t rfork(int flags);
717 PRE(sys_rfork)
719 PRINT("sys_rfork ( %" FMT_REGWORD "x )",ARG1);
720 PRE_REG_READ1(int, "rfork",
721 unsigned int, flags);
723 #if 0
724 cloneflags = ARG1;
726 if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
727 SET_STATUS_Failure( VKI_EINVAL );
728 return;
731 SET_STATUS_from_SysRes( do_clone(tid, ARG1));
733 if (SUCCESS) {
734 *flags |= SfYieldAfter;
736 #else
737 VG_(message)(Vg_UserMsg, "rfork() not implemented");
738 VG_(unimplemented)("Valgrind does not support rfork() yet.");
739 SET_STATUS_Failure( VKI_ENOSYS );
740 #endif
743 // SYS_preadv 289
744 // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
745 PRE(sys_preadv)
747 Int i;
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 );
758 } else {
759 if ((Int)ARG3 > 0)
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 );
771 POST(sys_preadv)
773 vg_assert(SUCCESS);
774 if (RES > 0) {
775 Int i;
776 struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2;
777 Int remains = RES;
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");
790 // SYS_pwritev 290
791 // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
792 PRE(sys_pwritev)
794 Int i;
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,
802 int, iovcnt,
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 );
807 } else {
808 if ((Int)ARG3 >= 0)
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 );
819 // SYS_sendfile 393
820 // int sendfile(int fd, int s, off_t offset, size_t nbytes,
821 // struct sf_hdtr *hdtr, off_t *sbytes, int flags);
822 PRE(sys_sendfile)
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);
832 if (ARG6 != 0)
833 PRE_MEM_READ("sendfile(hdtr)", ARG6, sizeof(struct vki_sf_hdtr));
835 if (ARG7 != 0)
836 PRE_MEM_WRITE( "sendfile(sbytes)", ARG7, sizeof(vki_off_t) );
839 POST(sys_sendfile)
841 if (ARG7 != 0 ) {
842 POST_MEM_WRITE( ARG7, sizeof( vki_off_t ) );
846 // SYS_sigreturn 417
847 // int sigreturn(const ucontext_t *scp);
848 PRE(sys_sigreturn)
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);
881 else
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);
904 not yet.
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);
915 PRE(sys_getcontext)
917 ThreadState* tst;
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);
927 return;
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);
941 PRE(sys_setcontext)
943 ThreadState* tst;
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);
961 return;
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);
979 PRE(sys_swapcontext)
981 struct vki_ucontext *ucp, *oucp;
982 ThreadState* tst;
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);
997 return;
999 tst = VG_(get_ThreadState)(tid);
1002 * Save the context.
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;
1027 // SYS_thr_new 455
1028 // int thr_new(struct thr_param *param, int param_size);
1029 PRE(sys_thr_new)
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);
1036 SysRes res;
1037 vki_sigset_t blockall, savedmask;
1038 struct vki_thr_param tp;
1039 Int idx = -1;
1040 Addr stk;
1042 PRINT("thr_new ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2);
1043 PRE_REG_READ2(int, "thr_new",
1044 struct thr_param *, param,
1045 int, param_size);
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 );
1050 return;
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
1068 of this gunk.
1070 The parent gets the child's new tid returned from clone, but the
1071 child gets 0.
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
1082 child. */
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 );
1106 if (debug)
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)) {
1137 /* clone failed */
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 );
1142 } else {
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
1149 to run */
1150 *flags |= SfYieldAfter;
1153 /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */
1154 SET_STATUS_from_SysRes(res);
1157 // SYS_pread 475
1158 // ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
1159 PRE(sys_pread)
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 );
1169 else
1170 PRE_MEM_WRITE( "pread(buf)", ARG2, ARG3 );
1173 POST(sys_pread)
1175 vg_assert(SUCCESS);
1176 POST_MEM_WRITE( ARG2, RES );
1179 // SYS_pwrite 476
1180 // ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
1181 PRE(sys_pwrite)
1183 Bool ok;
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)))
1195 ok = True;
1196 if (!ok)
1197 SET_STATUS_Failure( VKI_EBADF );
1198 else
1199 PRE_MEM_READ( "pwrite(buf)", ARG2, ARG3 );
1202 // SYS_mmap 477
1203 // void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
1204 PRE(sys_mmap)
1206 SysRes r;
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);
1219 // SYS_lseek 478
1220 // off_t lseek(int fildes, off_t offset, int whence);
1221 PRE(sys_lseek)
1223 PRINT("sys_lseek ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "d )", SARG1,MERGE64(ARG2,ARG3),SARG4);
1224 PRE_REG_READ4(long, "lseek",
1225 unsigned int, fd,
1226 vki_uint32_t, MERGE64_FIRST(offset),
1227 vki_uint32_t, MERGE64_SECOND(offset),
1228 unsigned int, whence);
1231 // SYS_truncate 479
1232 // int truncate(const char *path, off_t length);
1233 PRE(sys_truncate)
1235 *flags |= SfMayBlock;
1236 PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %llu )", ARG1,(char *)ARG1,MERGE64(ARG2,ARG3));
1237 PRE_REG_READ3(long, "truncate",
1238 const char *, path,
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);
1246 PRE(sys_ftruncate)
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)
1304 vg_assert(SUCCESS);
1305 if (RES == 0)
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),
1349 int, advice);
1352 // SYS_wait6 532
1353 // pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
1354 // struct __wrusage *wrusage, siginfo_t *infop);
1355 PRE(sys_wait6)
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));
1365 if (ARG6) {
1366 PRE_MEM_WRITE("wait6(wrusage)", ARG6, sizeof(struct vki___wrusage));
1368 if (ARG7) {
1369 PRE_MEM_WRITE("wait6(infop)", ARG7, sizeof(vki_siginfo_t));
1373 POST(sys_wait6)
1375 POST_MEM_WRITE(ARG4, sizeof(int));
1376 if (ARG6) {
1377 POST_MEM_WRITE(ARG6, sizeof(struct vki___wrusage));
1380 if (ARG7) {
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
1389 // SYS_procctl 544
1390 // int procctl(idtype_t idtype, id_t id, int cmd, void *arg);
1391 PRE(sys_procctl)
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);
1399 switch (ARG4) {
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));
1409 break;
1410 case VKI_PROC_REAP_STATUS:
1411 PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_status));
1412 break;
1413 case VKI_PROC_REAP_GETPIDS:
1414 PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_pids));
1415 break;
1416 case VKI_PROC_REAP_KILL:
1417 /* The first three fields are reads
1418 * int rk_sig;
1419 * u_int rk_flags;
1420 * pid_t rk_subtree;
1422 * The last two fields are writes
1423 * u_int rk_killed;
1424 * pid_t rk_fpid;
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));
1430 break;
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:
1439 default:
1440 break;
1444 POST(sys_procctl)
1446 switch (ARG4) {
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));
1449 break;
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));
1458 default:
1459 break;
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 );
1504 #endif
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. */
1511 ThreadState* tst;
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
1525 ret addr */
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);
1532 return;
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;
1566 #undef PRE
1567 #undef POST
1570 #endif /* defined(VGP_x86_freebsd) */
1573 /*--------------------------------------------------------------------*/
1574 /*--- end ---*/
1575 /*--------------------------------------------------------------------*/