ef.c revision 134358
1214501Srpaulo/* 2214501Srpaulo * Copyright (c) 2000, Boris Popov 3214501Srpaulo * All rights reserved. 4214501Srpaulo * 5252726Srpaulo * Redistribution and use in source and binary forms, with or without 6214501Srpaulo * modification, are permitted provided that the following conditions 7214501Srpaulo * are met: 8214501Srpaulo * 1. Redistributions of source code must retain the above copyright 9214501Srpaulo * notice, this list of conditions and the following disclaimer. 10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11214501Srpaulo * notice, this list of conditions and the following disclaimer in the 12214501Srpaulo * documentation and/or other materials provided with the distribution. 13214501Srpaulo * 3. All advertising materials mentioning features or use of this software 14214501Srpaulo * must display the following acknowledgement: 15214501Srpaulo * This product includes software developed by Boris Popov. 16214501Srpaulo * 4. Neither the name of the author nor the names of any co-contributors 17214501Srpaulo * may be used to endorse or promote products derived from this software 18214501Srpaulo * without specific prior written permission. 19214501Srpaulo * 20214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30214501Srpaulo * SUCH DAMAGE. 31214501Srpaulo * 32214501Srpaulo * $FreeBSD: head/usr.sbin/kldxref/ef.c 134358 2004-08-27 00:51:21Z iedowse $ 33214501Srpaulo */ 34214501Srpaulo 35214501Srpaulo#include <sys/param.h> 36214501Srpaulo#include <sys/linker.h> 37214501Srpaulo#include <string.h> 38214501Srpaulo#include <stdio.h> 39214501Srpaulo#include <stdlib.h> 40214501Srpaulo#include <unistd.h> 41214501Srpaulo#include <errno.h> 42214501Srpaulo#include <fcntl.h> 43214501Srpaulo#include <machine/elf.h> 44214501Srpaulo#define FREEBSD_ELF 45214501Srpaulo#include <link.h> 46214501Srpaulo 47214501Srpaulo#include <err.h> 48214501Srpaulo 49214501Srpaulo#include "ef.h" 50214501Srpaulo 51214501Srpaulostruct ef_file { 52214501Srpaulo char* ef_name; 53214501Srpaulo struct elf_file *ef_efile; 54214501Srpaulo Elf_Phdr * ef_ph; 55214501Srpaulo int ef_fd; 56214501Srpaulo int ef_type; 57214501Srpaulo Elf_Ehdr ef_hdr; 58214501Srpaulo void* ef_fpage; /* First block of the file */ 59214501Srpaulo int ef_fplen; /* length of first block */ 60214501Srpaulo Elf_Dyn* ef_dyn; /* Symbol table etc. */ 61214501Srpaulo Elf_Hashelt ef_nbuckets; 62214501Srpaulo Elf_Hashelt ef_nchains; 63214501Srpaulo Elf_Hashelt* ef_buckets; 64214501Srpaulo Elf_Hashelt* ef_chains; 65214501Srpaulo Elf_Hashelt* ef_hashtab; 66214501Srpaulo Elf_Off ef_stroff; 67214501Srpaulo caddr_t ef_strtab; 68214501Srpaulo int ef_strsz; 69214501Srpaulo Elf_Off ef_symoff; 70214501Srpaulo Elf_Sym* ef_symtab; 71214501Srpaulo int ef_nsegs; 72214501Srpaulo Elf_Phdr * ef_segs[2]; 73214501Srpaulo int ef_verbose; 74214501Srpaulo Elf_Rel * ef_rel; /* relocation table */ 75214501Srpaulo int ef_relsz; /* number of entries */ 76214501Srpaulo Elf_Rela * ef_rela; /* relocation table */ 77214501Srpaulo int ef_relasz; /* number of entries */ 78214501Srpaulo}; 79214501Srpaulo 80214501Srpaulostatic void ef_print_phdr(Elf_Phdr *); 81214501Srpaulostatic u_long ef_get_offset(elf_file_t, Elf_Off); 82214501Srpaulostatic int ef_parse_dynamic(elf_file_t); 83214501Srpaulo 84214501Srpaulostatic int ef_get_type(elf_file_t ef); 85214501Srpaulostatic int ef_close(elf_file_t ef); 86214501Srpaulostatic int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); 87214501Srpaulostatic int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr); 88214501Srpaulostatic int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest); 89214501Srpaulostatic int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, 90214501Srpaulo void *dest); 91214501Srpaulostatic int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 92214501Srpaulo void **ptr); 93214501Srpaulostatic int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 94214501Srpaulo void **ptr); 95214501Srpaulostatic Elf_Addr ef_symaddr(elf_file_t ef, Elf_Word symidx); 96214501Srpaulostatic int ef_lookup_set(elf_file_t ef, const char *name, long *startp, 97214501Srpaulo long *stopp, long *countp); 98214501Srpaulostatic int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); 99214501Srpaulo 100214501Srpaulostatic struct elf_file_ops ef_file_ops = { 101214501Srpaulo ef_get_type, 102214501Srpaulo ef_close, 103214501Srpaulo ef_read, 104252726Srpaulo ef_read_entry, 105252726Srpaulo ef_seg_read, 106214501Srpaulo ef_seg_read_rel, 107214501Srpaulo ef_seg_read_entry, 108214501Srpaulo ef_seg_read_entry_rel, 109214501Srpaulo ef_symaddr, 110214501Srpaulo ef_lookup_set, 111214501Srpaulo ef_lookup_symbol 112214501Srpaulo}; 113252726Srpaulo 114252726Srpaulostatic void 115214501Srpauloef_print_phdr(Elf_Phdr *phdr) 116214501Srpaulo{ 117214501Srpaulo 118214501Srpaulo if ((phdr->p_flags & PF_W) == 0) { 119214501Srpaulo printf("text=0x%lx ", (long)phdr->p_filesz); 120214501Srpaulo } else { 121214501Srpaulo printf("data=0x%lx", (long)phdr->p_filesz); 122214501Srpaulo if (phdr->p_filesz < phdr->p_memsz) 123214501Srpaulo printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz)); 124214501Srpaulo printf(" "); 125252726Srpaulo } 126252726Srpaulo} 127214501Srpaulo 128214501Srpaulostatic u_long 129214501Srpauloef_get_offset(elf_file_t ef, Elf_Off off) 130214501Srpaulo{ 131252726Srpaulo Elf_Phdr *ph; 132252726Srpaulo int i; 133252726Srpaulo 134252726Srpaulo for (i = 0; i < ef->ef_nsegs; i++) { 135252726Srpaulo ph = ef->ef_segs[i]; 136252726Srpaulo if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) { 137252726Srpaulo return ph->p_offset + (off - ph->p_vaddr); 138252726Srpaulo } 139252726Srpaulo } 140214501Srpaulo return 0; 141252726Srpaulo} 142252726Srpaulo 143214501Srpaulostatic int 144252726Srpauloef_get_type(elf_file_t ef) 145252726Srpaulo{ 146252726Srpaulo 147214501Srpaulo return (ef->ef_type); 148214501Srpaulo} 149214501Srpaulo 150214501Srpaulo/* 151214501Srpaulo * next three functions copied from link_elf.c 152214501Srpaulo */ 153214501Srpaulostatic unsigned long 154214501Srpauloelf_hash(const char *name) 155252726Srpaulo{ 156252726Srpaulo const unsigned char *p = (const unsigned char *) name; 157214501Srpaulo unsigned long h = 0; 158214501Srpaulo unsigned long g; 159214501Srpaulo 160252726Srpaulo while (*p != '\0') { 161214501Srpaulo h = (h << 4) + *p++; 162214501Srpaulo if ((g = h & 0xf0000000) != 0) 163214501Srpaulo h ^= g >> 24; 164214501Srpaulo h &= ~g; 165214501Srpaulo } 166214501Srpaulo return h; 167252726Srpaulo} 168252726Srpaulo 169214501Srpaulostatic int 170214501Srpauloef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 171252726Srpaulo{ 172252726Srpaulo unsigned long symnum; 173214501Srpaulo Elf_Sym* symp; 174214501Srpaulo char *strp; 175252726Srpaulo unsigned long hash; 176214501Srpaulo 177214501Srpaulo /* First, search hashed global symbols */ 178214501Srpaulo hash = elf_hash(name); 179214501Srpaulo symnum = ef->ef_buckets[hash % ef->ef_nbuckets]; 180214501Srpaulo 181214501Srpaulo while (symnum != STN_UNDEF) { 182214501Srpaulo if (symnum >= ef->ef_nchains) { 183214501Srpaulo warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 184214501Srpaulo ef->ef_name); 185214501Srpaulo return ENOENT; 186214501Srpaulo } 187214501Srpaulo 188214501Srpaulo symp = ef->ef_symtab + symnum; 189214501Srpaulo if (symp->st_name == 0) { 190214501Srpaulo warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 191214501Srpaulo ef->ef_name); 192214501Srpaulo return ENOENT; 193214501Srpaulo } 194214501Srpaulo 195214501Srpaulo strp = ef->ef_strtab + symp->st_name; 196214501Srpaulo 197214501Srpaulo if (strcmp(name, strp) == 0) { 198214501Srpaulo if (symp->st_shndx != SHN_UNDEF || 199214501Srpaulo (symp->st_value != 0 && 200214501Srpaulo ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 201214501Srpaulo *sym = symp; 202214501Srpaulo return 0; 203214501Srpaulo } else 204214501Srpaulo return ENOENT; 205214501Srpaulo } 206214501Srpaulo 207214501Srpaulo symnum = ef->ef_chains[symnum]; 208214501Srpaulo } 209214501Srpaulo 210214501Srpaulo return ENOENT; 211214501Srpaulo} 212214501Srpaulo 213214501Srpaulostatic int 214214501Srpauloef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, 215214501Srpaulo long *countp) 216214501Srpaulo{ 217214501Srpaulo Elf_Sym *sym; 218214501Srpaulo char *setsym; 219214501Srpaulo int error, len; 220214501Srpaulo 221214501Srpaulo len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 222214501Srpaulo setsym = malloc(len); 223214501Srpaulo if (setsym == NULL) 224214501Srpaulo return (ENOMEM); 225214501Srpaulo 226214501Srpaulo /* get address of first entry */ 227214501Srpaulo snprintf(setsym, len, "%s%s", "__start_set_", name); 228214501Srpaulo error = ef_lookup_symbol(ef, setsym, &sym); 229214501Srpaulo if (error) 230214501Srpaulo goto out; 231214501Srpaulo *startp = sym->st_value; 232214501Srpaulo 233214501Srpaulo /* get address of last entry */ 234214501Srpaulo snprintf(setsym, len, "%s%s", "__stop_set_", name); 235214501Srpaulo error = ef_lookup_symbol(ef, setsym, &sym); 236214501Srpaulo if (error) 237214501Srpaulo goto out; 238214501Srpaulo *stopp = sym->st_value; 239214501Srpaulo 240214501Srpaulo /* and the number of entries */ 241214501Srpaulo *countp = (*stopp - *startp) / sizeof(void *); 242214501Srpaulo 243214501Srpauloout: 244214501Srpaulo free(setsym); 245214501Srpaulo return (error); 246214501Srpaulo} 247214501Srpaulo 248214501Srpaulostatic Elf_Addr 249214501Srpauloef_symaddr(elf_file_t ef, Elf_Word symidx) 250214501Srpaulo{ 251214501Srpaulo const Elf_Sym *sym; 252214501Srpaulo 253214501Srpaulo if (symidx >= ef->ef_nchains) 254214501Srpaulo return (0); 255214501Srpaulo sym = ef->ef_symtab + symidx; 256214501Srpaulo 257214501Srpaulo if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 258214501Srpaulo sym->st_shndx != SHN_UNDEF && sym->st_value != 0) 259214501Srpaulo return (sym->st_value); 260214501Srpaulo return (0); 261214501Srpaulo} 262214501Srpaulo 263214501Srpaulostatic int 264214501Srpauloef_parse_dynamic(elf_file_t ef) 265214501Srpaulo{ 266214501Srpaulo Elf_Dyn *dp; 267214501Srpaulo Elf_Hashelt hashhdr[2]; 268214501Srpaulo/* int plttype = DT_REL;*/ 269214501Srpaulo int error; 270214501Srpaulo Elf_Off rel_off; 271214501Srpaulo Elf_Off rela_off; 272214501Srpaulo int rel_sz; 273214501Srpaulo int rela_sz; 274214501Srpaulo int rel_entry; 275252726Srpaulo int rela_entry; 276252726Srpaulo 277252726Srpaulo rel_off = rela_off = 0; 278214501Srpaulo rel_sz = rela_sz = 0; 279252726Srpaulo rel_entry = rela_entry = 0; 280214501Srpaulo for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) { 281214501Srpaulo switch (dp->d_tag) { 282214501Srpaulo case DT_HASH: 283214501Srpaulo error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr), 284214501Srpaulo sizeof(hashhdr), hashhdr); 285214501Srpaulo if (error) { 286214501Srpaulo warnx("can't read hash header (%lx)", 287214501Srpaulo ef_get_offset(ef, dp->d_un.d_ptr)); 288214501Srpaulo return error; 289214501Srpaulo } 290214501Srpaulo ef->ef_nbuckets = hashhdr[0]; 291214501Srpaulo ef->ef_nchains = hashhdr[1]; 292214501Srpaulo error = ef_read_entry(ef, -1, 293214501Srpaulo (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt), 294214501Srpaulo (void**)&ef->ef_hashtab); 295214501Srpaulo if (error) { 296214501Srpaulo warnx("can't read hash table"); 297214501Srpaulo return error; 298214501Srpaulo } 299214501Srpaulo ef->ef_buckets = ef->ef_hashtab; 300214501Srpaulo ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets; 301214501Srpaulo break; 302214501Srpaulo case DT_STRTAB: 303214501Srpaulo ef->ef_stroff = dp->d_un.d_ptr; 304214501Srpaulo break; 305214501Srpaulo case DT_STRSZ: 306214501Srpaulo ef->ef_strsz = dp->d_un.d_val; 307214501Srpaulo break; 308214501Srpaulo case DT_SYMTAB: 309214501Srpaulo ef->ef_symoff = dp->d_un.d_ptr; 310214501Srpaulo break; 311214501Srpaulo case DT_SYMENT: 312214501Srpaulo if (dp->d_un.d_val != sizeof(Elf_Sym)) 313214501Srpaulo return EFTYPE; 314214501Srpaulo break; 315214501Srpaulo case DT_REL: 316214501Srpaulo if (rel_off != 0) 317214501Srpaulo warnx("second DT_REL entry ignored"); 318214501Srpaulo rel_off = dp->d_un.d_ptr; 319214501Srpaulo break; 320214501Srpaulo case DT_RELSZ: 321214501Srpaulo if (rel_sz != 0) 322214501Srpaulo warnx("second DT_RELSZ entry ignored"); 323214501Srpaulo rel_sz = dp->d_un.d_val; 324214501Srpaulo break; 325214501Srpaulo case DT_RELENT: 326214501Srpaulo if (rel_entry != 0) 327214501Srpaulo warnx("second DT_RELENT entry ignored"); 328214501Srpaulo rel_entry = dp->d_un.d_val; 329214501Srpaulo break; 330214501Srpaulo case DT_RELA: 331214501Srpaulo if (rela_off != 0) 332214501Srpaulo warnx("second DT_RELA entry ignored"); 333214501Srpaulo rela_off = dp->d_un.d_ptr; 334214501Srpaulo break; 335214501Srpaulo case DT_RELASZ: 336214501Srpaulo if (rela_sz != 0) 337214501Srpaulo warnx("second DT_RELASZ entry ignored"); 338214501Srpaulo rela_sz = dp->d_un.d_val; 339214501Srpaulo break; 340214501Srpaulo case DT_RELAENT: 341214501Srpaulo if (rela_entry != 0) 342214501Srpaulo warnx("second DT_RELAENT entry ignored"); 343214501Srpaulo rela_entry = dp->d_un.d_val; 344214501Srpaulo break; 345214501Srpaulo } 346214501Srpaulo } 347214501Srpaulo if (ef->ef_symoff == 0) { 348214501Srpaulo warnx("%s: no .dynsym section found\n", ef->ef_name); 349214501Srpaulo return EFTYPE; 350214501Srpaulo } 351214501Srpaulo if (ef->ef_stroff == 0) { 352214501Srpaulo warnx("%s: no .dynstr section found\n", ef->ef_name); 353214501Srpaulo return EFTYPE; 354214501Srpaulo } 355214501Srpaulo if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff), 356214501Srpaulo ef->ef_nchains * sizeof(Elf_Sym), 357214501Srpaulo (void**)&ef->ef_symtab) != 0) { 358214501Srpaulo if (ef->ef_verbose) 359214501Srpaulo warnx("%s: can't load .dynsym section (0x%lx)", 360214501Srpaulo ef->ef_name, (long)ef->ef_symoff); 361214501Srpaulo return EIO; 362214501Srpaulo } 363214501Srpaulo if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz, 364214501Srpaulo (void**)&ef->ef_strtab) != 0) { 365214501Srpaulo warnx("can't load .dynstr section"); 366214501Srpaulo return EIO; 367214501Srpaulo } 368214501Srpaulo if (rel_off != 0) { 369214501Srpaulo if (rel_entry == 0) { 370214501Srpaulo warnx("%s: no DT_RELENT for DT_REL", ef->ef_name); 371214501Srpaulo return (EFTYPE); 372214501Srpaulo } 373214501Srpaulo if (rel_entry != sizeof(Elf_Rel)) { 374214501Srpaulo warnx("%s: inconsistent DT_RELENT value", 375214501Srpaulo ef->ef_name); 376214501Srpaulo return (EFTYPE); 377214501Srpaulo } 378214501Srpaulo if (rel_sz % rel_entry != 0) { 379214501Srpaulo warnx("%s: inconsistent values for DT_RELSZ and " 380214501Srpaulo "DT_RELENT", ef->ef_name); 381214501Srpaulo return (EFTYPE); 382214501Srpaulo } 383214501Srpaulo if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz, 384214501Srpaulo (void **)&ef->ef_rel) != 0) { 385214501Srpaulo warnx("%s: cannot load DT_REL section", ef->ef_name); 386214501Srpaulo return (EIO); 387214501Srpaulo } 388214501Srpaulo ef->ef_relsz = rel_sz / rel_entry; 389214501Srpaulo if (ef->ef_verbose) 390214501Srpaulo warnx("%s: %d REL entries", ef->ef_name, 391214501Srpaulo ef->ef_relsz); 392214501Srpaulo } 393214501Srpaulo if (rela_off != 0) { 394214501Srpaulo if (rela_entry == 0) { 395214501Srpaulo warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name); 396214501Srpaulo return (EFTYPE); 397214501Srpaulo } 398214501Srpaulo if (rela_entry != sizeof(Elf_Rela)) { 399214501Srpaulo warnx("%s: inconsistent DT_RELAENT value", 400214501Srpaulo ef->ef_name); 401214501Srpaulo return (EFTYPE); 402214501Srpaulo } 403214501Srpaulo if (rela_sz % rela_entry != 0) { 404214501Srpaulo warnx("%s: inconsistent values for DT_RELASZ and " 405214501Srpaulo "DT_RELAENT", ef->ef_name); 406214501Srpaulo return (EFTYPE); 407214501Srpaulo } 408214501Srpaulo if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz, 409214501Srpaulo (void **)&ef->ef_rela) != 0) { 410214501Srpaulo warnx("%s: cannot load DT_RELA section", ef->ef_name); 411214501Srpaulo return (EIO); 412214501Srpaulo } 413214501Srpaulo ef->ef_relasz = rela_sz / rela_entry; 414214501Srpaulo if (ef->ef_verbose) 415214501Srpaulo warnx("%s: %d RELA entries", ef->ef_name, 416214501Srpaulo ef->ef_relasz); 417214501Srpaulo } 418214501Srpaulo return 0; 419214501Srpaulo} 420252726Srpaulo 421214501Srpaulostatic int 422214501Srpauloef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 423252726Srpaulo{ 424214501Srpaulo ssize_t r; 425214501Srpaulo 426214501Srpaulo if (offset != (Elf_Off)-1) { 427214501Srpaulo if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 428214501Srpaulo return EIO; 429214501Srpaulo } 430214501Srpaulo 431214501Srpaulo r = read(ef->ef_fd, dest, len); 432214501Srpaulo if (r != -1 && (size_t)r == len) 433214501Srpaulo return 0; 434214501Srpaulo else 435214501Srpaulo return EIO; 436214501Srpaulo} 437214501Srpaulo 438214501Srpaulostatic int 439214501Srpauloef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 440214501Srpaulo{ 441214501Srpaulo int error; 442214501Srpaulo 443214501Srpaulo *ptr = malloc(len); 444214501Srpaulo if (*ptr == NULL) 445214501Srpaulo return ENOMEM; 446214501Srpaulo error = ef_read(ef, offset, len, *ptr); 447214501Srpaulo if (error) 448214501Srpaulo free(*ptr); 449252726Srpaulo return error; 450252726Srpaulo} 451214501Srpaulo 452214501Srpaulostatic int 453214501Srpauloef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 454252726Srpaulo{ 455252726Srpaulo u_long ofs = ef_get_offset(ef, offset); 456252726Srpaulo 457252726Srpaulo if (ofs == 0) { 458252726Srpaulo if (ef->ef_verbose) 459252726Srpaulo warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 460252726Srpaulo ef->ef_name, (long)offset, ofs); 461252726Srpaulo return EFAULT; 462252726Srpaulo } 463252726Srpaulo return ef_read(ef, ofs, len, dest); 464252726Srpaulo} 465252726Srpaulo 466252726Srpaulostatic int 467252726Srpauloef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 468252726Srpaulo{ 469252726Srpaulo u_long ofs = ef_get_offset(ef, offset); 470252726Srpaulo const Elf_Rela *a; 471252726Srpaulo const Elf_Rel *r; 472252726Srpaulo int error; 473252726Srpaulo 474252726Srpaulo if (ofs == 0) { 475252726Srpaulo if (ef->ef_verbose) 476252726Srpaulo warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 477252726Srpaulo ef->ef_name, (long)offset, ofs); 478252726Srpaulo return EFAULT; 479252726Srpaulo } 480252726Srpaulo if ((error = ef_read(ef, ofs, len, dest)) != 0) 481252726Srpaulo return (error); 482252726Srpaulo 483252726Srpaulo for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) { 484252726Srpaulo error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, offset, len, 485252726Srpaulo dest); 486252726Srpaulo if (error != 0) 487252726Srpaulo return (error); 488252726Srpaulo } 489252726Srpaulo for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) { 490252726Srpaulo error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, offset, len, 491252726Srpaulo dest); 492252726Srpaulo if (error != 0) 493252726Srpaulo return (error); 494214501Srpaulo } 495214501Srpaulo return (0); 496214501Srpaulo} 497214501Srpaulo 498214501Srpaulostatic int 499214501Srpauloef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 500214501Srpaulo{ 501214501Srpaulo int error; 502214501Srpaulo 503214501Srpaulo *ptr = malloc(len); 504252726Srpaulo if (*ptr == NULL) 505252726Srpaulo return ENOMEM; 506214501Srpaulo error = ef_seg_read(ef, offset, len, *ptr); 507214501Srpaulo if (error) 508214501Srpaulo free(*ptr); 509252726Srpaulo return error; 510214501Srpaulo} 511214501Srpaulo 512252726Srpaulostatic int 513214501Srpauloef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 514214501Srpaulo{ 515214501Srpaulo int error; 516214501Srpaulo 517214501Srpaulo *ptr = malloc(len); 518214501Srpaulo if (*ptr == NULL) 519214501Srpaulo return ENOMEM; 520214501Srpaulo error = ef_seg_read_rel(ef, offset, len, *ptr); 521214501Srpaulo if (error) 522214501Srpaulo free(*ptr); 523214501Srpaulo return error; 524214501Srpaulo} 525214501Srpaulo 526214501Srpauloint 527214501Srpauloef_open(const char *filename, struct elf_file *efile, int verbose) 528214501Srpaulo{ 529214501Srpaulo elf_file_t ef; 530214501Srpaulo Elf_Ehdr *hdr; 531214501Srpaulo int fd; 532214501Srpaulo int error; 533214501Srpaulo int phlen, res; 534214501Srpaulo int nsegs; 535214501Srpaulo Elf_Phdr *phdr, *phdyn, *phphdr, *phlimit; 536214501Srpaulo 537214501Srpaulo if (filename == NULL) 538214501Srpaulo return EFTYPE; 539214501Srpaulo if ((fd = open(filename, O_RDONLY)) == -1) 540214501Srpaulo return errno; 541214501Srpaulo 542214501Srpaulo ef = malloc(sizeof(*ef)); 543214501Srpaulo if (ef == NULL) { 544214501Srpaulo close(fd); 545214501Srpaulo return (ENOMEM); 546214501Srpaulo } 547214501Srpaulo 548214501Srpaulo efile->ef_ef = ef; 549214501Srpaulo efile->ef_ops = &ef_file_ops; 550214501Srpaulo 551214501Srpaulo bzero(ef, sizeof(*ef)); 552214501Srpaulo ef->ef_verbose = verbose; 553214501Srpaulo ef->ef_fd = fd; 554214501Srpaulo ef->ef_name = strdup(filename); 555214501Srpaulo ef->ef_efile = efile; 556214501Srpaulo hdr = (Elf_Ehdr *)&ef->ef_hdr; 557214501Srpaulo do { 558214501Srpaulo res = read(fd, hdr, sizeof(*hdr)); 559214501Srpaulo error = EFTYPE; 560214501Srpaulo if (res != sizeof(*hdr)) 561214501Srpaulo break; 562214501Srpaulo if (!IS_ELF(*hdr)) 563214501Srpaulo break; 564214501Srpaulo if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 565214501Srpaulo hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 566214501Srpaulo hdr->e_ident[EI_VERSION] != EV_CURRENT || 567214501Srpaulo hdr->e_version != EV_CURRENT || 568214501Srpaulo hdr->e_machine != ELF_TARG_MACH || 569214501Srpaulo hdr->e_phentsize != sizeof(Elf_Phdr)) 570214501Srpaulo break; 571214501Srpaulo phlen = hdr->e_phnum * sizeof(Elf_Phdr); 572214501Srpaulo if (ef_read_entry(ef, hdr->e_phoff, phlen, 573214501Srpaulo (void**)&ef->ef_ph) != 0) 574214501Srpaulo break; 575214501Srpaulo phdr = ef->ef_ph; 576214501Srpaulo phlimit = phdr + hdr->e_phnum; 577214501Srpaulo nsegs = 0; 578214501Srpaulo phdyn = NULL; 579214501Srpaulo phphdr = NULL; 580214501Srpaulo while (phdr < phlimit) { 581214501Srpaulo if (verbose > 1) 582214501Srpaulo ef_print_phdr(phdr); 583214501Srpaulo switch (phdr->p_type) { 584214501Srpaulo case PT_LOAD: 585214501Srpaulo if (nsegs == 2) { 586214501Srpaulo warnx("%s: too many sections", 587214501Srpaulo filename); 588214501Srpaulo break; 589214501Srpaulo } 590214501Srpaulo ef->ef_segs[nsegs++] = phdr; 591214501Srpaulo break; 592214501Srpaulo case PT_PHDR: 593214501Srpaulo phphdr = phdr; 594214501Srpaulo break; 595214501Srpaulo case PT_DYNAMIC: 596214501Srpaulo phdyn = phdr; 597214501Srpaulo break; 598214501Srpaulo } 599214501Srpaulo phdr++; 600214501Srpaulo } 601214501Srpaulo if (verbose > 1) 602214501Srpaulo printf("\n"); 603214501Srpaulo ef->ef_nsegs = nsegs; 604214501Srpaulo if (phdyn == NULL) { 605214501Srpaulo warnx("file isn't dynamically-linked"); 606214501Srpaulo break; 607214501Srpaulo } 608214501Srpaulo if (ef_read_entry(ef, phdyn->p_offset, 609214501Srpaulo phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) { 610214501Srpaulo printf("ef_read_entry failed\n"); 611214501Srpaulo break; 612214501Srpaulo } 613214501Srpaulo error = ef_parse_dynamic(ef); 614214501Srpaulo if (error) 615214501Srpaulo break; 616214501Srpaulo if (hdr->e_type == ET_DYN) { 617214501Srpaulo ef->ef_type = EFT_KLD; 618214501Srpaulo/* pad = (u_int)dest & PAGE_MASK; 619214501Srpaulo if (pad) 620214501Srpaulo dest += PAGE_SIZE - pad;*/ 621214501Srpaulo error = 0; 622214501Srpaulo } else if (hdr->e_type == ET_EXEC) { 623252726Srpaulo/* dest = hdr->e_entry; 624252726Srpaulo if (dest == 0) 625252726Srpaulo break;*/ 626252726Srpaulo ef->ef_type = EFT_KERNEL; 627214501Srpaulo error = 0; 628214501Srpaulo } else 629214501Srpaulo break; 630214501Srpaulo } while(0); 631214501Srpaulo if (error) 632214501Srpaulo ef_close(ef); 633214501Srpaulo return error; 634214501Srpaulo} 635214501Srpaulo 636214501Srpaulostatic int 637214501Srpauloef_close(elf_file_t ef) 638214501Srpaulo{ 639214501Srpaulo close(ef->ef_fd); 640214501Srpaulo/* if (ef->ef_fpage) 641252726Srpaulo free(ef->ef_fpage);*/ 642214501Srpaulo if (ef->ef_name) 643214501Srpaulo free(ef->ef_name); 644214501Srpaulo ef->ef_efile->ef_ops = NULL; 645214501Srpaulo ef->ef_efile->ef_ef = NULL; 646214501Srpaulo free(ef); 647214501Srpaulo return 0; 648214501Srpaulo} 649214501Srpaulo