jseward | 2886b0e | 2004-01-04 03:46:11 +0000 | [diff] [blame] | 1 | |
nethercote | bb1c991 | 2004-01-04 16:43:23 +0000 | [diff] [blame] | 2 | /*--------------------------------------------------------------------*/ |
nethercote | 107e1c0 | 2004-10-13 17:55:31 +0000 | [diff] [blame] | 3 | /*--- User-mode execve(), and other stuff shared between stage1 ---*/ |
njn | 08a2e17 | 2005-06-21 22:47:54 +0000 | [diff] [blame] | 4 | /*--- and stage2. m_ume.c ---*/ |
nethercote | bb1c991 | 2004-01-04 16:43:23 +0000 | [diff] [blame] | 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
jseward | 2886b0e | 2004-01-04 03:46:11 +0000 | [diff] [blame] | 7 | /* |
njn | b9c427c | 2004-12-01 14:14:42 +0000 | [diff] [blame] | 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
jseward | 2886b0e | 2004-01-04 03:46:11 +0000 | [diff] [blame] | 10 | |
njn | 5361242 | 2005-03-12 16:22:54 +0000 | [diff] [blame] | 11 | Copyright (C) 2000-2005 Julian Seward |
jseward | 2886b0e | 2004-01-04 03:46:11 +0000 | [diff] [blame] | 12 | jseward@acm.org |
| 13 | |
| 14 | This program is free software; you can redistribute it and/or |
| 15 | modify it under the terms of the GNU General Public License as |
| 16 | published by the Free Software Foundation; either version 2 of the |
| 17 | License, or (at your option) any later version. |
| 18 | |
| 19 | This program is distributed in the hope that it will be useful, but |
| 20 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 22 | General Public License for more details. |
| 23 | |
| 24 | You should have received a copy of the GNU General Public License |
| 25 | along with this program; if not, write to the Free Software |
| 26 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 27 | 02111-1307, USA. |
| 28 | |
| 29 | The GNU General Public License is contained in the file COPYING. |
| 30 | */ |
| 31 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 32 | |
| 33 | #define _GNU_SOURCE |
| 34 | #define _FILE_OFFSET_BITS 64 |
| 35 | |
njn | f844cb6 | 2005-06-19 16:07:49 +0000 | [diff] [blame] | 36 | // It seems that on SuSE 9.1 (x86) something in <fcntl.h> messes up stuff |
| 37 | // acquired indirectly from vki-x86-linux.h. Therefore our headers must be |
| 38 | // included ahead of the glibc ones. This fix is a kludge; the right |
| 39 | // solution is to entirely remove the glibc dependency. |
sewardj | 4b0c071 | 2005-06-19 15:58:33 +0000 | [diff] [blame] | 40 | #include "pub_core_basics.h" |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 41 | #include "pub_core_aspacemgr.h" // various mapping fns |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 42 | #include "pub_core_debuglog.h" |
sewardj | 4b0c071 | 2005-06-19 15:58:33 +0000 | [diff] [blame] | 43 | #include "pub_core_libcbase.h" |
| 44 | #include "pub_core_machine.h" |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 45 | #include "pub_core_libcprint.h" |
| 46 | #include "pub_core_libcfile.h" // VG_(close) et al |
| 47 | #include "pub_core_libcproc.h" // VG_(geteuid), VG_(getegid) |
| 48 | #include "pub_core_libcassert.h" // VG_(exit), vg_assert |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 49 | #include "pub_core_mallocfree.h" // VG_(malloc), VG_(free) |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 50 | #include "pub_core_syscall.h" // VG_(strerror) |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 51 | #include "vki_unistd.h" // mmap-related constants |
| 52 | |
njn | 08a2e17 | 2005-06-21 22:47:54 +0000 | [diff] [blame] | 53 | #include "pub_core_ume.h" |
sewardj | 4b0c071 | 2005-06-19 15:58:33 +0000 | [diff] [blame] | 54 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 55 | |
sewardj | fbd78b2 | 2005-06-19 16:14:06 +0000 | [diff] [blame] | 56 | #if VG_WORDSIZE == 8 |
nethercote | 3f45815 | 2004-11-01 18:42:23 +0000 | [diff] [blame] | 57 | #define ESZ(x) Elf64_##x |
sewardj | fbd78b2 | 2005-06-19 16:14:06 +0000 | [diff] [blame] | 58 | #elif VG_WORDSIZE == 4 |
nethercote | 3f45815 | 2004-11-01 18:42:23 +0000 | [diff] [blame] | 59 | #define ESZ(x) Elf32_##x |
| 60 | #else |
sewardj | fbd78b2 | 2005-06-19 16:14:06 +0000 | [diff] [blame] | 61 | #error VG_WORDSIZE needs to ==4 or ==8 |
nethercote | 3f45815 | 2004-11-01 18:42:23 +0000 | [diff] [blame] | 62 | #endif |
| 63 | |
nethercote | 1fe5450 | 2004-07-26 15:28:33 +0000 | [diff] [blame] | 64 | struct elfinfo |
| 65 | { |
| 66 | ESZ(Ehdr) e; |
| 67 | ESZ(Phdr) *p; |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 68 | Int fd; |
nethercote | 1fe5450 | 2004-07-26 15:28:33 +0000 | [diff] [blame] | 69 | }; |
| 70 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 71 | static void check_mmap(SysRes res, Addr base, SizeT len) |
nethercote | bfed1c8 | 2004-07-17 12:57:44 +0000 | [diff] [blame] | 72 | { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 73 | if (res.isError) { |
| 74 | VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME.\n", |
| 75 | (ULong)base, (Long)len); |
| 76 | VG_(exit)(1); |
nethercote | bfed1c8 | 2004-07-17 12:57:44 +0000 | [diff] [blame] | 77 | } |
| 78 | } |
| 79 | |
njn | fcb7c3e | 2005-06-18 15:54:25 +0000 | [diff] [blame] | 80 | /*------------------------------------------------------------*/ |
nethercote | 31779c7 | 2004-07-30 21:50:15 +0000 | [diff] [blame] | 81 | /*--- Finding auxv on the stack ---*/ |
| 82 | /*------------------------------------------------------------*/ |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 83 | |
njn | 62ff0f2 | 2005-06-21 23:03:36 +0000 | [diff] [blame] | 84 | struct ume_auxv *VG_(find_auxv)(UWord* sp) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 85 | { |
nethercote | ebf1d86 | 2004-11-01 18:22:05 +0000 | [diff] [blame] | 86 | sp++; // skip argc (Nb: is word-sized, not int-sized!) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 87 | |
nethercote | ebf1d86 | 2004-11-01 18:22:05 +0000 | [diff] [blame] | 88 | while (*sp != 0) // skip argv |
| 89 | sp++; |
| 90 | sp++; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 91 | |
nethercote | ebf1d86 | 2004-11-01 18:22:05 +0000 | [diff] [blame] | 92 | while (*sp != 0) // skip env |
| 93 | sp++; |
| 94 | sp++; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 95 | |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 96 | #if defined(VGA_ppc32) || defined(VGA_ppc64) |
cerion | 85665ca | 2005-06-20 15:51:07 +0000 | [diff] [blame] | 97 | # if defined AT_IGNOREPPC |
| 98 | while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries |
| 99 | sp += 2; |
| 100 | # endif |
| 101 | #endif |
| 102 | |
nethercote | ebf1d86 | 2004-11-01 18:22:05 +0000 | [diff] [blame] | 103 | return (struct ume_auxv *)sp; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 104 | } |
| 105 | |
nethercote | 31779c7 | 2004-07-30 21:50:15 +0000 | [diff] [blame] | 106 | /*------------------------------------------------------------*/ |
| 107 | /*--- Loading ELF files ---*/ |
| 108 | /*------------------------------------------------------------*/ |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 109 | |
sewardj | 2c5ffbe | 2005-03-12 13:32:06 +0000 | [diff] [blame] | 110 | static |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 111 | struct elfinfo *readelf(Int fd, const char *filename) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 112 | { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 113 | SysRes sres; |
| 114 | struct elfinfo *e = VG_(malloc)(sizeof(*e)); |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 115 | Int phsz; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 116 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 117 | vg_assert(e); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 118 | e->fd = fd; |
| 119 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 120 | sres = VG_(pread)(fd, &e->e, sizeof(e->e), 0); |
| 121 | if (sres.isError || sres.val != sizeof(e->e)) { |
| 122 | VG_(printf)("valgrind: %s: can't read ELF header: %s\n", |
| 123 | filename, VG_(strerror)(sres.val)); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 124 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 125 | } |
| 126 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 127 | if (VG_(memcmp)(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) { |
| 128 | VG_(printf)("valgrind: %s: bad ELF magic number\n", filename); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 129 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 130 | } |
njn | af839f5 | 2005-06-23 03:27:57 +0000 | [diff] [blame] | 131 | if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 132 | VG_(printf)("valgrind: wrong ELF executable class " |
| 133 | "(eg. 32-bit instead of 64-bit)\n"); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 134 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 135 | } |
sewardj | 6e340c7 | 2005-07-10 00:53:42 +0000 | [diff] [blame] | 136 | if (e->e.e_ident[EI_DATA] != VG_ELF_DATA2XXX) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 137 | VG_(printf)("valgrind: executable has wrong endian-ness\n"); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 138 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 139 | } |
| 140 | if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 141 | VG_(printf)("valgrind: this is not an executable\n"); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 142 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 143 | } |
| 144 | |
njn | af839f5 | 2005-06-23 03:27:57 +0000 | [diff] [blame] | 145 | if (e->e.e_machine != VG_ELF_MACHINE) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 146 | VG_(printf)("valgrind: executable is not for " |
| 147 | "this architecture\n"); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 148 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | if (e->e.e_phentsize != sizeof(ESZ(Phdr))) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 152 | VG_(printf)("valgrind: sizeof ELF Phdr wrong\n"); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 153 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum; |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 157 | e->p = VG_(malloc)(phsz); |
| 158 | vg_assert(e->p); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 159 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 160 | sres = VG_(pread)(fd, e->p, phsz, e->e.e_phoff); |
| 161 | if (sres.isError || sres.val != phsz) { |
| 162 | VG_(printf)("valgrind: can't read phdr: %s\n", |
| 163 | VG_(strerror)(sres.val)); |
| 164 | VG_(free)(e->p); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 165 | goto bad; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | return e; |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 169 | |
| 170 | bad: |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 171 | VG_(free)(e); |
njn | 12f266f | 2005-06-28 19:20:46 +0000 | [diff] [blame] | 172 | return NULL; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 173 | } |
| 174 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 175 | /* Map an ELF file. Returns the brk address. */ |
sewardj | 2c5ffbe | 2005-03-12 13:32:06 +0000 | [diff] [blame] | 176 | static |
fitzhardinge | b50068f | 2004-02-24 23:42:55 +0000 | [diff] [blame] | 177 | ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 178 | { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 179 | Int i; |
| 180 | SysRes res; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 181 | ESZ(Addr) elfbrk = 0; |
| 182 | |
| 183 | for(i = 0; i < e->e.e_phnum; i++) { |
| 184 | ESZ(Phdr) *ph = &e->p[i]; |
| 185 | ESZ(Addr) addr, brkaddr; |
| 186 | ESZ(Word) memsz; |
| 187 | |
| 188 | if (ph->p_type != PT_LOAD) |
| 189 | continue; |
| 190 | |
nethercote | 6c3cf41 | 2004-10-26 13:32:11 +0000 | [diff] [blame] | 191 | addr = ph->p_vaddr+base; |
| 192 | memsz = ph->p_memsz; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 193 | brkaddr = addr+memsz; |
| 194 | |
| 195 | if (brkaddr > elfbrk) |
| 196 | elfbrk = brkaddr; |
| 197 | } |
| 198 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 199 | for(i = 0; i < e->e.e_phnum; i++) { |
| 200 | ESZ(Phdr) *ph = &e->p[i]; |
| 201 | ESZ(Addr) addr, bss, brkaddr; |
| 202 | ESZ(Off) off; |
| 203 | ESZ(Word) filesz; |
| 204 | ESZ(Word) memsz; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 205 | unsigned prot = 0; |
| 206 | |
| 207 | if (ph->p_type != PT_LOAD) |
| 208 | continue; |
| 209 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 210 | if (ph->p_flags & PF_X) prot |= VKI_PROT_EXEC; |
| 211 | if (ph->p_flags & PF_W) prot |= VKI_PROT_WRITE; |
| 212 | if (ph->p_flags & PF_R) prot |= VKI_PROT_READ; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 213 | |
nethercote | 6c3cf41 | 2004-10-26 13:32:11 +0000 | [diff] [blame] | 214 | addr = ph->p_vaddr+base; |
| 215 | off = ph->p_offset; |
| 216 | filesz = ph->p_filesz; |
| 217 | bss = addr+filesz; |
| 218 | memsz = ph->p_memsz; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 219 | brkaddr = addr+memsz; |
| 220 | |
njn | f7fbe6c | 2004-11-30 11:40:24 +0000 | [diff] [blame] | 221 | // Tom says: In the following, do what the Linux kernel does and only |
| 222 | // map the pages that are required instead of rounding everything to |
| 223 | // the specified alignment (ph->p_align). (AMD64 doesn't work if you |
| 224 | // use ph->p_align -- part of stage2's memory gets trashed somehow.) |
njn | 098da06 | 2005-03-26 16:22:43 +0000 | [diff] [blame] | 225 | // |
| 226 | // The condition handles the case of a zero-length segment. |
njn | 13bfd85 | 2005-06-02 03:52:53 +0000 | [diff] [blame] | 227 | if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 228 | if (0) VG_(debugLog)(0,"ume","mmap_file_fixed_client #1\n"); |
| 229 | res = VG_(am_mmap_file_fixed_client)( |
| 230 | VG_PGROUNDDN(addr), |
| 231 | VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr), |
| 232 | prot, /*VKI_MAP_FIXED|VKI_MAP_PRIVATE, */ |
| 233 | e->fd, VG_PGROUNDDN(off) |
| 234 | ); |
| 235 | if (0) VG_(am_show_nsegments)(0,"after #1"); |
| 236 | check_mmap(res, VG_PGROUNDDN(addr), |
| 237 | VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr)); |
njn | 098da06 | 2005-03-26 16:22:43 +0000 | [diff] [blame] | 238 | } |
njn | f7fbe6c | 2004-11-30 11:40:24 +0000 | [diff] [blame] | 239 | |
| 240 | // if memsz > filesz, fill the remainder with zeroed pages |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 241 | if (memsz > filesz) { |
| 242 | UInt bytes; |
| 243 | |
njn | 13bfd85 | 2005-06-02 03:52:53 +0000 | [diff] [blame] | 244 | bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss); |
nethercote | bfed1c8 | 2004-07-17 12:57:44 +0000 | [diff] [blame] | 245 | if (bytes > 0) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 246 | if (0) VG_(debugLog)(0,"ume","mmap_anon_fixed_client #2\n"); |
| 247 | res = VG_(am_mmap_anon_fixed_client)( |
| 248 | VG_PGROUNDUP(bss), bytes, |
| 249 | prot |
| 250 | ); |
| 251 | if (0) VG_(am_show_nsegments)(0,"after #2"); |
| 252 | check_mmap(res, VG_PGROUNDUP(bss), bytes); |
nethercote | bfed1c8 | 2004-07-17 12:57:44 +0000 | [diff] [blame] | 253 | } |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 254 | |
nethercote | 73b526f | 2004-10-31 18:48:21 +0000 | [diff] [blame] | 255 | bytes = bss & (VKI_PAGE_SIZE - 1); |
njn | 098da06 | 2005-03-26 16:22:43 +0000 | [diff] [blame] | 256 | |
| 257 | // The 'prot' condition allows for a read-only bss |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 258 | if ((prot & VKI_PROT_WRITE) && (bytes > 0)) { |
nethercote | 73b526f | 2004-10-31 18:48:21 +0000 | [diff] [blame] | 259 | bytes = VKI_PAGE_SIZE - bytes; |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 260 | VG_(memset)((char *)bss, 0, bytes); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 261 | } |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | return elfbrk; |
| 266 | } |
| 267 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 268 | static Bool match_ELF(const char *hdr, Int len) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 269 | { |
| 270 | ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr; |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 271 | return (len > sizeof(*e)) && VG_(memcmp)(&e->e_ident[0], ELFMAG, SELFMAG) == 0; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 272 | } |
| 273 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 274 | |
| 275 | /* load_ELF pulls an ELF executable into the address space, prepares |
| 276 | it for execution, and writes info about it into INFO. In |
| 277 | particular it fills in .init_eip, which is the starting point. |
| 278 | |
| 279 | Returns zero on success, non-zero (a VKI_E.. value) on failure. |
| 280 | |
| 281 | The sequence of activities is roughly as follows: |
| 282 | |
| 283 | - use readelf() to extract program header info from the exe file. |
| 284 | |
| 285 | - scan the program header, collecting info (not sure what all those |
| 286 | info-> fields are, or whether they are used, but still) and in |
| 287 | particular looking out fo the PT_INTERP header, which describes |
| 288 | the interpreter. If such a field is found, the space needed to |
| 289 | hold the interpreter is computed into interp_size. |
| 290 | |
| 291 | - map the executable in, by calling mapelf(). This maps in all |
| 292 | loadable sections, and I _think_ also creates any .bss areas |
| 293 | required. mapelf() returns the address just beyond the end of |
| 294 | the furthest-along mapping it creates. The executable is mapped |
| 295 | starting at EBASE, which is usually read from it (eg, 0x8048000 |
| 296 | etc) except if it's a PIE, in which case I'm not sure what |
| 297 | happens. |
| 298 | |
| 299 | The returned address is recorded in info->brkbase as the start |
| 300 | point of the brk (data) segment, as it is traditional to place |
| 301 | the data segment just after the executable. Neither load_ELF nor |
| 302 | mapelf creates the brk segment, though: that is for the caller of |
| 303 | load_ELF to attend to. |
| 304 | |
| 305 | - If the initial phdr scan didn't find any mention of an |
| 306 | interpreter (interp == NULL), this must be a statically linked |
| 307 | executable, and we're pretty much done. |
| 308 | |
| 309 | - Otherwise, we need to use mapelf() a second time to load the |
| 310 | interpreter. The interpreter can go anywhere, but mapelf() wants |
| 311 | to be told a specific address to put it at. So an advisory query |
| 312 | is passed to aspacem, asking where it would put an anonymous |
| 313 | client mapping of size INTERP_SIZE. That address is then used |
| 314 | as the mapping address for the interpreter. |
| 315 | |
| 316 | - The entry point in INFO is set to the interpreter's entry point, |
| 317 | and we're done. */ |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 318 | static Int load_ELF(Int fd, const HChar* name, /*MOD*/ExeInfo* info) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 319 | { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 320 | SysRes sres; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 321 | struct elfinfo *e; |
| 322 | struct elfinfo *interp = NULL; |
fitzhardinge | ca9bd9c | 2004-09-08 20:05:02 +0000 | [diff] [blame] | 323 | ESZ(Addr) minaddr = ~0; /* lowest mapped address */ |
| 324 | ESZ(Addr) maxaddr = 0; /* highest mapped address */ |
| 325 | ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */ |
| 326 | ESZ(Word) interp_size = 0; /* interpreter size */ |
nethercote | 73b526f | 2004-10-31 18:48:21 +0000 | [diff] [blame] | 327 | ESZ(Word) interp_align = VKI_PAGE_SIZE; |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 328 | Int i; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 329 | void *entry; |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 330 | ESZ(Addr) ebase = 0; |
| 331 | |
| 332 | #ifdef HAVE_PIE |
| 333 | ebase = info->exe_base; |
| 334 | #endif |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 335 | |
| 336 | e = readelf(fd, name); |
| 337 | |
| 338 | if (e == NULL) |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 339 | return VKI_ENOEXEC; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 340 | |
tom | d6dd991 | 2005-07-18 15:52:30 +0000 | [diff] [blame] | 341 | /* The kernel maps position-independent executables at TASK_SIZE*2/3; |
| 342 | duplicate this behavior as close as we can. */ |
| 343 | if (e->e.e_type == ET_DYN && ebase == 0) { |
| 344 | ebase = VG_PGROUNDDN(info->exe_base + (info->exe_end - info->exe_base) * 2 / 3); |
| 345 | } |
| 346 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 347 | info->phnum = e->e.e_phnum; |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 348 | info->entry = e->e.e_entry + ebase; |
sewardj | b5f6f51 | 2005-03-10 23:59:00 +0000 | [diff] [blame] | 349 | info->phdr = 0; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 350 | |
| 351 | for(i = 0; i < e->e.e_phnum; i++) { |
| 352 | ESZ(Phdr) *ph = &e->p[i]; |
| 353 | |
| 354 | switch(ph->p_type) { |
| 355 | case PT_PHDR: |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 356 | info->phdr = ph->p_vaddr + ebase; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 357 | break; |
| 358 | |
| 359 | case PT_LOAD: |
| 360 | if (ph->p_vaddr < minaddr) |
| 361 | minaddr = ph->p_vaddr; |
| 362 | if (ph->p_vaddr+ph->p_memsz > maxaddr) |
| 363 | maxaddr = ph->p_vaddr+ph->p_memsz; |
| 364 | break; |
| 365 | |
| 366 | case PT_INTERP: { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 367 | char *buf = VG_(malloc)(ph->p_filesz+1); |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 368 | Int j; |
| 369 | Int intfd; |
| 370 | Int baseaddr_set; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 371 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 372 | vg_assert(buf); |
| 373 | VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 374 | buf[ph->p_filesz] = '\0'; |
| 375 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 376 | sres = VG_(open)(buf, VKI_O_RDONLY, 0); |
| 377 | if (sres.isError) { |
| 378 | VG_(printf)("valgrind: m_ume.c: can't open interpreter\n"); |
| 379 | VG_(exit)(1); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 380 | } |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 381 | intfd = sres.val; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 382 | |
| 383 | interp = readelf(intfd, buf); |
| 384 | if (interp == NULL) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 385 | VG_(printf)("valgrind: m_ume.c: can't read interpreter\n"); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 386 | return 1; |
| 387 | } |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 388 | VG_(free)(buf); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 389 | |
| 390 | baseaddr_set = 0; |
| 391 | for(j = 0; j < interp->e.e_phnum; j++) { |
| 392 | ESZ(Phdr) *iph = &interp->p[j]; |
| 393 | ESZ(Addr) end; |
| 394 | |
| 395 | if (iph->p_type != PT_LOAD) |
| 396 | continue; |
| 397 | |
| 398 | if (!baseaddr_set) { |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 399 | interp_addr = iph->p_vaddr; |
| 400 | interp_align = iph->p_align; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 401 | baseaddr_set = 1; |
| 402 | } |
| 403 | |
| 404 | /* assumes that all segments in the interp are close */ |
| 405 | end = (iph->p_vaddr - interp_addr) + iph->p_memsz; |
| 406 | |
| 407 | if (end > interp_size) |
| 408 | interp_size = end; |
| 409 | } |
| 410 | break; |
nethercote | b24cbc8 | 2004-09-03 23:25:33 +0000 | [diff] [blame] | 411 | |
| 412 | default: |
| 413 | // do nothing |
| 414 | break; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 415 | } |
| 416 | } |
| 417 | } |
| 418 | |
sewardj | b5f6f51 | 2005-03-10 23:59:00 +0000 | [diff] [blame] | 419 | if (info->phdr == 0) |
tom | d6dd991 | 2005-07-18 15:52:30 +0000 | [diff] [blame] | 420 | info->phdr = minaddr + ebase + e->e.e_phoff; |
sewardj | b5f6f51 | 2005-03-10 23:59:00 +0000 | [diff] [blame] | 421 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 422 | if (info->exe_base != info->exe_end) { |
| 423 | if (minaddr >= maxaddr || |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 424 | (minaddr + ebase < info->exe_base || |
| 425 | maxaddr + ebase > info->exe_end)) { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 426 | VG_(printf)("Executable range %p-%p is outside the\n" |
| 427 | "acceptable range %p-%p\n", |
tom | 151a639 | 2005-11-11 12:30:36 +0000 | [diff] [blame] | 428 | (char *)minaddr + ebase, (char *)maxaddr + ebase, |
| 429 | (char *)info->exe_base, (char *)info->exe_end); |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 430 | return VKI_ENOMEM; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 431 | } |
| 432 | } |
| 433 | |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 434 | info->brkbase = mapelf(e, ebase); /* map the executable */ |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 435 | |
fitzhardinge | 9236079 | 2003-12-24 10:11:11 +0000 | [diff] [blame] | 436 | if (info->brkbase == 0) |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 437 | return VKI_ENOMEM; |
fitzhardinge | 9236079 | 2003-12-24 10:11:11 +0000 | [diff] [blame] | 438 | |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 439 | if (interp != NULL) { |
| 440 | /* reserve a chunk of address space for interpreter */ |
tom | 069e641 | 2005-11-01 19:46:07 +0000 | [diff] [blame] | 441 | MapRequest mreq; |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 442 | Addr advised; |
| 443 | Bool ok; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 444 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 445 | /* Don't actually reserve the space. Just get an advisory |
| 446 | indicating where it would be allocated, and pass that to |
| 447 | mapelf(), which in turn asks aspacem to do some fixed maps at |
| 448 | the specified address. This is a bit of hack, but it should |
| 449 | work because there should be no intervening transactions with |
sewardj | 09f6173 | 2005-11-02 19:41:21 +0000 | [diff] [blame] | 450 | aspacem which could cause those fixed maps to fail. |
| 451 | |
| 452 | Placement policy is: |
| 453 | |
| 454 | if the interpreter asks to be loaded at zero |
| 455 | ignore that and put it wherever we like (mappings at zero |
| 456 | are bad news) |
| 457 | else |
| 458 | try and put it where it asks for, but if that doesn't work, |
| 459 | just put it anywhere. |
| 460 | */ |
| 461 | if (interp_addr == 0) { |
| 462 | mreq.rkind = MAny; |
| 463 | mreq.start = 0; |
| 464 | mreq.len = interp_size; |
| 465 | } else { |
| 466 | mreq.rkind = MHint; |
| 467 | mreq.start = interp_addr; |
| 468 | mreq.len = interp_size; |
| 469 | } |
| 470 | |
tom | 069e641 | 2005-11-01 19:46:07 +0000 | [diff] [blame] | 471 | advised = VG_(am_get_advisory)( &mreq, True/*client*/, &ok ); |
sewardj | 09f6173 | 2005-11-02 19:41:21 +0000 | [diff] [blame] | 472 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 473 | if (!ok) { |
| 474 | /* bomb out */ |
| 475 | SysRes res = VG_(mk_SysRes_Error)(VKI_EINVAL); |
| 476 | if (0) VG_(printf)("reserve for interp: failed\n"); |
| 477 | check_mmap(res, (Addr)interp_addr, interp_size); |
| 478 | /*NOTREACHED*/ |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 479 | } |
| 480 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 481 | (void)mapelf(interp, (ESZ(Addr))advised - interp_addr); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 482 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 483 | VG_(close)(interp->fd); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 484 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 485 | entry = (void *)(advised - interp_addr + interp->e.e_entry); |
| 486 | info->interp_base = (ESZ(Addr))advised; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 487 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 488 | VG_(free)(interp->p); |
| 489 | VG_(free)(interp); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 490 | } else |
tom | d6dd991 | 2005-07-18 15:52:30 +0000 | [diff] [blame] | 491 | entry = (void *)(ebase + e->e.e_entry); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 492 | |
nethercote | 7f39002 | 2004-10-25 17:18:24 +0000 | [diff] [blame] | 493 | info->exe_base = minaddr + ebase; |
| 494 | info->exe_end = maxaddr + ebase; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 495 | |
sewardj | bd8951e | 2005-12-06 21:47:38 +0000 | [diff] [blame] | 496 | #if defined(VGP_ppc64_linux) |
| 497 | /* On PPC64, a func ptr is represented by a TOC entry ptr. This |
| 498 | TOC entry contains three words; the first word is the function |
| 499 | address, the second word is the TOC ptr (r2), and the third word |
| 500 | is the static chain value. */ |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 501 | info->init_ip = ((ULong*)entry)[0]; |
| 502 | info->init_toc = ((ULong*)entry)[1]; |
sewardj | bd8951e | 2005-12-06 21:47:38 +0000 | [diff] [blame] | 503 | #else |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 504 | info->init_ip = (Addr)entry; |
| 505 | info->init_toc = 0; /* meaningless on this platform */ |
sewardj | bd8951e | 2005-12-06 21:47:38 +0000 | [diff] [blame] | 506 | #endif |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 507 | VG_(free)(e->p); |
| 508 | VG_(free)(e); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 509 | |
| 510 | return 0; |
| 511 | } |
| 512 | |
| 513 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 514 | static Bool match_script(char *hdr, Int len) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 515 | { |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 516 | Char* end = hdr + len; |
| 517 | Char* interp = hdr + 2; |
| 518 | |
| 519 | // len < 4: need '#', '!', plus at least a '/' and one more char |
| 520 | if (len < 4) return False; |
| 521 | if (0 != VG_(memcmp)(hdr, "#!", 2)) return False; |
| 522 | |
| 523 | // Find interpreter name, make sure it's an absolute path (starts with |
| 524 | // '/') and has at least one more char. |
| 525 | while (interp < end && VG_(isspace)(*interp)) interp++; |
| 526 | if (*interp != '/') return False; // absolute path only for interpreter |
| 527 | if (interp == end) return False; // nothing after the '/' |
| 528 | |
| 529 | // Here we should get the full interpreter name and check it with |
| 530 | // check_executable(). See the "EXEC FAILED" failure when running shell |
| 531 | // for an example. |
| 532 | |
| 533 | return True; // looks like a #! script |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 534 | } |
| 535 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 536 | // Forward declaration. |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 537 | static Int do_exec_inner(const HChar* exe, ExeInfo* info); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 538 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 539 | /* returns: 0 = success, non-0 is failure */ |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 540 | static Int load_script(Int fd, const HChar* name, ExeInfo* info) |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 541 | { |
| 542 | Char hdr[VKI_PAGE_SIZE]; |
| 543 | Int len = VKI_PAGE_SIZE; |
| 544 | Int eol; |
| 545 | Char* interp; |
| 546 | Char* end; |
| 547 | Char* cp; |
| 548 | Char* arg = NULL; |
| 549 | SysRes res; |
| 550 | |
| 551 | // Read the first part of the file. |
| 552 | res = VG_(pread)(fd, hdr, len, 0); |
| 553 | if (res.isError) { |
| 554 | VG_(close)(fd); |
| 555 | return VKI_EACCES; |
| 556 | } else { |
| 557 | len = res.val; |
| 558 | } |
| 559 | |
| 560 | vg_assert('#' == hdr[0] && '!' == hdr[1]); |
| 561 | |
| 562 | end = hdr + len; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 563 | interp = hdr + 2; |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 564 | while (interp < end && VG_(isspace)(*interp)) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 565 | interp++; |
| 566 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 567 | vg_assert(*interp == '/'); /* absolute path only for interpreter */ |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 568 | |
| 569 | /* skip over interpreter name */ |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 570 | for (cp = interp; cp < end && !VG_(isspace)(*cp); cp++) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 571 | ; |
| 572 | |
| 573 | eol = (*cp == '\n'); |
| 574 | |
| 575 | *cp++ = '\0'; |
| 576 | |
| 577 | if (!eol && cp < end) { |
| 578 | /* skip space before arg */ |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 579 | while (cp < end && VG_(isspace)(*cp)) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 580 | cp++; |
| 581 | |
| 582 | /* arg is from here to eol */ |
| 583 | arg = cp; |
| 584 | while (cp < end && *cp != '\n') |
| 585 | cp++; |
| 586 | *cp = '\0'; |
| 587 | } |
| 588 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 589 | info->interp_name = VG_(strdup)(interp); |
| 590 | vg_assert(NULL != info->interp_name); |
nethercote | 71980f0 | 2004-01-24 18:18:54 +0000 | [diff] [blame] | 591 | if (arg != NULL && *arg != '\0') { |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 592 | info->interp_args = VG_(strdup)(arg); |
| 593 | vg_assert(NULL != info->interp_args); |
nethercote | 71980f0 | 2004-01-24 18:18:54 +0000 | [diff] [blame] | 594 | } |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 595 | |
| 596 | if (info->argv && info->argv[0] != NULL) |
| 597 | info->argv[0] = (char *)name; |
| 598 | |
| 599 | if (0) |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 600 | VG_(printf)("#! script: interp_name=\"%s\" interp_args=\"%s\"\n", |
| 601 | info->interp_name, info->interp_args); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 602 | |
| 603 | return do_exec_inner(interp, info); |
| 604 | } |
| 605 | |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 606 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 607 | typedef enum { |
| 608 | VG_EXE_FORMAT_ELF = 1, |
| 609 | VG_EXE_FORMAT_SCRIPT = 2, |
| 610 | } ExeFormat; |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 611 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 612 | // Check the file looks executable. |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 613 | SysRes VG_(pre_exec_check)(const HChar* exe_name, Int* out_fd) |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 614 | { |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 615 | Int fd, ret; |
| 616 | SysRes res; |
| 617 | Char buf[VKI_PAGE_SIZE]; |
| 618 | SizeT bufsz = VKI_PAGE_SIZE, fsz; |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 619 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 620 | // Check it's readable |
| 621 | res = VG_(open)(exe_name, VKI_O_RDONLY, 0); |
| 622 | if (res.isError) { |
| 623 | return res; |
| 624 | } |
| 625 | fd = res.val; |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 626 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 627 | // Check we have execute permissions |
| 628 | ret = VG_(check_executable)((HChar*)exe_name); |
| 629 | if (0 != ret) { |
| 630 | VG_(close)(fd); |
| 631 | return VG_(mk_SysRes_Error)(ret); |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 632 | } |
| 633 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 634 | fsz = VG_(fsize)(fd); |
| 635 | if (fsz < bufsz) |
| 636 | bufsz = fsz; |
| 637 | |
| 638 | res = VG_(pread)(fd, buf, bufsz, 0); |
| 639 | if (res.isError || res.val != bufsz) { |
| 640 | VG_(close)(fd); |
| 641 | return VG_(mk_SysRes_Error)(VKI_EACCES); |
| 642 | } |
| 643 | bufsz = res.val; |
| 644 | |
| 645 | if (match_ELF(buf, bufsz)) { |
| 646 | res = VG_(mk_SysRes_Success)(VG_EXE_FORMAT_ELF); |
| 647 | } else if (match_script(buf, bufsz)) { |
| 648 | res = VG_(mk_SysRes_Success)(VG_EXE_FORMAT_SCRIPT); |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 649 | } else { |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 650 | res = VG_(mk_SysRes_Error)(VKI_ENOEXEC); |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 651 | } |
| 652 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 653 | // Write the 'out_fd' param if necessary, or close the file. |
| 654 | if (!res.isError && out_fd) { |
| 655 | *out_fd = fd; |
| 656 | } else { |
| 657 | VG_(close)(fd); |
| 658 | } |
| 659 | |
| 660 | return res; |
fitzhardinge | fd7da3a | 2004-09-08 20:05:29 +0000 | [diff] [blame] | 661 | } |
| 662 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 663 | // returns: 0 = success, non-0 is failure |
| 664 | // |
| 665 | // We can execute only ELF binaries or scripts that begin with "#!". (Not, |
| 666 | // for example, scripts that don't begin with "#!"; see the VG_(do_exec)() |
| 667 | // invocation from m_main.c for how that's handled.) |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 668 | static Int do_exec_inner(const HChar *exe, ExeInfo* info) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 669 | { |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 670 | SysRes res; |
| 671 | Int fd; |
| 672 | Int ret; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 673 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 674 | res = VG_(pre_exec_check)(exe, &fd); |
| 675 | if (res.isError) |
| 676 | return res.val; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 677 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 678 | switch (res.val) { |
| 679 | case VG_EXE_FORMAT_ELF: ret = load_ELF (fd, exe, info); break; |
| 680 | case VG_EXE_FORMAT_SCRIPT: ret = load_script(fd, exe, info); break; |
| 681 | default: |
| 682 | vg_assert2(0, "unrecognised VG_EXE_FORMAT value\n"); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 683 | } |
| 684 | |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 685 | VG_(close)(fd); |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 686 | |
| 687 | return ret; |
| 688 | } |
| 689 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 690 | |
| 691 | static Bool is_hash_bang_file(Char* f) |
| 692 | { |
| 693 | SysRes res = VG_(open)(f, VKI_O_RDONLY, 0); |
| 694 | if (!res.isError) { |
| 695 | Char buf[3] = {0,0,0}; |
| 696 | Int fd = res.val; |
| 697 | Int n = VG_(read)(fd, buf, 2); |
| 698 | if (n == 2 && VG_STREQ("#!", buf)) |
| 699 | return True; |
| 700 | } |
| 701 | return False; |
| 702 | } |
| 703 | |
| 704 | // Look at the first 80 chars, and if any are greater than 127, it's binary. |
| 705 | // This is crude, but should be good enough. Note that it fails on a |
| 706 | // zero-length file, as we want. |
| 707 | static Bool is_binary_file(Char* f) |
| 708 | { |
| 709 | SysRes res = VG_(open)(f, VKI_O_RDONLY, 0); |
| 710 | if (!res.isError) { |
| 711 | UChar buf[80]; |
| 712 | Int fd = res.val; |
| 713 | Int n = VG_(read)(fd, buf, 80); |
| 714 | Int i; |
| 715 | for (i = 0; i < n; i++) { |
| 716 | if (buf[i] > 127) |
| 717 | return True; // binary char found |
| 718 | } |
| 719 | return False; |
| 720 | } else { |
| 721 | // Something went wrong. This will only happen if we earlier |
| 722 | // succeeded in opening the file but fail here (eg. the file was |
| 723 | // deleted between then and now). |
| 724 | VG_(printf)("valgrind: %s: unknown error\n", f); |
| 725 | VG_(exit)(126); // 126 == NOEXEC |
| 726 | } |
| 727 | } |
| 728 | |
| 729 | // If the do_exec fails we try to emulate what the shell does (I used |
| 730 | // bash as a guide). It's worth noting that the shell can execute some |
| 731 | // things that VG_(do_exec)() (which subsitutes for the kernel's exec()) |
| 732 | // will refuse to (eg. scripts lacking a "#!" prefix). |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 733 | static Int do_exec_shell_followup(Int ret, HChar* exe_name, |
| 734 | ExeInfo* info) |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 735 | { |
| 736 | Char* default_interp_name = "/bin/sh"; |
| 737 | SysRes res; |
| 738 | struct vki_stat st; |
| 739 | |
| 740 | if (VKI_ENOEXEC == ret) { |
| 741 | // It was an executable file, but in an unacceptable format. Probably |
| 742 | // is a shell script lacking the "#!" prefix; try to execute it so. |
| 743 | |
| 744 | // Is it a binary file? |
| 745 | if (is_binary_file(exe_name)) { |
| 746 | VG_(printf)("valgrind: %s: cannot execute binary file\n", exe_name); |
| 747 | VG_(exit)(126); // 126 == NOEXEC |
| 748 | } |
| 749 | |
| 750 | // Looks like a script. Run it with /bin/sh. This includes |
| 751 | // zero-length files. |
| 752 | |
| 753 | info->interp_name = VG_(strdup)(default_interp_name); |
| 754 | info->interp_args = NULL; |
| 755 | if (info->argv && info->argv[0] != NULL) |
| 756 | info->argv[0] = (char *)exe_name; |
| 757 | |
| 758 | ret = do_exec_inner(info->interp_name, info); |
| 759 | |
| 760 | if (0 != ret) { |
| 761 | // Something went wrong with executing the default interpreter |
| 762 | VG_(printf)("valgrind: %s: bad interpreter (%s): %s\n", |
| 763 | exe_name, info->interp_name, VG_(strerror)(ret)); |
| 764 | VG_(exit)(126); // 126 == NOEXEC |
| 765 | } |
| 766 | |
| 767 | } else if (0 != ret) { |
| 768 | // Something else went wrong. Try to make the error more specific, |
| 769 | // and then print a message and abort. |
| 770 | |
| 771 | // Was it a directory? |
| 772 | res = VG_(stat)(exe_name, &st); |
| 773 | if (!res.isError && VKI_S_ISDIR(st.st_mode)) { |
| 774 | VG_(printf)("valgrind: %s: is a directory\n", exe_name); |
| 775 | |
| 776 | // Was it not executable? |
| 777 | } else if (0 != VG_(check_executable)(exe_name)) { |
| 778 | VG_(printf)("valgrind: %s: %s\n", exe_name, VG_(strerror)(ret)); |
| 779 | |
| 780 | // Did it start with "#!"? If so, it must have been a bad interpreter. |
| 781 | } else if (is_hash_bang_file(exe_name)) { |
| 782 | VG_(printf)("valgrind: %s: bad interpreter: %s\n", |
| 783 | exe_name, VG_(strerror)(ret)); |
| 784 | |
| 785 | // Otherwise it was something else. |
| 786 | } else { |
| 787 | VG_(printf)("valgrind: %s\n", exe_name, VG_(strerror)(ret)); |
| 788 | } |
| 789 | // 126 means NOEXEC; I think this is Posix, and that in some cases we |
| 790 | // should be returning 127, meaning NOTFOUND. Oh well. |
| 791 | VG_(exit)(126); |
| 792 | } |
| 793 | return ret; |
| 794 | } |
| 795 | |
| 796 | |
| 797 | // This emulates the kernel's exec(). If it fails, it then emulates the |
| 798 | // shell's handling of the situation. |
nethercote | ea147e7 | 2004-07-26 15:43:57 +0000 | [diff] [blame] | 799 | // See ume.h for an indication of which entries of 'info' are inputs, which |
| 800 | // are outputs, and which are both. |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 801 | /* returns: 0 = success, non-0 is failure */ |
sewardj | 13247ca | 2005-12-30 22:52:20 +0000 | [diff] [blame] | 802 | Int VG_(do_exec)(const HChar* exe_name, ExeInfo* info) |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 803 | { |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 804 | Int ret; |
| 805 | |
nethercote | d6a5687 | 2004-07-26 15:32:47 +0000 | [diff] [blame] | 806 | info->interp_name = NULL; |
| 807 | info->interp_args = NULL; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 808 | |
njn | 7375061 | 2005-10-14 03:11:30 +0000 | [diff] [blame] | 809 | ret = do_exec_inner(exe_name, info); |
| 810 | |
| 811 | if (0 != ret) { |
| 812 | ret = do_exec_shell_followup(ret, (Char*)exe_name, info); |
| 813 | } |
| 814 | return ret; |
fitzhardinge | 7e343cd | 2003-12-16 02:14:00 +0000 | [diff] [blame] | 815 | } |
nethercote | bb1c991 | 2004-01-04 16:43:23 +0000 | [diff] [blame] | 816 | |
| 817 | /*--------------------------------------------------------------------*/ |
njn | 08a2e17 | 2005-06-21 22:47:54 +0000 | [diff] [blame] | 818 | /*--- end ---*/ |
nethercote | bb1c991 | 2004-01-04 16:43:23 +0000 | [diff] [blame] | 819 | /*--------------------------------------------------------------------*/ |