blob: de0f45de7a62df8d11cb365aa0674a02c4327da9 [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)
nethercote545fe672004-11-01 16:52:43 +0000118 printf("doing auxv %p %4lld: %lld %p\n",
119 auxv, (ULong)auxv->a_type, (ULong)auxv->u.a_val, auxv->u.a_ptr);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000120
121 switch(auxv->a_type) {
122 case AT_PHDR:
123 seen |= 1;
mueller5ed88f22004-01-06 16:02:29 +0000124 auxv->u.a_val = info->phdr;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000125 break;
126
127 case AT_PHNUM:
128 seen |= 2;
mueller5ed88f22004-01-06 16:02:29 +0000129 auxv->u.a_val = info->phnum;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000130 break;
131
132 case AT_BASE:
133 seen |= 4;
mueller5ed88f22004-01-06 16:02:29 +0000134 auxv->u.a_val = info->interp_base;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000135 break;
136
137 case AT_ENTRY:
138 seen |= 8;
mueller5ed88f22004-01-06 16:02:29 +0000139 auxv->u.a_val = info->entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000140 break;
fitzhardingea1d37c02004-06-14 02:36:09 +0000141
nethercoteeda6b282004-06-15 08:34:10 +0000142#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
143#ifdef AT_SYSINFO
fitzhardingea1d37c02004-06-14 02:36:09 +0000144 case AT_SYSINFO:
nethercoteeda6b282004-06-15 08:34:10 +0000145#endif
nethercote079acf62004-06-14 11:56:59 +0000146#ifdef AT_SYSINFO_EHDR
fitzhardingea1d37c02004-06-14 02:36:09 +0000147 case AT_SYSINFO_EHDR:
nethercote079acf62004-06-14 11:56:59 +0000148#endif
fitzhardingea1d37c02004-06-14 02:36:09 +0000149 auxv->a_type = AT_IGNORE;
150 break;
nethercoteeda6b282004-06-15 08:34:10 +0000151#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000152 }
153 }
154
155 /* If we didn't see all the entries we need to fix up, then we
156 can't make the new executable viable. */
157 if (seen != 0xf) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000158 fprintf(stderr, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000159 exit(1);
160 }
161
162 return v_init_esp;
163}
164
nethercote969ecf12004-10-13 17:29:01 +0000165
166/*------------------------------------------------------------*/
167/*--- Address space padding ---*/
168/*------------------------------------------------------------*/
169
170static void check_mmap(void* res, void* base, int len)
171{
172 if ((void*)-1 == res) {
173 fprintf(stderr, "valgrind: padding mmap(%p, %d) failed during startup.\n"
174 "valgrind: is there a hard virtual memory limit set?\n",
175 base, len);
176 exit(1);
177 }
178}
179
180typedef struct {
181 char* fillgap_start;
182 char* fillgap_end;
183 int fillgap_padfile;
184} fillgap_extra;
185
186static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
187 int maj, int min, int ino, void* e)
188{
189 fillgap_extra* extra = e;
190
191 if (segstart >= extra->fillgap_end)
192 return 0;
193
194 if (segstart > extra->fillgap_start) {
195 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
196 PROT_NONE, MAP_FIXED|MAP_PRIVATE,
197 extra->fillgap_padfile, 0);
198 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
199 }
200 extra->fillgap_start = segend;
201
202 return 1;
203}
204
205// Choose a name for the padfile, open it.
206int as_openpadfile(void)
207{
208 char buf[256];
209 int padfile;
210 int seq = 1;
211 do {
212 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
213 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
214 unlink(buf);
215 if (padfile == -1 && errno != EEXIST) {
216 fprintf(stderr, "valgrind: couldn't open padfile\n");
217 exit(44);
218 }
219 } while(padfile == -1);
220
221 return padfile;
222}
223
224// Pad all the empty spaces in a range of address space to stop interlopers.
225void as_pad(void *start, void *end, int padfile)
226{
227 fillgap_extra extra;
228 extra.fillgap_start = start;
229 extra.fillgap_end = end;
230 extra.fillgap_padfile = padfile;
231
232 foreach_map(fillgap, &extra);
233
234 if (extra.fillgap_start < extra.fillgap_end) {
235 void* res = mmap(extra.fillgap_start,
236 extra.fillgap_end - extra.fillgap_start,
237 PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
238 check_mmap(res, extra.fillgap_start,
239 extra.fillgap_end - extra.fillgap_start);
240 }
241}
242
243
244/*------------------------------------------------------------*/
245/*--- main() and related pieces ---*/
246/*------------------------------------------------------------*/
247
nethercote31779c72004-07-30 21:50:15 +0000248static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
249 int min, int ino, void* dummy) {
thughes4ad52d02004-06-27 17:37:21 +0000250 printf("mapping %10p-%10p %s %02x:%02x %d\n",
251 start, end, perm, maj, min, ino);
252 return 1;
253}
254
nethercote9d072422004-10-13 17:58:36 +0000255static void main2(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000256{
nethercote31779c72004-07-30 21:50:15 +0000257 int err, padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000258 struct exeinfo info;
259 extern char _end;
260 int *esp;
261 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
262
nethercote5462ef72004-10-26 17:03:54 +0000263 info.exe_end = PGROUNDDN(init_sp);
nethercote7f390022004-10-25 17:18:24 +0000264#ifdef HAVE_PIE
265 info.exe_base = ROUNDDN(info.exe_end - 0x02000000, 0x10000000);
266 assert(info.exe_base >= PGROUNDUP(&_end));
267 info.map_base = info.exe_base + 0x01000000;
268#else
nethercote7f390022004-10-25 17:18:24 +0000269 // If this system doesn't have PIE (position-independent executables),
270 // we have to choose a hardwired location for stage2.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000271 info.exe_base = PGROUNDUP(&_end);
nethercote7f390022004-10-25 17:18:24 +0000272 info.map_base = KICKSTART_BASE + 0x01000000;
273#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000274
fitzhardinge7e343cd2003-12-16 02:14:00 +0000275 info.argv = NULL;
276
fitzhardingea49f9b52003-12-16 22:26:45 +0000277 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000278
279 err = do_exec(buf, &info);
280
281 if (err != 0) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000282 fprintf(stderr, "valgrind: failed to load %s: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000283 buf, strerror(err));
284 exit(1);
285 }
286
287 /* Make sure stage2's dynamic linker can't tromp on the lower part
288 of the address space. */
nethercote31779c72004-07-30 21:50:15 +0000289 padfile = as_openpadfile();
290 as_pad(0, (void *)info.map_base, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000291
nethercotec25c4492004-10-18 11:52:17 +0000292 esp = fix_auxv(init_sp, &info, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000293
294 if (0) {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000295 printf("---------- launch stage 2 ----------\n");
296 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
nethercote31779c72004-07-30 21:50:15 +0000297 foreach_map(prmap, /*dummy*/NULL);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000298 }
299
nethercotea3c3cf22004-11-01 18:38:00 +0000300 jmp_with_stack(info.init_eip, (Addr)esp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000301}
302
nethercotec25c4492004-10-18 11:52:17 +0000303int main(int argc, char** argv)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000304{
fitzhardinge716c2c12004-03-09 00:57:45 +0000305 struct rlimit rlim;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000306 const char *cp = getenv(VALGRINDLIB);
307
308 if (cp != NULL)
309 valgrind_lib = cp;
310
nethercotec25c4492004-10-18 11:52:17 +0000311 // Initial stack pointer is to argc, which is immediately before argv[0]
nethercote41c75da2004-10-18 15:34:14 +0000312 // on the stack. Nb: Assumes argc is word-aligned.
nethercotec25c4492004-10-18 11:52:17 +0000313 init_sp = argv - 1;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000314
fitzhardinge716c2c12004-03-09 00:57:45 +0000315 /* Set the address space limit as high as it will go, since we make
316 a lot of very large mappings. */
317 getrlimit(RLIMIT_AS, &rlim);
318 rlim.rlim_cur = rlim.rlim_max;
319 setrlimit(RLIMIT_AS, &rlim);
320
fitzhardinge7e343cd2003-12-16 02:14:00 +0000321 /* move onto another stack so we can play with the main one */
nethercotea3c3cf22004-11-01 18:38:00 +0000322 jmp_with_stack((Addr)main2, (Addr)stack + sizeof(stack));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000323}
nethercotebb1c9912004-01-04 16:43:23 +0000324
325/*--------------------------------------------------------------------*/
326/*--- end stage1.c ---*/
327/*--------------------------------------------------------------------*/