|
From: Steve V.
|
The following patches enables Valgrind to produce useful results for User Mode Linux. At a high level, there are three changes: additional heuristics for dealing with stacks, a couple more combinations of clone flags, and special clone flag to disown a child ASAP. Please consider these patches for merging or send feedback about what prevents them from being merged. Thanks, Steve |
|
From: Steve V.
|
This patch allows the stack to be in a mem-mapped file.
Index: valgrind/coregrind/m_signals.c
===================================================================
--- valgrind.orig/coregrind/m_signals.c 2008-08-21 15:42:14.000000000 -0700
+++ valgrind/coregrind/m_signals.c 2008-08-21 17:44:07.000000000 -0700
@@ -1667,7 +1667,7 @@
= seg ? VG_(am_next_nsegment)( (NSegment*)seg, True/*fwds*/ )
: NULL;
- if (seg && seg->kind == SkAnonC)
+ if (seg && (seg->kind == SkAnonC || seg->kind == SkFileC))
/* addr is already mapped. Nothing to do. */
return True;
|
|
From: Steve V.
|
do_clone() uses the passed stack pointer to guess at the scope of the
new stack and registers it. Somtimes this guess is bad enough to cause
problems. This patch will first check to see if the passed stack pointer
is already part of a registered stack. If it is, use that stack and don't
register a new stack. (Bug 168538)
Index: valgrind/coregrind/m_stacks.c
===================================================================
--- valgrind.orig/coregrind/m_stacks.c 2008-08-21 15:42:21.000000000 -0700
+++ valgrind/coregrind/m_stacks.c 2008-08-21 15:44:17.000000000 -0700
@@ -171,6 +171,17 @@
}
/*
+ * Lookup the passed stack pointer and try to determine if it points to
+ * an already registered stack.
+ */
+Bool VG_(is_stack_registered)(Addr sp)
+{
+ if (find_stack_by_addr(sp) == NULL)
+ return False;
+ return True;
+}
+
+/*
* Register a new stack from start - end. This is invoked from the
* VALGRIND_STACK_REGISTER client request, and is also called just before
* we start the client running, to register the main process stack.
Index: valgrind/coregrind/m_syswrap/syswrap-x86-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-21 15:42:44.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-21 15:44:17.000000000 -0700
@@ -260,11 +260,12 @@
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. */
+ /* Unless the client stack is already registered, we don't really know
+ where it is, because it's 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. */
+ if (!VG_(is_stack_registered)((Addr)esp)) {
seg = VG_(am_find_nsegment)((Addr)esp);
if (seg && seg->kind != SkResvn) {
ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(esp);
@@ -280,6 +281,11 @@
ctid, esp);
ctst->client_stack_szB = 0;
}
+ } else {
+ if (debug)
+ VG_(printf)("tid %d: client stack already registered (%#lx)\n",
+ ctid, esp);
+ }
/* Assume the clone will succeed, and tell any tool that wants to
know that this thread has come into existence. We cannot defer
Index: valgrind/coregrind/pub_core_stacks.h
===================================================================
--- valgrind.orig/coregrind/pub_core_stacks.h 2008-08-21 15:42:21.000000000 -0700
+++ valgrind/coregrind/pub_core_stacks.h 2008-08-21 15:44:17.000000000 -0700
@@ -40,6 +40,7 @@
extern void VG_(deregister_stack) ( UWord id );
extern void VG_(change_stack) ( UWord id, Addr start, Addr end );
extern void VG_(stack_limits) ( Addr SP, Addr *start, Addr *end );
+extern Bool VG_(is_stack_registered) ( Addr SP );
extern VG_REGPARM(3)
void VG_(unknown_SP_update) ( Addr old_SP, Addr new_SP, UInt otag );
|
|
From: Steve V.
|
Valgrind currently ignores the child_sp parameter to clone when the flags
make it a fork like clone. This patch passes the child_sp down and uses
it to update the stack pointer in the new child.
Index: valgrind/coregrind/m_syswrap/priv_syswrap-linux.h
===================================================================
--- valgrind.orig/coregrind/m_syswrap/priv_syswrap-linux.h 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/coregrind/m_syswrap/priv_syswrap-linux.h 2008-08-21 16:06:25.000000000 -0700
@@ -38,7 +38,7 @@
extern Addr ML_(allocstack) ( ThreadId tid );
extern void ML_(call_on_new_stack_0_1) ( Addr stack, Addr retaddr,
void (*f)(Word), Word arg1 );
-extern SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
+extern SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags, Addr child_esp,
Int* parent_tidptr, Int* child_tidptr );
Index: valgrind/coregrind/m_syswrap/syswrap-amd64-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-amd64-linux.c 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-amd64-linux.c 2008-08-21 16:06:25.000000000 -0700
@@ -432,6 +432,7 @@
SET_STATUS_from_SysRes(
ML_(do_fork_clone)(tid,
cloneflags, /* flags */
+ (Addr)ARG2, /* child ESP */
(Int *)ARG3, /* parent_tidptr */
(Int *)ARG4)); /* child_tidptr */
break;
Index: valgrind/coregrind/m_syswrap/syswrap-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-linux.c 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-linux.c 2008-08-21 16:13:08.000000000 -0700
@@ -51,6 +51,8 @@
#include "pub_core_signals.h"
#include "pub_core_syscall.h"
#include "pub_core_syswrap.h"
+#include "pub_core_machine.h" // VG_STACK_PTR
+
#include "priv_types_n_macros.h"
#include "priv_syswrap-generic.h"
@@ -297,7 +299,7 @@
/* Do a clone which is really a fork() */
-SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
+SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags, Addr child_esp,
Int* parent_tidptr, Int* child_tidptr )
{
vki_sigset_t fork_saved_mask;
@@ -331,6 +333,10 @@
if (!res.isError && res.res == 0) {
/* child */
+ ThreadState *const ctst = VG_(get_ThreadState)(tid);
+ if (child_esp) /* Set the stack pointer */
+ ctst->arch.vex.VG_STACK_PTR = child_esp;
+
VG_(do_atfork_child)(tid);
/* restore signal mask */
Index: valgrind/coregrind/m_syswrap/syswrap-ppc32-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-ppc32-linux.c 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-ppc32-linux.c 2008-08-21 16:06:25.000000000 -0700
@@ -1005,6 +1005,7 @@
SET_STATUS_from_SysRes(
ML_(do_fork_clone)(tid,
cloneflags, /* flags */
+ (Addr)ARG2, /* child SP */
(Int *)ARG3, /* parent_tidptr */
(Int *)ARG5)); /* child_tidptr */
break;
Index: valgrind/coregrind/m_syswrap/syswrap-ppc64-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-ppc64-linux.c 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-ppc64-linux.c 2008-08-21 16:06:25.000000000 -0700
@@ -984,6 +984,7 @@
SET_STATUS_from_SysRes(
ML_(do_fork_clone)(tid,
cloneflags, /* flags */
+ (Addr)ARG2, /* child SP */
(Int *)ARG3, /* parent_tidptr */
(Int *)ARG5)); /* child_tidptr */
break;
Index: valgrind/coregrind/m_syswrap/syswrap-x86-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-21 16:06:25.000000000 -0700
@@ -923,6 +923,7 @@
SET_STATUS_from_SysRes(
ML_(do_fork_clone)(tid,
cloneflags, /* flags */
+ (Addr)ARG2, /* child ESP */
(Int *)ARG3, /* parent_tidptr */
(Int *)ARG5)); /* child_tidptr */
break;
Index: valgrind/none/tests/x86/clone-fork-child-sp.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/none/tests/x86/clone-fork-child-sp.c 2008-08-21 16:06:25.000000000 -0700
@@ -0,0 +1,37 @@
+#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 arg=%d\n", &argp, *p);
+ fflush(stdout);
+ return 0;
+}
+
+typedef void (*sighandler_t)(int);
+
+void handler(int signo)
+{
+ printf("handler signo=%d\n", signo);
+}
+
+int x = 39;
+
+int main(int argc, char *argv[])
+{
+ int status = 0;
+ sighandler_t rv = signal(SIGCHLD, handler);
+ void *stack = mmap((void *)0x300000, 4096, PROT_READ|PROT_WRITE,
+ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ int pid = clone(fn_child, 4096+ stack, 0 | SIGCHLD, &x, 0,0,0);
+ if (pid < 0)
+ perror("clone failed");
+ waitpid(pid, &status, 0);
+ printf("status= %x\n", status);
+ return 0;
+}
Index: valgrind/none/tests/x86/clone-fork-child-sp.stderr.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/none/tests/x86/clone-fork-child-sp.stderr.exp 2008-08-21 16:06:25.000000000 -0700
@@ -0,0 +1,3 @@
+
+
+
Index: valgrind/none/tests/x86/clone-fork-child-sp.stdout.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/none/tests/x86/clone-fork-child-sp.stdout.exp 2008-08-21 16:06:25.000000000 -0700
@@ -0,0 +1,3 @@
+child stack=0x300ff0 arg=39
+handler signo=17
+status= 0
Index: valgrind/none/tests/x86/clone-fork-child-sp.vgtest
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ valgrind/none/tests/x86/clone-fork-child-sp.vgtest 2008-08-21 16:06:25.000000000 -0700
@@ -0,0 +1 @@
+prog: clone-fork-child-sp
Index: valgrind/none/tests/x86/Makefile.am
===================================================================
--- valgrind.orig/none/tests/x86/Makefile.am 2008-08-21 16:05:14.000000000 -0700
+++ valgrind/none/tests/x86/Makefile.am 2008-08-21 16:06:25.000000000 -0700
@@ -47,6 +47,8 @@
movx.stderr.exp movx.stdout.exp movx.vgtest \
pushpopseg.stderr.exp pushpopseg.stdout.exp pushpopseg.vgtest \
sbbmisc.stderr.exp sbbmisc.stdout.exp sbbmisc.vgtest \
+ clone-fork-child-sp.stderr.exp clone-fork-child-sp.stdout.exp \
+ clone-fork-child-sp.vgtest \
seg_override.stderr.exp seg_override.stdout.exp seg_override.vgtest \
sigcontext.stdout.exp sigcontext.stderr.exp sigcontext.vgtest \
smc1.stderr.exp smc1.stdout.exp smc1.vgtest \
@@ -68,6 +70,7 @@
getseg incdec_alt $(INSN_TESTS) \
jcxz \
lahf looper movx int pushpopseg sbbmisc \
+ clone-fork-child-sp \
seg_override sigcontext smc1 yield
if BUILD_SSSE3_TESTS
check_PROGRAMS += ssse3_misaligned
|
|
From: Steve V.
|
This patch handles more combinations of flag arguments to clone(),
specifically more variations of VKI_CLONE_FILES and VKI_CLONE_FS are allowed.
Index: valgrind/coregrind/m_syswrap/syswrap-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-linux.c 2008-08-21 16:13:08.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-linux.c 2008-08-21 16:28:12.000000000 -0700
@@ -307,7 +307,7 @@
SysRes res;
if (flags & (VKI_CLONE_SETTLS | VKI_CLONE_FS | VKI_CLONE_VM
- | VKI_CLONE_FILES | VKI_CLONE_VFORK))
+ | VKI_CLONE_VFORK))
return VG_(mk_SysRes_Error)( VKI_EINVAL );
/* Block all signals during fork, so that we can fix things up in
Index: valgrind/coregrind/m_syswrap/syswrap-x86-linux.c
===================================================================
--- valgrind.orig/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-21 16:06:25.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-21 16:32:26.000000000 -0700
@@ -905,6 +905,7 @@
switch (cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS
| VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
+ case VKI_CLONE_VM | VKI_CLONE_FILES:
/* thread creation */
SET_STATUS_from_SysRes(
do_clone(tid,
@@ -915,6 +916,7 @@
(vki_modify_ldt_t *)ARG4)); /* set_tls */
break;
+ case VKI_CLONE_FILES: /* fork with shared fd's */
case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
/* FALLTHROUGH - assume vfork == fork */
cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
|
|
From: Steve V.
|
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-22 10:06:17.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-linux.c 2008-08-22 10:17:23.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-22 10:06:17.000000000 -0700
+++ valgrind/coregrind/m_syswrap/syswrap-x86-linux.c 2008-08-22 10:50:25.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-22 10:04:48.000000000 -0700
+++ valgrind/include/vki/vki-linux.h 2008-08-22 10:06:30.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-22 10:06:30.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-22 10:06:30.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-22 10:06:30.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-22 10:06:30.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-22 10:04:48.000000000 -0700
+++ valgrind/memcheck/tests/x86/Makefile.am 2008-08-22 10:06:30.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-22 10:06:03.000000000 -0700
+++ valgrind/coregrind/m_syswrap/priv_syswrap-linux.h 2008-08-22 10:34:21.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
|
|
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
|