blob: 9a9eba675fc708bfc89561c4e3dc0d459dc7f47d [file] [log] [blame]
jseward2886b0e2004-01-04 03:46:11 +00001
nethercotebb1c9912004-01-04 16:43:23 +00002/*--------------------------------------------------------------------*/
nethercote71980f02004-01-24 18:18:54 +00003/*--- Startup: preliminaries stage1.c ---*/
nethercotebb1c9912004-01-04 16:43:23 +00004/*--------------------------------------------------------------------*/
5
jseward2886b0e2004-01-04 03:46:11 +00006/*
7 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
9
10 Copyright (C) 2000-2004 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
fitzhardinge7e343cd2003-12-16 02:14:00 +000031#define _FILE_OFFSET_BITS 64
32
nethercote969ecf12004-10-13 17:29:01 +000033#include <errno.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000034#include <stdio.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000035#include <string.h>
36#include <stdlib.h>
37#include <assert.h>
38#include <signal.h>
39#include <fcntl.h>
nethercote969ecf12004-10-13 17:29:01 +000040#include <sys/mman.h>
fitzhardinge716c2c12004-03-09 00:57:45 +000041#include <sys/resource.h>
nethercote969ecf12004-10-13 17:29:01 +000042#include <unistd.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000043
nethercotef1e5e152004-09-01 23:58:16 +000044#include "core.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000045#include "ume.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000046
47static int stack[SIGSTKSZ*4];
fitzhardinge7e343cd2003-12-16 02:14:00 +000048
nethercotec25c4492004-10-18 11:52:17 +000049// Initial stack pointer, which points to argc.
50static void* init_sp;
51
fitzhardinge7e343cd2003-12-16 02:14:00 +000052/* Where we expect to find all our aux files (namely, stage2) */
53static const char *valgrind_lib = VG_LIBDIR;
54
55/* stage2's name */
56static const char stage2[] = "stage2";
57
nethercote969ecf12004-10-13 17:29:01 +000058/*------------------------------------------------------------*/
59/*--- Auxv modification ---*/
60/*------------------------------------------------------------*/
61
fitzhardinge7e343cd2003-12-16 02:14:00 +000062/* Modify the auxv the kernel gave us to make it look like we were
63 execed as the shared object.
64
65 This also inserts a new entry into the auxv table so we can
66 communicate some extra information to stage2 (namely, the fd of the
67 padding file, so it can identiry and remove the padding later).
68*/
nethercote31779c72004-07-30 21:50:15 +000069static void *fix_auxv(void *v_init_esp, const struct exeinfo *info,
70 int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +000071{
72 struct ume_auxv *auxv;
73 int *newesp;
74 int seen;
75 int delta;
76 int i;
77 static const int new_entries = 2;
78
79 /* make sure we're running on the private stack */
80 assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]);
81
82 /* find the beginning of the AUXV table */
83 auxv = find_auxv(v_init_esp);
84
85 /* Work out how we should move things to make space for the new
86 auxv entry. It seems that ld.so wants a 16-byte aligned stack on
87 entry, so make sure that's the case. */
88 newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf);
89 delta = (char *)v_init_esp - (char *)newesp;
90
91 memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp);
92
93 v_init_esp = (void *)newesp;
94 auxv -= delta/sizeof(*auxv);
95
96 /* stage2 needs this so it can clean up the padding we leave in
97 place when we start it */
98 auxv[0].a_type = AT_UME_PADFD;
nethercote31779c72004-07-30 21:50:15 +000099 auxv[0].u.a_val = padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000100
101 /* This will be needed by valgrind itself so that it can
102 subsequently execve() children. This needs to be done here
103 because /proc/self/exe will go away once we unmap stage1. */
104 auxv[1].a_type = AT_UME_EXECFD;
mueller5ed88f22004-01-06 16:02:29 +0000105 auxv[1].u.a_val = open("/proc/self/exe", O_RDONLY);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000106
107 /* make sure the rest are sane */
108 for(i = new_entries; i < delta/sizeof(*auxv); i++) {
109 auxv[i].a_type = AT_IGNORE;
mueller5ed88f22004-01-06 16:02:29 +0000110 auxv[i].u.a_val = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000111 }
112
113 /* OK, go through and patch up the auxv entries to match the new
114 executable */
115 seen = 0;
116 for(; auxv->a_type != AT_NULL; auxv++) {
117 if (0)
mueller5ed88f22004-01-06 16:02:29 +0000118 printf("doing auxv %p %4x: %d %p\n", auxv, auxv->a_type, auxv->u.a_val, auxv->u.a_ptr);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000119
120 switch(auxv->a_type) {
121 case AT_PHDR:
122 seen |= 1;
mueller5ed88f22004-01-06 16:02:29 +0000123 auxv->u.a_val = info->phdr;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000124 break;
125
126 case AT_PHNUM:
127 seen |= 2;
mueller5ed88f22004-01-06 16:02:29 +0000128 auxv->u.a_val = info->phnum;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000129 break;
130
131 case AT_BASE:
132 seen |= 4;
mueller5ed88f22004-01-06 16:02:29 +0000133 auxv->u.a_val = info->interp_base;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000134 break;
135
136 case AT_ENTRY:
137 seen |= 8;
mueller5ed88f22004-01-06 16:02:29 +0000138 auxv->u.a_val = info->entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000139 break;
fitzhardingea1d37c02004-06-14 02:36:09 +0000140
nethercoteeda6b282004-06-15 08:34:10 +0000141#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
142#ifdef AT_SYSINFO
fitzhardingea1d37c02004-06-14 02:36:09 +0000143 case AT_SYSINFO:
nethercoteeda6b282004-06-15 08:34:10 +0000144#endif
nethercote079acf62004-06-14 11:56:59 +0000145#ifdef AT_SYSINFO_EHDR
fitzhardingea1d37c02004-06-14 02:36:09 +0000146 case AT_SYSINFO_EHDR:
nethercote079acf62004-06-14 11:56:59 +0000147#endif
fitzhardingea1d37c02004-06-14 02:36:09 +0000148 auxv->a_type = AT_IGNORE;
149 break;
nethercoteeda6b282004-06-15 08:34:10 +0000150#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000151 }
152 }
153
154 /* If we didn't see all the entries we need to fix up, then we
155 can't make the new executable viable. */
156 if (seen != 0xf) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000157 fprintf(stderr, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000158 exit(1);
159 }
160
161 return v_init_esp;
162}
163
nethercote969ecf12004-10-13 17:29:01 +0000164
165/*------------------------------------------------------------*/
166/*--- Address space padding ---*/
167/*------------------------------------------------------------*/
168
169static void check_mmap(void* res, void* base, int len)
170{
171 if ((void*)-1 == res) {
172 fprintf(stderr, "valgrind: padding mmap(%p, %d) failed during startup.\n"
173 "valgrind: is there a hard virtual memory limit set?\n",
174 base, len);
175 exit(1);
176 }
177}
178
179typedef struct {
180 char* fillgap_start;
181 char* fillgap_end;
182 int fillgap_padfile;
183} fillgap_extra;
184
185static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
186 int maj, int min, int ino, void* e)
187{
188 fillgap_extra* extra = e;
189
190 if (segstart >= extra->fillgap_end)
191 return 0;
192
193 if (segstart > extra->fillgap_start) {
194 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
195 PROT_NONE, MAP_FIXED|MAP_PRIVATE,
196 extra->fillgap_padfile, 0);
197 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
198 }
199 extra->fillgap_start = segend;
200
201 return 1;
202}
203
204// Choose a name for the padfile, open it.
205int as_openpadfile(void)
206{
207 char buf[256];
208 int padfile;
209 int seq = 1;
210 do {
211 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
212 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
213 unlink(buf);
214 if (padfile == -1 && errno != EEXIST) {
215 fprintf(stderr, "valgrind: couldn't open padfile\n");
216 exit(44);
217 }
218 } while(padfile == -1);
219
220 return padfile;
221}
222
223// Pad all the empty spaces in a range of address space to stop interlopers.
224void as_pad(void *start, void *end, int padfile)
225{
226 fillgap_extra extra;
227 extra.fillgap_start = start;
228 extra.fillgap_end = end;
229 extra.fillgap_padfile = padfile;
230
231 foreach_map(fillgap, &extra);
232
233 if (extra.fillgap_start < extra.fillgap_end) {
234 void* res = mmap(extra.fillgap_start,
235 extra.fillgap_end - extra.fillgap_start,
236 PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
237 check_mmap(res, extra.fillgap_start,
238 extra.fillgap_end - extra.fillgap_start);
239 }
240}
241
242
243/*------------------------------------------------------------*/
244/*--- main() and related pieces ---*/
245/*------------------------------------------------------------*/
246
nethercote31779c72004-07-30 21:50:15 +0000247static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
248 int min, int ino, void* dummy) {
thughes4ad52d02004-06-27 17:37:21 +0000249 printf("mapping %10p-%10p %s %02x:%02x %d\n",
250 start, end, perm, maj, min, ino);
251 return 1;
252}
253
nethercote9d072422004-10-13 17:58:36 +0000254static void main2(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000255{
nethercote31779c72004-07-30 21:50:15 +0000256 int err, padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000257 struct exeinfo info;
258 extern char _end;
259 int *esp;
260 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
261
nethercote5462ef72004-10-26 17:03:54 +0000262 info.exe_end = PGROUNDDN(init_sp);
nethercote7f390022004-10-25 17:18:24 +0000263#ifdef HAVE_PIE
264 info.exe_base = ROUNDDN(info.exe_end - 0x02000000, 0x10000000);
265 assert(info.exe_base >= PGROUNDUP(&_end));
266 info.map_base = info.exe_base + 0x01000000;
267#else
nethercote7f390022004-10-25 17:18:24 +0000268 // If this system doesn't have PIE (position-independent executables),
269 // we have to choose a hardwired location for stage2.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000270 info.exe_base = PGROUNDUP(&_end);
nethercote7f390022004-10-25 17:18:24 +0000271 info.map_base = KICKSTART_BASE + 0x01000000;
272#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000273
fitzhardinge7e343cd2003-12-16 02:14:00 +0000274 info.argv = NULL;
275
fitzhardingea49f9b52003-12-16 22:26:45 +0000276 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277
278 err = do_exec(buf, &info);
279
280 if (err != 0) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000281 fprintf(stderr, "valgrind: failed to load %s: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000282 buf, strerror(err));
283 exit(1);
284 }
285
286 /* Make sure stage2's dynamic linker can't tromp on the lower part
287 of the address space. */
nethercote31779c72004-07-30 21:50:15 +0000288 padfile = as_openpadfile();
289 as_pad(0, (void *)info.map_base, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000290
nethercotec25c4492004-10-18 11:52:17 +0000291 esp = fix_auxv(init_sp, &info, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000292
293 if (0) {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000294 printf("---------- launch stage 2 ----------\n");
295 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
nethercote31779c72004-07-30 21:50:15 +0000296 foreach_map(prmap, /*dummy*/NULL);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000297 }
298
nethercote107e1c02004-10-13 17:55:31 +0000299 jmp_with_stack(info.init_eip, (addr_t)esp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300}
301
nethercotec25c4492004-10-18 11:52:17 +0000302int main(int argc, char** argv)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000303{
fitzhardinge716c2c12004-03-09 00:57:45 +0000304 struct rlimit rlim;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000305 const char *cp = getenv(VALGRINDLIB);
306
307 if (cp != NULL)
308 valgrind_lib = cp;
309
nethercotec25c4492004-10-18 11:52:17 +0000310 // Initial stack pointer is to argc, which is immediately before argv[0]
nethercote41c75da2004-10-18 15:34:14 +0000311 // on the stack. Nb: Assumes argc is word-aligned.
nethercotec25c4492004-10-18 11:52:17 +0000312 init_sp = argv - 1;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000313
fitzhardinge716c2c12004-03-09 00:57:45 +0000314 /* Set the address space limit as high as it will go, since we make
315 a lot of very large mappings. */
316 getrlimit(RLIMIT_AS, &rlim);
317 rlim.rlim_cur = rlim.rlim_max;
318 setrlimit(RLIMIT_AS, &rlim);
319
fitzhardinge7e343cd2003-12-16 02:14:00 +0000320 /* move onto another stack so we can play with the main one */
nethercote9d072422004-10-13 17:58:36 +0000321 jmp_with_stack((addr_t)main2, (addr_t)stack + sizeof(stack));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000322}
nethercotebb1c9912004-01-04 16:43:23 +0000323
324/*--------------------------------------------------------------------*/
325/*--- end stage1.c ---*/
326/*--------------------------------------------------------------------*/