Statically allocate a page in the client address space for trampoline
code.  Currently this is just for signal returns, but there's the start
of sysinfo/vsyscalls support, as used by the TLS libraries.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2150 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/stage2.c b/coregrind/stage2.c
index 113103f..2c571e6 100644
--- a/coregrind/stage2.c
+++ b/coregrind/stage2.c
@@ -131,6 +131,8 @@
    The format of the stack is:
 
    higher address +-----------------+
+		  | Trampoline code |
+		  +-----------------+
                   |                 |
 		  : string table    :
 		  |                 |
@@ -168,6 +170,7 @@
    int envc;			/* total number of env vars */
    unsigned stacksize;		/* total client stack size */
    addr_t cl_esp;		/* client stack base (initial esp) */
+   addr_t cl_stacktop;		/* top of stack */
 
    /* ==================== compute sizes ==================== */
 
@@ -215,18 +218,25 @@
       sizeof(char **)*envc +		/* envp */
       sizeof(char **) +			/* terminal NULL */
       auxsize +				/* auxv */
-      ROUNDUP(stringsize, sizeof(int));	/* strings (aligned) */
+      ROUNDUP(stringsize, sizeof(int)) +/* strings (aligned) */
+      VKI_BYTES_PER_PAGE;		/* page for trampoline code */
 
    /* cl_esp is the client's stack pointer */
    cl_esp = client_end - stacksize;
    cl_esp = ROUNDDN(cl_esp, 16); /* make stack 16 byte aligned */
 
+   cl_stacktop = client_end;
+   cl_stacktop -= VKI_BYTES_PER_PAGE;
+
+   kp.cl_tramp_code = cl_stacktop;
+
    if (0)
       printf("stringsize=%d auxsize=%d stacksize=%d\n",
 	     stringsize, auxsize, stacksize);
 
+
    /* base of the string table (aligned) */
-   stringbase = strtab = (char *)(client_end - ROUNDUP(stringsize, sizeof(int)));
+   stringbase = strtab = (char *)(cl_stacktop - ROUNDUP(stringsize, sizeof(int)));
 
    kp.clstk_base = PGROUNDDN(cl_esp);
    kp.clstk_end = client_end;
@@ -336,18 +346,15 @@
 	 auxv->a_val = 0;
 	 break;
 
-#if 1
       case AT_SYSINFO:
+	 /* Leave this unmolested for now, but we'll update it later
+	    when we set up the client trapoline code page */
+	 break;
+
       case AT_SYSINFO_EHDR:
-	 /* trash vsyscalls for now
-				   
-  	    XXX should probably replace with our own sysinfo page so
-  	    we can intercept sysenter syscalls too - or at least note
-  	    the address so that we can catch jumps here
-	 */
+	 /* Trash this, because we don't reproduce it */
 	 auxv->a_type = AT_IGNORE;
 	 break;
-#endif
 
       default:
 	 /* stomp out anything we don't know about */
diff --git a/coregrind/ume.c b/coregrind/ume.c
index 192bdbe..080e725 100644
--- a/coregrind/ume.c
+++ b/coregrind/ume.c
@@ -322,7 +322,7 @@
 	 if (bb != b) {
 	    fprintf(stderr, "sbrk failed while adjusting brk base: "
 		    "perhaps we hit the datasize ulimit?\n");
-	    break;
+	    return 0;
 	 }
 	 b += delta;
       }
@@ -482,6 +482,9 @@
 
    info->brkbase = mapelf(e, 0, info->setbrk);		/* map the executable */
 
+   if (info->brkbase == 0)
+      return ENOMEM;
+
    if (interp != NULL) {
       /* reserve a chunk of address space for interpreter */
       char *base = (char *)info->exe_base;
diff --git a/coregrind/vg_helpers.S b/coregrind/vg_helpers.S
index 091f8e8..270caac 100644
--- a/coregrind/vg_helpers.S
+++ b/coregrind/vg_helpers.S
@@ -42,9 +42,13 @@
    at an arbitary address.  Therefore, this code must be completely
    position-independent.
 */
-.global VG_(signalreturn_bogusRA)
-.global VG_(signalreturn_bogusRA_length)
-VG_(signalreturn_bogusRA):
+.global VG_(trampoline_code_start)
+.global VG_(trampoline_code_length)
+.global VG_(tramp_sigreturn_offset)
+.global VG_(tramp_syscall_offset)
+	
+VG_(trampoline_code_start):
+sigreturn_start:	
 	subl	$20, %esp	# allocate arg block
 	movl	%esp, %edx	# %edx == &_zzq_args[0]
 	movl	$VG_USERREQ__SIGNAL_RETURNS, 0(%edx)	# request
@@ -63,9 +67,21 @@
 	# should never get here
 	ud2
 
-VG_(signalreturn_bogusRA_length):
-	.long . - VG_(signalreturn_bogusRA)
-
+	# We can point our sysinfo stuff here
+	.align 16
+syscall_start:	
+	int	$0x80
+	ret
+tramp_code_end:
+			
+.data
+VG_(trampoline_code_length):
+	.long tramp_code_end - VG_(trampoline_code_start)
+VG_(tramp_sigreturn_offset):
+	.long sigreturn_start - VG_(trampoline_code_start)
+VG_(tramp_syscall_offset):
+	.long syscall_start - VG_(trampoline_code_start)
+.text
 
 	
 /* ------------------ REAL CPU HELPERS ------------------ */
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 0ce9b13..a7f5f60 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -1341,13 +1341,16 @@
    Addr client_base;		/* start of client address space	*/
    Addr	client_end;		/* end of client address space		*/
    Addr client_mapbase;		/* base address of !MAP_FIXED mappings  */
+   Addr	clstk_base;		/* lowest address of client stack	*/
+   Addr	clstk_end;		/* highest address of client stack	*/
+   Addr cl_tramp_code;		/* syscall+signal trampoline code       */
+
    Addr	shadow_base;		/* start of skin's shadow memory	*/
    Addr shadow_end;		/* end of skin's shadow memory		*/
+
    Addr	vg_base;		/* start of Valgrind's memory		*/
    Addr vg_mmap_end;		/* end of Valgrind's mmap area		*/
    Addr	vg_end;			/* end of Valgrind's memory		*/
-   Addr	clstk_base;		/* lowest address of client stack	*/
-   Addr	clstk_end;		/* highest address of client stack	*/
 } KickstartParams;
 
 /* Entrypoint for kickstart */
@@ -1376,6 +1379,8 @@
 extern Addr VG_(client_mapbase); /* base of mappings */
 extern Addr VG_(clstk_base);	/* client stack range */
 extern Addr VG_(clstk_end);
+extern Addr VG_(client_trampoline_code);
+
 extern Addr VG_(brk_base);	/* start of brk */
 extern Addr VG_(brk_limit);	/* current brk */
 extern Addr VG_(shadow_base);	/* skin's shadow memory */
@@ -1742,9 +1747,11 @@
 
 extern void VG_(helper_undefined_instruction);
 
-/* NOT A FUNCTION; this is a bogus RETURN ADDRESS. */
-extern Char VG_(signalreturn_bogusRA);
-extern Int  VG_(signalreturn_bogusRA_length);	/* length */
+/* Information about trampoline code (for signal return and syscalls) */
+extern const Char VG_(trampoline_code_start);
+extern const Int  VG_(trampoline_code_length);
+extern const Int  VG_(tramp_sigreturn_offset);
+extern const Int  VG_(tramp_syscall_offset);
 
 /* ---------------------------------------------------------------------
    Things relating to the used skin
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 2dcfb7a..d91f487 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -124,6 +124,7 @@
 Addr VG_(client_base);	/* client address space limits */
 Addr VG_(client_end);
 Addr VG_(client_mapbase);
+Addr VG_(client_trampoline_code);
 Addr VG_(clstk_base);
 Addr VG_(clstk_end);
 Addr VG_(brk_base);	/* start of brk */
@@ -777,6 +778,7 @@
       switch(auxp[0]) {
       case VKI_AT_SYSINFO:
 	 VG_(sysinfo_page_exists) = True;
+	 auxp[1] = (Int)(VG_(client_trampoline_code) + VG_(tramp_syscall_offset));
 	 VG_(sysinfo_page_addr) = auxp[1];
 	 break;
       }
@@ -1392,6 +1394,7 @@
    VG_(client_mapbase)    = kp->client_mapbase;
    VG_(clstk_base)        = kp->clstk_base;
    VG_(clstk_end)         = kp->clstk_end;
+   vg_assert(VG_(clstk_end) == VG_(client_end));
 
    VG_(shadow_base)	  = kp->shadow_base;
    VG_(shadow_end)	  = kp->shadow_end;
@@ -1401,7 +1404,7 @@
 
    VG_(libdir)            = kp->libdir;
 
-   vg_assert(VG_(clstk_end) == VG_(client_end));
+   VG_(client_trampoline_code) = kp->cl_tramp_code;
 
    if (0) {
       if (VG_(have_ssestate))
diff --git a/coregrind/vg_memory.c b/coregrind/vg_memory.c
index ecb1d5c..0a91b03 100644
--- a/coregrind/vg_memory.c
+++ b/coregrind/vg_memory.c
@@ -468,7 +468,7 @@
 
    /* Everything must be page-aligned */
    vg_assert((a & (VKI_BYTES_PER_PAGE-1)) == 0);
-   vg_assert((len & (VKI_BYTES_PER_PAGE-1)) == 0);
+   len = PGROUNDUP(len);
 
    VG_(split_segment)(a);
    VG_(split_segment)(a+len);
@@ -661,16 +661,12 @@
    VG_(parse_procselfmaps) ( build_valgrind_map_callback );	/* just Valgrind mappings */
    VG_(parse_procselfmaps) ( build_segment_map_callback );	/* everything */
 
-   /* kludge: some newer kernels place a "sysinfo" page up high, with
-      vsyscalls in it, and possibly some other stuff in the future. */
-   if (VG_(sysinfo_page_exists)) {
-      // 2003-Sep-25, njn: Jeremy thinks the sysinfo page probably doesn't
-      // have any symbols that need to be loaded.  So just treat it like
-      // a non-executable page.
-      //VG_(new_exeseg_mmap)( VG_(sysinfo_page_addr), 4096 );
-      VG_TRACK( new_mem_startup, VG_(sysinfo_page_addr), 4096, 
-                True, True, True );
-     }
+   /* initialize our trampoline page (which is also sysinfo stuff) */
+   VG_(memcpy)((void *)VG_(client_trampoline_code), 
+	       &VG_(trampoline_code_start),
+	       VG_(trampoline_code_length));
+   VG_(mprotect)((void *)VG_(client_trampoline_code), VG_(trampoline_code_length), 
+		 VKI_PROT_READ|VKI_PROT_EXEC);
 }
 
 /*------------------------------------------------------------*/
diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c
index 50be2b6..bd1c92f 100644
--- a/coregrind/vg_signals.c
+++ b/coregrind/vg_signals.c
@@ -950,8 +950,6 @@
    sc->cr2 = (UInt)si->_sifields._sigfault._addr;
 }
 
-static Addr signalreturn_stub_addr = 0;
-
 /* Set up a stack frame (VgSigContext) for the client's signal
    handler.  This includes the signal number and a bogus return
    address.  */
@@ -1009,30 +1007,10 @@
    vg_assert( ((Char*)(&frame->magicE)) + sizeof(UInt) 
               == ((Char*)(esp_top_of_frame)) );
 
-   /* if the sigreturn stub isn't in the client address space yet,
-      allocate space for it and copy it into place. */
-   if (signalreturn_stub_addr == 0) {
-      UInt len = PGROUNDUP(VG_(signalreturn_bogusRA_length));
-
-      signalreturn_stub_addr = VG_(client_alloc)(0, len,
-						 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
-						 0);
-      VG_(memcpy)((void *)signalreturn_stub_addr, &VG_(signalreturn_bogusRA), 
-		  VG_(signalreturn_bogusRA_length));
-      VG_(mprotect)((void *)signalreturn_stub_addr, len, VKI_PROT_READ|VKI_PROT_EXEC);
-      VG_TRACK(new_mem_mmap, signalreturn_stub_addr, VG_(signalreturn_bogusRA_length),
-	       True, False, True);
-
-      if (VG_(clo_trace_signals))
-	 VG_(message)(Vg_DebugMsg, "Put sigreturn stub at %p-%p in client address space",
-		      signalreturn_stub_addr, 
-		      signalreturn_stub_addr + VG_(signalreturn_bogusRA_length));
-   }
-
    /* retaddr, sigNo, psigInfo, puContext fields are to be written */
    VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame", 
                             (Addr)frame, offsetof(VgSigFrame, handlerArgs) );
-   frame->retaddr    = (UInt)signalreturn_stub_addr;
+   frame->retaddr    = (UInt)VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
    frame->sigNo      = sigNo;
    frame->sigNo_private = sigNo;
    VG_TRACK( post_mem_write, (Addr)frame, offsetof(VgSigFrame, handlerArgs) );