|
From: Steve V.
|
First try was missing user visible define for CLONE_CHILD_LETGO.
This patch implements a valgrind specific clone flag (VKI_CLONE_CHILD_LETGO),
which instructs valgrind to run the child nativley. It is only implemented
for fork like clones and on x86 (currently).
Index: valgrind/coregrind/m_syswrap/syswrap-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-linux.c 2008-08-29 15:39:51.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-linux.c 2008-08-29 15:39:59.000000000 -0700
@@ -339,6 +339,14 @@
VG_(do_atfork_child)(tid);
+ if (flags & VKI_CLONE_CHILD_LETGO) {
+#if defined(VGP_x86_linux)
+ letgo_vex_x86_linux(&ctst->arch.vex, tid);
+ /* NORETURN */
+#else
+ VG_(message)(Vg_UserMsg, "CLONE_CHILD_LETGO is not yet implmented on this platform; ignoring.");
+#endif
+ }
/* restore signal mask */
VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
Index: valgrind/coregrind/m_syswrap/syswrap-x86-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-29 15:39:51.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-29 15:39:59.000000000 -0700
@@ -190,6 +190,83 @@
// forward declarations
static void setup_child ( ThreadArchState*, ThreadArchState*, Bool );
static SysRes sys_set_thread_area ( ThreadId, vki_modify_ldt_t* );
+static SysRes propagate_thread_area(ThreadId tid, VexGuestArchState *vex);
+SysRes letgo_vex_x86_linux(VexGuestArchState *vex, ThreadId tid);
+
+static SysRes propagate_thread_area(ThreadId tid, VexGuestArchState *vex)
+{
+ VexGuestX86SegDescr * sdp;
+ vki_modify_ldt_t ud;
+ SysRes res;
+
+ if (! vex->guest_GS)
+ return VG_(mk_SysRes_Success)( 0 );
+
+ VG_(memset)(&ud, 0, sizeof(ud));
+ sdp = (vex->guest_GS >> 3) + ((VexGuestX86SegDescr*)vex->guest_GDT);
+
+ ud.entry_number = -1;
+ ud.base_addr = sdp->LdtEnt.Bits.BaseLow | (sdp->LdtEnt.Bits.BaseMid << 16)
+ | (sdp->LdtEnt.Bits.BaseHi << 24);
+ ud.limit = sdp->LdtEnt.Bits.LimitLow | (sdp->LdtEnt.Bits.LimitHi << 16);
+ ud.seg_32bit = sdp->LdtEnt.Bits.Default_Big;
+ ud.contents = sdp->LdtEnt.Bits.Type >> 2;
+ ud.read_exec_only = 1 ^ (1 & (sdp->LdtEnt.Bits.Type >> 1));
+ ud.limit_in_pages = sdp->LdtEnt.Bits.Granularity;
+ ud.seg_not_present = 0;
+ ud.useable = 1;
+
+ res = VG_(do_syscall1)( __NR_set_thread_area, (UWord)&ud);
+ if (res.isError) {
+ VG_(printf)("propagate_thread_area set_thread_area failed\n");
+ } else {
+ vex->guest_GS = 3 | (ud.entry_number << 3);
+ }
+ return res;
+}
+
+SysRes letgo_vex_x86_linux(VexGuestArchState *vex, ThreadId tid)
+{
+ vki_sigset_t clear;
+ unsigned long * vex_stack;
+ unsigned short es;
+ SysRes res;
+
+ res = propagate_thread_area(tid, vex);
+ if (res.isError)
+ return res;
+
+ /* Put EIP and a PUSHAD frame on the vex stack */
+ vex->guest_ESP -= sizeof(unsigned long *);
+ vex_stack = ((unsigned long *) vex->guest_ESP) - 8;
+ vex_stack[8] = vex->guest_EIP;
+ vex_stack[7] = 0; /* return value of clone*/
+ vex_stack[6] = vex->guest_ECX;
+ vex_stack[5] = vex->guest_EDX;
+ vex_stack[4] = vex->guest_EBX;
+ vex_stack[3] = vex->guest_ESP;
+ vex_stack[2] = vex->guest_EBP;
+ vex_stack[1] = vex->guest_ESI;
+ vex_stack[0] = vex->guest_EDI;
+
+ es = vex->guest_ES;
+ if (es == 0)
+ asm("mov %%ds, %0\n" : "=r"(es));
+
+ VG_(sigemptyset)(&clear);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &clear, NULL);
+
+ /* Set the segment regs, change to the vex stack, restore regs and return */
+ asm("mov %0, %%es\n"
+ "mov %1, %%fs\n"
+ "mov %2, %%gs\n"
+ "movl %3, %%esp\n"
+ "popa\n"
+ "ret\n"
+ :: "r"(es), "r"(vex->guest_FS), "r"(vex->guest_GS), "r"(vex_stack) );
+
+ return VG_(mk_SysRes_Error)(-1); /* Make gcc happy */
+}
/*
When a client clones, we need to keep track of the new thread. This means:
@@ -901,6 +978,11 @@
goto reject;
}
+ /* Can't let a child run wild in a shared address space */
+ if ((cloneflags & (VKI_CLONE_VM | VKI_CLONE_VFORK | VKI_CLONE_CHILD_LETGO))
+ == (VKI_CLONE_VM | VKI_CLONE_CHILD_LETGO))
+ goto reject;
+
/* Only look at the flags we really care about */
switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
| VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
Index: valgrind/include/vki/vki-linux.h
===================================================================
--- valgrind.orig/include/vki/vki-linux.h 2008-08-29 15:39:51.000000000 -0700
+++ valgrind/include/vki/vki-linux.h 2008-08-29 15:39:59.000000000 -0700
@@ -322,6 +322,7 @@
#define VKI_CLONE_CHILD_CLEARTID 0x00200000 /* clear the TID in the child */
#define VKI_CLONE_DETACHED 0x00400000 /* Unused, ignored */
#define VKI_CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */
+#define VKI_CLONE_CHILD_LETGO 0x80000000 /* do not track fork like children*/
struct vki_sched_param {
int sched_priority;
Index: valgrind/memcheck/tests/x86/clone-fork-child-letgo.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/memcheck/tests/x86/clone-fork-child-letgo.c 2008-08-29 15:39:59.000000000 -0700
@@ -0,0 +1,62 @@
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int fn_child(void *argp)
+{
+ int *const p = (int *)argp;
+ printf("child stack=%p\n", &argp);
+ fflush(stdout);
+ if (p[1]) {
+ return p[0];
+ }
+ else {
+ return p[1];
+ }
+}
+
+typedef void (*sighandler_t)(int);
+
+void handler(int signo)
+{
+ printf("handler signo=%d\n", signo);
+}
+
+int my_clone(int (*fn)(void *), void *stack, unsigned xflags, void *arg)
+{
+/* The flags lack CLONE_VM, so the clone() is like a fork().
+ * A new process gets created, not a new thread.
+ */
+ int pid = clone(fn, stack,
+ xflags | SIGCHLD, arg, 0,0,0);
+ if (pid < 0)
+ perror("clone failed");
+ //waitpid(pid, &status, 0);
+ //printf("status= %x\n", status);
+ return 0;
+}
+
+#define L_STACKS (1024*1024)
+
+#define CLONE_CHILD_LETGO 0x80000000
+
+int main(int argc, char *argv[])
+{
+ int x[2];
+/* Space for two stacks. */
+ void *const stack = mmap((void *)0x300000, L_STACKS, PROT_READ|PROT_WRITE,
+ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+
+ x[0]= 12345; /* x[1] undefined */
+ signal(SIGCHLD, handler);
+
+/* Stack uses second half of mmap()ed space. */
+ my_clone(fn_child, L_STACKS + stack, 0, x);
+
+/* Stack uses first half of mmap()ed space. */
+ my_clone(fn_child, (L_STACKS>>1) + stack, CLONE_CHILD_LETGO, x);
+ return 0;
+}
Index: valgrind/memcheck/tests/x86/clone-fork-child-letgo.stderr.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/memcheck/tests/x86/clone-fork-child-letgo.stderr.exp 2008-08-29 15:39:59.000000000 -0700
@@ -0,0 +1,9 @@
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: fn_child (clone-fork-child-letgo.c:13)
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+malloc/free: in use at exit: 0 bytes in 0 blocks.
+malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
+For a detailed leak analysis, rerun with: --leak-check=yes
+For counts of detected errors, rerun with: -v
Index: valgrind/memcheck/tests/x86/clone-fork-child-letgo.stdout.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/memcheck/tests/x86/clone-fork-child-letgo.stdout.exp 2008-08-29 15:39:59.000000000 -0700
@@ -0,0 +1,2 @@
+child stack=0x37fff0
+child stack=0x3ffff0
Index: valgrind/memcheck/tests/x86/clone-fork-child-letgo.vgtest
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/memcheck/tests/x86/clone-fork-child-letgo.vgtest 2008-08-29 15:39:59.000000000 -0700
@@ -0,0 +1 @@
+prog: clone-fork-child-letgo
Index: valgrind/memcheck/tests/x86/Makefile.am
===================================================================
--- valgrind.orig/memcheck/tests/x86/Makefile.am 2008-08-29 15:39:51.000000000 -0700
+++ valgrind/memcheck/tests/x86/Makefile.am 2008-08-29 15:39:59.000000000 -0700
@@ -7,6 +7,7 @@
EXTRA_DIST = $(noinst_SCRIPTS) \
bug133694.vgtest bug133694.stderr.exp bug133694.stdout.exp \
bug152022.vgtest bug152022.stderr.exp bug152022.stdout.exp \
+ clone-fork-child-letgo.vgtest clone-fork-child-letgo.stderr.exp clone-fork-child-letgo.stdout.exp \
espindola2.vgtest espindola2.stderr.exp \
fpeflags.stderr.exp fpeflags.vgtest \
fxsave.vgtest fxsave.stdout.exp fxsave.stderr.exp \
@@ -35,6 +36,7 @@
check_PROGRAMS = \
bug133694 \
bug152022 \
+ clone-fork-child-letgo \
espindola2 \
fxsave \
int3-x86 \
Index: valgrind/coregrind/m_syswrap/priv_syswrap-linux.h
===================================================================
--- valgrind.orig/coregrind/m_syswrap/priv_syswrap-linux.h 2008-08-29 15:39:51.000000000 -0700
+++ valgrind/coregrind/m_syswrap/priv_syswrap-linux.h 2008-08-29 15:39:59.000000000 -0700
@@ -40,6 +40,10 @@
void (*f)(Word), Word arg1 );
extern SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags, Addr child_esp,
Int* parent_tidptr, Int* child_tidptr );
+#if defined(VGP_x86_linux)
+extern SysRes letgo_vex_x86_linux(VexGuestArchState *vex, ThreadId tid);
+#endif
+
// Linux-specific (but non-arch-specific) syscalls
Index: valgrind/include/valgrind.h
===================================================================
--- valgrind.orig/include/valgrind.h 2008-08-29 15:39:51.000000000 -0700
+++ valgrind/include/valgrind.h 2008-08-29 15:40:20.000000000 -0700
@@ -3913,6 +3913,16 @@
id, start, end, 0, 0); \
}
+#if defined(NVALGRIND)
+
+#define VALGRIND_CLONE_LETGO 0
+
+#else /* ! NVALGRIND */
+
+#define VALGRIND_CLONE_LETGO 0x80000000 /* do not track fork like children*/
+
+#endif /* NVALGRIND */
+
#undef PLAT_x86_linux
#undef PLAT_amd64_linux
|