blob: d056a1a161ac2479a868cb18cf7a21493a1c79da [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
49/* Where we expect to find all our aux files (namely, stage2) */
50static const char *valgrind_lib = VG_LIBDIR;
51
52/* stage2's name */
53static const char stage2[] = "stage2";
54
nethercote969ecf12004-10-13 17:29:01 +000055/*------------------------------------------------------------*/
56/*--- Auxv modification ---*/
57/*------------------------------------------------------------*/
58
fitzhardinge7e343cd2003-12-16 02:14:00 +000059/* Modify the auxv the kernel gave us to make it look like we were
60 execed as the shared object.
61
62 This also inserts a new entry into the auxv table so we can
63 communicate some extra information to stage2 (namely, the fd of the
64 padding file, so it can identiry and remove the padding later).
65*/
nethercote31779c72004-07-30 21:50:15 +000066static void *fix_auxv(void *v_init_esp, const struct exeinfo *info,
67 int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +000068{
69 struct ume_auxv *auxv;
70 int *newesp;
71 int seen;
72 int delta;
73 int i;
74 static const int new_entries = 2;
75
76 /* make sure we're running on the private stack */
77 assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]);
78
79 /* find the beginning of the AUXV table */
80 auxv = find_auxv(v_init_esp);
81
82 /* Work out how we should move things to make space for the new
83 auxv entry. It seems that ld.so wants a 16-byte aligned stack on
84 entry, so make sure that's the case. */
85 newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf);
86 delta = (char *)v_init_esp - (char *)newesp;
87
88 memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp);
89
90 v_init_esp = (void *)newesp;
91 auxv -= delta/sizeof(*auxv);
92
93 /* stage2 needs this so it can clean up the padding we leave in
94 place when we start it */
95 auxv[0].a_type = AT_UME_PADFD;
nethercote31779c72004-07-30 21:50:15 +000096 auxv[0].u.a_val = padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +000097
98 /* This will be needed by valgrind itself so that it can
99 subsequently execve() children. This needs to be done here
100 because /proc/self/exe will go away once we unmap stage1. */
101 auxv[1].a_type = AT_UME_EXECFD;
mueller5ed88f22004-01-06 16:02:29 +0000102 auxv[1].u.a_val = open("/proc/self/exe", O_RDONLY);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000103
104 /* make sure the rest are sane */
105 for(i = new_entries; i < delta/sizeof(*auxv); i++) {
106 auxv[i].a_type = AT_IGNORE;
mueller5ed88f22004-01-06 16:02:29 +0000107 auxv[i].u.a_val = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000108 }
109
110 /* OK, go through and patch up the auxv entries to match the new
111 executable */
112 seen = 0;
113 for(; auxv->a_type != AT_NULL; auxv++) {
114 if (0)
mueller5ed88f22004-01-06 16:02:29 +0000115 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 +0000116
117 switch(auxv->a_type) {
118 case AT_PHDR:
119 seen |= 1;
mueller5ed88f22004-01-06 16:02:29 +0000120 auxv->u.a_val = info->phdr;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000121 break;
122
123 case AT_PHNUM:
124 seen |= 2;
mueller5ed88f22004-01-06 16:02:29 +0000125 auxv->u.a_val = info->phnum;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000126 break;
127
128 case AT_BASE:
129 seen |= 4;
mueller5ed88f22004-01-06 16:02:29 +0000130 auxv->u.a_val = info->interp_base;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000131 break;
132
133 case AT_ENTRY:
134 seen |= 8;
mueller5ed88f22004-01-06 16:02:29 +0000135 auxv->u.a_val = info->entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000136 break;
fitzhardingea1d37c02004-06-14 02:36:09 +0000137
nethercoteeda6b282004-06-15 08:34:10 +0000138#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
139#ifdef AT_SYSINFO
fitzhardingea1d37c02004-06-14 02:36:09 +0000140 case AT_SYSINFO:
nethercoteeda6b282004-06-15 08:34:10 +0000141#endif
nethercote079acf62004-06-14 11:56:59 +0000142#ifdef AT_SYSINFO_EHDR
fitzhardingea1d37c02004-06-14 02:36:09 +0000143 case AT_SYSINFO_EHDR:
nethercote079acf62004-06-14 11:56:59 +0000144#endif
fitzhardingea1d37c02004-06-14 02:36:09 +0000145 auxv->a_type = AT_IGNORE;
146 break;
nethercoteeda6b282004-06-15 08:34:10 +0000147#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000148 }
149 }
150
151 /* If we didn't see all the entries we need to fix up, then we
152 can't make the new executable viable. */
153 if (seen != 0xf) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000154 fprintf(stderr, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000155 exit(1);
156 }
157
158 return v_init_esp;
159}
160
nethercote969ecf12004-10-13 17:29:01 +0000161
162/*------------------------------------------------------------*/
163/*--- Address space padding ---*/
164/*------------------------------------------------------------*/
165
166static void check_mmap(void* res, void* base, int len)
167{
168 if ((void*)-1 == res) {
169 fprintf(stderr, "valgrind: padding mmap(%p, %d) failed during startup.\n"
170 "valgrind: is there a hard virtual memory limit set?\n",
171 base, len);
172 exit(1);
173 }
174}
175
176typedef struct {
177 char* fillgap_start;
178 char* fillgap_end;
179 int fillgap_padfile;
180} fillgap_extra;
181
182static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
183 int maj, int min, int ino, void* e)
184{
185 fillgap_extra* extra = e;
186
187 if (segstart >= extra->fillgap_end)
188 return 0;
189
190 if (segstart > extra->fillgap_start) {
191 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
192 PROT_NONE, MAP_FIXED|MAP_PRIVATE,
193 extra->fillgap_padfile, 0);
194 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
195 }
196 extra->fillgap_start = segend;
197
198 return 1;
199}
200
201// Choose a name for the padfile, open it.
202int as_openpadfile(void)
203{
204 char buf[256];
205 int padfile;
206 int seq = 1;
207 do {
208 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
209 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
210 unlink(buf);
211 if (padfile == -1 && errno != EEXIST) {
212 fprintf(stderr, "valgrind: couldn't open padfile\n");
213 exit(44);
214 }
215 } while(padfile == -1);
216
217 return padfile;
218}
219
220// Pad all the empty spaces in a range of address space to stop interlopers.
221void as_pad(void *start, void *end, int padfile)
222{
223 fillgap_extra extra;
224 extra.fillgap_start = start;
225 extra.fillgap_end = end;
226 extra.fillgap_padfile = padfile;
227
228 foreach_map(fillgap, &extra);
229
230 if (extra.fillgap_start < extra.fillgap_end) {
231 void* res = mmap(extra.fillgap_start,
232 extra.fillgap_end - extra.fillgap_start,
233 PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
234 check_mmap(res, extra.fillgap_start,
235 extra.fillgap_end - extra.fillgap_start);
236 }
237}
238
239
240/*------------------------------------------------------------*/
241/*--- main() and related pieces ---*/
242/*------------------------------------------------------------*/
243
nethercote31779c72004-07-30 21:50:15 +0000244static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
245 int min, int ino, void* dummy) {
thughes4ad52d02004-06-27 17:37:21 +0000246 printf("mapping %10p-%10p %s %02x:%02x %d\n",
247 start, end, perm, maj, min, ino);
248 return 1;
249}
250
fitzhardinge7e343cd2003-12-16 02:14:00 +0000251static void hoops(void)
252{
nethercote31779c72004-07-30 21:50:15 +0000253 int err, padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000254 struct exeinfo info;
255 extern char _end;
256 int *esp;
257 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
258
259 info.exe_base = PGROUNDUP(&_end);
260 info.exe_end = PGROUNDDN(ume_exec_esp);
261
262 /* XXX FIXME: how can stage1 know where stage2 wants things placed?
263 Options:
264 - we could look for a symbol
265 - it could have a special PHDR (v. ELF specific)
266 - something else?
267 */
nethercoteb669ef72004-08-25 16:16:56 +0000268 info.map_base = KICKSTART_BASE + 0x01000000;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000269 info.argv = NULL;
270
fitzhardingea49f9b52003-12-16 22:26:45 +0000271 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000272
273 err = do_exec(buf, &info);
274
275 if (err != 0) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000276 fprintf(stderr, "valgrind: failed to load %s: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000277 buf, strerror(err));
278 exit(1);
279 }
280
281 /* Make sure stage2's dynamic linker can't tromp on the lower part
282 of the address space. */
nethercote31779c72004-07-30 21:50:15 +0000283 padfile = as_openpadfile();
284 as_pad(0, (void *)info.map_base, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000285
nethercote31779c72004-07-30 21:50:15 +0000286 esp = fix_auxv(ume_exec_esp, &info, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000287
288 if (0) {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289 printf("---------- launch stage 2 ----------\n");
290 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
nethercote31779c72004-07-30 21:50:15 +0000291 foreach_map(prmap, /*dummy*/NULL);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000292 }
293
nethercote107e1c02004-10-13 17:55:31 +0000294 jmp_with_stack(info.init_eip, (addr_t)esp);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000295}
296
nethercoteb24cbc82004-09-03 23:25:33 +0000297int main(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000298{
fitzhardinge716c2c12004-03-09 00:57:45 +0000299 struct rlimit rlim;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300 const char *cp = getenv(VALGRINDLIB);
301
302 if (cp != NULL)
303 valgrind_lib = cp;
304
305 assert(ume_exec_esp != NULL);
306
fitzhardinge716c2c12004-03-09 00:57:45 +0000307 /* Set the address space limit as high as it will go, since we make
308 a lot of very large mappings. */
309 getrlimit(RLIMIT_AS, &rlim);
310 rlim.rlim_cur = rlim.rlim_max;
311 setrlimit(RLIMIT_AS, &rlim);
312
fitzhardinge7e343cd2003-12-16 02:14:00 +0000313 /* move onto another stack so we can play with the main one */
nethercote107e1c02004-10-13 17:55:31 +0000314 jmp_with_stack((addr_t)hoops, (addr_t)stack + sizeof(stack));
fitzhardinge7e343cd2003-12-16 02:14:00 +0000315}
nethercotebb1c9912004-01-04 16:43:23 +0000316
317/*--------------------------------------------------------------------*/
318/*--- end stage1.c ---*/
319/*--------------------------------------------------------------------*/