ef.c revision 100272
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: head/usr.sbin/kldxref/ef.c 100272 2002-07-17 23:41:58Z peter $ 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#include <link.h> 4683322Speter 4783322Speter#include <err.h> 4883322Speter 4983322Speter#include "ef.h" 5083322Speter 5187551Smikehstatic void ef_print_phdr(Elf_Phdr *); 5287551Smikehstatic u_long ef_get_offset(elf_file_t, Elf_Off); 5387551Smikehstatic int ef_parse_dynamic(elf_file_t); 5487551Smikeh 5583322Spetervoid 5683322Speteref_print_phdr(Elf_Phdr *phdr) 5783322Speter{ 5883322Speter 5983322Speter if ((phdr->p_flags & PF_W) == 0) { 6083322Speter printf("text=0x%lx ", (long)phdr->p_filesz); 6183322Speter } else { 6283322Speter printf("data=0x%lx", (long)phdr->p_filesz); 6383322Speter if (phdr->p_filesz < phdr->p_memsz) 6483322Speter printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz)); 6583322Speter printf(" "); 6683322Speter } 6783322Speter} 6883322Speter 6983322Speteru_long 7083322Speteref_get_offset(elf_file_t ef, Elf_Off off) 7183322Speter{ 7283322Speter Elf_Phdr *ph; 7383322Speter int i; 7483322Speter 7583322Speter for (i = 0; i < ef->ef_nsegs; i++) { 7683322Speter ph = ef->ef_segs[i]; 7783322Speter if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) { 7883322Speter return ph->p_offset + (off - ph->p_vaddr); 7983322Speter } 8083322Speter } 8183322Speter return 0; 8283322Speter} 8383322Speter 8483322Speter/* 8583322Speter * next three functions copied from link_elf.c 8683322Speter */ 8783322Speterstatic unsigned long 8883322Speterelf_hash(const char *name) 8983322Speter{ 9083322Speter const unsigned char *p = (const unsigned char *) name; 9183322Speter unsigned long h = 0; 9283322Speter unsigned long g; 9383322Speter 9483322Speter while (*p != '\0') { 9583322Speter h = (h << 4) + *p++; 9683322Speter if ((g = h & 0xf0000000) != 0) 9783322Speter h ^= g >> 24; 9883322Speter h &= ~g; 9983322Speter } 10083322Speter return h; 10183322Speter} 10283322Speter 10383322Speterint 10483322Speteref_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 10583322Speter{ 10683322Speter unsigned long symnum; 10783322Speter Elf_Sym* symp; 10883322Speter char *strp; 10983322Speter unsigned long hash; 11083322Speter 11183322Speter /* First, search hashed global symbols */ 11283322Speter hash = elf_hash(name); 11383322Speter symnum = ef->ef_buckets[hash % ef->ef_nbuckets]; 11483322Speter 11583322Speter while (symnum != STN_UNDEF) { 11683322Speter if (symnum >= ef->ef_nchains) { 11783322Speter warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 11883322Speter ef->ef_name); 11983322Speter return ENOENT; 12083322Speter } 12183322Speter 12283322Speter symp = ef->ef_symtab + symnum; 12383322Speter if (symp->st_name == 0) { 12483322Speter warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", 12583322Speter ef->ef_name); 12683322Speter return ENOENT; 12783322Speter } 12883322Speter 12983322Speter strp = ef->ef_strtab + symp->st_name; 13083322Speter 13183322Speter if (strcmp(name, strp) == 0) { 13283322Speter if (symp->st_shndx != SHN_UNDEF || 13383322Speter (symp->st_value != 0 && 13483322Speter ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 13583322Speter *sym = symp; 13683322Speter return 0; 13783322Speter } else 13883322Speter return ENOENT; 13983322Speter } 14083322Speter 14183322Speter symnum = ef->ef_chains[symnum]; 14283322Speter } 14383322Speter 14483322Speter return ENOENT; 14583322Speter} 14683322Speter 14783322Speterint 14883322Speteref_parse_dynamic(elf_file_t ef) 14983322Speter{ 15083322Speter Elf_Dyn *dp; 15194414Speter Elf_Hashelt hashhdr[2]; 15283322Speter/* int plttype = DT_REL;*/ 15383322Speter int error; 15483322Speter 15583322Speter for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) { 15683322Speter switch (dp->d_tag) { 15783322Speter case DT_HASH: 15883322Speter error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr), 15983322Speter sizeof(hashhdr), hashhdr); 16083322Speter if (error) { 16183322Speter warnx("can't read hash header (%lx)", 16283322Speter ef_get_offset(ef, dp->d_un.d_ptr)); 16383322Speter return error; 16483322Speter } 16583322Speter ef->ef_nbuckets = hashhdr[0]; 16683322Speter ef->ef_nchains = hashhdr[1]; 16783322Speter error = ef_read_entry(ef, -1, 16894414Speter (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt), 16983322Speter (void**)&ef->ef_hashtab); 17083322Speter if (error) { 17183322Speter warnx("can't read hash table"); 17283322Speter return error; 17383322Speter } 17483322Speter ef->ef_buckets = ef->ef_hashtab; 17583322Speter ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets; 17683322Speter break; 17783322Speter case DT_STRTAB: 17883322Speter ef->ef_stroff = dp->d_un.d_ptr; 17983322Speter break; 18083322Speter case DT_STRSZ: 18183322Speter ef->ef_strsz = dp->d_un.d_val; 18283322Speter break; 18383322Speter case DT_SYMTAB: 18483322Speter ef->ef_symoff = dp->d_un.d_ptr; 18583322Speter break; 18683322Speter case DT_SYMENT: 18783322Speter if (dp->d_un.d_val != sizeof(Elf_Sym)) 18883322Speter return EFTYPE; 18983322Speter break; 19083322Speter } 19183322Speter } 19283322Speter if (ef->ef_symoff == 0) { 19383322Speter warnx("%s: no .dynsym section found\n", ef->ef_name); 19483322Speter return EFTYPE; 19583322Speter } 19683322Speter if (ef->ef_stroff == 0) { 19783322Speter warnx("%s: no .dynstr section found\n", ef->ef_name); 19883322Speter return EFTYPE; 19983322Speter } 20083322Speter if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff), 20183322Speter ef->ef_nchains * sizeof(Elf_Sym), 20283322Speter (void**)&ef->ef_symtab) != 0) { 20383322Speter if (ef->ef_verbose) 20483322Speter warnx("%s: can't load .dynsym section (0x%lx)", 20583322Speter ef->ef_name, (long)ef->ef_symoff); 20683322Speter return EIO; 20783322Speter } 20883322Speter if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz, 20983322Speter (void**)&ef->ef_strtab) != 0) { 21083322Speter warnx("can't load .dynstr section"); 21183322Speter return EIO; 21283322Speter } 21383322Speter return 0; 21483322Speter} 21583322Speter 21683322Speterint 21783322Speteref_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 21883322Speter{ 21987551Smikeh ssize_t r; 22083322Speter 22187551Smikeh if (offset != (Elf_Off)-1) { 22283322Speter if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 22383322Speter return EIO; 22483322Speter } 22587551Smikeh 22687551Smikeh r = read(ef->ef_fd, dest, len); 22787551Smikeh if (r != -1 && (size_t)r == len) 22887551Smikeh return 0; 22987551Smikeh else 23087551Smikeh return EIO; 23183322Speter} 23283322Speter 23383322Speterint 23483322Speteref_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 23583322Speter{ 23683322Speter int error; 23783322Speter 23883322Speter *ptr = malloc(len); 23983322Speter if (*ptr == NULL) 24083322Speter return ENOMEM; 24183322Speter error = ef_read(ef, offset, len, *ptr); 24283322Speter if (error) 24383322Speter free(*ptr); 24483322Speter return error; 24583322Speter} 24683322Speter 24783322Speterint 24883322Speteref_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) 24983322Speter{ 25083322Speter u_long ofs = ef_get_offset(ef, offset); 25183322Speter 25283322Speter if (ofs == 0) { 25383322Speter if (ef->ef_verbose) 25483322Speter warnx("ef_seg_read(%s): zero offset (%lx:%ld)", 25583322Speter ef->ef_name, (long)offset, ofs); 25683322Speter return EFAULT; 25783322Speter } 25883322Speter return ef_read(ef, ofs, len, dest); 25983322Speter} 26083322Speter 26183322Speterint 26283322Speteref_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) 26383322Speter{ 26483322Speter int error; 26583322Speter 26683322Speter *ptr = malloc(len); 26783322Speter if (*ptr == NULL) 26883322Speter return ENOMEM; 26983322Speter error = ef_seg_read(ef, offset, len, *ptr); 27083322Speter if (error) 27183322Speter free(*ptr); 27283322Speter return error; 27383322Speter} 27483322Speter 27583322Speterint 27683322Speteref_open(const char *filename, elf_file_t ef, int verbose) 27783322Speter{ 27883322Speter Elf_Ehdr *hdr; 27983322Speter int fd; 28083322Speter int error; 28183322Speter int phlen, res; 28283322Speter int nsegs; 28383322Speter Elf_Phdr *phdr, *phdyn, *phphdr, *phlimit; 28483322Speter 28583322Speter bzero(ef, sizeof(*ef)); 28683322Speter if (filename == NULL) 28783322Speter return EFTYPE; 28883322Speter ef->ef_verbose = verbose; 28983322Speter if ((fd = open(filename, O_RDONLY)) == -1) 29083322Speter return errno; 29183322Speter ef->ef_fd = fd; 29283322Speter ef->ef_name = strdup(filename); 29383322Speter hdr = (Elf_Ehdr *)&ef->ef_hdr; 29483322Speter do { 29583322Speter res = read(fd, hdr, sizeof(*hdr)); 29683322Speter error = EFTYPE; 29783322Speter if (res != sizeof(*hdr)) 29883322Speter break; 29983322Speter if (!IS_ELF(*hdr)) 30083322Speter break; 30183322Speter if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 30283322Speter hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 30383322Speter hdr->e_ident[EI_VERSION] != EV_CURRENT || 30483322Speter hdr->e_version != EV_CURRENT || 30583322Speter hdr->e_machine != ELF_TARG_MACH || 30683322Speter hdr->e_phentsize != sizeof(Elf_Phdr)) 30783322Speter break; 30883322Speter phlen = hdr->e_phnum * sizeof(Elf_Phdr); 30983322Speter if (ef_read_entry(ef, hdr->e_phoff, phlen, 31083322Speter (void**)&ef->ef_ph) != 0) 31183322Speter break; 31283322Speter phdr = ef->ef_ph; 31383322Speter phlimit = phdr + hdr->e_phnum; 31483322Speter nsegs = 0; 31583322Speter phdyn = NULL; 31683322Speter phphdr = NULL; 31783322Speter while (phdr < phlimit) { 31883322Speter if (verbose > 1) 31983322Speter ef_print_phdr(phdr); 32083322Speter switch (phdr->p_type) { 32183322Speter case PT_LOAD: 32283322Speter if (nsegs == 2) { 32383322Speter warnx("%s: too many sections", 32483322Speter filename); 32583322Speter break; 32683322Speter } 32783322Speter ef->ef_segs[nsegs++] = phdr; 32883322Speter break; 32983322Speter case PT_PHDR: 33083322Speter phphdr = phdr; 33183322Speter break; 33283322Speter case PT_DYNAMIC: 33383322Speter phdyn = phdr; 33483322Speter break; 33583322Speter } 33683322Speter phdr++; 33783322Speter } 33883322Speter if (verbose > 1) 33983322Speter printf("\n"); 34083322Speter ef->ef_nsegs = nsegs; 34183322Speter if (phdyn == NULL) { 34283322Speter warnx("file isn't dynamically-linked"); 34383322Speter break; 34483322Speter } 34583322Speter if (ef_read_entry(ef, phdyn->p_offset, 34683322Speter phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) { 34783322Speter printf("ef_read_entry failed\n"); 34883322Speter break; 34983322Speter } 35083322Speter error = ef_parse_dynamic(ef); 35183322Speter if (error) 35283322Speter break; 35383322Speter if (hdr->e_type == ET_DYN) { 35483322Speter ef->ef_type = EFT_KLD; 35583322Speter/* pad = (u_int)dest & PAGE_MASK; 35683322Speter if (pad) 35783322Speter dest += PAGE_SIZE - pad;*/ 35883322Speter error = 0; 35983322Speter } else if (hdr->e_type == ET_EXEC) { 36083322Speter/* dest = hdr->e_entry; 36183322Speter if (dest == 0) 36283322Speter break;*/ 36383322Speter ef->ef_type = EFT_KERNEL; 36483322Speter error = 0; 36583322Speter } else 36683322Speter break; 36783322Speter } while(0); 36883322Speter if (error) { 36983322Speter ef_close(ef); 37083322Speter if (ef->ef_verbose) 37183322Speter warnc(error, "elf_open(%s)", filename); 37283322Speter } 37383322Speter return error; 37483322Speter} 37583322Speter 37683322Speterint 37783322Speteref_close(elf_file_t ef) 37883322Speter{ 37983322Speter close(ef->ef_fd); 38083322Speter/* if (ef->ef_fpage) 38183322Speter free(ef->ef_fpage);*/ 38283322Speter if (ef->ef_name) 38383322Speter free(ef->ef_name); 38483322Speter return 0; 38583322Speter} 386