blob: 6e8d56dc9c97749f55b02cdef4694d4bd2b3b92e [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
46#include "ume.h"
47#include "ume_arch.h"
fitzhardinge7e343cd2003-12-16 02:14:00 +000048
49static int stack[SIGSTKSZ*4];
fitzhardinge7e343cd2003-12-16 02:14:00 +000050
51/* Where we expect to find all our aux files (namely, stage2) */
52static const char *valgrind_lib = VG_LIBDIR;
53
54/* stage2's name */
55static const char stage2[] = "stage2";
56
nethercote969ecf12004-10-13 17:29:01 +000057/*------------------------------------------------------------*/
58/*--- Auxv modification ---*/
59/*------------------------------------------------------------*/
60
fitzhardinge7e343cd2003-12-16 02:14:00 +000061/* Modify the auxv the kernel gave us to make it look like we were
62 execed as the shared object.
63
64 This also inserts a new entry into the auxv table so we can
65 communicate some extra information to stage2 (namely, the fd of the
66 padding file, so it can identiry and remove the padding later).
67*/
nethercote31779c72004-07-30 21:50:15 +000068static void *fix_auxv(void *v_init_esp, const struct exeinfo *info,
69 int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +000070{
71 struct ume_auxv *auxv;
72 int *newesp;
73 int seen;
74 int delta;
75 int i;
76 static const int new_entries = 2;
77
78 /* make sure we're running on the private stack */
79 assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]);
80
81 /* find the beginning of the AUXV table */
82 auxv = find_auxv(v_init_esp);
83
84 /* Work out how we should move things to make space for the new
85 auxv entry. It seems that ld.so wants a 16-byte aligned stack on
86 entry, so make sure that's the case. */
87 newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf);
88 delta = (char *)v_init_esp - (char *)newesp;
89
90 memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp);
91
92 v_init_esp = (void *)newesp;
93 auxv -= delta/sizeof(*auxv);
94
95 /* stage2 needs this so it can clean up the padding we leave in
96 place when we start it */
97 auxv[0].a_type = AT_UME_PADFD;
nethercote31779c72004-07-30 21:50:15 +000098 auxv[0].u.a_val = padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +000099
100 /* This will be needed by valgrind itself so that it can
101 subsequently execve() children. This needs to be done here
102 because /proc/self/exe will go away once we unmap stage1. */
103 auxv[1].a_type = AT_UME_EXECFD;
mueller5ed88f22004-01-06 16:02:29 +0000104 auxv[1].u.a_val = open("/proc/self/exe", O_RDONLY);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000105
106 /* make sure the rest are sane */
107 for(i = new_entries; i < delta/sizeof(*auxv); i++) {
108 auxv[i].a_type = AT_IGNORE;
mueller5ed88f22004-01-06 16:02:29 +0000109 auxv[i].u.a_val = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000110 }
111
112 /* OK, go through and patch up the auxv entries to match the new
113 executable */
114 seen = 0;
115 for(; auxv->a_type != AT_NULL; auxv++) {
116 if (0)
mueller5ed88f22004-01-06 16:02:29 +0000117 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 +0000118
119 switch(auxv->a_type) {
120 case AT_PHDR:
121 seen |= 1;
mueller5ed88f22004-01-06 16:02:29 +0000122 auxv->u.a_val = info->phdr;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000123 break;
124
125 case AT_PHNUM:
126 seen |= 2;
mueller5ed88f22004-01-06 16:02:29 +0000127 auxv->u.a_val = info->phnum;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000128 break;
129
130 case AT_BASE:
131 seen |= 4;
mueller5ed88f22004-01-06 16:02:29 +0000132 auxv->u.a_val = info->interp_base;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000133 break;
134
135 case AT_ENTRY:
136 seen |= 8;
mueller5ed88f22004-01-06 16:02:29 +0000137 auxv->u.a_val = info->entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000138 break;
fitzhardingea1d37c02004-06-14 02:36:09 +0000139
nethercoteeda6b282004-06-15 08:34:10 +0000140#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
141#ifdef AT_SYSINFO
fitzhardingea1d37c02004-06-14 02:36:09 +0000142 case AT_SYSINFO:
nethercoteeda6b282004-06-15 08:34:10 +0000143#endif
nethercote079acf62004-06-14 11:56:59 +0000144#ifdef AT_SYSINFO_EHDR
fitzhardingea1d37c02004-06-14 02:36:09 +0000145 case AT_SYSINFO_EHDR:
nethercote079acf62004-06-14 11:56:59 +0000146#endif
fitzhardingea1d37c02004-06-14 02:36:09 +0000147 auxv->a_type = AT_IGNORE;
148 break;
nethercoteeda6b282004-06-15 08:34:10 +0000149#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000150 }
151 }
152
153 /* If we didn't see all the entries we need to fix up, then we
154 can't make the new executable viable. */
155 if (seen != 0xf) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000156 fprintf(stderr, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000157 exit(1);
158 }
159
160 return v_init_esp;
161}
162
nethercote969ecf12004-10-13 17:29:01 +0000163
164/*------------------------------------------------------------*/
165/*--- Address space padding ---*/
166/*------------------------------------------------------------*/
167
168static void check_mmap(void* res, void* base, int len)
169{
170 if ((void*)-1 == res) {
171 fprintf(stderr, "valgrind: padding mmap(%p, %d) failed during startup.\n"
172 "valgrind: is there a hard virtual memory limit set?\n",
173 base, len);
174 exit(1);
175 }
176}
177
178typedef struct {
179 char* fillgap_start;
180 char* fillgap_end;
181 int fillgap_padfile;
182} fillgap_extra;
183
184static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
185 int maj, int min, int ino, void* e)
186{
187 fillgap_extra* extra = e;
188
189 if (segstart >= extra->fillgap_end)
190 return 0;
191
192 if (segstart > extra->fillgap_start) {
193 void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
194 PROT_NONE, MAP_FIXED|MAP_PRIVATE,
195 extra->fillgap_padfile, 0);
196 check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
197 }
198 extra->fillgap_start = segend;
199
200 return 1;
201}
202
203// Choose a name for the padfile, open it.
204int as_openpadfile(void)
205{
206 char buf[256];
207 int padfile;
208 int seq = 1;
209 do {
210 snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
211 padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
212 unlink(buf);
213 if (padfile == -1 && errno != EEXIST) {
214 fprintf(stderr, "valgrind: couldn't open padfile\n");
215 exit(44);
216 }
217 } while(padfile == -1);
218
219 return padfile;
220}
221
222// Pad all the empty spaces in a range of address space to stop interlopers.
223void as_pad(void *start, void *end, int padfile)
224{
225 fillgap_extra extra;
226 extra.fillgap_start = start;
227 extra.fillgap_end = end;
228 extra.fillgap_padfile = padfile;
229
230 foreach_map(fillgap, &extra);
231
232 if (extra.fillgap_start < extra.fillgap_end) {
233 void* res = mmap(extra.fillgap_start,
234 extra.fillgap_end - extra.fillgap_start,
235 PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
236 check_mmap(res, extra.fillgap_start,
237 extra.fillgap_end - extra.fillgap_start);
238 }
239}
240
241
242/*------------------------------------------------------------*/
243/*--- main() and related pieces ---*/
244/*------------------------------------------------------------*/
245
nethercote31779c72004-07-30 21:50:15 +0000246static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
247 int min, int ino, void* dummy) {
thughes4ad52d02004-06-27 17:37:21 +0000248 printf("mapping %10p-%10p %s %02x:%02x %d\n",
249 start, end, perm, maj, min, ino);
250 return 1;
251}
252
fitzhardinge7e343cd2003-12-16 02:14:00 +0000253static void hoops(void)
254{
nethercote31779c72004-07-30 21:50:15 +0000255 int err, padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000256 struct exeinfo info;
257 extern char _end;
258 int *esp;
259 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
260
261 info.exe_base = PGROUNDUP(&_end);
262 info.exe_end = PGROUNDDN(ume_exec_esp);
263
264 /* XXX FIXME: how can stage1 know where stage2 wants things placed?
265 Options:
266 - we could look for a symbol
267 - it could have a special PHDR (v. ELF specific)
268 - something else?
269 */
nethercoteb669ef72004-08-25 16:16:56 +0000270 info.map_base = KICKSTART_BASE + 0x01000000;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000271 info.argv = NULL;
272
fitzhardingea49f9b52003-12-16 22:26:45 +0000273 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000274
275 err = do_exec(buf, &info);
276
277 if (err != 0) {
nethercote2e1cb4c2004-08-05 12:16:13 +0000278 fprintf(stderr, "valgrind: failed to load %s: %s\n",
fitzhardinge7e343cd2003-12-16 02:14:00 +0000279 buf, strerror(err));
280 exit(1);
281 }
282
283 /* Make sure stage2's dynamic linker can't tromp on the lower part
284 of the address space. */
nethercote31779c72004-07-30 21:50:15 +0000285 padfile = as_openpadfile();
286 as_pad(0, (void *)info.map_base, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000287
nethercote31779c72004-07-30 21:50:15 +0000288 esp = fix_auxv(ume_exec_esp, &info, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000289
290 if (0) {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000291 printf("---------- launch stage 2 ----------\n");
292 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
nethercote31779c72004-07-30 21:50:15 +0000293 foreach_map(prmap, /*dummy*/NULL);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000294 }
295
296 ume_go(info.init_eip, (addr_t)esp);
297}
298
nethercoteb24cbc82004-09-03 23:25:33 +0000299int main(void)
fitzhardinge7e343cd2003-12-16 02:14:00 +0000300{
fitzhardinge716c2c12004-03-09 00:57:45 +0000301 struct rlimit rlim;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000302 const char *cp = getenv(VALGRINDLIB);
303
304 if (cp != NULL)
305 valgrind_lib = cp;
306
307 assert(ume_exec_esp != NULL);
308
fitzhardinge716c2c12004-03-09 00:57:45 +0000309 /* Set the address space limit as high as it will go, since we make
310 a lot of very large mappings. */
311 getrlimit(RLIMIT_AS, &rlim);
312 rlim.rlim_cur = rlim.rlim_max;
313 setrlimit(RLIMIT_AS, &rlim);
314
fitzhardinge7e343cd2003-12-16 02:14:00 +0000315 /* move onto another stack so we can play with the main one */
316 ume_go((addr_t)hoops, (addr_t)stack + sizeof(stack));
317}
nethercotebb1c9912004-01-04 16:43:23 +0000318
319/*--------------------------------------------------------------------*/
320/*--- end stage1.c ---*/
321/*--------------------------------------------------------------------*/