regtest: callgrind bug497723 again, order of output can vary
[valgrind.git] / coregrind / m_syswrap / syswrap-x86-freebsd.c
blob0ad3dda26443d2a272f497a96d523bf5c6456bc3
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*)(HWord)vex->guest_LDT );
406 vex->guest_LDT = (HWord)NULL;
409 if (vex->guest_GDT != (HWord)NULL) {
410 free_LDT_or_GDT( (VexGuestX86SegDescr*)(HWord)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*)(HWord)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*)(HWord)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 // removed
607 // freebsd6_pwrite 174
608 // removed
610 // SYS_freebsd6_mmap 197
611 // removed
613 // freebsd6_lseek 199
614 // removed
616 // freebsd6_truncate 200
617 // removed
619 // freebsd6_ftruncate 201
620 // removed
622 // SYS_clock_getcpuclockid2 247
623 // no manpage for this, from syscalls.master
624 // int clock_getcpuclockid2(id_t id, int which, _Out_ clockid_t *clock_id);
625 PRE(sys_clock_getcpuclockid2)
627 PRINT("sys_clock_getcpuclockid2( %lld, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
628 (vki_id_t)MERGE64(ARG1,ARG2),SARG3,ARG4);
629 PRE_REG_READ4(int, "clock_getcpuclockid2",
630 vki_uint32_t, MERGE64_FIRST(offset),
631 vki_uint32_t, MERGE64_SECOND(offset),
632 int, len, clockid_t *, clock_id);
633 PRE_MEM_WRITE("clock_getcpuclockid2(clock_id)", ARG3, sizeof(vki_clockid_t));
636 // SYS_rfork 251
637 // pid_t rfork(int flags);
638 PRE(sys_rfork)
640 PRINT("sys_rfork ( %" FMT_REGWORD "x )",ARG1);
641 PRE_REG_READ1(int, "rfork",
642 unsigned int, flags);
644 #if 0
645 cloneflags = ARG1;
647 if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
648 SET_STATUS_Failure( VKI_EINVAL );
649 return;
652 SET_STATUS_from_SysRes( do_clone(tid, ARG1));
654 if (SUCCESS) {
655 *flags |= SfYieldAfter;
657 #else
658 VG_(message)(Vg_UserMsg, "rfork() not implemented\n");
659 if ((UInt)ARG1 == VKI_RFSPAWN) {
660 // posix_spawn uses RFSPAWN and it will fall back to vfork
661 // if it sees EINVAL
662 SET_STATUS_Failure(VKI_EINVAL);
663 } else {
664 SET_STATUS_Failure(VKI_ENOSYS);
666 #endif
669 // SYS_preadv 289
670 // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
671 PRE(sys_preadv)
673 Int i;
674 struct vki_iovec * vec;
675 *flags |= SfMayBlock;
676 PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
677 FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5));
678 PRE_REG_READ5(ssize_t, "preadv",
679 int, fd, const struct iovec *, iov,
680 int, iovcnt, vki_uint32_t, MERGE64_FIRST(offset),
681 vki_uint32_t, MERGE64_SECOND(offset));
682 if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) {
683 SET_STATUS_Failure( VKI_EBADF );
684 } else {
685 if ((Int)ARG3 > 0)
686 PRE_MEM_READ( "preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec) );
688 if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
689 vec = (struct vki_iovec *)(Addr)ARG2;
690 for (i = 0; i < (Int)ARG3; i++)
691 PRE_MEM_WRITE( "preadv(iov[...])",
692 (Addr)vec[i].iov_base, vec[i].iov_len );
697 POST(sys_preadv)
699 vg_assert(SUCCESS);
700 if (RES > 0) {
701 Int i;
702 struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2;
703 Int remains = RES;
705 /* RES holds the number of bytes read. */
706 for (i = 0; i < (Int)ARG3; i++) {
707 Int nReadThisBuf = vec[i].iov_len;
708 if (nReadThisBuf > remains) nReadThisBuf = remains;
709 POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
710 remains -= nReadThisBuf;
711 if (remains < 0) VG_(core_panic)("preadv: remains < 0");
716 // SYS_pwritev 290
717 // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
718 PRE(sys_pwritev)
720 Int i;
721 struct vki_iovec * vec;
722 *flags |= SfMayBlock;
723 PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
724 FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5));
726 PRE_REG_READ5(ssize_t, "pwritev",
727 int, fd, const struct iovec *, iov,
728 int, iovcnt,
729 vki_uint32_t, MERGE64_FIRST(offset),
730 vki_uint32_t, MERGE64_SECOND(offset));
731 if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) {
732 SET_STATUS_Failure( VKI_EBADF );
733 } else {
734 if ((Int)ARG3 >= 0)
735 PRE_MEM_READ( "pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) );
736 if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
737 vec = (struct vki_iovec *)(Addr)ARG2;
738 for (i = 0; i < (Int)ARG3; i++)
739 PRE_MEM_READ( "pwritev(iov[...])",
740 (Addr)vec[i].iov_base, vec[i].iov_len );
745 // SYS_sendfile 393
746 // int sendfile(int fd, int s, off_t offset, size_t nbytes,
747 // struct sf_hdtr *hdtr, off_t *sbytes, int flags);
748 PRE(sys_sendfile)
750 *flags |= SfMayBlock;
751 PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
752 SARG1,SARG2,LOHI64(ARG3,ARG4),ARG5,ARG6,ARG7,SARG8);
753 PRE_REG_READ8(int, "sendfile",
754 int, fd, int, s, unsigned int, offset_low,
755 unsigned int, offset_high, size_t, nbytes,
756 void *, hdtr, vki_off_t *, sbytes, int, flags);
758 if (ARG6 != 0)
759 PRE_MEM_READ("sendfile(hdtr)", ARG6, sizeof(struct vki_sf_hdtr));
761 if (ARG7 != 0)
762 PRE_MEM_WRITE( "sendfile(sbytes)", ARG7, sizeof(vki_off_t) );
765 POST(sys_sendfile)
767 if (ARG7 != 0 ) {
768 POST_MEM_WRITE( ARG7, sizeof( vki_off_t ) );
772 // SYS_sigreturn 417
773 // int sigreturn(const ucontext_t *scp);
774 PRE(sys_sigreturn)
776 PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
777 PRE_REG_READ1(int, "sigreturn",
778 struct vki_ucontext *, scp);
780 PRE_MEM_READ( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
781 PRE_MEM_WRITE( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
785 static void restore_mcontext(ThreadState *tst, struct vki_mcontext *sc)
787 tst->arch.vex.guest_EAX = sc->eax;
788 tst->arch.vex.guest_ECX = sc->ecx;
789 tst->arch.vex.guest_EDX = sc->edx;
790 tst->arch.vex.guest_EBX = sc->ebx;
791 tst->arch.vex.guest_EBP = sc->ebp;
792 tst->arch.vex.guest_ESP = sc->esp;
793 tst->arch.vex.guest_ESI = sc->esi;
794 tst->arch.vex.guest_EDI = sc->edi;
795 tst->arch.vex.guest_EIP = sc->eip;
796 tst->arch.vex.guest_CS = sc->cs;
797 tst->arch.vex.guest_SS = sc->ss;
798 tst->arch.vex.guest_DS = sc->ds;
799 tst->arch.vex.guest_ES = sc->es;
800 tst->arch.vex.guest_FS = sc->fs;
801 tst->arch.vex.guest_GS = sc->gs;
803 * XXX: missing support for other flags.
805 if (sc->eflags & 0x0001)
806 LibVEX_GuestX86_put_eflag_c(1, &tst->arch.vex);
807 else
808 LibVEX_GuestX86_put_eflag_c(0, &tst->arch.vex);
811 static void fill_mcontext(ThreadState *tst, struct vki_mcontext *sc)
813 sc->eax = tst->arch.vex.guest_EAX;
814 sc->ecx = tst->arch.vex.guest_ECX;
815 sc->edx = tst->arch.vex.guest_EDX;
816 sc->ebx = tst->arch.vex.guest_EBX;
817 sc->ebp = tst->arch.vex.guest_EBP;
818 sc->esp = tst->arch.vex.guest_ESP;
819 sc->esi = tst->arch.vex.guest_ESI;
820 sc->edi = tst->arch.vex.guest_EDI;
821 sc->eip = tst->arch.vex.guest_EIP;
822 sc->cs = tst->arch.vex.guest_CS;
823 sc->ss = tst->arch.vex.guest_SS;
824 sc->ds = tst->arch.vex.guest_DS;
825 sc->es = tst->arch.vex.guest_ES;
826 sc->fs = tst->arch.vex.guest_FS;
827 sc->gs = tst->arch.vex.guest_GS;
828 sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
830 not yet.
831 VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate));
833 sc->fpformat = VKI_FPFMT_NODEV;
834 sc->ownedfp = VKI_FPOWNED_NONE;
835 sc->len = sizeof(*sc);
836 VG_(memset)(sc->spare2, 0, sizeof(sc->spare2));
839 // SYS_getcontext 421
840 // int getcontext(ucontext_t *ucp);
841 PRE(sys_getcontext)
843 ThreadState* tst;
844 struct vki_ucontext *uc;
846 PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1);
847 PRE_REG_READ1(int, "getcontext",
848 struct vki_ucontext *, ucp);
849 PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
850 uc = (struct vki_ucontext *)ARG1;
851 if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) {
852 SET_STATUS_Failure(VKI_EINVAL);
853 return;
855 tst = VG_(get_ThreadState)(tid);
856 fill_mcontext(tst, &uc->uc_mcontext);
857 uc->uc_mcontext.eax = 0;
858 uc->uc_mcontext.edx = 0;
859 uc->uc_mcontext.eflags &= ~0x0001; /* PSL_C */
860 uc->uc_sigmask = tst->sig_mask;
861 VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__));
862 SET_STATUS_Success(0);
865 // SYS_setcontext 422
866 // int setcontext(const ucontext_t *ucp);
867 PRE(sys_setcontext)
869 ThreadState* tst;
870 struct vki_ucontext *uc;
872 PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", ARG1);
873 PRE_REG_READ1(long, "setcontext",
874 struct vki_ucontext *, ucp);
876 PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
878 vg_assert(VG_(is_valid_tid)(tid));
879 vg_assert(tid >= 1 && tid < VG_N_THREADS);
880 vg_assert(VG_(is_running_thread)(tid));
882 tst = VG_(get_ThreadState)(tid);
883 uc = (struct vki_ucontext *)ARG1;
884 if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) {
885 SET_STATUS_Failure(VKI_EINVAL);
886 return;
889 restore_mcontext(tst, &uc->uc_mcontext);
890 tst->sig_mask = uc->uc_sigmask;
891 tst->tmp_sig_mask = uc->uc_sigmask;
893 /* Tell the driver not to update the guest state with the "result",
894 and set a bogus result to keep it happy. */
895 *flags |= SfNoWriteResult;
896 SET_STATUS_Success(0);
898 /* Check to see if some any signals arose as a result of this. */
899 *flags |= SfPollAfter;
902 // SYS_swapcontext 423
903 // int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
904 PRE(sys_swapcontext)
906 struct vki_ucontext *ucp, *oucp;
907 ThreadState* tst;
909 PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2);
910 PRE_REG_READ2(long, "swapcontext",
911 struct vki_ucontext *, oucp, struct vki_ucontext *, ucp);
913 PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) );
914 PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) );
916 oucp = (struct vki_ucontext *)ARG1;
917 ucp = (struct vki_ucontext *)ARG2;
918 if (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) ||
919 !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) ||
920 ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)) {
921 SET_STATUS_Failure(VKI_EINVAL);
922 return;
924 tst = VG_(get_ThreadState)(tid);
927 * Save the context.
929 fill_mcontext(tst, &oucp->uc_mcontext);
930 oucp->uc_mcontext.eax = 0;
931 oucp->uc_mcontext.edx = 0;
932 oucp->uc_mcontext.eflags &= ~0x0001; /* PSL_C */
933 oucp->uc_sigmask = tst->sig_mask;
934 VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__));
937 * Switch to new one.
939 restore_mcontext(tst, &ucp->uc_mcontext);
940 tst->sig_mask = ucp->uc_sigmask;
941 tst->tmp_sig_mask = ucp->uc_sigmask;
943 /* Tell the driver not to update the guest state with the "result",
944 and set a bogus result to keep it happy. */
945 *flags |= SfNoWriteResult;
946 SET_STATUS_Success(0);
948 /* Check to see if some any signals arose as a result of this. */
949 *flags |= SfPollAfter;
952 // SYS_thr_new 455
953 // int thr_new(struct thr_param *param, int param_size);
954 PRE(sys_thr_new)
956 static const Bool debug = False;
958 ThreadId ctid = VG_(alloc_ThreadState)();
959 ThreadState* ptst = VG_(get_ThreadState)(tid);
960 ThreadState* ctst = VG_(get_ThreadState)(ctid);
961 SysRes res;
962 vki_sigset_t blockall, savedmask;
963 struct vki_thr_param tp;
964 Int idx = -1;
965 Addr stk;
967 PRINT("thr_new ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2);
968 PRE_REG_READ2(int, "thr_new",
969 struct thr_param *, param,
970 int, param_size);
972 PRE_MEM_READ( "thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare));
973 if (!ML_(safe_to_deref)( (void*)ARG1, offsetof(struct vki_thr_param, spare))) {
974 SET_STATUS_Failure( VKI_EFAULT );
975 return;
977 VG_(memset)(&tp, 0, sizeof(tp));
978 VG_(memcpy)(&tp, (void *)ARG1, offsetof(struct vki_thr_param, spare));
979 PRE_MEM_WRITE("clone(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long));
980 PRE_MEM_WRITE("clone(child_tidptr)", (Addr)tp.child_tid, sizeof(long));
982 VG_(sigfillset)(&blockall);
984 vg_assert(VG_(is_running_thread)(tid));
985 vg_assert(VG_(is_valid_tid)(ctid));
987 /* Copy register state
989 On linux, both parent and child return to the same place, and the code
990 following the clone syscall works out which is which, so we
991 don't need to worry about it.
992 On FreeBSD, thr_new arranges a direct call. We don't actually need any
993 of this gunk.
995 The parent gets the child's new tid returned from clone, but the
996 child gets 0.
998 If the clone call specifies a NULL rsp for the new thread, then
999 it actually gets a copy of the parent's rsp.
1001 /* We inherit our parent's guest state. */
1002 ctst->arch.vex = ptst->arch.vex;
1003 ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1;
1004 ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2;
1006 /* Make sys_clone appear to have returned Success(0) in the
1007 child. */
1008 ctst->arch.vex.guest_EAX = 0;
1009 ctst->arch.vex.guest_EDX = 0;
1010 LibVEX_GuestX86_put_eflag_c(0, &ctst->arch.vex);
1012 x86_setup_LDT_GDT(&ctst->arch, &ptst->arch);
1014 ctst->os_state.parent = tid;
1016 /* inherit signal mask */
1017 ctst->sig_mask = ptst->sig_mask;
1018 ctst->tmp_sig_mask = ptst->sig_mask;
1020 /* Linux has to guess, we don't */
1021 ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size;
1022 ctst->client_stack_szB = tp.stack_size;
1023 ctst->os_state.stk_id = VG_(register_stack)((Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size);
1025 /* Assume the clone will succeed, and tell any tool that wants to
1026 know that this thread has come into existence. If the clone
1027 fails, we'll send out a ll_exit notification for it at the out:
1028 label below, to clean up. */
1029 VG_TRACK ( pre_thread_ll_create, tid, ctid );
1031 if (debug)
1032 VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base);
1034 sys_set_thread_area( ctid, &idx, tp.tls_base );
1036 ctst->arch.vex.guest_GS = (idx << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */
1037 tp.tls_base = 0; /* Don't have the kernel do it too */
1039 /* start the thread with everything blocked */
1040 VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
1042 /* Set the client state for scheduler to run libthr's trampoline */
1043 ctst->arch.vex.guest_ESP = (Addr)tp.stack_base + tp.stack_size - 8;
1044 ctst->arch.vex.guest_EIP = (Addr)tp.start_func;
1045 *(UWord *)(ctst->arch.vex.guest_ESP + 4) = (UWord)tp.arg; /* Client arg */
1046 *(UWord *)(ctst->arch.vex.guest_ESP + 0) = 0; /* fake return addr */
1048 /* Set up valgrind's trampoline on its own stack */
1049 stk = ML_(allocstack)(ctid);
1050 tp.stack_base = (void *)ctst->os_state.valgrind_stack_base;
1051 tp.stack_size = (Addr)stk - (Addr)tp.stack_base;
1052 /* This is for thr_new() to run valgrind's trampoline */
1053 tp.start_func = (void *)ML_(start_thread_NORETURN);
1054 tp.arg = &VG_(threads)[ctid];
1056 /* Create the new thread */
1057 res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp));
1059 VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
1061 if (sr_isError(res)) {
1062 /* clone failed */
1063 VG_(cleanup_thread)(&ctst->arch);
1064 ctst->status = VgTs_Empty;
1065 /* oops. Better tell the tool the thread exited in a hurry :-) */
1066 VG_TRACK( pre_thread_ll_exit, ctid );
1067 } else {
1069 POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long));
1070 POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long));
1071 POST_MEM_WRITE((Addr)ctst->arch.vex.guest_ESP, 8);
1073 /* Thread creation was successful; let the child have the chance
1074 to run */
1075 *flags |= SfYieldAfter;
1078 /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */
1079 SET_STATUS_from_SysRes(res);
1082 // SYS_pread 475
1083 // ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
1084 PRE(sys_pread)
1086 *flags |= SfMayBlock;
1087 PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4, ARG5);
1088 PRE_REG_READ5(ssize_t, "pread",
1089 unsigned int, fd, char *, buf, vki_size_t, count,
1090 unsigned int, off_low, unsigned int, off_high);
1092 if (!ML_(fd_allowed)(ARG1, "pread", tid, False))
1093 SET_STATUS_Failure( VKI_EBADF );
1094 else
1095 PRE_MEM_WRITE( "pread(buf)", ARG2, ARG3 );
1098 POST(sys_pread)
1100 vg_assert(SUCCESS);
1101 POST_MEM_WRITE( ARG2, RES );
1104 // SYS_pwrite 476
1105 // ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
1106 PRE(sys_pwrite)
1108 Bool ok;
1109 *flags |= SfMayBlock;
1110 PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %llu )", ARG1, ARG2, ARG3, MERGE64(ARG4, ARG5));
1111 PRE_REG_READ5(ssize_t, "pwrite",
1112 unsigned int, fd, const char *, buf, vki_size_t, count,
1113 vki_uint32_t, MERGE64_FIRST(offset),
1114 vki_uint32_t, MERGE64_SECOND(offset));
1115 /* check to see if it is allowed. If not, try for an exemption from
1116 --sim-hints=enable-outer (used for self hosting). */
1117 ok = ML_(fd_allowed)(ARG1, "pwrite", tid, False);
1118 if (!ok && ARG1 == 2/*stderr*/
1119 && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints)))
1120 ok = True;
1121 if (!ok)
1122 SET_STATUS_Failure( VKI_EBADF );
1123 else
1124 PRE_MEM_READ( "pwrite(buf)", ARG2, ARG3 );
1127 // SYS_mmap 477
1128 // void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
1129 PRE(sys_mmap)
1131 SysRes r;
1133 PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu )",
1134 ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6, ARG7) );
1135 PRE_REG_READ7(void *, "mmap",
1136 void *, addr, size_t, len, int, prot, int, flags, int, fd,
1137 vki_uint32_t, MERGE64_FIRST(offset),
1138 vki_uint32_t, MERGE64_SECOND(offset));
1140 r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6,ARG7) );
1141 SET_STATUS_from_SysRes(r);
1144 // SYS_lseek 478
1145 // off_t lseek(int fildes, off_t offset, int whence);
1146 PRE(sys_lseek)
1148 PRINT("sys_lseek ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "d )", SARG1,MERGE64(ARG2,ARG3),SARG4);
1149 PRE_REG_READ4(long, "lseek",
1150 unsigned int, fd,
1151 vki_uint32_t, MERGE64_FIRST(offset),
1152 vki_uint32_t, MERGE64_SECOND(offset),
1153 unsigned int, whence);
1156 // SYS_truncate 479
1157 // int truncate(const char *path, off_t length);
1158 PRE(sys_truncate)
1160 *flags |= SfMayBlock;
1161 PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %llu )", ARG1,(char *)ARG1,MERGE64(ARG2,ARG3));
1162 PRE_REG_READ3(long, "truncate",
1163 const char *, path,
1164 vki_uint32_t, MERGE64_FIRST(length),
1165 vki_uint32_t, MERGE64_SECOND(length));
1166 PRE_MEM_RASCIIZ( "truncate(path)", ARG1 );
1169 // SYS_ftruncate 480
1170 // int ftruncate(int fd, off_t length);
1171 PRE(sys_ftruncate)
1173 *flags |= SfMayBlock;
1174 PRINT("sys_ftruncate ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", SARG1,ARG2,ARG3);
1175 PRE_REG_READ3(int, "ftruncate", int, fd,
1176 vki_uint32_t, MERGE64_FIRST(length),
1177 vki_uint32_t, MERGE64_SECOND(length));
1180 // SYS_cpuset_setid 485
1181 // int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid);
1182 PRE(sys_cpuset_setid)
1184 PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )",
1185 SARG1, MERGE64(ARG2,ARG3), ARG4);
1186 PRE_REG_READ4(int, "cpuset_setid", vki_cpuwhich_t, which,
1187 vki_uint32_t, MERGE64_FIRST(id),
1188 vki_uint32_t, MERGE64_SECOND(id),
1189 vki_cpusetid_t,setid);
1192 // SYS_cpuset_getid 486
1193 // int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id,
1194 // cpusetid_t *setid);
1195 PRE(sys_cpuset_getid)
1197 PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )",
1198 SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5);
1199 PRE_REG_READ5(int, "cpuset_getid", vki_cpulevel_t, level,
1200 vki_cpuwhich_t, which,
1201 vki_uint32_t, MERGE64_FIRST(id),
1202 vki_uint32_t, MERGE64_SECOND(id),
1203 vki_cpusetid_t *,setid);
1204 PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t));
1207 POST(sys_cpuset_getid)
1209 POST_MEM_WRITE(ARG5, sizeof(vki_cpusetid_t));
1212 // SYS_cpuset_getaffinity 487
1213 // int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
1214 // size_t setsize, cpuset_t *mask);
1215 PRE(sys_cpuset_getaffinity)
1217 PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %lld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
1218 ARG1, ARG2, (vki_id_t)MERGE64(ARG3, ARG4), ARG5, ARG6);
1219 PRE_REG_READ6(int, "cpuset_getaffinity",
1220 vki_cpulevel_t, level, vki_cpuwhich_t, which,
1221 vki_uint32_t, MERGE64_FIRST(id),
1222 vki_uint32_t, MERGE64_SECOND(id),
1223 size_t, setsize, void *, mask);
1224 PRE_MEM_WRITE("cpuset_getaffinity", ARG6, ARG5);
1227 POST(sys_cpuset_getaffinity)
1229 vg_assert(SUCCESS);
1230 if (RES == 0)
1231 POST_MEM_WRITE( ARG6, ARG5 );
1234 // SYS_cpuset_setaffinity 488
1235 // int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
1236 // size_t setsize, const cpuset_t *mask);
1237 PRE(sys_cpuset_setaffinity)
1240 PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
1241 ARG1, ARG2, MERGE64(ARG3, ARG4), ARG5, ARG6);
1242 PRE_REG_READ6(int, "cpuset_setaffinity",
1243 vki_cpulevel_t, level, vki_cpuwhich_t, which,
1244 vki_uint32_t, MERGE64_FIRST(id),
1245 vki_uint32_t, MERGE64_SECOND(id),
1246 size_t, setsize, void *, mask);
1247 PRE_MEM_READ("cpuset_setaffinity", ARG6, ARG5);
1250 // SYS_posix_fallocate 530
1251 // int posix_fallocate(int fd, off_t offset, off_t len);
1252 PRE(sys_posix_fallocate)
1254 PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %llu, %llu )",
1255 SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4, ARG5));
1256 PRE_REG_READ5(long, "posix_fallocate",
1257 int, fd, vki_uint32_t, MERGE64_FIRST(offset),
1258 vki_uint32_t, MERGE64_SECOND(offset),
1259 vki_uint32_t, MERGE64_FIRST(len),
1260 vki_uint32_t, MERGE64_SECOND(len));
1263 // SYS_posix_fadvise 531
1264 // int posix_fadvise(int fd, off_t offset, off_t len, int advice);
1265 PRE(sys_posix_fadvise)
1267 PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %llu, %llu, %" FMT_REGWORD "d )",
1268 SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4,ARG5), SARG6);
1269 PRE_REG_READ6(long, "posix_fadvise",
1270 int, fd, vki_uint32_t, MERGE64_FIRST(offset),
1271 vki_uint32_t, MERGE64_SECOND(offset),
1272 vki_uint32_t, MERGE64_FIRST(len),
1273 vki_uint32_t, MERGE64_SECOND(len),
1274 int, advice);
1277 // SYS_wait6 532
1278 // pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
1279 // struct __wrusage *wrusage, siginfo_t *infop);
1280 PRE(sys_wait6)
1282 PRINT("sys_wait6 ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
1283 SARG1, MERGE64(ARG2, ARG3), ARG4, SARG5, ARG6, ARG7);
1284 PRE_REG_READ7(pid_t, "wait6", vki_idtype_t, idtype,
1285 vki_uint32_t, MERGE64_FIRST(id),
1286 vki_uint32_t, MERGE64_SECOND(id),
1287 int *, status, int, options,
1288 struct vki___wrusage *, wrusage, vki_siginfo_t *,infop);
1289 PRE_MEM_WRITE("wait6(status)", ARG4, sizeof(int));
1290 if (ARG6) {
1291 PRE_MEM_WRITE("wait6(wrusage)", ARG6, sizeof(struct vki___wrusage));
1293 if (ARG7) {
1294 PRE_MEM_WRITE("wait6(infop)", ARG7, sizeof(vki_siginfo_t));
1298 POST(sys_wait6)
1300 POST_MEM_WRITE(ARG4, sizeof(int));
1301 if (ARG6) {
1302 POST_MEM_WRITE(ARG6, sizeof(struct vki___wrusage));
1305 if (ARG7) {
1306 POST_MEM_WRITE(ARG7, sizeof(vki_siginfo_t));
1310 // SYS_procctl 544
1311 // int procctl(idtype_t idtype, id_t id, int cmd, void *data);
1312 PRE(sys_procctl)
1314 PRINT("sys_procctl ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD"d, %#" FMT_REGWORD "x )",
1315 SARG1, MERGE64(ARG2, ARG3), SARG4, ARG5);
1316 PRE_REG_READ5(int, "procctl", vki_idtype_t, idtype,
1317 vki_uint32_t, MERGE64_FIRST(id),
1318 vki_uint32_t, MERGE64_SECOND(id),
1319 int, cmd, void *, data);
1320 switch (ARG4) {
1321 case VKI_PROC_ASLR_CTL:
1322 case VKI_PROC_SPROTECT:
1323 case VKI_PROC_TRACE_CTL:
1324 case VKI_PROC_TRAPCAP_CTL:
1325 case VKI_PROC_PDEATHSIG_CTL:
1326 case VKI_PROC_STACKGAP_CTL:
1327 case VKI_PROC_NO_NEW_PRIVS_CTL:
1328 case VKI_PROC_WXMAP_CTL:
1329 PRE_MEM_READ("procctl(data)", ARG5, sizeof(int));
1330 break;
1331 case VKI_PROC_REAP_STATUS:
1332 PRE_MEM_READ("procctl(data)", ARG5, sizeof(struct vki_procctl_reaper_status));
1333 break;
1334 case VKI_PROC_REAP_GETPIDS:
1335 PRE_MEM_READ("procctl(data)", ARG5, sizeof(struct vki_procctl_reaper_pids));
1336 break;
1337 case VKI_PROC_REAP_KILL:
1338 /* The first three fields are reads
1339 * int rk_sig;
1340 * u_int rk_flags;
1341 * pid_t rk_subtree;
1343 * The last two fields are writes
1344 * u_int rk_killed;
1345 * pid_t rk_fpid;
1347 * There is also a pad field
1349 PRE_MEM_READ("procctl(data)", ARG5, sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t));
1350 PRE_MEM_WRITE("procctl(data)", ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
1351 break;
1352 case VKI_PROC_ASLR_STATUS:
1353 case VKI_PROC_PDEATHSIG_STATUS:
1354 case VKI_PROC_STACKGAP_STATUS:
1355 case VKI_PROC_TRAPCAP_STATUS:
1356 case VKI_PROC_TRACE_STATUS:
1357 PRE_MEM_WRITE("procctl(data)", ARG5, sizeof(int));
1358 case VKI_PROC_REAP_ACQUIRE:
1359 case VKI_PROC_REAP_RELEASE:
1360 default:
1361 break;
1365 POST(sys_procctl)
1367 switch (ARG4) {
1368 case VKI_PROC_REAP_KILL:
1369 POST_MEM_WRITE(ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
1370 break;
1371 case VKI_PROC_ASLR_STATUS:
1372 case VKI_PROC_PDEATHSIG_STATUS:
1373 case VKI_PROC_STACKGAP_STATUS:
1374 case VKI_PROC_TRAPCAP_STATUS:
1375 case VKI_PROC_TRACE_STATUS:
1376 case VKI_PROC_NO_NEW_PRIVS_STATUS:
1377 case VKI_PROC_WXMAP_STATUS:
1378 POST_MEM_WRITE(ARG5, sizeof(int));
1379 default:
1380 break;
1384 // SYS_mknodat 559
1385 // int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
1386 PRE(sys_mknodat)
1388 PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 );
1389 PRE_REG_READ5(long, "mknodat",
1390 int, fd, const char *, path, vki_mode_t, mode, vki_uint32_t, MERGE64_FIRST(dev), vki_uint32_t, MERGE64_SECOND(idev))
1391 PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 );
1394 // SYS_cpuset_getdomain 561
1395 // int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
1396 // size_t setsize, domainset_t *mask, int *policy);
1397 PRE(sys_cpuset_getdomain)
1399 PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
1400 SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, ARG7);
1401 PRE_REG_READ7(int, "cpuset_getdomain",
1402 cpulevel_t, level, cpuwhich_t, which,
1403 vki_uint32_t, MERGE64_FIRST(id),
1404 vki_uint32_t, MERGE64_SECOND(id),
1405 size_t, setsize, vki_domainset_t *, mask, int *, policy);
1406 // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
1407 PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG6, ARG5 );
1408 PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG7, sizeof(int) );
1411 POST(sys_cpuset_getdomain)
1413 POST_MEM_WRITE(ARG5, ARG4 );
1414 POST_MEM_WRITE(ARG6, sizeof(int) );
1417 // SYS_cpuset_setdomain 562
1418 // int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
1419 // size_t setsize, const domainset_t *mask, int policy);
1420 PRE(sys_cpuset_setdomain)
1422 PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
1423 SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, SARG7);
1424 PRE_REG_READ7(int, "cpuset_getdomain",
1425 cpulevel_t, level, cpuwhich_t, which,
1426 vki_uint32_t, MERGE64_FIRST(id),
1427 vki_uint32_t, MERGE64_SECOND(id),
1428 size_t, setsize, vki_domainset_t *, mask, int, policy);
1429 // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
1430 PRE_MEM_READ( "cpuset_getdomain(mask)", ARG6, ARG5 );
1433 PRE(sys_fake_sigreturn)
1435 /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
1436 an explanation of what follows. */
1438 ThreadState* tst;
1439 struct vki_ucontext *uc;
1440 PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
1441 PRE_REG_READ1(long, "sigreturn",
1442 struct vki_ucontext *, scp);
1444 PRE_MEM_READ( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
1445 PRE_MEM_WRITE( "sigreturn(scp)", ARG1, sizeof(struct vki_ucontext) );
1447 vg_assert(VG_(is_valid_tid)(tid));
1448 vg_assert(tid >= 1 && tid < VG_N_THREADS);
1449 vg_assert(VG_(is_running_thread)(tid));
1451 /* Adjust esp to point to start of frame; skip back up over handler
1452 ret addr */
1453 tst = VG_(get_ThreadState)(tid);
1454 tst->arch.vex.guest_ESP -= sizeof(Addr); /* QQQ should be redundant */
1456 uc = (struct vki_ucontext *)ARG1;
1457 if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) {
1458 SET_STATUS_Failure(VKI_EINVAL);
1459 return;
1462 /* This is only so that the EIP is (might be) useful to report if
1463 something goes wrong in the sigreturn */
1464 ML_(fixup_guest_state_to_restart_syscall)(&tst->arch);
1466 /* Restore register state from frame and remove it */
1467 VG_(sigframe_destroy)(tid);
1469 /* For unclear reasons, it appears we need the syscall to return
1470 without changing %EAX. Since %EAX is the return value, and can
1471 denote either success or failure, we must set up so that the
1472 driver logic copies it back unchanged. Also, note %EAX is of
1473 the guest registers written by VG_(sigframe_destroy). */
1474 int eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
1475 SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_freebsd)( tst->arch.vex.guest_EAX,
1476 tst->arch.vex.guest_EDX, (eflags & 1) != 0 ? True : False) );
1479 * Signal handler might have changed the signal mask. Respect that.
1481 tst->sig_mask = uc->uc_sigmask;
1482 tst->tmp_sig_mask = uc->uc_sigmask;
1484 /* Tell the driver not to update the guest state with the "result",
1485 and set a bogus result to keep it happy. */
1486 *flags |= SfNoWriteResult;
1487 SET_STATUS_Success(0);
1489 /* Check to see if any signals arose as a result of this. */
1490 *flags |= SfPollAfter;
1493 #undef PRE
1494 #undef POST
1497 #endif /* defined(VGP_x86_freebsd) */
1500 /*--------------------------------------------------------------------*/
1501 /*--- end ---*/
1502 /*--------------------------------------------------------------------*/