blob: c2ce3765223b14b1d0d27fef75ec3af5fe755d37 [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/*
njnb9c427c2004-12-01 14:14:42 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
jseward2886b0e2004-01-04 03:46:11 +00009
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
jseward2886b0e2004-01-04 03:46:11 +000011 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"
sewardjb5f6f512005-03-10 23:59:00 +000046#include "memcheck/memcheck.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000047
48static int stack[SIGSTKSZ*4];
fitzhardinge7e343cd2003-12-16 02:14:00 +000049
nethercotec25c4492004-10-18 11:52:17 +000050// Initial stack pointer, which points to argc.
51static void* init_sp;
52
fitzhardinge7e343cd2003-12-16 02:14:00 +000053/* Where we expect to find all our aux files (namely, stage2) */
54static const char *valgrind_lib = VG_LIBDIR;
55
56/* stage2's name */
57static const char stage2[] = "stage2";
58
nethercote969ecf12004-10-13 17:29:01 +000059/*------------------------------------------------------------*/
60/*--- Auxv modification ---*/
61/*------------------------------------------------------------*/
62
fitzhardinge7e343cd2003-12-16 02:14:00 +000063/* Modify the auxv the kernel gave us to make it look like we were
64 execed as the shared object.
65
66 This also inserts a new entry into the auxv table so we can
67 communicate some extra information to stage2 (namely, the fd of the
68 padding file, so it can identiry and remove the padding later).
69*/
nethercote31779c72004-07-30 21:50:15 +000070static void *fix_auxv(void *v_init_esp, const struct exeinfo *info,
71 int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +000072{
73 struct ume_auxv *auxv;
74 int *newesp;
75 int seen;
76 int delta;
77 int i;
78 static const int new_entries = 2;
79
80 /* make sure we're running on the private stack */
81 assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]);
82
83 /* find the beginning of the AUXV table */
84 auxv = find_auxv(v_init_esp);
85
86 /* Work out how we should move things to make space for the new
87 auxv entry. It seems that ld.so wants a 16-byte aligned stack on
88 entry, so make sure that's the case. */
89 newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf);
90 delta = (char *)v_init_esp - (char *)newesp;
91
92 memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp);
93
94 v_init_esp = (void *)newesp;
95 auxv -= delta/sizeof(*auxv);
96
97 /* stage2 needs this so it can clean up the padding we leave in
98 place when we start it */
99 auxv[0].a_type = AT_UME_PADFD;
nethercote31779c72004-07-30 21:50:15 +0000100 auxv[0].u.a_val = padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000101
102 /* This will be needed by valgrind itself so that it can
103 subsequently execve() children. This needs to be done here
104 because /proc/self/exe will go away once we unmap stage1. */
105 auxv[1].a_type = AT_UME_EXECFD;
mueller5ed88f22004-01-06 16:02:29 +0000106 auxv[1].u.a_val = open("/proc/self/exe", O_RDONLY);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000107
108 /* make sure the rest are sane */
109 for(i = new_entries; i < delta/sizeof(*auxv); i++) {
110 auxv[i].a_type = AT_IGNORE;
mueller5ed88f22004-01-06 16:02:29 +0000111 auxv[i].u.a_val = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000112 }
113
114 /* OK, go through and patch up the auxv entries to match the new
115 executable */
116 seen = 0;
117 for(; auxv->a_type != AT_NULL; auxv++) {
118 if (0)
sewardjb5f6f512005-03-10 23:59:00 +0000119 printf("doing auxv %p %5lld: %lld %p\n",
120 auxv, (Long)auxv->a_type, (Long)auxv->u.a_val, auxv->u.a_ptr);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000121
122 switch(auxv->a_type) {
123 case AT_PHDR:
124 seen |= 1;
mueller5ed88f22004-01-06 16:02:29 +0000125 auxv->u.a_val = info->phdr;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000126 break;
127
128 case AT_PHNUM:
129 seen |= 2;
mueller5ed88f22004-01-06 16:02:29 +0000130 auxv->u.a_val = info->phnum;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000131 break;
132
133 case AT_BASE:
134 seen |= 4;
mueller5ed88f22004-01-06 16:02:29 +0000135 auxv->u.a_val = info->interp_base;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000136 break;
137
138 case AT_ENTRY:
139 seen |= 8;
mueller5ed88f22004-01-06 16:02:29 +0000140 auxv->u.a_val = info->entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000141 break;
fitzhardingea1d37c02004-06-14 02:36:09 +0000142
nethercoteeda6b282004-06-15 08:34:10 +0000143#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
144#ifdef AT_SYSINFO
fitzhardingea1d37c02004-06-14 02:36:09 +0000145 case AT_SYSINFO:
nethercoteeda6b282004-06-15 08:34:10 +0000146#endif
nethercote079acf62004-06-14 11:56:59 +0000147#ifdef AT_SYSINFO_EHDR
fitzhardingea1d37c02004-06-14 02:36:09 +0000148 case AT_SYSINFO_EHDR:
nethercote079acf62004-06-14 11:56:59 +0000149#endif
fitzhardingea1d37c02004-06-14 02:36:09 +0000150 auxv->a_type = AT_IGNORE;
151 break;
nethercoteeda6b282004-06-15 08:34:10 +0000152#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000153 }
154 }
155
156 /* If we didn't see all the entries we need to fix up, then we
157 can't make the new executable viable. */
158 if (seen != 0xf) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000159 fprintf(stderr, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000160 exit(1);
161 }
162
163 return v_init_esp;
164}
165
nethercote969ecf12004-10-13 17:29:01 +0000166
167/*------------------------------------------------------------*/
168/*--- Address space padding ---*/
169/*------------------------------------------------------------*/
170
171static void check_mmap(void* res, void* base, int len)
172{
173 if ((void*)-1 == res) {
174 fprintf(stderr, "valgrind: padding mmap(%p, %d) failed during startup.\n"
175 "valgrind: is there a hard virtual memory limit set?\n",
176 base, len);
177 exit(1);
178 }
179}
180
181typedef struct {
182 char* fillgap_start;
183 char* fillgap_end;
184 int fillgap_padfile;
185} fillgap_extra;
186
187static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
188 int maj, int min, int ino, void* e)
189{
190 fillgap_extra* extra = e;
191
192 if (segstart >= extra->fillgap_end)
193 return 0;
194
195 if (segstart > extra->fillgap_start) {
196 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
197 PROT_NONE, MAP_FIXED|MAP_PRIVATE,
198 extra->fillgap_padfile, 0);
199 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
200 }
201 extra->fillgap_start = segend;
202
203 return 1;
204}
205
206// Choose a name for the padfile, open it.
sewardj2c5ffbe2005-03-12 13:32:06 +0000207static
nethercote969ecf12004-10-13 17:29:01 +0000208int as_openpadfile(void)
209{
210 char buf[256];
211 int padfile;
212 int seq = 1;
213 do {
214 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
215 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
216 unlink(buf);
217 if (padfile == -1 && errno != EEXIST) {
218 fprintf(stderr, "valgrind: couldn't open padfile\n");
219 exit(44);
220 }
221 } while(padfile == -1);
222
223 return padfile;
224}
225
226// Pad all the empty spaces in a range of address space to stop interlopers.
sewardj2c5ffbe2005-03-12 13:32:06 +0000227static
nethercote969ecf12004-10-13 17:29:01 +0000228void as_pad(void *start, void *end, int padfile)
229{
230 fillgap_extra extra;
231 extra.fillgap_start = start;
232 extra.fillgap_end = end;
233 extra.fillgap_padfile = padfile;
234
235 foreach_map(fillgap, &extra);
236
237 if (extra.fillgap_start < extra.fillgap_end) {
238 void* res = mmap(extra.fillgap_start,
239 extra.fillgap_end - extra.fillgap_start,
240 PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
241 check_mmap(res, extra.fillgap_start,
242 extra.fillgap_end - extra.fillgap_start);
243 }
244}
245
246
247/*------------------------------------------------------------*/
248/*--- main() and related pieces ---*/
249/*------------------------------------------------------------*/
250
nethercote31779c72004-07-30 21:50:15 +0000251static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
252 int min, int ino, void* dummy) {
thughes4ad52d02004-06-27 17:37:21 +0000253 printf("mapping %10p-%10p %s %02x:%02x %d\n",
254 start, end, perm, maj, min, ino);
255 return 1;
256}
257
sewardj7f082a62005-03-22 01:55:35 +0000258
nethercote9d072422004-10-13 17:58:36 +0000259static void main2(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000260{
nethercote31779c72004-07-30 21:50:15 +0000261 int err, padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000262 struct exeinfo info;
263 extern char _end;
264 int *esp;
265 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
nethercote5462ef72004-10-26 17:03:54 +0000266 info.exe_end = PGROUNDDN(init_sp);
nethercote7f390022004-10-25 17:18:24 +0000267#ifdef HAVE_PIE
268 info.exe_base = ROUNDDN(info.exe_end - 0x02000000, 0x10000000);
269 assert(info.exe_base >= PGROUNDUP(&_end));
270 info.map_base = info.exe_base + 0x01000000;
271#else
nethercote7f390022004-10-25 17:18:24 +0000272 // If this system doesn't have PIE (position-independent executables),
273 // we have to choose a hardwired location for stage2.
fitzhardinge7e343cd2003-12-16 02:14:00 +0000274 info.exe_base = PGROUNDUP(&_end);
nethercote7f390022004-10-25 17:18:24 +0000275 info.map_base = KICKSTART_BASE + 0x01000000;
276#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277
fitzhardinge7e343cd2003-12-16 02:14:00 +0000278 info.argv = NULL;
279
fitzhardingea49f9b52003-12-16 22:26:45 +0000280 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000281
282 err = do_exec(buf, &info);
283
284 if (err != 0) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000285 fprintf(stderr, "valgrind: failed to load %s: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000286 buf, strerror(err));
287 exit(1);
288 }
289
290 /* Make sure stage2's dynamic linker can't tromp on the lower part
291 of the address space. */
nethercote31779c72004-07-30 21:50:15 +0000292 padfile = as_openpadfile();
293 as_pad(0, (void *)info.map_base, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000294
nethercotec25c4492004-10-18 11:52:17 +0000295 esp = fix_auxv(init_sp, &info, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000296
297 if (0) {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000298 printf("---------- launch stage 2 ----------\n");
299 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
nethercote31779c72004-07-30 21:50:15 +0000300 foreach_map(prmap, /*dummy*/NULL);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000301 }
302
sewardj7f082a62005-03-22 01:55:35 +0000303 jump_and_switch_stacks(
304 (Addr) esp, /* stack */
305 (Addr) info.init_eip /* where to */
306 );
307
308 /*NOTREACHED*/
309 assert(0);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000310}
311
sewardj7f082a62005-03-22 01:55:35 +0000312
nethercotec25c4492004-10-18 11:52:17 +0000313int main(int argc, char** argv)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000314{
fitzhardinge716c2c12004-03-09 00:57:45 +0000315 struct rlimit rlim;
sewardjb5f6f512005-03-10 23:59:00 +0000316 const char *cp;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000317
nethercotec25c4492004-10-18 11:52:17 +0000318 // Initial stack pointer is to argc, which is immediately before argv[0]
nethercote41c75da2004-10-18 15:34:14 +0000319 // on the stack. Nb: Assumes argc is word-aligned.
nethercotec25c4492004-10-18 11:52:17 +0000320 init_sp = argv - 1;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000321
sewardjb5f6f512005-03-10 23:59:00 +0000322 /* The Linux libc startup sequence leaves this in an apparently
323 undefined state, but it really is defined, so mark it so. */
324 VALGRIND_MAKE_READABLE(init_sp, sizeof(int));
325
326 cp = getenv(VALGRINDLIB);
327
328 if (cp != NULL)
329 valgrind_lib = cp;
330
fitzhardinge716c2c12004-03-09 00:57:45 +0000331 /* Set the address space limit as high as it will go, since we make
332 a lot of very large mappings. */
333 getrlimit(RLIMIT_AS, &rlim);
334 rlim.rlim_cur = rlim.rlim_max;
335 setrlimit(RLIMIT_AS, &rlim);
336
fitzhardinge7e343cd2003-12-16 02:14:00 +0000337 /* move onto another stack so we can play with the main one */
sewardj7f082a62005-03-22 01:55:35 +0000338 jump_and_switch_stacks(
sewardj957ef8d2005-03-22 02:03:09 +0000339 (Addr) stack + sizeof(stack), /* stack */
340 (Addr) main2 /* where to */
sewardj7f082a62005-03-22 01:55:35 +0000341 );
342
343 /*NOTREACHED*/
344 assert(0);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000345}
nethercotebb1c9912004-01-04 16:43:23 +0000346
347/*--------------------------------------------------------------------*/
348/*--- end stage1.c ---*/
349/*--------------------------------------------------------------------*/