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) );