PERFORCE change 153061 for review
Peter Wemm
peter at FreeBSD.org
Sun Nov 16 16:29:30 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=153061
Change 153061 by peter at peter_overcee on 2008/11/17 00:29:25
Add rfork() stubs. On i386, assume ports/devel/linuxthreads. On amd64, fail.
We need to be able to predict the stack location in the new child, and the
rfork() syscall has nothing to do with that. The only consumer that I know of
that uses this is linuxthreads (which is i386-only in ports), and we have to sniff
the undocumented register contents before it calls rfork() in clone.S.
It is stubbed out right now anyway.
Affected files ...
.. //depot/projects/valgrind/coregrind/m_syswrap/syswrap-amd64-freebsd.c#9 edit
.. //depot/projects/valgrind/coregrind/m_syswrap/syswrap-freebsd.c#32 edit
.. //depot/projects/valgrind/coregrind/m_syswrap/syswrap-x86-freebsd.c#15 edit
Differences ...
==== //depot/projects/valgrind/coregrind/m_syswrap/syswrap-amd64-freebsd.c#9 (text+ko) ====
@@ -258,6 +258,17 @@
SET_STATUS_from_SysRes(res);
}
+PRE(sys_rfork)
+{
+ PRINT("sys_rfork ( %#lx )", ARG1 );
+ PRE_REG_READ1(long, "rfork", int, flags);
+
+ VG_(message)(Vg_UserMsg, "rfork() not implemented");
+ VG_(unimplemented)("Valgrind does not support rfork().");
+
+ SET_STATUS_Failure(VKI_ENOSYS);
+}
+
PRE(sys_sigreturn)
{
ThreadState* tst;
==== //depot/projects/valgrind/coregrind/m_syswrap/syswrap-freebsd.c#32 (text+ko) ====
@@ -3371,7 +3371,7 @@
// BSDXY(__NR_ntp_gettime, sys_ntp_gettime), // 248
// nosys 249
// BSDXY(__NR_minherit, sys_minherit), // 250
-// BSDX_(__NR_rfork, sys_rfork), // 251
+ BSDX_(__NR_rfork, sys_rfork), // 251
GENXY(__NR_openbsd_poll, sys_poll), // 252
BSDX_(__NR_issetugid, sys_issetugid), // 253
==== //depot/projects/valgrind/coregrind/m_syswrap/syswrap-x86-freebsd.c#15 (text+ko) ====
@@ -98,6 +98,219 @@
);
+#if 0
+/*
+ Perform a rfork system call. rfork is strange because it has
+ fork()-like return-twice semantics, so it needs special
+ handling here.
+
+ Upon entry, we have:
+
+ int (fn)(void*) in 0+FSZ(%esp)
+ void* child_stack in 4+FSZ(%esp)
+ int flags in 8+FSZ(%esp)
+ void* arg in 12+FSZ(%esp)
+ pid_t* child_tid in 16+FSZ(%esp)
+ pid_t* parent_tid in 20+FSZ(%esp)
+ void* tls_ptr in 24+FSZ(%esp)
+
+ System call requires:
+
+ int $__NR_clone in %eax
+ int flags in %ebx
+ void* child_stack in %ecx
+ pid_t* parent_tid in %edx
+ pid_t* child_tid in %edi
+ void* tls_ptr in %esi
+
+ Returns an Int encoded in the linux-x86 way, not a SysRes.
+ */
+#define FSZ "4+4+4+4" /* frame size = retaddr+ebx+edi+esi */
+#define __NR_CLONE VG_STRINGIFY(__NR_clone)
+#define __NR_EXIT VG_STRINGIFY(__NR_exit)
+
+extern
+Int do_syscall_clone_x86_freebsd ( Word (*fn)(void *),
+ void* stack,
+ Int flags,
+ void* arg,
+ Int* child_tid,
+ Int* parent_tid,
+ vki_modify_ldt_t * );
+asm(
+".text\n"
+"do_syscall_clone_x86_freebsd:\n"
+" push %ebx\n"
+" push %edi\n"
+" push %esi\n"
+
+ /* set up child stack with function and arg */
+" movl 4+"FSZ"(%esp), %ecx\n" /* syscall arg2: child stack */
+" movl 12+"FSZ"(%esp), %ebx\n" /* fn arg */
+" movl 0+"FSZ"(%esp), %eax\n" /* fn */
+" lea -8(%ecx), %ecx\n" /* make space on stack */
+" movl %ebx, 4(%ecx)\n" /* fn arg */
+" movl %eax, 0(%ecx)\n" /* fn */
+
+ /* get other args to clone */
+" movl 8+"FSZ"(%esp), %ebx\n" /* syscall arg1: flags */
+" movl 20+"FSZ"(%esp), %edx\n" /* syscall arg3: parent tid * */
+" movl 16+"FSZ"(%esp), %edi\n" /* syscall arg5: child tid * */
+" movl 24+"FSZ"(%esp), %esi\n" /* syscall arg4: tls_ptr * */
+" movl $"__NR_CLONE", %eax\n"
+" int $0x80\n" /* clone() */
+" testl %eax, %eax\n" /* child if retval == 0 */
+" jnz 1f\n"
+
+ /* CHILD - call thread function */
+" popl %eax\n"
+" call *%eax\n" /* call fn */
+
+ /* exit with result */
+" movl %eax, %ebx\n" /* arg1: return value from fn */
+" movl $"__NR_EXIT", %eax\n"
+" int $0x80\n"
+
+ /* Hm, exit returned */
+" ud2\n"
+
+"1:\n" /* PARENT or ERROR */
+" pop %esi\n"
+" pop %edi\n"
+" pop %ebx\n"
+" ret\n"
+".previous\n"
+);
+
+#undef FSZ
+#undef __NR_CLONE
+#undef __NR_EXIT
+
+
+// forward declarations
+static void setup_child ( ThreadArchState*, ThreadArchState*, Bool );
+
+/*
+ When a client clones, we need to keep track of the new thread. This means:
+ 1. allocate a ThreadId+ThreadState+stack for the the thread
+
+ 2. initialize the thread's new VCPU state
+
+ 3. create the thread using the same args as the client requested,
+ but using the scheduler entrypoint for EIP, and a separate stack
+ for ESP.
+ */
+static SysRes do_rfork ( ThreadId ptid,
+ UInt flags)
+{
+ static const Bool debug = False;
+
+ Addr esp;
+ ThreadId ctid = VG_(alloc_ThreadState)();
+ ThreadState* ptst = VG_(get_ThreadState)(ptid);
+ ThreadState* ctst = VG_(get_ThreadState)(ctid);
+ UWord* stack;
+ NSegment const* seg;
+ SysRes res;
+ Int eax;
+ vki_sigset_t blockall, savedmask;
+
+ VG_(sigfillset)(&blockall);
+
+ vg_assert(VG_(is_running_thread)(ptid));
+ vg_assert(VG_(is_valid_tid)(ctid));
+
+ stack = (UWord*)ML_(allocstack)(ctid);
+ if (stack == NULL) {
+ res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
+ goto out;
+ }
+
+ /* Copy register state
+
+ Both parent and child return to the same place, and the code
+ following the clone syscall works out which is which, so we
+ don't need to worry about it.
+
+ The parent gets the child's new tid returned from clone, but the
+ child gets 0.
+
+ If the clone call specifies a NULL esp for the new thread, then
+ it actually gets a copy of the parent's esp.
+ */
+ /* Note: the clone call done by the Quadrics Elan3 driver specifies
+ clone flags of 0xF00, and it seems to rely on the assumption
+ that the child inherits a copy of the parent's GDT.
+ setup_child takes care of setting that up. */
+ setup_child( &ctst->arch, &ptst->arch, True );
+
+ /* Make sys_clone appear to have returned Success(0) in the
+ child. */
+ ctst->arch.vex.guest_EAX = 0;
+
+ /* Assume linuxthreads port storing its intended stack in %esi */
+ esp = ctst->arch.vex.guest_ESI;
+
+ ctst->os_state.parent = ptid;
+
+ /* inherit signal mask */
+ ctst->sig_mask = ptst->sig_mask;
+ ctst->tmp_sig_mask = ptst->sig_mask;
+
+ /* We don't really know where the client stack is, because its
+ allocated by the client. The best we can do is look at the
+ memory mappings and try to derive some useful information. We
+ assume that esp starts near its highest possible value, and can
+ only go down to the start of the mmaped segment. */
+ seg = VG_(am_find_nsegment)((Addr)esp);
+ if (seg && seg->kind != SkResvn) {
+ ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(esp);
+ ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;
+
+ VG_(register_stack)(seg->start, ctst->client_stack_highest_word);
+
+ if (debug)
+ VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
+ ctid, seg->start, VG_PGROUNDUP(esp));
+ } else {
+ VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%#lx) unmapped\n",
+ ctid, esp);
+ ctst->client_stack_szB = 0;
+ }
+
+ /* Assume the clone will succeed, and tell any tool that wants to
+ know that this thread has come into existence. We cannot defer
+ it beyond this point because sys_set_thread_area, just below,
+ causes tCheck to assert by making references to the new ThreadId
+ if we don't state the new thread exists prior to that point.
+ If the clone fails, we'll send out a ll_exit notification for it
+ at the out: label below, to clean up. */
+ VG_TRACK ( pre_thread_ll_create, ptid, ctid );
+
+ /* start the thread with everything blocked */
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
+
+ /* Create the new thread */
+ /* XXX need to see what happens with tids etc with rfork */
+ eax = do_syscall_clone_x86_freebsd(
+ ML_(start_thread_NORETURN), stack, flags /*, &VG_(threads)[ctid], NULL*/ );
+ res = VG_(mk_SysRes_x86_freebsd)( eax ); /* XXX edx returns too! */
+
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
+
+ out:
+ if (res.isError) {
+ /* clone failed */
+ VG_(cleanup_thread)(&ctst->arch);
+ ctst->status = VgTs_Empty;
+ /* oops. Better tell the tool the thread exited in a hurry :-) */
+ VG_TRACK( pre_thread_ll_exit, ctid );
+ }
+
+ return res;
+}
+#endif
+
/* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr */
static
@@ -249,6 +462,40 @@
}
+#if 0
+static void setup_child ( /*OUT*/ ThreadArchState *child,
+ /*IN*/ ThreadArchState *parent,
+ Bool inherit_parents_GDT )
+{
+ /* We inherit our parent's guest state. */
+ child->vex = parent->vex;
+ child->vex_shadow1 = parent->vex_shadow1;
+ child->vex_shadow2 = parent->vex_shadow2;
+
+ /* We inherit our parent's LDT. */
+ if (parent->vex.guest_LDT == (HWord)NULL) {
+ /* We hope this is the common case. */
+ child->vex.guest_LDT = (HWord)NULL;
+ } else {
+ /* No luck .. we have to take a copy of the parent's. */
+ child->vex.guest_LDT = (HWord)alloc_zeroed_x86_LDT();
+ copy_LDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_LDT,
+ (VexGuestX86SegDescr*)child->vex.guest_LDT );
+ }
+
+ /* Either we start with an empty GDT (the usual case) or inherit a
+ copy of our parents' one (Quadrics Elan3 driver -style clone
+ only). */
+ child->vex.guest_GDT = (HWord)NULL;
+
+ if (inherit_parents_GDT && parent->vex.guest_GDT != (HWord)NULL) {
+ child->vex.guest_GDT = (HWord)alloc_zeroed_x86_GDT();
+ copy_GDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_GDT,
+ (VexGuestX86SegDescr*)child->vex.guest_GDT );
+ }
+}
+#endif
+
/* ---------------------------------------------------------------------
PRE/POST wrappers for x86/Linux-specific syscalls
------------------------------------------------------------------ */
@@ -394,6 +641,34 @@
SET_STATUS_from_SysRes(res);
}
+
+PRE(sys_rfork)
+{
+ PRINT("sys_rfork ( %lx )",ARG1);
+ PRE_REG_READ1(int, "rfork",
+ unsigned int, flags);
+
+#if 0
+ cloneflags = ARG1;
+
+ if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
+ SET_STATUS_Failure( VKI_EINVAL );
+ return;
+ }
+
+ SET_STATUS_from_SysRes( do_clone(tid, ARG1));
+
+ if (SUCCESS) {
+ *flags |= SfYieldAfter;
+ }
+#else
+ VG_(message)(Vg_UserMsg, "No rfork for you!");
+ VG_(unimplemented)
+ ("Valgrind does not support rfork() yet.");
+ SET_STATUS_Failure( VKI_ENOSYS );
+#endif
+}
+
PRE(sys_sigreturn)
{
/* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
More information about the p4-projects
mailing list