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 50269014Semaste#define MAXSEGS 2 51134358Siedowsestruct ef_file { 52134358Siedowse char* ef_name; 53134358Siedowse struct elf_file *ef_efile; 54134358Siedowse Elf_Phdr * ef_ph; 55134358Siedowse int ef_fd; 56134358Siedowse int ef_type; 57134358Siedowse Elf_Ehdr ef_hdr; 58134358Siedowse void* ef_fpage; /* First block of the file */ 59134358Siedowse int ef_fplen; /* length of first block */ 60134358Siedowse Elf_Dyn* ef_dyn; /* Symbol table etc. */ 61134358Siedowse Elf_Hashelt ef_nbuckets; 62134358Siedowse Elf_Hashelt ef_nchains; 63134358Siedowse Elf_Hashelt* ef_buckets; 64134358Siedowse Elf_Hashelt* ef_chains; 65134358Siedowse Elf_Hashelt* ef_hashtab; 66134358Siedowse Elf_Off ef_stroff; 67134358Siedowse caddr_t ef_strtab; 68134358Siedowse int ef_strsz; 69134358Siedowse Elf_Off ef_symoff; 70134358Siedowse Elf_Sym* ef_symtab; 71134358Siedowse int ef_nsegs; 72269014Semaste Elf_Phdr * ef_segs[MAXSEGS]; 73134358Siedowse int ef_verbose; 74134358Siedowse Elf_Rel * ef_rel; /* relocation table */ 75134358Siedowse int ef_relsz; /* number of entries */ 76134358Siedowse Elf_Rela * ef_rela; /* relocation table */ 77134358Siedowse int ef_relasz; /* number of entries */ 78134358Siedowse}; 79134358Siedowse 8087551Smikehstatic void ef_print_phdr(Elf_Phdr *); 8187551Smikehstatic u_long ef_get_offset(elf_file_t, Elf_Off); 8287551Smikehstatic int ef_parse_dynamic(elf_file_t); 8387551Smikeh 84134358Siedowsestatic int ef_get_type(elf_file_t ef); 85134358Siedowsestatic int ef_close(elf_file_t ef); 86134358Siedowsestatic int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); 87134358Siedowsestatic int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr); 88134358Siedowsestatic int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest); 89134358Siedowsestatic int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, 90134358Siedowse void *dest); 91134358Siedowsestatic int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 92134358Siedowse void **ptr); 93134358Siedowsestatic int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 94134358Siedowse void **ptr); 95153504Smarcelstatic Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx); 96134358Siedowsestatic int ef_lookup_set(elf_file_t ef, const char *name, long *startp, 97134358Siedowse long *stopp, long *countp); 98134358Siedowsestatic int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); 99134358Siedowse 100134358Siedowsestatic struct elf_file_ops ef_file_ops = { 101134358Siedowse ef_get_type, 102134358Siedowse ef_close, 103134358Siedowse ef_read, 104134358Siedowse ef_read_entry, 105134358Siedowse ef_seg_read, 106134358Siedowse ef_seg_read_rel, 107134358Siedowse ef_seg_read_entry, 108134358Siedowse ef_seg_read_entry_rel, 109134358Siedowse ef_symaddr, 110134358Siedowse ef_lookup_set, 111134358Siedowse ef_lookup_symbol 112134358Siedowse}; 113134358Siedowse 114134358Siedowsestatic void 11583322Speteref_print_phdr(Elf_Phdr *phdr) 11683322Speter{ 11783322Speter 11883322Speter if ((phdr->p_flags & PF_W) == 0) { 11983322Speter printf("text=0x%lx ", (long)phdr->p_filesz); 12083322Speter } else { 12183322Speter printf("data=0x%lx", (long)phdr->p_filesz); 12283322Speter if (phdr->p_filesz < phdr->p_memsz) 12383322Speter printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz)); 12483322Speter printf(" "); 12583322Speter } 12683322Speter} 12783322Speter 128134358Siedowsestatic u_long 12983322Speteref_get_offset(elf_file_t ef, Elf_Off off) 13083322Speter{ 13183322Speter Elf_Phdr *ph; 13283322Speter int i; 13383322Speter 13483322Speter for (i = 0; i < ef->ef_nsegs; i++) { 13583322Speter ph = ef->ef_segs[i]; 13683322Speter if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) { 13783322Speter return ph->p_offset + (off - ph->p_vaddr); 13883322Speter } 13983322Speter } 14083322Speter return 0; 14183322Speter} 14283322Speter 143134358Siedowsestatic int 144134358Siedowseef_get_type(elf_file_t ef) 145134358Siedowse{ 146134358Siedowse 147134358Siedowse return (ef->ef_type); 148134358Siedowse} 149134358Siedowse 15083322Speter/* 15183322Speter * next three functions copied from link_elf.c 15283322Speter */ 15383322Speterstatic unsigned long 15483322Speterelf_hash(const char *name) 15583322Speter{ 15683322Speter const unsigned char *p = (const unsigned char *) name; 15783322Speter unsigned long h = 0; 15883322Speter unsigned long g; 15983322Speter 16083322Speter while (*p != '\0') { 16183322Speter h = (h << 4) + *p++; 16283322Speter if ((g = h & 0xf0000000) != 0) 16383322Speter h ^= g >> 24; 16483322Speter h &= ~g; 16583322Speter } 16683322Speter return h; 16783322Speter} 16883322Speter 169134358Siedowsestatic int 17083322Speteref_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 17183322Speter{ 17283322Speter unsigned long symnum; 17383322Speter Elf_Sym* symp; 17483322Speter char *strp; 17583322Speter unsigned long hash; 17683322Speter 17783322Speter /* First, search hashed global symbols */ 17883322Speter hash = elf_hash(name); 17983322Speter symnum = ef->ef_buckets[hash % ef->ef_nbuckets]; 18083322Speter 18183322Speter while (symnum != STN_UNDEF) { 18283322Speter if (symnum >= ef->ef_nchains) { 18383322Speter warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 18483322Speter ef->ef_name); 18583322Speter return ENOENT; 18683322Speter } 18783322Speter 18883322Speter symp = ef->ef_symtab + symnum; 18983322Speter if (symp->st_name == 0) { 19083322Speter warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 19183322Speter ef->ef_name); 19283322Speter return ENOENT; 19383322Speter } 19483322Speter 19583322Speter strp = ef->ef_strtab + symp->st_name; 19683322Speter 19783322Speter if (strcmp(name, strp) == 0) { 19883322Speter if (symp->st_shndx != SHN_UNDEF || 19983322Speter (symp->st_value != 0 && 20083322Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 20183322Speter *sym = symp; 20283322Speter return 0; 20383322Speter } else 20483322Speter return ENOENT; 20583322Speter } 20683322Speter 20783322Speter symnum = ef->ef_chains[symnum]; 20883322Speter } 20983322Speter 21083322Speter return ENOENT; 21183322Speter} 21283322Speter 213134358Siedowsestatic int 214134358Siedowseef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, 215134358Siedowse long *countp) 216134358Siedowse{ 217134358Siedowse Elf_Sym *sym; 218134358Siedowse char *setsym; 219134358Siedowse int error, len; 220134358Siedowse 221134358Siedowse len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 222134358Siedowse setsym = malloc(len); 223134358Siedowse if (setsym == NULL) 224134358Siedowse return (ENOMEM); 225134358Siedowse 226134358Siedowse /* get address of first entry */ 227134358Siedowse snprintf(setsym, len, "%s%s", "__start_set_", name); 228134358Siedowse error = ef_lookup_symbol(ef, setsym, &sym); 229134358Siedowse if (error) 230134358Siedowse goto out; 231134358Siedowse *startp = sym->st_value; 232134358Siedowse 233134358Siedowse /* get address of last entry */ 234134358Siedowse snprintf(setsym, len, "%s%s", "__stop_set_", name); 235134358Siedowse error = ef_lookup_symbol(ef, setsym, &sym); 236134358Siedowse if (error) 237134358Siedowse goto out; 238134358Siedowse *stopp = sym->st_value; 239134358Siedowse 240134358Siedowse /* and the number of entries */ 241134358Siedowse *countp = (*stopp - *startp) / sizeof(void *); 242134358Siedowse 243134358Siedowseout: 244134358Siedowse free(setsym); 245134358Siedowse return (error); 246134358Siedowse} 247134358Siedowse 248134358Siedowsestatic Elf_Addr 249153504Smarcelef_symaddr(elf_file_t ef, Elf_Size symidx) 250134358Siedowse{ 251134358Siedowse const Elf_Sym *sym; 252134358Siedowse 253134358Siedowse if (symidx >= ef->ef_nchains) 254134358Siedowse return (0); 255134358Siedowse sym = ef->ef_symtab + symidx; 256134358Siedowse 257134358Siedowse if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 258134358Siedowse sym->st_shndx != SHN_UNDEF && sym->st_value != 0) 259134358Siedowse return (sym->st_value); 260134358Siedowse return (0); 261134358Siedowse} 262134358Siedowse 263134358Siedowsestatic int 26483322Speteref_parse_dynamic(elf_file_t ef) 26583322Speter{ 26683322Speter Elf_Dyn *dp; 26794414Speter Elf_Hashelt hashhdr[2]; 26883322Speter/* int plttype = DT_REL;*/ 26983322Speter int error; 270109607Sjake Elf_Off rel_off; 271109607Sjake Elf_Off rela_off; 272109607Sjake int rel_sz; 273109607Sjake int rela_sz; 274109607Sjake int rel_entry; 275109607Sjake int rela_entry; 27683322Speter 277109607Sjake rel_off = rela_off = 0; 278109607Sjake rel_sz = rela_sz = 0; 279109607Sjake rel_entry = rela_entry = 0; 28083322Speter for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) { 28183322Speter switch (dp->d_tag) { 28283322Speter case DT_HASH: 28383322Speter error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr), 28483322Speter sizeof(hashhdr), hashhdr); 28583322Speter if (error) { 28683322Speter warnx("can't read hash header (%lx)", 28783322Speter ef_get_offset(ef, dp->d_un.d_ptr)); 28883322Speter return error; 28983322Speter } 29083322Speter ef->ef_nbuckets = hashhdr[0]; 29183322Speter ef->ef_nchains = hashhdr[1]; 29283322Speter error = ef_read_entry(ef, -1, 29394414Speter (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt), 29483322Speter (void**)&ef->ef_hashtab); 29583322Speter if (error) { 29683322Speter warnx("can't read hash table"); 29783322Speter return error; 29883322Speter } 29983322Speter ef->ef_buckets = ef->ef_hashtab; 30083322Speter ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets; 30183322Speter break; 30283322Speter case DT_STRTAB: 30383322Speter ef->ef_stroff = dp->d_un.d_ptr; 30483322Speter break; 30583322Speter case DT_STRSZ: 30683322Speter ef->ef_strsz = dp->d_un.d_val; 30783322Speter break; 30883322Speter case DT_SYMTAB: 30983322Speter ef->ef_symoff = dp->d_un.d_ptr; 31083322Speter break; 31183322Speter case DT_SYMENT: 31283322Speter if (dp->d_un.d_val != sizeof(Elf_Sym)) 31383322Speter return EFTYPE; 31483322Speter break; 315109607Sjake case DT_REL: 316109607Sjake if (rel_off != 0) 317109607Sjake warnx("second DT_REL entry ignored"); 318109607Sjake rel_off = dp->d_un.d_ptr; 319109607Sjake break; 320109607Sjake case DT_RELSZ: 321109607Sjake if (rel_sz != 0) 322109607Sjake warnx("second DT_RELSZ entry ignored"); 323109607Sjake rel_sz = dp->d_un.d_val; 324109607Sjake break; 325109607Sjake case DT_RELENT: 326109607Sjake if (rel_entry != 0) 327109607Sjake warnx("second DT_RELENT entry ignored"); 328109607Sjake rel_entry = dp->d_un.d_val; 329109607Sjake break; 330109607Sjake case DT_RELA: 331109607Sjake if (rela_off != 0) 332109607Sjake warnx("second DT_RELA entry ignored"); 333109607Sjake rela_off = dp->d_un.d_ptr; 334109607Sjake break; 335109607Sjake case DT_RELASZ: 336109607Sjake if (rela_sz != 0) 337109607Sjake warnx("second DT_RELASZ entry ignored"); 338109607Sjake rela_sz = dp->d_un.d_val; 339109607Sjake break; 340109607Sjake case DT_RELAENT: 341109607Sjake if (rela_entry != 0) 342109607Sjake warnx("second DT_RELAENT entry ignored"); 343109607Sjake rela_entry = dp->d_un.d_val; 344109607Sjake break; 34583322Speter } 34683322Speter } 34783322Speter if (ef->ef_symoff == 0) { 34883322Speter warnx("%s: no .dynsym section found\n", ef->ef_name); 34983322Speter return EFTYPE; 35083322Speter } 35183322Speter if (ef->ef_stroff == 0) { 35283322Speter warnx("%s: no .dynstr section found\n", ef->ef_name); 35383322Speter return EFTYPE; 35483322Speter } 35583322Speter if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff), 35683322Speter ef->ef_nchains * sizeof(Elf_Sym), 35783322Speter (void**)&ef->ef_symtab) != 0) { 35883322Speter if (ef->ef_verbose) 35983322Speter warnx("%s: can't load .dynsym section (0x%lx)", 36083322Speter ef->ef_name, (long)ef->ef_symoff); 36183322Speter return EIO; 36283322Speter } 36383322Speter if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz, 36483322Speter (void**)&ef->ef_strtab) != 0) { 36583322Speter warnx("can't load .dynstr section"); 36683322Speter return EIO; 36783322Speter } 368109607Sjake if (rel_off != 0) { 369109607Sjake if (rel_entry == 0) { 370109607Sjake warnx("%s: no DT_RELENT for DT_REL", ef->ef_name); 371109607Sjake return (EFTYPE); 372109607Sjake } 373109607Sjake if (rel_entry != sizeof(Elf_Rel)) { 374109607Sjake warnx("%s: inconsistent DT_RELENT value", 375109607Sjake ef->ef_name); 376109607Sjake return (EFTYPE); 377109607Sjake } 378109607Sjake if (rel_sz % rel_entry != 0) { 379109607Sjake warnx("%s: inconsistent values for DT_RELSZ and " 380109607Sjake "DT_RELENT", ef->ef_name); 381109607Sjake return (EFTYPE); 382109607Sjake } 383109607Sjake if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz, 384109607Sjake (void **)&ef->ef_rel) != 0) { 385109607Sjake warnx("%s: cannot load DT_REL section", ef->ef_name); 386109607Sjake return (EIO); 387109607Sjake } 388109607Sjake ef->ef_relsz = rel_sz / rel_entry; 389109607Sjake if (ef->ef_verbose) 390109607Sjake warnx("%s: %d REL entries", ef->ef_name, 391109607Sjake ef->ef_relsz); 392109607Sjake } 393109607Sjake if (rela_off != 0) { 394109607Sjake if (rela_entry == 0) { 395109607Sjake warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name); 396109607Sjake return (EFTYPE); 397109607Sjake } 398109607Sjake if (rela_entry != sizeof(Elf_Rela)) { 399109607Sjake warnx("%s: inconsistent DT_RELAENT value", 400109607Sjake ef->ef_name); 401109607Sjake return (EFTYPE); 402109607Sjake } 403109607Sjake if (rela_sz % rela_entry != 0) { 404109607Sjake warnx("%s: inconsistent values for DT_RELASZ and " 405109607Sjake "DT_RELAENT", ef->ef_name); 406109607Sjake return (EFTYPE); 407109607Sjake } 408109607Sjake if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz, 409109607Sjake (void **)&ef->ef_rela) != 0) { 410109607Sjake warnx("%s: cannot load DT_RELA section", ef->ef_name); 411109607Sjake return (EIO); 412109607Sjake } 413109607Sjake ef->ef_relasz = rela_sz / rela_entry; 414109607Sjake if (ef->ef_verbose) 415109607Sjake warnx("%s: %d RELA entries", ef->ef_name, 416109607Sjake ef->ef_relasz); 417109607Sjake } 41883322Speter return 0; 41983322Speter} 42083322Speter 421134358Siedowsestatic int 42283322Speteref_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 42383322Speter{ 42487551Smikeh ssize_t r; 42583322Speter 42687551Smikeh if (offset != (Elf_Off)-1) { 42783322Speter if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 42883322Speter return EIO; 42983322Speter } 43087551Smikeh 43187551Smikeh r = read(ef->ef_fd, dest, len); 43287551Smikeh if (r != -1 && (size_t)r == len) 43387551Smikeh return 0; 43487551Smikeh else 43587551Smikeh return EIO; 43683322Speter} 43783322Speter 438134358Siedowsestatic int 43983322Speteref_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 44083322Speter{ 44183322Speter int error; 44283322Speter 44383322Speter *ptr = malloc(len); 44483322Speter if (*ptr == NULL) 44583322Speter return ENOMEM; 44683322Speter error = ef_read(ef, offset, len, *ptr); 44783322Speter if (error) 44883322Speter free(*ptr); 44983322Speter return error; 45083322Speter} 45183322Speter 452134358Siedowsestatic int 45383322Speteref_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 45483322Speter{ 45583322Speter u_long ofs = ef_get_offset(ef, offset); 45683322Speter 45783322Speter if (ofs == 0) { 45883322Speter if (ef->ef_verbose) 45983322Speter warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 46083322Speter ef->ef_name, (long)offset, ofs); 46183322Speter return EFAULT; 46283322Speter } 46383322Speter return ef_read(ef, ofs, len, dest); 46483322Speter} 46583322Speter 466134358Siedowsestatic int 467109607Sjakeef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 468109607Sjake{ 469109607Sjake u_long ofs = ef_get_offset(ef, offset); 470134358Siedowse const Elf_Rela *a; 471134358Siedowse const Elf_Rel *r; 472109607Sjake int error; 473109607Sjake 474109607Sjake if (ofs == 0) { 475109607Sjake if (ef->ef_verbose) 476109607Sjake warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 477109607Sjake ef->ef_name, (long)offset, ofs); 478109607Sjake return EFAULT; 479109607Sjake } 480109607Sjake if ((error = ef_read(ef, ofs, len, dest)) != 0) 481109607Sjake return (error); 482134358Siedowse 483134358Siedowse for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) { 484134450Siedowse error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len, 485134358Siedowse dest); 486134358Siedowse if (error != 0) 487134358Siedowse return (error); 488134358Siedowse } 489134358Siedowse for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) { 490134450Siedowse error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len, 491134358Siedowse dest); 492134358Siedowse if (error != 0) 493134358Siedowse return (error); 494134358Siedowse } 495134358Siedowse return (0); 496109607Sjake} 497109607Sjake 498134358Siedowsestatic int 49983322Speteref_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 50083322Speter{ 50183322Speter int error; 50283322Speter 50383322Speter *ptr = malloc(len); 50483322Speter if (*ptr == NULL) 50583322Speter return ENOMEM; 50683322Speter error = ef_seg_read(ef, offset, len, *ptr); 50783322Speter if (error) 50883322Speter free(*ptr); 50983322Speter return error; 51083322Speter} 51183322Speter 512134358Siedowsestatic int 513109607Sjakeef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 514109607Sjake{ 515109607Sjake int error; 516109607Sjake 517109607Sjake *ptr = malloc(len); 518109607Sjake if (*ptr == NULL) 519109607Sjake return ENOMEM; 520109607Sjake error = ef_seg_read_rel(ef, offset, len, *ptr); 521109607Sjake if (error) 522109607Sjake free(*ptr); 523109607Sjake return error; 524109607Sjake} 525109607Sjake 526109607Sjakeint 527134358Siedowseef_open(const char *filename, struct elf_file *efile, int verbose) 52883322Speter{ 529134358Siedowse elf_file_t ef; 53083322Speter Elf_Ehdr *hdr; 53183322Speter int fd; 53283322Speter int error; 53383322Speter int phlen, res; 53483322Speter int nsegs; 535237258Seadler Elf_Phdr *phdr, *phdyn, *phlimit; 53683322Speter 53783322Speter if (filename == NULL) 53883322Speter return EFTYPE; 53983322Speter if ((fd = open(filename, O_RDONLY)) == -1) 54083322Speter return errno; 541134358Siedowse 542134358Siedowse ef = malloc(sizeof(*ef)); 543134358Siedowse if (ef == NULL) { 544134358Siedowse close(fd); 545134358Siedowse return (ENOMEM); 546134358Siedowse } 547134358Siedowse 548134358Siedowse efile->ef_ef = ef; 549134358Siedowse efile->ef_ops = &ef_file_ops; 550134358Siedowse 551134358Siedowse bzero(ef, sizeof(*ef)); 552134358Siedowse ef->ef_verbose = verbose; 55383322Speter ef->ef_fd = fd; 55483322Speter ef->ef_name = strdup(filename); 555134358Siedowse ef->ef_efile = efile; 55683322Speter hdr = (Elf_Ehdr *)&ef->ef_hdr; 55783322Speter do { 55883322Speter res = read(fd, hdr, sizeof(*hdr)); 55983322Speter error = EFTYPE; 56083322Speter if (res != sizeof(*hdr)) 56183322Speter break; 56283322Speter if (!IS_ELF(*hdr)) 56383322Speter break; 56483322Speter if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 56583322Speter hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 56683322Speter hdr->e_ident[EI_VERSION] != EV_CURRENT || 56783322Speter hdr->e_version != EV_CURRENT || 56883322Speter hdr->e_machine != ELF_TARG_MACH || 56983322Speter hdr->e_phentsize != sizeof(Elf_Phdr)) 57083322Speter break; 57183322Speter phlen = hdr->e_phnum * sizeof(Elf_Phdr); 57283322Speter if (ef_read_entry(ef, hdr->e_phoff, phlen, 57383322Speter (void**)&ef->ef_ph) != 0) 57483322Speter break; 57583322Speter phdr = ef->ef_ph; 57683322Speter phlimit = phdr + hdr->e_phnum; 57783322Speter nsegs = 0; 57883322Speter phdyn = NULL; 57983322Speter while (phdr < phlimit) { 58083322Speter if (verbose > 1) 58183322Speter ef_print_phdr(phdr); 58283322Speter switch (phdr->p_type) { 58383322Speter case PT_LOAD: 584269014Semaste if (nsegs < MAXSEGS) 585269014Semaste ef->ef_segs[nsegs] = phdr; 586269014Semaste nsegs++; 58783322Speter break; 58883322Speter case PT_PHDR: 58983322Speter break; 59083322Speter case PT_DYNAMIC: 59183322Speter phdyn = phdr; 59283322Speter break; 59383322Speter } 59483322Speter phdr++; 59583322Speter } 59683322Speter if (verbose > 1) 59783322Speter printf("\n"); 59883322Speter if (phdyn == NULL) { 599242277Skientzle warnx("Skipping %s: not dynamically-linked", 600242277Skientzle filename); 60183322Speter break; 602269014Semaste } else if (nsegs > MAXSEGS) { 603269014Semaste warnx("%s: too many sections", filename); 604269014Semaste break; 60583322Speter } 606269014Semaste ef->ef_nsegs = nsegs; 60783322Speter if (ef_read_entry(ef, phdyn->p_offset, 60883322Speter phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) { 60983322Speter printf("ef_read_entry failed\n"); 61083322Speter break; 61183322Speter } 61283322Speter error = ef_parse_dynamic(ef); 61383322Speter if (error) 61483322Speter break; 61583322Speter if (hdr->e_type == ET_DYN) { 61683322Speter ef->ef_type = EFT_KLD; 61783322Speter/* pad = (u_int)dest & PAGE_MASK; 61883322Speter if (pad) 61983322Speter dest += PAGE_SIZE - pad;*/ 62083322Speter error = 0; 62183322Speter } else if (hdr->e_type == ET_EXEC) { 62283322Speter/* dest = hdr->e_entry; 62383322Speter if (dest == 0) 62483322Speter break;*/ 62583322Speter ef->ef_type = EFT_KERNEL; 62683322Speter error = 0; 62783322Speter } else 62883322Speter break; 62983322Speter } while(0); 630134358Siedowse if (error) 63183322Speter ef_close(ef); 63283322Speter return error; 63383322Speter} 63483322Speter 635134358Siedowsestatic int 63683322Speteref_close(elf_file_t ef) 63783322Speter{ 63883322Speter close(ef->ef_fd); 63983322Speter/* if (ef->ef_fpage) 64083322Speter free(ef->ef_fpage);*/ 64183322Speter if (ef->ef_name) 64283322Speter free(ef->ef_name); 643134358Siedowse ef->ef_efile->ef_ops = NULL; 644134358Siedowse ef->ef_efile->ef_ef = NULL; 645134358Siedowse free(ef); 64683322Speter return 0; 64783322Speter} 648