|
From: Jeremy F. <je...@go...> - 2005-01-16 17:11:17
|
CVS commit by fitzhardinge:
Allocate the same-sized (internal, Valgrind) stack for the initial thread
as all the other threads, rather than using the growable stack the kernel
gave us. This change does not affect the behaviour of the client stack
at all.
M +10 -2 core.h 1.65
M +2 -2 stage1.c 1.32
M +1 -1 ume.h 1.17
M +18 -1 vg_main.c 1.237
M +0 -13 vg_scheduler.c 1.211
M +0 -10 linux/core_os.c 1.6
M +1 -0 x86/Makefile.am 1.21
M +3 -3 x86/jmp_with_stack.c 1.3
M +41 -4 x86-linux/syscalls.c 1.14
--- valgrind/coregrind/core.h #1.64:1.65
@@ -1717,9 +1717,17 @@ extern void VGA_(os_state_clear)(ThreadS
extern void VGA_(os_state_init)(ThreadState *);
-// Run a thread from beginning to end. Does not return.
+// Run a thread from beginning to end. Does not return if tid == VG_(master_tid).
void VGA_(thread_wrapper)(ThreadId tid);
+// Like VGA_(thread_wrapper), but it allocates a stack before calling
+// to VGA_(thread_wrapper) on that stack, as if it had been set up by
+// clone()
+void VGA_(main_thread_wrapper)(ThreadId tid) __attribute__ ((__noreturn__));
+
+// Return how many bytes of a thread's Valgrind stack are unused
+Int VGA_(stack_unused)(ThreadId tid);
+
// Terminate the process. Does not return.
-void VGA_(terminate)(ThreadId tid, VgSchedReturnCode src);
+void VGA_(terminate)(ThreadId tid, VgSchedReturnCode src) __attribute__((__noreturn__));
// wait until all other threads are dead
--- valgrind/coregrind/stage1.c #1.31:1.32
@@ -298,5 +298,5 @@ static void main2(void)
}
- jmp_with_stack(info.init_eip, (Addr)esp);
+ jmp_with_stack((void (*)(void))info.init_eip, (Addr)esp);
}
@@ -320,5 +320,5 @@ int main(int argc, char** argv)
/* move onto another stack so we can play with the main one */
- jmp_with_stack((Addr)main2, (Addr)stack + sizeof(stack));
+ jmp_with_stack(main2, (Addr)stack + sizeof(stack));
}
--- valgrind/coregrind/ume.h #1.16:1.17
@@ -48,5 +48,5 @@ void foreach_map(int (*fn)(char *start,
// Jump to a new 'ip' with the stack 'sp'.
-void jmp_with_stack(Addr ip, Addr sp) __attribute__((noreturn));
+void jmp_with_stack(void (*eip)(void), Addr sp) __attribute__((noreturn));
/*------------------------------------------------------------*/
--- valgrind/coregrind/vg_main.c #1.236:1.237
@@ -2411,4 +2411,6 @@ static void build_segment_map_callback (
void VG_(sanity_check_general) ( Bool force_expensive )
{
+ ThreadId tid;
+
VGP_PUSHCC(VgpCoreCheapSanity);
@@ -2452,6 +2454,21 @@ void VG_(sanity_check_general) ( Bool fo
}
+ /* Check that Segments and /proc/self/maps match up */
vg_assert(VG_(sanity_check_memory)());
+ /* Look for stack overruns. Visit all threads. */
+ for(tid = 1; tid < VG_N_THREADS; tid++) {
+ Int remains;
+
+ if (VG_(threads)[tid].status == VgTs_Empty ||
+ VG_(threads)[tid].status == VgTs_Zombie)
+ continue;
+
+ remains = VGA_(stack_unused)(tid);
+ if (remains < VKI_PAGE_SIZE)
+ VG_(message)(Vg_DebugMsg, "WARNING: Thread %d is within %d bytes of running out of stack!",
+ tid, remains);
+ }
+
/*
if ((sanity_fast_count % 500) == 0) VG_(mallocSanityCheckAll)();
@@ -2841,5 +2858,5 @@ int main(int argc, char **argv, char **e
vg_assert(VG_(master_tid) == 1);
- VGA_(thread_wrapper)(1);
+ VGA_(main_thread_wrapper)(1);
abort();
--- valgrind/coregrind/vg_scheduler.c #1.210:1.211
@@ -1142,5 +1142,4 @@ void scheduler_sanity ( ThreadId tid )
{
Bool bad = False;
- UInt *esp;
if (!VG_(is_running_thread)(tid)) {
@@ -1157,16 +1156,4 @@ void scheduler_sanity ( ThreadId tid )
bad = True;
}
-
- /* Check to see if we're running out of stack. Not much use
- really, since this is the outer part of the call tree. We
- should really fill the stack with a marker pattern and look for
- the low-water mark. */
- esp = (UInt *)&tid;
- if (esp < VG_(threads)[tid].os_state.stack + (VKI_PAGE_SIZE/sizeof(*esp)))
- VG_(message)(Vg_DebugMsg,
- "WARNING: Thread %d is within %d bytes of running out of stack!",
- VKI_PAGE_SIZE);
-
- /* Can't do much about checking client thread stack space */
}
--- valgrind/coregrind/linux/core_os.c #1.5:1.6
@@ -30,14 +30,4 @@ void VGA_(thread_wrapper)(ThreadId tid)
tid, &tid);
- if (tid == 1) {
- /* Thread 1 has its stack on the main process stack, and so
- is expandable. Do this so that backtraces are printed
- properly.
- XXX Perhaps it should have a private stack too?
- */
- tst->os_state.stack = (UInt *)VG_(valgrind_last) - VG_STACK_SIZE_W;
- tst->os_state.stacksize = VG_STACK_SIZE_W;
- }
-
VG_TRACK ( post_thread_create, tst->os_state.parent, tid );
--- valgrind/coregrind/x86/Makefile.am #1.20:1.21
@@ -23,4 +23,5 @@
helpers.S \
dispatch.S \
+ jmp_with_stack.c \
signal.c \
state.c
--- valgrind/coregrind/x86/jmp_with_stack.c #1.2:1.3
@@ -32,8 +32,8 @@
after exec; it therefore also clears all the other registers.
*/
-void jmp_with_stack(Addr eip, Addr esp)
+void jmp_with_stack(void (*eip)(void), Addr esp)
{
asm volatile ("movl %1, %%esp;" /* set esp */
- "pushl %%eax;" /* push esp */
+ "pushl %%eax;" /* push eip */
"xorl %%eax,%%eax;" /* clear registers */
"xorl %%ebx,%%ebx;"
--- valgrind/coregrind/x86-linux/syscalls.c #1.13:1.14
@@ -30,4 +30,5 @@
#include "core.h"
+#include "ume.h" /* for jmp_with_stack */
/* These are addresses within VGA_(client_syscall). See syscall.S for details. */
@@ -139,4 +140,6 @@ Bool VGA_(interrupted_syscall)(arch_thre
They're allocated lazily, but never freed.
*/
+#define FILL 0xdeadbeef
+
static UInt *allocstack(ThreadId tid)
{
@@ -159,9 +162,11 @@ static UInt *allocstack(ThreadId tid)
}
- esp = tst->os_state.stack + tst->os_state.stacksize;
+ for(esp = tst->os_state.stack; esp < (tst->os_state.stack + tst->os_state.stacksize); esp++)
+ *esp = FILL;
+ /* esp is left at top of stack */
if (0)
- VG_(printf)("stack for tid %d at %p; esp=%p\n",
- tid, tst->os_state.stack,
+ VG_(printf)("stack for tid %d at %p (%x); esp=%p\n",
+ tid, tst->os_state.stack, *tst->os_state.stack,
esp);
@@ -169,4 +174,36 @@ static UInt *allocstack(ThreadId tid)
}
+/* Return how many bytes of this stack have not been used */
+Int VGA_(stack_unused)(ThreadId tid)
+{
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ UInt *p;
+
+ for (p = tst->os_state.stack;
+ p && (p < (tst->os_state.stack + tst->os_state.stacksize));
+ p++)
+ if (*p != FILL)
+ break;
+
+ if (0)
+ VG_(printf)("p=%p %x tst->os_state.stack=%p\n", p, *p, tst->os_state.stack);
+
+ return (p - tst->os_state.stack) * sizeof(*p);
+}
+
+/*
+ Allocate a stack for the main thread, and call VGA_(thread_wrapper)
+ on that stack.
+ */
+void VGA_(main_thread_wrapper)(ThreadId tid)
+{
+ UInt *esp = allocstack(tid);
+
+ vg_assert(tid == VG_(master_tid));
+
+ *--esp = tid; /* set arg */
+ *--esp = 0; /* bogus return address */
+ jmp_with_stack((void (*)(void))VGA_(thread_wrapper), (Addr)esp);
+}
static Int start_thread(void *arg)
|