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