1 1.9 dogcow /* $NetBSD: elf.c,v 1.9 2007/03/05 21:05:01 dogcow Exp $ */ 2 1.4 takemura 3 1.4 takemura /*- 4 1.4 takemura * Copyright (c) 1999 Shin Takemura. 5 1.4 takemura * All rights reserved. 6 1.4 takemura * 7 1.4 takemura * This software is part of the PocketBSD. 8 1.4 takemura * 9 1.4 takemura * Redistribution and use in source and binary forms, with or without 10 1.4 takemura * modification, are permitted provided that the following conditions 11 1.4 takemura * are met: 12 1.4 takemura * 1. Redistributions of source code must retain the above copyright 13 1.4 takemura * notice, this list of conditions and the following disclaimer. 14 1.4 takemura * 2. Redistributions in binary form must reproduce the above copyright 15 1.4 takemura * notice, this list of conditions and the following disclaimer in the 16 1.4 takemura * documentation and/or other materials provided with the distribution. 17 1.4 takemura * 3. All advertising materials mentioning features or use of this software 18 1.4 takemura * must display the following acknowledgement: 19 1.4 takemura * This product includes software developed by the PocketBSD project 20 1.4 takemura * and its contributors. 21 1.4 takemura * 4. Neither the name of the project nor the names of its contributors 22 1.4 takemura * may be used to endorse or promote products derived from this software 23 1.4 takemura * without specific prior written permission. 24 1.4 takemura * 25 1.4 takemura * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 1.4 takemura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 1.4 takemura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 1.4 takemura * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 1.4 takemura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 1.4 takemura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 1.4 takemura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 1.4 takemura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 1.4 takemura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 1.4 takemura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 1.4 takemura * SUCH DAMAGE. 36 1.4 takemura * 37 1.4 takemura */ 38 1.4 takemura #include <pbsdboot.h> 39 1.4 takemura 40 1.4 takemura #define ELFSIZE 32 41 1.4 takemura //#include <sys/param.h> 42 1.4 takemura //#include <sys/exec.h> 43 1.4 takemura #include <sys/exec_elf.h> 44 1.4 takemura 45 1.4 takemura #if 1 46 1.4 takemura #define LOAD_DEBUG_INFO 47 1.4 takemura #define DEBUG_INFO_ALIGN 4096 48 1.4 takemura #define ROUNDUP(a, n) ((((int)(a)) + (n)-1)/(n)*(n)) 49 1.4 takemura #endif 50 1.4 takemura 51 1.4 takemura static int 52 1.8 christos scanfile(int fd, void **start, void **end, void **entry, int load); 53 1.4 takemura 54 1.4 takemura static long total_bytes = 0; 55 1.4 takemura 56 1.4 takemura int 57 1.8 christos getinfo(int fd, void **start, void **end) 58 1.4 takemura { 59 1.4 takemura return (scanfile(fd, start, end, NULL, 0)); 60 1.4 takemura } 61 1.4 takemura 62 1.4 takemura int 63 1.8 christos loadfile(int fd, void **entry) 64 1.4 takemura { 65 1.4 takemura return (scanfile(fd, NULL, NULL, entry, 1)); 66 1.4 takemura } 67 1.4 takemura 68 1.4 takemura enum { 69 1.4 takemura VMEM_CLEAR, VMEM_LOAD, VMEM_COPY 70 1.4 takemura }; 71 1.4 takemura 72 1.4 takemura int 73 1.8 christos vmem_sub(int opr, void* xxx, void *addr, int nbytes, int *byte_count) 74 1.4 takemura { 75 1.4 takemura int n; 76 1.9 dogcow void *end_addr, *vaddr; 77 1.4 takemura int count = 0; 78 1.4 takemura int progress = 0; 79 1.4 takemura int fd = (int)xxx; 80 1.8 christos void *src_addr = (void *)xxx; 81 1.4 takemura 82 1.4 takemura debug_printf(TEXT("loadfile_sub(%x-%x, %S)\n"), 83 1.4 takemura addr, addr + nbytes, 84 1.4 takemura opr == VMEM_CLEAR ? "clear" : (opr == VMEM_LOAD ? "load" : "copy")); 85 1.4 takemura 86 1.4 takemura for (end_addr = addr + nbytes; 87 1.4 takemura addr < end_addr; 88 1.4 takemura addr += n) { 89 1.4 takemura if ((vaddr = vmem_get(addr, &n)) == NULL) { 90 1.4 takemura debug_printf(TEXT("vmem_get(0x%x) failed.\n"), addr); 91 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("vmem_get(0x%x) failed.\n"), addr); 92 1.4 takemura return (-1); 93 1.4 takemura } 94 1.4 takemura if (end_addr < addr + n) { 95 1.4 takemura n = end_addr - addr; 96 1.4 takemura } 97 1.4 takemura switch (opr) { 98 1.4 takemura case VMEM_CLEAR: 99 1.4 takemura memset(vaddr, 0, n); 100 1.4 takemura break; 101 1.4 takemura case VMEM_LOAD: 102 1.4 takemura if (read(fd, vaddr, n) != n) { 103 1.4 takemura debug_printf(TEXT("read segment error.\n")); 104 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read segment error.\n")); 105 1.4 takemura return (-1); 106 1.4 takemura } 107 1.4 takemura break; 108 1.4 takemura case VMEM_COPY: 109 1.4 takemura memcpy(vaddr, src_addr, n); 110 1.4 takemura src_addr += n; 111 1.4 takemura break; 112 1.4 takemura } 113 1.4 takemura if (total_bytes != 0) { 114 1.4 takemura int tmp_progress = *byte_count * 100 / total_bytes; 115 1.4 takemura *byte_count += n; 116 1.4 takemura if (progress != tmp_progress) { 117 1.4 takemura progress = tmp_progress; 118 1.4 takemura if (CheckCancel(progress)) { 119 1.4 takemura return (-1); 120 1.4 takemura } 121 1.4 takemura } 122 1.4 takemura } 123 1.4 takemura } 124 1.4 takemura return (0); 125 1.4 takemura } 126 1.4 takemura 127 1.4 takemura 128 1.4 takemura static int 129 1.8 christos scanfile(int fd, void **start, void **end, void **entry, int load) 130 1.4 takemura { 131 1.4 takemura Elf_Ehdr elfx, *elf = &elfx; 132 1.4 takemura int i, first; 133 1.4 takemura long byte_count; 134 1.4 takemura int progress; 135 1.4 takemura Elf_Shdr *shtbl = NULL; 136 1.4 takemura Elf_Phdr *phtbl = NULL; 137 1.9 dogcow void *min_addr, *max_addr; 138 1.4 takemura int sh_symidx, sh_stridx; 139 1.4 takemura int dbg_hdr_size = sizeof(Elf_Ehdr) + sizeof(Elf_Shdr) * 2; 140 1.4 takemura 141 1.4 takemura if (lseek(fd, 0, SEEK_SET) == -1) { 142 1.4 takemura debug_printf(TEXT("seek error\n")); 143 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek error.\n")); 144 1.4 takemura goto error_cleanup; 145 1.4 takemura } 146 1.4 takemura if (read(fd, (void*)elf, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr)) { 147 1.4 takemura debug_printf(TEXT("read header error\n")); 148 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read header error.\n")); 149 1.4 takemura goto error_cleanup; 150 1.4 takemura } 151 1.4 takemura 152 1.4 takemura if ((phtbl = (Elf_Phdr *)alloc(sizeof(*phtbl) * elf->e_phnum)) == NULL || 153 1.4 takemura (shtbl = (Elf_Shdr *)alloc(sizeof(*shtbl) * elf->e_shnum)) == NULL) { 154 1.4 takemura debug_printf(TEXT("alloc() error\n")); 155 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("malloc() error.\n")); 156 1.4 takemura goto error_cleanup; 157 1.4 takemura } 158 1.4 takemura 159 1.4 takemura if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) { 160 1.4 takemura debug_printf(TEXT("seek for program header table error\n")); 161 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek for program header table error.\n")); 162 1.4 takemura goto error_cleanup; 163 1.4 takemura } 164 1.4 takemura if (read(fd, (void *)phtbl, sizeof(Elf_Phdr) * elf->e_phnum) 165 1.4 takemura != (int)(sizeof(Elf_Phdr) * elf->e_phnum)) { 166 1.4 takemura debug_printf(TEXT("read program header table error\n")); 167 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read program header table error.\n")); 168 1.4 takemura goto error_cleanup; 169 1.4 takemura } 170 1.4 takemura 171 1.4 takemura if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) { 172 1.4 takemura debug_printf(TEXT("seek for segment header table error.\n")); 173 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek for segment header table error.\n")); 174 1.4 takemura goto error_cleanup; 175 1.4 takemura } 176 1.4 takemura if (read(fd, (void *)shtbl, sizeof(Elf_Shdr) * elf->e_shnum) 177 1.4 takemura != (int)(sizeof(Elf_Shdr) * elf->e_shnum)) { 178 1.4 takemura debug_printf(TEXT("read segment header table error\n")); 179 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read segment header table error.\n")); 180 1.4 takemura goto error_cleanup; 181 1.4 takemura } 182 1.4 takemura 183 1.4 takemura /* 184 1.4 takemura * scan program header table 185 1.4 takemura */ 186 1.4 takemura first = 1; 187 1.4 takemura byte_count = 0; 188 1.4 takemura progress = 0; 189 1.4 takemura for (i = 0; i < elf->e_phnum; i++) { 190 1.4 takemura if (phtbl[i].p_type != PT_LOAD) { 191 1.4 takemura continue; 192 1.4 takemura } 193 1.4 takemura 194 1.8 christos if (first || max_addr < (void *)(phtbl[i].p_vaddr + phtbl[i].p_memsz)) { 195 1.8 christos max_addr = (void *)(phtbl[i].p_vaddr + phtbl[i].p_memsz); 196 1.4 takemura } 197 1.8 christos if (first || (void *)phtbl[i].p_vaddr < min_addr) { 198 1.8 christos min_addr = (void *)phtbl[i].p_vaddr; 199 1.4 takemura } 200 1.4 takemura 201 1.4 takemura if (load) { 202 1.4 takemura if (lseek(fd, phtbl[i].p_offset, SEEK_SET) == -1) { 203 1.4 takemura debug_printf(TEXT("seek for segment error\n")); 204 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek for segment error.\n")); 205 1.4 takemura goto error_cleanup; 206 1.4 takemura } 207 1.4 takemura 208 1.4 takemura if (vmem_sub(VMEM_LOAD, (void*)fd, 209 1.8 christos (void *)phtbl[i].p_vaddr, 210 1.4 takemura phtbl[i].p_filesz, 211 1.4 takemura &byte_count) != 0) { 212 1.4 takemura goto error_cleanup; 213 1.4 takemura } 214 1.4 takemura if (vmem_sub(VMEM_CLEAR, NULL, 215 1.8 christos (void *)phtbl[i].p_vaddr + phtbl[i].p_filesz, 216 1.4 takemura phtbl[i].p_memsz - phtbl[i].p_filesz, 217 1.4 takemura &byte_count) != 0) { 218 1.4 takemura goto error_cleanup; 219 1.4 takemura } 220 1.4 takemura } else { 221 1.4 takemura byte_count += phtbl[i].p_memsz; 222 1.4 takemura } 223 1.4 takemura 224 1.4 takemura first = 0; 225 1.4 takemura } 226 1.4 takemura 227 1.4 takemura if (first) { 228 1.4 takemura debug_printf(TEXT("can't find loadable segment\n")); 229 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("can't find loadable segment\n")); 230 1.4 takemura goto error_cleanup; 231 1.4 takemura } 232 1.4 takemura total_bytes = byte_count; 233 1.4 takemura 234 1.4 takemura debug_printf(TEXT("entry=%x addr=%x-%x\n"), 235 1.4 takemura elf->e_entry, min_addr, max_addr); 236 1.4 takemura 237 1.4 takemura #ifdef LOAD_DEBUG_INFO 238 1.4 takemura if (pref.load_debug_info) { 239 1.4 takemura /* 240 1.4 takemura * scan section header table 241 1.6 wiz * to search for debugging information 242 1.4 takemura */ 243 1.4 takemura sh_symidx = -1; 244 1.4 takemura sh_stridx = -1; 245 1.4 takemura for (i = 0; i < elf->e_shnum; i++) { 246 1.4 takemura if (shtbl[i].sh_type == SHT_SYMTAB) { 247 1.4 takemura sh_symidx = i; 248 1.4 takemura } 249 1.4 takemura if ((shtbl[i].sh_type == SHT_STRTAB) 250 1.4 takemura && (shtbl[i].sh_size >= 0x4000)) { 251 1.4 takemura sh_stridx = i; 252 1.4 takemura } 253 1.4 takemura } 254 1.4 takemura if (sh_symidx == -1 || sh_stridx == -1) { 255 1.6 wiz debug_printf(TEXT("debugging information not found\n")); 256 1.4 takemura } else 257 1.4 takemura if (load) { 258 1.4 takemura Elf_Ehdr dbg_eh; 259 1.4 takemura Elf_Shdr dbg_sh[2]; 260 1.4 takemura memset(&dbg_eh, 0, sizeof(Elf_Ehdr)); 261 1.4 takemura memset(dbg_sh, 0, sizeof(Elf_Shdr) * 2); 262 1.4 takemura 263 1.4 takemura memcpy(dbg_eh.e_ident, elf->e_ident, 264 1.4 takemura sizeof(elf->e_ident)); 265 1.4 takemura dbg_eh.e_machine = elf->e_machine; 266 1.4 takemura dbg_eh.e_version = elf->e_version; 267 1.4 takemura dbg_eh.e_entry = 0; 268 1.4 takemura dbg_eh.e_phoff = 0; 269 1.4 takemura dbg_eh.e_shoff = sizeof(Elf_Ehdr); 270 1.4 takemura dbg_eh.e_flags = elf->e_flags; 271 1.4 takemura dbg_eh.e_ehsize = sizeof(Elf_Ehdr); 272 1.4 takemura dbg_eh.e_phentsize = 0; 273 1.4 takemura dbg_eh.e_phnum = 0; 274 1.4 takemura dbg_eh.e_shentsize = sizeof(Elf_Shdr); 275 1.4 takemura dbg_eh.e_shnum = 2; 276 1.4 takemura dbg_eh.e_shstrndx = 0; /* ??? */ 277 1.4 takemura 278 1.4 takemura /* 279 1.4 takemura * XXX, pass debug info size in e_entry. 280 1.4 takemura */ 281 1.4 takemura dbg_eh.e_entry = ROUNDUP(dbg_hdr_size + 282 1.4 takemura shtbl[sh_symidx].sh_size + 283 1.4 takemura shtbl[sh_stridx].sh_size, 284 1.4 takemura DEBUG_INFO_ALIGN); 285 1.4 takemura 286 1.4 takemura if (vmem_sub(VMEM_COPY, (void*)&dbg_eh, 287 1.4 takemura max_addr, 288 1.4 takemura sizeof(Elf_Ehdr), 289 1.4 takemura &byte_count) != 0) { 290 1.4 takemura goto error_cleanup; 291 1.4 takemura } 292 1.4 takemura 293 1.4 takemura dbg_sh[0].sh_type = shtbl[sh_symidx].sh_type; 294 1.4 takemura dbg_sh[0].sh_offset = dbg_hdr_size; 295 1.4 takemura dbg_sh[0].sh_size = shtbl[sh_symidx].sh_size; 296 1.4 takemura dbg_sh[0].sh_addralign = shtbl[sh_symidx].sh_addralign; 297 1.4 takemura dbg_sh[1].sh_type = shtbl[sh_stridx].sh_type; 298 1.4 takemura dbg_sh[1].sh_offset = dbg_hdr_size + shtbl[sh_symidx].sh_size; 299 1.4 takemura dbg_sh[1].sh_size = shtbl[sh_stridx].sh_size; 300 1.4 takemura dbg_sh[1].sh_addralign = shtbl[sh_stridx].sh_addralign; 301 1.4 takemura if (vmem_sub(VMEM_COPY, (void*)dbg_sh, 302 1.4 takemura max_addr + sizeof(Elf_Ehdr), 303 1.4 takemura sizeof(Elf_Shdr) * 2, 304 1.4 takemura &byte_count) != 0) { 305 1.4 takemura goto error_cleanup; 306 1.4 takemura } 307 1.4 takemura 308 1.4 takemura if (lseek(fd, shtbl[sh_symidx].sh_offset, SEEK_SET) == -1) { 309 1.4 takemura debug_printf(TEXT("seek for debug symbol error\n")); 310 1.4 takemura msg_printf(MSG_ERROR, whoami, 311 1.4 takemura TEXT("seek for segment error.\n")); 312 1.4 takemura goto error_cleanup; 313 1.4 takemura } 314 1.4 takemura if (vmem_sub(VMEM_LOAD, (void*)fd, 315 1.4 takemura max_addr + dbg_hdr_size, 316 1.4 takemura shtbl[sh_symidx].sh_size, 317 1.4 takemura &byte_count) != 0) { 318 1.4 takemura goto error_cleanup; 319 1.4 takemura } 320 1.4 takemura 321 1.4 takemura if (lseek(fd, shtbl[sh_stridx].sh_offset, SEEK_SET) == -1) { 322 1.4 takemura debug_printf(TEXT("seek for string table error\n")); 323 1.4 takemura msg_printf(MSG_ERROR, whoami, 324 1.4 takemura TEXT("seek for segment error.\n")); 325 1.4 takemura goto error_cleanup; 326 1.4 takemura } 327 1.4 takemura if (vmem_sub(VMEM_LOAD, (void*)fd, 328 1.4 takemura max_addr + dbg_hdr_size + shtbl[sh_symidx].sh_size, 329 1.4 takemura shtbl[sh_stridx].sh_size, 330 1.4 takemura &byte_count) != 0) { 331 1.4 takemura goto error_cleanup; 332 1.4 takemura } 333 1.4 takemura } else { 334 1.4 takemura /* 335 1.6 wiz * make space for debugging information 336 1.4 takemura */ 337 1.4 takemura int dbg_info_size = ROUNDUP(dbg_hdr_size + 338 1.4 takemura shtbl[sh_symidx].sh_size + 339 1.4 takemura shtbl[sh_stridx].sh_size, 340 1.4 takemura DEBUG_INFO_ALIGN); 341 1.5 toshii debug_printf(TEXT("%x bytes debug information\n"), 342 1.4 takemura dbg_info_size); 343 1.4 takemura max_addr += dbg_info_size; 344 1.4 takemura total_bytes += dbg_info_size; 345 1.4 takemura } 346 1.4 takemura } 347 1.4 takemura #endif /* LOAD_DEBUG_INFO */ 348 1.4 takemura 349 1.7 christos if (phtbl) dealloc(phtbl, sizeof(*phtbl) * elf->e_phnum); 350 1.7 christos if (shtbl) dealloc(shtbl, sizeof(*shtbl) * elf->e_shnum); 351 1.4 takemura 352 1.4 takemura if (start) *start = min_addr; 353 1.4 takemura if (end) *end = max_addr; 354 1.8 christos if (entry) *entry = (void *)elf->e_entry; 355 1.4 takemura return (0); 356 1.4 takemura 357 1.4 takemura error_cleanup: 358 1.7 christos if (phtbl) dealloc(phtbl, sizeof(*phtbl) * elf->e_phnum); 359 1.7 christos if (shtbl) dealloc(shtbl, sizeof(*shtbl) * elf->e_shnum); 360 1.4 takemura return (-1); 361 1.4 takemura } 362