blob: ce408d7986e0dc3ab2200de0313ce7a8f82ad991 [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];
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
57/* Modify the auxv the kernel gave us to make it look like we were
58 execed as the shared object.
59
60 This also inserts a new entry into the auxv table so we can
61 communicate some extra information to stage2 (namely, the fd of the
62 padding file, so it can identiry and remove the padding later).
63*/
nethercote31779c72004-07-30 21:50:15 +000064static void *fix_auxv(void *v_init_esp, const struct exeinfo *info,
65 int padfile)
fitzhardinge7e343cd2003-12-16 02:14:00 +000066{
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;
nethercote31779c72004-07-30 21:50:15 +000094 auxv[0].u.a_val = padfile;
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
nethercoteeda6b282004-06-15 08:34:10 +0000136#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
137#ifdef AT_SYSINFO
fitzhardingea1d37c02004-06-14 02:36:09 +0000138 case AT_SYSINFO:
nethercoteeda6b282004-06-15 08:34:10 +0000139#endif
nethercote079acf62004-06-14 11:56:59 +0000140#ifdef AT_SYSINFO_EHDR
fitzhardingea1d37c02004-06-14 02:36:09 +0000141 case AT_SYSINFO_EHDR:
nethercote079acf62004-06-14 11:56:59 +0000142#endif
fitzhardingea1d37c02004-06-14 02:36:09 +0000143 auxv->a_type = AT_IGNORE;
144 break;
nethercoteeda6b282004-06-15 08:34:10 +0000145#endif
fitzhardinge7e343cd2003-12-16 02:14:00 +0000146 }
147 }
148
149 /* If we didn't see all the entries we need to fix up, then we
150 can't make the new executable viable. */
151 if (seen != 0xf) {
152 fprintf(stderr, "fix_auxv: we didn't see enough auxv entries (seen=%x)\n", seen);
153 exit(1);
154 }
155
156 return v_init_esp;
157}
158
nethercote31779c72004-07-30 21:50:15 +0000159static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
160 int min, int ino, void* dummy) {
thughes4ad52d02004-06-27 17:37:21 +0000161 printf("mapping %10p-%10p %s %02x:%02x %d\n",
162 start, end, perm, maj, min, ino);
163 return 1;
164}
165
fitzhardinge7e343cd2003-12-16 02:14:00 +0000166static void hoops(void)
167{
nethercote31779c72004-07-30 21:50:15 +0000168 int err, padfile;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000169 struct exeinfo info;
170 extern char _end;
171 int *esp;
172 char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
173
174 info.exe_base = PGROUNDUP(&_end);
175 info.exe_end = PGROUNDDN(ume_exec_esp);
176
177 /* XXX FIXME: how can stage1 know where stage2 wants things placed?
178 Options:
179 - we could look for a symbol
180 - it could have a special PHDR (v. ELF specific)
181 - something else?
182 */
nethercotec314eba2004-07-15 12:59:41 +0000183 info.map_base = 0xb1000000;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000184 info.argv = NULL;
185
fitzhardingea49f9b52003-12-16 22:26:45 +0000186 snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000187
188 err = do_exec(buf, &info);
189
190 if (err != 0) {
191 fprintf(stderr, "failed to load %s: %s\n",
192 buf, strerror(err));
193 exit(1);
194 }
195
196 /* Make sure stage2's dynamic linker can't tromp on the lower part
197 of the address space. */
nethercote31779c72004-07-30 21:50:15 +0000198 padfile = as_openpadfile();
199 as_pad(0, (void *)info.map_base, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000200
nethercote31779c72004-07-30 21:50:15 +0000201 esp = fix_auxv(ume_exec_esp, &info, padfile);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000202
203 if (0) {
fitzhardinge7e343cd2003-12-16 02:14:00 +0000204 printf("---------- launch stage 2 ----------\n");
205 printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
nethercote31779c72004-07-30 21:50:15 +0000206 foreach_map(prmap, /*dummy*/NULL);
fitzhardinge7e343cd2003-12-16 02:14:00 +0000207 }
208
209 ume_go(info.init_eip, (addr_t)esp);
210}
211
212int main(int argc, char **argv)
213{
fitzhardinge716c2c12004-03-09 00:57:45 +0000214 struct rlimit rlim;
fitzhardinge7e343cd2003-12-16 02:14:00 +0000215 const char *cp = getenv(VALGRINDLIB);
216
217 if (cp != NULL)
218 valgrind_lib = cp;
219
220 assert(ume_exec_esp != NULL);
221
fitzhardinge716c2c12004-03-09 00:57:45 +0000222 /* Set the address space limit as high as it will go, since we make
223 a lot of very large mappings. */
224 getrlimit(RLIMIT_AS, &rlim);
225 rlim.rlim_cur = rlim.rlim_max;
226 setrlimit(RLIMIT_AS, &rlim);
227
fitzhardinge7e343cd2003-12-16 02:14:00 +0000228 /* move onto another stack so we can play with the main one */
229 ume_go((addr_t)hoops, (addr_t)stack + sizeof(stack));
230}
nethercotebb1c9912004-01-04 16:43:23 +0000231
232/*--------------------------------------------------------------------*/
233/*--- end stage1.c ---*/
234/*--------------------------------------------------------------------*/