blob: 389e2c65fcff44cd08d37f5cc2ff16e4305b4ecb [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
33#include <stdio.h>
34#include <elf.h>
35#include <string.h>
36#include <stdlib.h>
37#include <assert.h>
38#include <signal.h>
39#include <fcntl.h>
40#include <errno.h>
fitzhardinge716c2c12004-03-09 00:57:45 +000041#include <sys/resource.h>
fitzhardinge7e343cd2003-12-16 02:14:00 +000042
43#include "vg_include.h"
44
45#include "ume.h"
46#include "ume_arch.h"
47#include "ume_archdefs.h"
48
49static int stack[SIGSTKSZ*4];
50static int our_argc;
51
52/* 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
58/* Modify the auxv the kernel gave us to make it look like we were
59 execed as the shared object.
60
61 This also inserts a new entry into the auxv table so we can
62 communicate some extra information to stage2 (namely, the fd of the
63 padding file, so it can identiry and remove the padding later).
64*/
65static void *fix_auxv(void *v_init_esp, const struct exeinfo *info)
66{
67 struct ume_auxv *auxv;
68 int *newesp;
69 int seen;
70 int delta;
71 int i;
72 static const int new_entries = 2;
73
74 /* make sure we're running on the private stack */
75 assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]);
76
77 /* find the beginning of the AUXV table */
78 auxv = find_auxv(v_init_esp);
79
80 /* Work out how we should move things to make space for the new
81 auxv entry. It seems that ld.so wants a 16-byte aligned stack on
82 entry, so make sure that's the case. */
83 newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf);
84 delta = (char *)v_init_esp - (char *)newesp;
85
86 memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp);
87
88 v_init_esp = (void *)newesp;
89 auxv -= delta/sizeof(*auxv);
90
91 /* stage2 needs this so it can clean up the padding we leave in
92 place when we start it */
93 auxv[0].a_type = AT_UME_PADFD;
mueller5ed88f22004-01-06 16:02:29 +000094 auxv[0].u.a_val = as_getpadfd();
fitzhardinge7e343cd2003-12-16 02:14:00 +000095
96 /* This will be needed by valgrind itself so that it can
97 subsequently execve() children. This needs to be done here
98 because /proc/self/exe will go away once we unmap stage1. */
99 auxv[1].a_type = AT_UME_EXECFD;
mueller5ed88f22004-01-06 16:02:29 +0000100 auxv[1].u.a_val = open("/proc/self/exe", O_RDONLY);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000101
102 /* make sure the rest are sane */
103 for(i = new_entries; i < delta/sizeof(*auxv); i++) {
104 auxv[i].a_type = AT_IGNORE;
mueller5ed88f22004-01-06 16:02:29 +0000105 auxv[i].u.a_val = 0;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000106 }
107
108 /* OK, go through and patch up the auxv entries to match the new
109 executable */
110 seen = 0;
111 for(; auxv->a_type != AT_NULL; auxv++) {
112 if (0)
mueller5ed88f22004-01-06 16:02:29 +0000113 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 +0000114
115 switch(auxv->a_type) {
116 case AT_PHDR:
117 seen |= 1;
mueller5ed88f22004-01-06 16:02:29 +0000118 auxv->u.a_val = info->phdr;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000119 break;
120
121 case AT_PHNUM:
122 seen |= 2;
mueller5ed88f22004-01-06 16:02:29 +0000123 auxv->u.a_val = info->phnum;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000124 break;
125
126 case AT_BASE:
127 seen |= 4;
mueller5ed88f22004-01-06 16:02:29 +0000128 auxv->u.a_val = info->interp_base;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000129 break;
130
131 case AT_ENTRY:
132 seen |= 8;
mueller5ed88f22004-01-06 16:02:29 +0000133 auxv->u.a_val = info->entry;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000134 break;
fitzhardingea1d37c02004-06-14 02:36:09 +0000135
136 case AT_SYSINFO:
137 case AT_SYSINFO_EHDR:
138 auxv->a_type = AT_IGNORE;
139 break;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000140 }
141 }
142
143 /* If we didn't see all the entries we need to fix up, then we
144 can't make the new executable viable. */
145 if (seen != 0xf) {
146 fprintf(stderr, "fix_auxv: we didn't see enough auxv entries (seen=%x)\n", seen);
147 exit(1);
148 }
149
150 return v_init_esp;
151}
152
153static void hoops(void)
154{
155 int err;
156 struct exeinfo info;
157 extern char _end;
158 int *esp;
159 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
160
161 info.exe_base = PGROUNDUP(&_end);
162 info.exe_end = PGROUNDDN(ume_exec_esp);
163
164 /* XXX FIXME: how can stage1 know where stage2 wants things placed?
165 Options:
166 - we could look for a symbol
167 - it could have a special PHDR (v. ELF specific)
168 - something else?
169 */
170 info.map_base = 0xb0000000;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000171 info.argv = NULL;
172
fitzhardingea49f9b52003-12-16 22:26:45 +0000173 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000174
175 err = do_exec(buf, &info);
176
177 if (err != 0) {
178 fprintf(stderr, "failed to load %s: %s\n",
179 buf, strerror(err));
180 exit(1);
181 }
182
183 /* Make sure stage2's dynamic linker can't tromp on the lower part
184 of the address space. */
185 as_pad(0, (void *)info.map_base);
186
187 esp = fix_auxv(ume_exec_esp, &info);
188
189 if (0) {
190 int prmap(void *start, void *end, const char *perm, off_t off, int maj, int min, int ino) {
191 printf("mapping %10p-%10p %s %02x:%02x %d\n",
192 start, end, perm, maj, min, ino);
193 return 1;
194 }
195 printf("---------- launch stage 2 ----------\n");
196 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
197 foreach_map(prmap);
198 }
199
200 ume_go(info.init_eip, (addr_t)esp);
201}
202
203int main(int argc, char **argv)
204{
fitzhardinge716c2c12004-03-09 00:57:45 +0000205 struct rlimit rlim;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000206 const char *cp = getenv(VALGRINDLIB);
207
208 if (cp != NULL)
209 valgrind_lib = cp;
210
211 assert(ume_exec_esp != NULL);
212
213 our_argc = argc;
214
fitzhardinge716c2c12004-03-09 00:57:45 +0000215 /* Set the address space limit as high as it will go, since we make
216 a lot of very large mappings. */
217 getrlimit(RLIMIT_AS, &rlim);
218 rlim.rlim_cur = rlim.rlim_max;
219 setrlimit(RLIMIT_AS, &rlim);
220
fitzhardinge7e343cd2003-12-16 02:14:00 +0000221 /* move onto another stack so we can play with the main one */
222 ume_go((addr_t)hoops, (addr_t)stack + sizeof(stack));
223}
nethercotebb1c9912004-01-04 16:43:23 +0000224
225/*--------------------------------------------------------------------*/
226/*--- end stage1.c ---*/
227/*--------------------------------------------------------------------*/