183322Speter/* 283322Speter * Copyright (c) 2000, Boris Popov 383322Speter * All rights reserved. 483322Speter * 583322Speter * Redistribution and use in source and binary forms, with or without 683322Speter * modification, are permitted provided that the following conditions 783322Speter * are met: 883322Speter * 1. Redistributions of source code must retain the above copyright 983322Speter * notice, this list of conditions and the following disclaimer. 1083322Speter * 2. Redistributions in binary form must reproduce the above copyright 1183322Speter * notice, this list of conditions and the following disclaimer in the 1283322Speter * documentation and/or other materials provided with the distribution. 1383322Speter * 3. All advertising materials mentioning features or use of this software 1483322Speter * must display the following acknowledgement: 1583322Speter * This product includes software developed by Boris Popov. 1683322Speter * 4. Neither the name of the author nor the names of any co-contributors 1783322Speter * may be used to endorse or promote products derived from this software 1883322Speter * without specific prior written permission. 1983322Speter * 2083322Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2183322Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2283322Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2383322Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2483322Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2583322Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2683322Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2783322Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2883322Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2983322Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3083322Speter * SUCH DAMAGE. 3183322Speter * 3283322Speter * $FreeBSD$ 3383322Speter */ 3483322Speter 3583322Speter#include <sys/param.h> 3683322Speter#include <sys/linker.h> 3783322Speter#include <string.h> 38100272Speter#include <stdio.h> 39100272Speter#include <stdlib.h> 40100272Speter#include <unistd.h> 41100272Speter#include <errno.h> 42100272Speter#include <fcntl.h> 4383322Speter#include <machine/elf.h> 4483322Speter#define FREEBSD_ELF 4583322Speter 4683322Speter#include <err.h> 4783322Speter 4883322Speter#include "ef.h" 4983322Speter 50134358Siedowsestruct ef_file { 51134358Siedowse char* ef_name; 52134358Siedowse struct elf_file *ef_efile; 53134358Siedowse Elf_Phdr * ef_ph; 54134358Siedowse int ef_fd; 55134358Siedowse int ef_type; 56134358Siedowse Elf_Ehdr ef_hdr; 57134358Siedowse void* ef_fpage; /* First block of the file */ 58134358Siedowse int ef_fplen; /* length of first block */ 59134358Siedowse Elf_Dyn* ef_dyn; /* Symbol table etc. */ 60134358Siedowse Elf_Hashelt ef_nbuckets; 61134358Siedowse Elf_Hashelt ef_nchains; 62134358Siedowse Elf_Hashelt* ef_buckets; 63134358Siedowse Elf_Hashelt* ef_chains; 64134358Siedowse Elf_Hashelt* ef_hashtab; 65134358Siedowse Elf_Off ef_stroff; 66134358Siedowse caddr_t ef_strtab; 67134358Siedowse int ef_strsz; 68134358Siedowse Elf_Off ef_symoff; 69134358Siedowse Elf_Sym* ef_symtab; 70134358Siedowse int ef_nsegs; 71134358Siedowse Elf_Phdr * ef_segs[2]; 72134358Siedowse int ef_verbose; 73134358Siedowse Elf_Rel * ef_rel; /* relocation table */ 74134358Siedowse int ef_relsz; /* number of entries */ 75134358Siedowse Elf_Rela * ef_rela; /* relocation table */ 76134358Siedowse int ef_relasz; /* number of entries */ 77134358Siedowse}; 78134358Siedowse 7987551Smikehstatic void ef_print_phdr(Elf_Phdr *); 8087551Smikehstatic u_long ef_get_offset(elf_file_t, Elf_Off); 8187551Smikehstatic int ef_parse_dynamic(elf_file_t); 8287551Smikeh 83134358Siedowsestatic int ef_get_type(elf_file_t ef); 84134358Siedowsestatic int ef_close(elf_file_t ef); 85134358Siedowsestatic int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); 86134358Siedowsestatic int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr); 87134358Siedowsestatic int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest); 88134358Siedowsestatic int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, 89134358Siedowse void *dest); 90134358Siedowsestatic int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 91134358Siedowse void **ptr); 92134358Siedowsestatic int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 93134358Siedowse void **ptr); 94153504Smarcelstatic Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx); 95134358Siedowsestatic int ef_lookup_set(elf_file_t ef, const char *name, long *startp, 96134358Siedowse long *stopp, long *countp); 97134358Siedowsestatic int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); 98134358Siedowse 99134358Siedowsestatic struct elf_file_ops ef_file_ops = { 100134358Siedowse ef_get_type, 101134358Siedowse ef_close, 102134358Siedowse ef_read, 103134358Siedowse ef_read_entry, 104134358Siedowse ef_seg_read, 105134358Siedowse ef_seg_read_rel, 106134358Siedowse ef_seg_read_entry, 107134358Siedowse ef_seg_read_entry_rel, 108134358Siedowse ef_symaddr, 109134358Siedowse ef_lookup_set, 110134358Siedowse ef_lookup_symbol 111134358Siedowse}; 112134358Siedowse 113134358Siedowsestatic void 11483322Speteref_print_phdr(Elf_Phdr *phdr) 11583322Speter{ 11683322Speter 11783322Speter if ((phdr->p_flags & PF_W) == 0) { 11883322Speter printf("text=0x%lx ", (long)phdr->p_filesz); 11983322Speter } else { 12083322Speter printf("data=0x%lx", (long)phdr->p_filesz); 12183322Speter if (phdr->p_filesz < phdr->p_memsz) 12283322Speter printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz)); 12383322Speter printf(" "); 12483322Speter } 12583322Speter} 12683322Speter 127134358Siedowsestatic u_long 12883322Speteref_get_offset(elf_file_t ef, Elf_Off off) 12983322Speter{ 13083322Speter Elf_Phdr *ph; 13183322Speter int i; 13283322Speter 13383322Speter for (i = 0; i < ef->ef_nsegs; i++) { 13483322Speter ph = ef->ef_segs[i]; 13583322Speter if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) { 13683322Speter return ph->p_offset + (off - ph->p_vaddr); 13783322Speter } 13883322Speter } 13983322Speter return 0; 14083322Speter} 14183322Speter 142134358Siedowsestatic int 143134358Siedowseef_get_type(elf_file_t ef) 144134358Siedowse{ 145134358Siedowse 146134358Siedowse return (ef->ef_type); 147134358Siedowse} 148134358Siedowse 14983322Speter/* 15083322Speter * next three functions copied from link_elf.c 15183322Speter */ 15283322Speterstatic unsigned long 15383322Speterelf_hash(const char *name) 15483322Speter{ 15583322Speter const unsigned char *p = (const unsigned char *) name; 15683322Speter unsigned long h = 0; 15783322Speter unsigned long g; 15883322Speter 15983322Speter while (*p != '\0') { 16083322Speter h = (h << 4) + *p++; 16183322Speter if ((g = h & 0xf0000000) != 0) 16283322Speter h ^= g >> 24; 16383322Speter h &= ~g; 16483322Speter } 16583322Speter return h; 16683322Speter} 16783322Speter 168134358Siedowsestatic int 16983322Speteref_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 17083322Speter{ 17183322Speter unsigned long symnum; 17283322Speter Elf_Sym* symp; 17383322Speter char *strp; 17483322Speter unsigned long hash; 17583322Speter 17683322Speter /* First, search hashed global symbols */ 17783322Speter hash = elf_hash(name); 17883322Speter symnum = ef->ef_buckets[hash % ef->ef_nbuckets]; 17983322Speter 18083322Speter while (symnum != STN_UNDEF) { 18183322Speter if (symnum >= ef->ef_nchains) { 18283322Speter warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 18383322Speter ef->ef_name); 18483322Speter return ENOENT; 18583322Speter } 18683322Speter 18783322Speter symp = ef->ef_symtab + symnum; 18883322Speter if (symp->st_name == 0) { 18983322Speter warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 19083322Speter ef->ef_name); 19183322Speter return ENOENT; 19283322Speter } 19383322Speter 19483322Speter strp = ef->ef_strtab + symp->st_name; 19583322Speter 19683322Speter if (strcmp(name, strp) == 0) { 19783322Speter if (symp->st_shndx != SHN_UNDEF || 19883322Speter (symp->st_value != 0 && 19983322Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 20083322Speter *sym = symp; 20183322Speter return 0; 20283322Speter } else 20383322Speter return ENOENT; 20483322Speter } 20583322Speter 20683322Speter symnum = ef->ef_chains[symnum]; 20783322Speter } 20883322Speter 20983322Speter return ENOENT; 21083322Speter} 21183322Speter 212134358Siedowsestatic int 213134358Siedowseef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, 214134358Siedowse long *countp) 215134358Siedowse{ 216134358Siedowse Elf_Sym *sym; 217134358Siedowse char *setsym; 218134358Siedowse int error, len; 219134358Siedowse 220134358Siedowse len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 221134358Siedowse setsym = malloc(len); 222134358Siedowse if (setsym == NULL) 223134358Siedowse return (ENOMEM); 224134358Siedowse 225134358Siedowse /* get address of first entry */ 226134358Siedowse snprintf(setsym, len, "%s%s", "__start_set_", name); 227134358Siedowse error = ef_lookup_symbol(ef, setsym, &sym); 228134358Siedowse if (error) 229134358Siedowse goto out; 230134358Siedowse *startp = sym->st_value; 231134358Siedowse 232134358Siedowse /* get address of last entry */ 233134358Siedowse snprintf(setsym, len, "%s%s", "__stop_set_", name); 234134358Siedowse error = ef_lookup_symbol(ef, setsym, &sym); 235134358Siedowse if (error) 236134358Siedowse goto out; 237134358Siedowse *stopp = sym->st_value; 238134358Siedowse 239134358Siedowse /* and the number of entries */ 240134358Siedowse *countp = (*stopp - *startp) / sizeof(void *); 241134358Siedowse 242134358Siedowseout: 243134358Siedowse free(setsym); 244134358Siedowse return (error); 245134358Siedowse} 246134358Siedowse 247134358Siedowsestatic Elf_Addr 248153504Smarcelef_symaddr(elf_file_t ef, Elf_Size symidx) 249134358Siedowse{ 250134358Siedowse const Elf_Sym *sym; 251134358Siedowse 252134358Siedowse if (symidx >= ef->ef_nchains) 253134358Siedowse return (0); 254134358Siedowse sym = ef->ef_symtab + symidx; 255134358Siedowse 256134358Siedowse if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 257134358Siedowse sym->st_shndx != SHN_UNDEF && sym->st_value != 0) 258134358Siedowse return (sym->st_value); 259134358Siedowse return (0); 260134358Siedowse} 261134358Siedowse 262134358Siedowsestatic int 26383322Speteref_parse_dynamic(elf_file_t ef) 26483322Speter{ 26583322Speter Elf_Dyn *dp; 26694414Speter Elf_Hashelt hashhdr[2]; 26783322Speter/* int plttype = DT_REL;*/ 26883322Speter int error; 269109607Sjake Elf_Off rel_off; 270109607Sjake Elf_Off rela_off; 271109607Sjake int rel_sz; 272109607Sjake int rela_sz; 273109607Sjake int rel_entry; 274109607Sjake int rela_entry; 27583322Speter 276109607Sjake rel_off = rela_off = 0; 277109607Sjake rel_sz = rela_sz = 0; 278109607Sjake rel_entry = rela_entry = 0; 27983322Speter for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) { 28083322Speter switch (dp->d_tag) { 28183322Speter case DT_HASH: 28283322Speter error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr), 28383322Speter sizeof(hashhdr), hashhdr); 28483322Speter if (error) { 28583322Speter warnx("can't read hash header (%lx)", 28683322Speter ef_get_offset(ef, dp->d_un.d_ptr)); 28783322Speter return error; 28883322Speter } 28983322Speter ef->ef_nbuckets = hashhdr[0]; 29083322Speter ef->ef_nchains = hashhdr[1]; 29183322Speter error = ef_read_entry(ef, -1, 29294414Speter (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt), 29383322Speter (void**)&ef->ef_hashtab); 29483322Speter if (error) { 29583322Speter warnx("can't read hash table"); 29683322Speter return error; 29783322Speter } 29883322Speter ef->ef_buckets = ef->ef_hashtab; 29983322Speter ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets; 30083322Speter break; 30183322Speter case DT_STRTAB: 30283322Speter ef->ef_stroff = dp->d_un.d_ptr; 30383322Speter break; 30483322Speter case DT_STRSZ: 30583322Speter ef->ef_strsz = dp->d_un.d_val; 30683322Speter break; 30783322Speter case DT_SYMTAB: 30883322Speter ef->ef_symoff = dp->d_un.d_ptr; 30983322Speter break; 31083322Speter case DT_SYMENT: 31183322Speter if (dp->d_un.d_val != sizeof(Elf_Sym)) 31283322Speter return EFTYPE; 31383322Speter break; 314109607Sjake case DT_REL: 315109607Sjake if (rel_off != 0) 316109607Sjake warnx("second DT_REL entry ignored"); 317109607Sjake rel_off = dp->d_un.d_ptr; 318109607Sjake break; 319109607Sjake case DT_RELSZ: 320109607Sjake if (rel_sz != 0) 321109607Sjake warnx("second DT_RELSZ entry ignored"); 322109607Sjake rel_sz = dp->d_un.d_val; 323109607Sjake break; 324109607Sjake case DT_RELENT: 325109607Sjake if (rel_entry != 0) 326109607Sjake warnx("second DT_RELENT entry ignored"); 327109607Sjake rel_entry = dp->d_un.d_val; 328109607Sjake break; 329109607Sjake case DT_RELA: 330109607Sjake if (rela_off != 0) 331109607Sjake warnx("second DT_RELA entry ignored"); 332109607Sjake rela_off = dp->d_un.d_ptr; 333109607Sjake break; 334109607Sjake case DT_RELASZ: 335109607Sjake if (rela_sz != 0) 336109607Sjake warnx("second DT_RELASZ entry ignored"); 337109607Sjake rela_sz = dp->d_un.d_val; 338109607Sjake break; 339109607Sjake case DT_RELAENT: 340109607Sjake if (rela_entry != 0) 341109607Sjake warnx("second DT_RELAENT entry ignored"); 342109607Sjake rela_entry = dp->d_un.d_val; 343109607Sjake break; 34483322Speter } 34583322Speter } 34683322Speter if (ef->ef_symoff == 0) { 34783322Speter warnx("%s: no .dynsym section found\n", ef->ef_name); 34883322Speter return EFTYPE; 34983322Speter } 35083322Speter if (ef->ef_stroff == 0) { 35183322Speter warnx("%s: no .dynstr section found\n", ef->ef_name); 35283322Speter return EFTYPE; 35383322Speter } 35483322Speter if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff), 35583322Speter ef->ef_nchains * sizeof(Elf_Sym), 35683322Speter (void**)&ef->ef_symtab) != 0) { 35783322Speter if (ef->ef_verbose) 35883322Speter warnx("%s: can't load .dynsym section (0x%lx)", 35983322Speter ef->ef_name, (long)ef->ef_symoff); 36083322Speter return EIO; 36183322Speter } 36283322Speter if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz, 36383322Speter (void**)&ef->ef_strtab) != 0) { 36483322Speter warnx("can't load .dynstr section"); 36583322Speter return EIO; 36683322Speter } 367109607Sjake if (rel_off != 0) { 368109607Sjake if (rel_entry == 0) { 369109607Sjake warnx("%s: no DT_RELENT for DT_REL", ef->ef_name); 370109607Sjake return (EFTYPE); 371109607Sjake } 372109607Sjake if (rel_entry != sizeof(Elf_Rel)) { 373109607Sjake warnx("%s: inconsistent DT_RELENT value", 374109607Sjake ef->ef_name); 375109607Sjake return (EFTYPE); 376109607Sjake } 377109607Sjake if (rel_sz % rel_entry != 0) { 378109607Sjake warnx("%s: inconsistent values for DT_RELSZ and " 379109607Sjake "DT_RELENT", ef->ef_name); 380109607Sjake return (EFTYPE); 381109607Sjake } 382109607Sjake if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz, 383109607Sjake (void **)&ef->ef_rel) != 0) { 384109607Sjake warnx("%s: cannot load DT_REL section", ef->ef_name); 385109607Sjake return (EIO); 386109607Sjake } 387109607Sjake ef->ef_relsz = rel_sz / rel_entry; 388109607Sjake if (ef->ef_verbose) 389109607Sjake warnx("%s: %d REL entries", ef->ef_name, 390109607Sjake ef->ef_relsz); 391109607Sjake } 392109607Sjake if (rela_off != 0) { 393109607Sjake if (rela_entry == 0) { 394109607Sjake warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name); 395109607Sjake return (EFTYPE); 396109607Sjake } 397109607Sjake if (rela_entry != sizeof(Elf_Rela)) { 398109607Sjake warnx("%s: inconsistent DT_RELAENT value", 399109607Sjake ef->ef_name); 400109607Sjake return (EFTYPE); 401109607Sjake } 402109607Sjake if (rela_sz % rela_entry != 0) { 403109607Sjake warnx("%s: inconsistent values for DT_RELASZ and " 404109607Sjake "DT_RELAENT", ef->ef_name); 405109607Sjake return (EFTYPE); 406109607Sjake } 407109607Sjake if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz, 408109607Sjake (void **)&ef->ef_rela) != 0) { 409109607Sjake warnx("%s: cannot load DT_RELA section", ef->ef_name); 410109607Sjake return (EIO); 411109607Sjake } 412109607Sjake ef->ef_relasz = rela_sz / rela_entry; 413109607Sjake if (ef->ef_verbose) 414109607Sjake warnx("%s: %d RELA entries", ef->ef_name, 415109607Sjake ef->ef_relasz); 416109607Sjake } 41783322Speter return 0; 41883322Speter} 41983322Speter 420134358Siedowsestatic int 42183322Speteref_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 42283322Speter{ 42387551Smikeh ssize_t r; 42483322Speter 42587551Smikeh if (offset != (Elf_Off)-1) { 42683322Speter if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 42783322Speter return EIO; 42883322Speter } 42987551Smikeh 43087551Smikeh r = read(ef->ef_fd, dest, len); 43187551Smikeh if (r != -1 && (size_t)r == len) 43287551Smikeh return 0; 43387551Smikeh else 43487551Smikeh return EIO; 43583322Speter} 43683322Speter 437134358Siedowsestatic int 43883322Speteref_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 43983322Speter{ 44083322Speter int error; 44183322Speter 44283322Speter *ptr = malloc(len); 44383322Speter if (*ptr == NULL) 44483322Speter return ENOMEM; 44583322Speter error = ef_read(ef, offset, len, *ptr); 44683322Speter if (error) 44783322Speter free(*ptr); 44883322Speter return error; 44983322Speter} 45083322Speter 451134358Siedowsestatic int 45283322Speteref_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 45383322Speter{ 45483322Speter u_long ofs = ef_get_offset(ef, offset); 45583322Speter 45683322Speter if (ofs == 0) { 45783322Speter if (ef->ef_verbose) 45883322Speter warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 45983322Speter ef->ef_name, (long)offset, ofs); 46083322Speter return EFAULT; 46183322Speter } 46283322Speter return ef_read(ef, ofs, len, dest); 46383322Speter} 46483322Speter 465134358Siedowsestatic int 466109607Sjakeef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 467109607Sjake{ 468109607Sjake u_long ofs = ef_get_offset(ef, offset); 469134358Siedowse const Elf_Rela *a; 470134358Siedowse const Elf_Rel *r; 471109607Sjake int error; 472109607Sjake 473109607Sjake if (ofs == 0) { 474109607Sjake if (ef->ef_verbose) 475109607Sjake warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 476109607Sjake ef->ef_name, (long)offset, ofs); 477109607Sjake return EFAULT; 478109607Sjake } 479109607Sjake if ((error = ef_read(ef, ofs, len, dest)) != 0) 480109607Sjake return (error); 481134358Siedowse 482134358Siedowse for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) { 483134450Siedowse error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len, 484134358Siedowse dest); 485134358Siedowse if (error != 0) 486134358Siedowse return (error); 487134358Siedowse } 488134358Siedowse for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) { 489134450Siedowse error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len, 490134358Siedowse dest); 491134358Siedowse if (error != 0) 492134358Siedowse return (error); 493134358Siedowse } 494134358Siedowse return (0); 495109607Sjake} 496109607Sjake 497134358Siedowsestatic int 49883322Speteref_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 49983322Speter{ 50083322Speter int error; 50183322Speter 50283322Speter *ptr = malloc(len); 50383322Speter if (*ptr == NULL) 50483322Speter return ENOMEM; 50583322Speter error = ef_seg_read(ef, offset, len, *ptr); 50683322Speter if (error) 50783322Speter free(*ptr); 50883322Speter return error; 50983322Speter} 51083322Speter 511134358Siedowsestatic int 512109607Sjakeef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 513109607Sjake{ 514109607Sjake int error; 515109607Sjake 516109607Sjake *ptr = malloc(len); 517109607Sjake if (*ptr == NULL) 518109607Sjake return ENOMEM; 519109607Sjake error = ef_seg_read_rel(ef, offset, len, *ptr); 520109607Sjake if (error) 521109607Sjake free(*ptr); 522109607Sjake return error; 523109607Sjake} 524109607Sjake 525109607Sjakeint 526134358Siedowseef_open(const char *filename, struct elf_file *efile, int verbose) 52783322Speter{ 528134358Siedowse elf_file_t ef; 52983322Speter Elf_Ehdr *hdr; 53083322Speter int fd; 53183322Speter int error; 53283322Speter int phlen, res; 53383322Speter int nsegs; 534237415Seadler Elf_Phdr *phdr, *phdyn, *phlimit; 53583322Speter 53683322Speter if (filename == NULL) 53783322Speter return EFTYPE; 53883322Speter if ((fd = open(filename, O_RDONLY)) == -1) 53983322Speter return errno; 540134358Siedowse 541134358Siedowse ef = malloc(sizeof(*ef)); 542134358Siedowse if (ef == NULL) { 543134358Siedowse close(fd); 544134358Siedowse return (ENOMEM); 545134358Siedowse } 546134358Siedowse 547134358Siedowse efile->ef_ef = ef; 548134358Siedowse efile->ef_ops = &ef_file_ops; 549134358Siedowse 550134358Siedowse bzero(ef, sizeof(*ef)); 551134358Siedowse ef->ef_verbose = verbose; 55283322Speter ef->ef_fd = fd; 55383322Speter ef->ef_name = strdup(filename); 554134358Siedowse ef->ef_efile = efile; 55583322Speter hdr = (Elf_Ehdr *)&ef->ef_hdr; 55683322Speter do { 55783322Speter res = read(fd, hdr, sizeof(*hdr)); 55883322Speter error = EFTYPE; 55983322Speter if (res != sizeof(*hdr)) 56083322Speter break; 56183322Speter if (!IS_ELF(*hdr)) 56283322Speter break; 56383322Speter if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 56483322Speter hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 56583322Speter hdr->e_ident[EI_VERSION] != EV_CURRENT || 56683322Speter hdr->e_version != EV_CURRENT || 56783322Speter hdr->e_machine != ELF_TARG_MACH || 56883322Speter hdr->e_phentsize != sizeof(Elf_Phdr)) 56983322Speter break; 57083322Speter phlen = hdr->e_phnum * sizeof(Elf_Phdr); 57183322Speter if (ef_read_entry(ef, hdr->e_phoff, phlen, 57283322Speter (void**)&ef->ef_ph) != 0) 57383322Speter break; 57483322Speter phdr = ef->ef_ph; 57583322Speter phlimit = phdr + hdr->e_phnum; 57683322Speter nsegs = 0; 57783322Speter phdyn = NULL; 57883322Speter while (phdr < phlimit) { 57983322Speter if (verbose > 1) 58083322Speter ef_print_phdr(phdr); 58183322Speter switch (phdr->p_type) { 58283322Speter case PT_LOAD: 58383322Speter if (nsegs == 2) { 58483322Speter warnx("%s: too many sections", 58583322Speter filename); 58683322Speter break; 58783322Speter } 58883322Speter ef->ef_segs[nsegs++] = phdr; 58983322Speter break; 59083322Speter case PT_PHDR: 59183322Speter break; 59283322Speter case PT_DYNAMIC: 59383322Speter phdyn = phdr; 59483322Speter break; 59583322Speter } 59683322Speter phdr++; 59783322Speter } 59883322Speter if (verbose > 1) 59983322Speter printf("\n"); 60083322Speter ef->ef_nsegs = nsegs; 60183322Speter if (phdyn == NULL) { 60283322Speter warnx("file isn't dynamically-linked"); 60383322Speter break; 60483322Speter } 60583322Speter if (ef_read_entry(ef, phdyn->p_offset, 60683322Speter phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) { 60783322Speter printf("ef_read_entry failed\n"); 60883322Speter break; 60983322Speter } 61083322Speter error = ef_parse_dynamic(ef); 61183322Speter if (error) 61283322Speter break; 61383322Speter if (hdr->e_type == ET_DYN) { 61483322Speter ef->ef_type = EFT_KLD; 61583322Speter/* pad = (u_int)dest & PAGE_MASK; 61683322Speter if (pad) 61783322Speter dest += PAGE_SIZE - pad;*/ 61883322Speter error = 0; 61983322Speter } else if (hdr->e_type == ET_EXEC) { 62083322Speter/* dest = hdr->e_entry; 62183322Speter if (dest == 0) 62283322Speter break;*/ 62383322Speter ef->ef_type = EFT_KERNEL; 62483322Speter error = 0; 62583322Speter } else 62683322Speter break; 62783322Speter } while(0); 628134358Siedowse if (error) 62983322Speter ef_close(ef); 63083322Speter return error; 63183322Speter} 63283322Speter 633134358Siedowsestatic int 63483322Speteref_close(elf_file_t ef) 63583322Speter{ 63683322Speter close(ef->ef_fd); 63783322Speter/* if (ef->ef_fpage) 63883322Speter free(ef->ef_fpage);*/ 63983322Speter if (ef->ef_name) 64083322Speter free(ef->ef_name); 641134358Siedowse ef->ef_efile->ef_ops = NULL; 642134358Siedowse ef->ef_efile->ef_ef = NULL; 643134358Siedowse free(ef); 64483322Speter return 0; 64583322Speter} 646