Index: head/usr.sbin/kldxref/ef.c =================================================================== --- head/usr.sbin/kldxref/ef.c (revision 328093) +++ head/usr.sbin/kldxref/ef.c (revision 328094) @@ -1,674 +1,674 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include -#include + +#include +#include +#include #include #include +#include #include -#include -#include #include #define FREEBSD_ELF -#include - #include "ef.h" #define MAXSEGS 3 struct ef_file { - char* ef_name; + char *ef_name; struct elf_file *ef_efile; - Elf_Phdr * ef_ph; + Elf_Phdr *ef_ph; int ef_fd; int ef_type; Elf_Ehdr ef_hdr; - void* ef_fpage; /* First block of the file */ + void *ef_fpage; /* First block of the file */ int ef_fplen; /* length of first block */ - Elf_Dyn* ef_dyn; /* Symbol table etc. */ + Elf_Dyn *ef_dyn; /* Symbol table etc. */ Elf_Hashelt ef_nbuckets; Elf_Hashelt ef_nchains; - Elf_Hashelt* ef_buckets; - Elf_Hashelt* ef_chains; - Elf_Hashelt* ef_hashtab; + Elf_Hashelt *ef_buckets; + Elf_Hashelt *ef_chains; + Elf_Hashelt *ef_hashtab; Elf_Off ef_stroff; caddr_t ef_strtab; int ef_strsz; Elf_Off ef_symoff; - Elf_Sym* ef_symtab; + Elf_Sym *ef_symtab; int ef_nsegs; - Elf_Phdr * ef_segs[MAXSEGS]; + Elf_Phdr *ef_segs[MAXSEGS]; int ef_verbose; - Elf_Rel * ef_rel; /* relocation table */ + Elf_Rel *ef_rel; /* relocation table */ int ef_relsz; /* number of entries */ - Elf_Rela * ef_rela; /* relocation table */ + Elf_Rela *ef_rela; /* relocation table */ int ef_relasz; /* number of entries */ }; -static void ef_print_phdr(Elf_Phdr *); -static u_long ef_get_offset(elf_file_t, Elf_Off); -static int ef_parse_dynamic(elf_file_t); +static void ef_print_phdr(Elf_Phdr *); +static u_long ef_get_offset(elf_file_t, Elf_Off); +static int ef_parse_dynamic(elf_file_t); -static int ef_get_type(elf_file_t ef); -static int ef_close(elf_file_t ef); -static int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); -static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr); -static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest); -static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, - void *dest); -static int ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, - char *dest); -static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, - void **ptr); -static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, - void **ptr); -static Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx); -static int ef_lookup_set(elf_file_t ef, const char *name, long *startp, - long *stopp, long *countp); -static int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); +static int ef_get_type(elf_file_t ef); +static int ef_close(elf_file_t ef); +static int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); +static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, + void **ptr); +static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, + void *dest); +static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, + void *dest); +static int ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, + char *dest); +static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, + void **ptr); +static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, + void **ptr); + +static Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx); +static int ef_lookup_set(elf_file_t ef, const char *name, long *startp, + long *stopp, long *countp); +static int ef_lookup_symbol(elf_file_t ef, const char* name, + Elf_Sym** sym); + static struct elf_file_ops ef_file_ops = { - ef_get_type, - ef_close, - ef_read, - ef_read_entry, - ef_seg_read, - ef_seg_read_rel, - ef_seg_read_string, - ef_seg_read_entry, - ef_seg_read_entry_rel, - ef_symaddr, - ef_lookup_set, - ef_lookup_symbol + .get_type = ef_get_type, + .close = ef_close, + .read = ef_read, + .read_entry = ef_read_entry, + .seg_read = ef_seg_read, + .seg_read_rel = ef_seg_read_rel, + .seg_read_string = ef_seg_read_string, + .seg_read_entry = ef_seg_read_entry, + .seg_read_entry_rel = ef_seg_read_entry_rel, + .symaddr = ef_symaddr, + .lookup_set = ef_lookup_set, + .lookup_symbol = ef_lookup_symbol }; static void ef_print_phdr(Elf_Phdr *phdr) { if ((phdr->p_flags & PF_W) == 0) { printf("text=0x%lx ", (long)phdr->p_filesz); } else { printf("data=0x%lx", (long)phdr->p_filesz); if (phdr->p_filesz < phdr->p_memsz) printf("+0x%lx", (long)(phdr->p_memsz - phdr->p_filesz)); printf(" "); } } static u_long ef_get_offset(elf_file_t ef, Elf_Off off) { Elf_Phdr *ph; int i; for (i = 0; i < ef->ef_nsegs; i++) { ph = ef->ef_segs[i]; if (off >= ph->p_vaddr && off < ph->p_vaddr + ph->p_memsz) { - return ph->p_offset + (off - ph->p_vaddr); + return (ph->p_offset + (off - ph->p_vaddr)); } } - return 0; + return (0); } static int ef_get_type(elf_file_t ef) { return (ef->ef_type); } /* * next three functions copied from link_elf.c */ static unsigned long elf_hash(const char *name) { - const unsigned char *p = (const unsigned char *) name; - unsigned long h = 0; - unsigned long g; + unsigned long h, g; + const unsigned char *p; + h = 0; + p = (const unsigned char *)name; while (*p != '\0') { h = (h << 4) + *p++; if ((g = h & 0xf0000000) != 0) h ^= g >> 24; h &= ~g; } - return h; + return (h); } static int ef_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) { - unsigned long symnum; - Elf_Sym* symp; + unsigned long hash, symnum; + Elf_Sym *symp; char *strp; - unsigned long hash; /* First, search hashed global symbols */ hash = elf_hash(name); symnum = ef->ef_buckets[hash % ef->ef_nbuckets]; while (symnum != STN_UNDEF) { if (symnum >= ef->ef_nchains) { warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", ef->ef_name); - return ENOENT; + return (ENOENT); } symp = ef->ef_symtab + symnum; if (symp->st_name == 0) { warnx("ef_lookup_symbol: file %s have corrupted symbol table\n", ef->ef_name); - return ENOENT; + return (ENOENT); } strp = ef->ef_strtab + symp->st_name; if (strcmp(name, strp) == 0) { if (symp->st_shndx != SHN_UNDEF || (symp->st_value != 0 && ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { *sym = symp; - return 0; + return (0); } else - return ENOENT; + return (ENOENT); } symnum = ef->ef_chains[symnum]; } - return ENOENT; + return (ENOENT); } static int ef_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, long *countp) { Elf_Sym *sym; char *setsym; int error, len; len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ setsym = malloc(len); if (setsym == NULL) - return (ENOMEM); + return (errno); /* get address of first entry */ snprintf(setsym, len, "%s%s", "__start_set_", name); error = ef_lookup_symbol(ef, setsym, &sym); - if (error) + if (error != 0) goto out; *startp = sym->st_value; /* get address of last entry */ snprintf(setsym, len, "%s%s", "__stop_set_", name); error = ef_lookup_symbol(ef, setsym, &sym); - if (error) + if (error != 0) goto out; *stopp = sym->st_value; /* and the number of entries */ *countp = (*stopp - *startp) / sizeof(void *); out: free(setsym); return (error); } static Elf_Addr ef_symaddr(elf_file_t ef, Elf_Size symidx) { const Elf_Sym *sym; if (symidx >= ef->ef_nchains) return (0); sym = ef->ef_symtab + symidx; if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && sym->st_shndx != SHN_UNDEF && sym->st_value != 0) return (sym->st_value); return (0); } static int ef_parse_dynamic(elf_file_t ef) { Elf_Dyn *dp; Elf_Hashelt hashhdr[2]; -/* int plttype = DT_REL;*/ int error; Elf_Off rel_off; Elf_Off rela_off; int rel_sz; int rela_sz; int rel_entry; int rela_entry; rel_off = rela_off = 0; rel_sz = rela_sz = 0; rel_entry = rela_entry = 0; for (dp = ef->ef_dyn; dp->d_tag != DT_NULL; dp++) { switch (dp->d_tag) { case DT_HASH: error = ef_read(ef, ef_get_offset(ef, dp->d_un.d_ptr), sizeof(hashhdr), hashhdr); - if (error) { + if (error != 0) { warnx("can't read hash header (%lx)", ef_get_offset(ef, dp->d_un.d_ptr)); - return error; + return (error); } ef->ef_nbuckets = hashhdr[0]; ef->ef_nchains = hashhdr[1]; error = ef_read_entry(ef, -1, (hashhdr[0] + hashhdr[1]) * sizeof(Elf_Hashelt), (void**)&ef->ef_hashtab); - if (error) { + if (error != 0) { warnx("can't read hash table"); - return error; + return (error); } ef->ef_buckets = ef->ef_hashtab; ef->ef_chains = ef->ef_buckets + ef->ef_nbuckets; break; case DT_STRTAB: ef->ef_stroff = dp->d_un.d_ptr; break; case DT_STRSZ: ef->ef_strsz = dp->d_un.d_val; break; case DT_SYMTAB: ef->ef_symoff = dp->d_un.d_ptr; break; case DT_SYMENT: if (dp->d_un.d_val != sizeof(Elf_Sym)) - return EFTYPE; + return (EFTYPE); break; case DT_REL: if (rel_off != 0) warnx("second DT_REL entry ignored"); rel_off = dp->d_un.d_ptr; break; case DT_RELSZ: if (rel_sz != 0) warnx("second DT_RELSZ entry ignored"); rel_sz = dp->d_un.d_val; break; case DT_RELENT: if (rel_entry != 0) warnx("second DT_RELENT entry ignored"); rel_entry = dp->d_un.d_val; break; case DT_RELA: if (rela_off != 0) warnx("second DT_RELA entry ignored"); rela_off = dp->d_un.d_ptr; break; case DT_RELASZ: if (rela_sz != 0) warnx("second DT_RELASZ entry ignored"); rela_sz = dp->d_un.d_val; break; case DT_RELAENT: if (rela_entry != 0) warnx("second DT_RELAENT entry ignored"); rela_entry = dp->d_un.d_val; break; } } if (ef->ef_symoff == 0) { warnx("%s: no .dynsym section found\n", ef->ef_name); - return EFTYPE; + return (EFTYPE); } if (ef->ef_stroff == 0) { warnx("%s: no .dynstr section found\n", ef->ef_name); - return EFTYPE; + return (EFTYPE); } if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_symoff), ef->ef_nchains * sizeof(Elf_Sym), (void**)&ef->ef_symtab) != 0) { if (ef->ef_verbose) warnx("%s: can't load .dynsym section (0x%lx)", ef->ef_name, (long)ef->ef_symoff); - return EIO; + return (EIO); } if (ef_read_entry(ef, ef_get_offset(ef, ef->ef_stroff), ef->ef_strsz, (void**)&ef->ef_strtab) != 0) { warnx("can't load .dynstr section"); - return EIO; + return (EIO); } if (rel_off != 0) { if (rel_entry == 0) { warnx("%s: no DT_RELENT for DT_REL", ef->ef_name); return (EFTYPE); } if (rel_entry != sizeof(Elf_Rel)) { warnx("%s: inconsistent DT_RELENT value", ef->ef_name); return (EFTYPE); } if (rel_sz % rel_entry != 0) { warnx("%s: inconsistent values for DT_RELSZ and " "DT_RELENT", ef->ef_name); return (EFTYPE); } if (ef_read_entry(ef, ef_get_offset(ef, rel_off), rel_sz, (void **)&ef->ef_rel) != 0) { warnx("%s: cannot load DT_REL section", ef->ef_name); return (EIO); } ef->ef_relsz = rel_sz / rel_entry; if (ef->ef_verbose) warnx("%s: %d REL entries", ef->ef_name, ef->ef_relsz); } if (rela_off != 0) { if (rela_entry == 0) { warnx("%s: no DT_RELAENT for DT_RELA", ef->ef_name); return (EFTYPE); } if (rela_entry != sizeof(Elf_Rela)) { warnx("%s: inconsistent DT_RELAENT value", ef->ef_name); return (EFTYPE); } if (rela_sz % rela_entry != 0) { warnx("%s: inconsistent values for DT_RELASZ and " "DT_RELAENT", ef->ef_name); return (EFTYPE); } if (ef_read_entry(ef, ef_get_offset(ef, rela_off), rela_sz, (void **)&ef->ef_rela) != 0) { warnx("%s: cannot load DT_RELA section", ef->ef_name); return (EIO); } ef->ef_relasz = rela_sz / rela_entry; if (ef->ef_verbose) warnx("%s: %d RELA entries", ef->ef_name, ef->ef_relasz); } - return 0; + return (0); } static int ef_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) { ssize_t r; if (offset != (Elf_Off)-1) { if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) - return EIO; + return (EIO); } r = read(ef->ef_fd, dest, len); if (r != -1 && (size_t)r == len) - return 0; + return (0); else - return EIO; + return (EIO); } static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) { int error; *ptr = malloc(len); if (*ptr == NULL) - return ENOMEM; + return (errno); error = ef_read(ef, offset, len, *ptr); - if (error) + if (error != 0) free(*ptr); - return error; + return (error); } static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void*dest) { - u_long ofs = ef_get_offset(ef, offset); + u_long ofs; + ofs = ef_get_offset(ef, offset); if (ofs == 0) { if (ef->ef_verbose) warnx("ef_seg_read(%s): zero offset (%lx:%ld)", ef->ef_name, (long)offset, ofs); - return EFAULT; + return (EFAULT); } return ef_read(ef, ofs, len, dest); } static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest) { - u_long ofs = ef_get_offset(ef, offset); + u_long ofs; const Elf_Rela *a; const Elf_Rel *r; int error; + ofs = ef_get_offset(ef, offset); if (ofs == 0) { if (ef->ef_verbose) warnx("ef_seg_read_rel(%s): zero offset (%lx:%ld)", ef->ef_name, (long)offset, ofs); - return EFAULT; + return (EFAULT); } if ((error = ef_read(ef, ofs, len, dest)) != 0) return (error); for (r = ef->ef_rel; r < &ef->ef_rel[ef->ef_relsz]; r++) { error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, 0, offset, len, dest); if (error != 0) return (error); } for (a = ef->ef_rela; a < &ef->ef_rela[ef->ef_relasz]; a++) { error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 0, offset, len, dest); if (error != 0) return (error); } return (0); } static int ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest) { - u_long ofs = ef_get_offset(ef, offset); + u_long ofs; ssize_t r; + ofs = ef_get_offset(ef, offset); if (ofs == 0 || ofs == (Elf_Off)-1) { if (ef->ef_verbose) warnx("ef_seg_read_string(%s): bad offset (%lx:%ld)", ef->ef_name, (long)offset, ofs); return (EFAULT); } r = pread(ef->ef_fd, dest, len, ofs); if (r < 0) return (errno); if (strnlen(dest, len) == len) return (EFAULT); return (0); } static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) { int error; *ptr = malloc(len); if (*ptr == NULL) - return ENOMEM; + return (errno); error = ef_seg_read(ef, offset, len, *ptr); - if (error) + if (error != 0) free(*ptr); - return error; + return (error); } static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void**ptr) { int error; *ptr = malloc(len); if (*ptr == NULL) - return ENOMEM; + return (errno); error = ef_seg_read_rel(ef, offset, len, *ptr); - if (error) + if (error != 0) free(*ptr); - return error; + return (error); } int ef_open(const char *filename, struct elf_file *efile, int verbose) { elf_file_t ef; Elf_Ehdr *hdr; int fd; int error; int phlen, res; int nsegs; Elf_Phdr *phdr, *phdyn, *phlimit; if (filename == NULL) - return EFTYPE; + return (EINVAL); if ((fd = open(filename, O_RDONLY)) == -1) - return errno; + return (errno); ef = malloc(sizeof(*ef)); if (ef == NULL) { close(fd); - return (ENOMEM); + return (errno); } efile->ef_ef = ef; efile->ef_ops = &ef_file_ops; bzero(ef, sizeof(*ef)); ef->ef_verbose = verbose; ef->ef_fd = fd; ef->ef_name = strdup(filename); ef->ef_efile = efile; hdr = (Elf_Ehdr *)&ef->ef_hdr; do { res = read(fd, hdr, sizeof(*hdr)); error = EFTYPE; if (res != sizeof(*hdr)) break; if (!IS_ELF(*hdr)) break; if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || hdr->e_phentsize != sizeof(Elf_Phdr)) break; phlen = hdr->e_phnum * sizeof(Elf_Phdr); if (ef_read_entry(ef, hdr->e_phoff, phlen, (void**)&ef->ef_ph) != 0) break; phdr = ef->ef_ph; phlimit = phdr + hdr->e_phnum; nsegs = 0; phdyn = NULL; while (phdr < phlimit) { if (verbose > 1) ef_print_phdr(phdr); switch (phdr->p_type) { case PT_LOAD: if (nsegs < MAXSEGS) ef->ef_segs[nsegs] = phdr; nsegs++; break; case PT_PHDR: break; case PT_DYNAMIC: phdyn = phdr; break; } phdr++; } if (verbose > 1) printf("\n"); if (phdyn == NULL) { warnx("Skipping %s: not dynamically-linked", filename); break; } else if (nsegs > MAXSEGS) { warnx("%s: too many segments", filename); break; } ef->ef_nsegs = nsegs; if (ef_read_entry(ef, phdyn->p_offset, phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) { printf("ef_read_entry failed\n"); break; } error = ef_parse_dynamic(ef); - if (error) + if (error != 0) break; if (hdr->e_type == ET_DYN) { ef->ef_type = EFT_KLD; -/* pad = (u_int)dest & PAGE_MASK; - if (pad) - dest += PAGE_SIZE - pad;*/ error = 0; } else if (hdr->e_type == ET_EXEC) { -/* dest = hdr->e_entry; - if (dest == 0) - break;*/ ef->ef_type = EFT_KERNEL; error = 0; } else break; } while(0); - if (error) + if (error != 0) ef_close(ef); - return error; + return (error); } static int ef_close(elf_file_t ef) { + close(ef->ef_fd); -/* if (ef->ef_fpage) - free(ef->ef_fpage);*/ if (ef->ef_name) free(ef->ef_name); ef->ef_efile->ef_ops = NULL; ef->ef_efile->ef_ef = NULL; free(ef); - return 0; + return (0); } Index: head/usr.sbin/kldxref/ef_aarch64.c =================================================================== --- head/usr.sbin/kldxref/ef_aarch64.c (revision 328093) +++ head/usr.sbin/kldxref/ef_aarch64.c (revision 328094) @@ -1,77 +1,74 @@ /*- * Copyright (c) 2005 Peter Grehan. * Copyright 1996-1998 John D. Polstra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include "ef.h" -#include - /* * Apply relocations to the values obtained from the file. `relbase' is the * target relocation address of the section, and `dataoff/len' is the region * that is to be relocated, and has been copied to *dest */ int ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase, Elf_Off dataoff, size_t len, void *dest) { - Elf_Addr *where, addend; - Elf_Size rtype, symidx; - const Elf_Rela *rela; + Elf_Addr *where, addend; + Elf_Size rtype; + const Elf_Rela *rela; if (reltype != EF_RELOC_RELA) return (EINVAL); rela = (const Elf_Rela *)reldata; where = (Elf_Addr *) ((Elf_Off)dest - dataoff + rela->r_offset); addend = rela->r_addend; rtype = ELF_R_TYPE(rela->r_info); - symidx = ELF_R_SYM(rela->r_info); if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len) - return (0); + return (0); switch(rtype) { case R_AARCH64_RELATIVE: *where = relbase + addend; break; case R_AARCH64_ABS64: break; default: warnx("unhandled relocation type %lu", rtype); break; } return (0); } Index: head/usr.sbin/kldxref/ef_obj.c =================================================================== --- head/usr.sbin/kldxref/ef_obj.c (revision 328093) +++ head/usr.sbin/kldxref/ef_obj.c (revision 328094) @@ -1,632 +1,634 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000, Boris Popov * Copyright (c) 1998-2000 Doug Rabson * Copyright (c) 2004 Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include -#include + +#include +#include +#include #include #include +#include #include -#include -#include #include #define FREEBSD_ELF -#include - #include "ef.h" typedef struct { void *addr; Elf_Off size; int flags; int sec; /* Original section */ char *name; } Elf_progent; typedef struct { Elf_Rel *rel; int nrel; int sec; } Elf_relent; typedef struct { Elf_Rela *rela; int nrela; int sec; } Elf_relaent; struct ef_file { char *ef_name; int ef_fd; Elf_Ehdr ef_hdr; struct elf_file *ef_efile; caddr_t address; Elf_Off size; Elf_Shdr *e_shdr; Elf_progent *progtab; int nprogtab; Elf_relaent *relatab; int nrela; Elf_relent *reltab; int nrel; Elf_Sym *ddbsymtab; /* The symbol table we are using */ long ddbsymcnt; /* Number of symbols */ caddr_t ddbstrtab; /* String table */ long ddbstrcnt; /* number of bytes in string table */ caddr_t shstrtab; /* Section name string table */ long shstrcnt; /* number of bytes in string table */ int ef_verbose; }; -static int ef_obj_get_type(elf_file_t ef); -static int ef_obj_close(elf_file_t ef); -static int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); -static int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, - void **ptr); -static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, - void *dest); -static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, - void *dest); -static int ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, - char *dest); -static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, - void **ptr); -static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, - void **ptr); -static Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx); -static int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, - long *stopp, long *countp); -static int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); +static int ef_obj_get_type(elf_file_t ef); +static int ef_obj_close(elf_file_t ef); +static int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, + void* dest); +static int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, + void **ptr); +static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, + void *dest); +static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, + void *dest); +static int ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, + size_t len, char *dest); +static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, + void **ptr); +static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, + size_t len, void **ptr); +static Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx); +static int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, + long *stopp, long *countp); +static int ef_obj_lookup_symbol(elf_file_t ef, const char* name, + Elf_Sym** sym); static struct elf_file_ops ef_obj_file_ops = { - ef_obj_get_type, - ef_obj_close, - ef_obj_read, - ef_obj_read_entry, - ef_obj_seg_read, - ef_obj_seg_read_rel, - ef_obj_seg_read_string, - ef_obj_seg_read_entry, - ef_obj_seg_read_entry_rel, - ef_obj_symaddr, - ef_obj_lookup_set, - ef_obj_lookup_symbol + .get_type = ef_obj_get_type, + .close = ef_obj_close, + .read = ef_obj_read, + .read_entry = ef_obj_read_entry, + .seg_read = ef_obj_seg_read, + .seg_read_rel = ef_obj_seg_read_rel, + .seg_read_string = ef_obj_seg_read_string, + .seg_read_entry = ef_obj_seg_read_entry, + .seg_read_entry_rel = ef_obj_seg_read_entry_rel, + .symaddr = ef_obj_symaddr, + .lookup_set = ef_obj_lookup_set, + .lookup_symbol = ef_obj_lookup_symbol }; static int ef_obj_get_type(elf_file_t __unused ef) { return (EFT_KLD); } static int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) { Elf_Sym *symp; const char *strp; int i; for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { strp = ef->ddbstrtab + symp->st_name; if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) { *sym = symp; - return 0; + return (0); } } - return ENOENT; + return (ENOENT); } static int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, long *countp) { int i; for (i = 0; i < ef->nprogtab; i++) { if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && strcmp(ef->progtab[i].name + 4, name) == 0) { *startp = (char *)ef->progtab[i].addr - ef->address; *stopp = (char *)ef->progtab[i].addr + ef->progtab[i].size - ef->address; *countp = (*stopp - *startp) / sizeof(void *); return (0); } } return (ESRCH); } static Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx) { const Elf_Sym *sym; if (symidx >= (size_t) ef->ddbsymcnt) return (0); sym = ef->ddbsymtab + symidx; if (sym->st_shndx != SHN_UNDEF) return (sym->st_value - (Elf_Addr)ef->address); return (0); } static int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) { ssize_t r; if (offset != (Elf_Off)-1) { if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) - return EIO; + return (EIO); } r = read(ef->ef_fd, dest, len); if (r != -1 && (size_t)r == len) - return 0; + return (0); else - return EIO; + return (EIO); } static int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) { int error; *ptr = malloc(len); if (*ptr == NULL) - return ENOMEM; + return (errno); error = ef_obj_read(ef, offset, len, *ptr); - if (error) + if (error != 0) free(*ptr); - return error; + return (error); } static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) { if (offset + len > ef->size) { if (ef->ef_verbose) warnx("ef_obj_seg_read(%s): bad offset/len (%lx:%ld)", ef->ef_name, (long)offset, (long)len); return (EFAULT); } bcopy(ef->address + offset, dest, len); return (0); } static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest) { char *memaddr; Elf_Rel *r; Elf_Rela *a; Elf_Off secbase, dataoff; int error, i, sec; if (offset + len > ef->size) { if (ef->ef_verbose) warnx("ef_obj_seg_read_rel(%s): bad offset/len (%lx:%ld)", ef->ef_name, (long)offset, (long)len); return (EFAULT); } bcopy(ef->address + offset, dest, len); /* Find out which section contains the data. */ memaddr = ef->address + offset; sec = -1; secbase = dataoff = 0; for (i = 0; i < ef->nprogtab; i++) { if (ef->progtab[i].addr == NULL) continue; if (memaddr < (char *)ef->progtab[i].addr || memaddr + len > (char *)ef->progtab[i].addr + ef->progtab[i].size) continue; sec = ef->progtab[i].sec; /* We relocate to address 0. */ secbase = (char *)ef->progtab[i].addr - ef->address; dataoff = memaddr - ef->address; break; } if (sec == -1) return (EFAULT); /* Now do the relocations. */ for (i = 0; i < ef->nrel; i++) { if (ef->reltab[i].sec != sec) continue; for (r = ef->reltab[i].rel; r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) { error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase, dataoff, len, dest); if (error != 0) return (error); } } for (i = 0; i < ef->nrela; i++) { if (ef->relatab[i].sec != sec) continue; for (a = ef->relatab[i].rela; a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) { error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, secbase, dataoff, len, dest); if (error != 0) return (error); } } return (0); } static int ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest) { if (offset >= ef->size) { if (ef->ef_verbose) warnx("ef_obj_seg_read_string(%s): bad offset (%lx)", ef->ef_name, (long)offset); return (EFAULT); } if (ef->size - offset < len) len = ef->size - offset; if (strnlen(ef->address + offset, len) == len) return (EFAULT); memcpy(dest, ef->address + offset, len); return (0); } static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) { int error; *ptr = malloc(len); if (*ptr == NULL) - return ENOMEM; + return (errno); error = ef_obj_seg_read(ef, offset, len, *ptr); - if (error) + if (error != 0) free(*ptr); - return error; + return (error); } static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) { int error; *ptr = malloc(len); if (*ptr == NULL) - return ENOMEM; + return (errno); error = ef_obj_seg_read_rel(ef, offset, len, *ptr); - if (error) + if (error != 0) free(*ptr); - return error; + return (error); } int ef_obj_open(const char *filename, struct elf_file *efile, int verbose) { elf_file_t ef; Elf_Ehdr *hdr; Elf_Shdr *shdr; Elf_Sym *es; char *mapbase; void *vtmp; size_t mapsize, alignmask, max_addralign; int error, fd, pb, ra, res, rl; int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex; if (filename == NULL) - return EFTYPE; + return (EINVAL); if ((fd = open(filename, O_RDONLY)) == -1) - return errno; + return (errno); ef = calloc(1, sizeof(*ef)); if (ef == NULL) { close(fd); - return (ENOMEM); + return (errno); } efile->ef_ef = ef; efile->ef_ops = &ef_obj_file_ops; ef->ef_verbose = verbose; ef->ef_fd = fd; ef->ef_name = strdup(filename); ef->ef_efile = efile; hdr = (Elf_Ehdr *)&ef->ef_hdr; res = read(fd, hdr, sizeof(*hdr)); error = EFTYPE; if (res != sizeof(*hdr)) goto out; if (!IS_ELF(*hdr)) goto out; if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || hdr->e_type != ET_REL) goto out; nbytes = hdr->e_shnum * hdr->e_shentsize; if (nbytes == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) goto out; if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) { printf("ef_read_entry failed\n"); goto out; } ef->e_shdr = shdr = vtmp; /* Scan the section header for information and table sizing. */ nsym = 0; symtabindex = -1; symstrindex = -1; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: ef->nprogtab++; break; case SHT_SYMTAB: nsym++; symtabindex = i; symstrindex = shdr[i].sh_link; break; case SHT_REL: ef->nrel++; break; case SHT_RELA: ef->nrela++; break; case SHT_STRTAB: break; } } if (ef->nprogtab == 0) { warnx("%s: file has no contents", filename); goto out; } if (nsym != 1) { warnx("%s: file has no valid symbol table", filename); goto out; } if (symstrindex < 0 || symstrindex > hdr->e_shnum || shdr[symstrindex].sh_type != SHT_STRTAB) { warnx("%s: file has invalid symbol strings", filename); goto out; } /* Allocate space for tracking the load chunks */ if (ef->nprogtab != 0) ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); if (ef->nrel != 0) ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); if (ef->nrela != 0) ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); if ((ef->nprogtab != 0 && ef->progtab == NULL) || (ef->nrel != 0 && ef->reltab == NULL) || (ef->nrela != 0 && ef->relatab == NULL)) { printf("malloc failed\n"); error = ENOMEM; goto out; } ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset, shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) { printf("ef_read_entry failed\n"); goto out; } ef->ddbstrcnt = shdr[symstrindex].sh_size; if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset, shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) { printf("ef_read_entry failed\n"); goto out; } /* Do we have a string table for the section names? */ shstrindex = -1; if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { shstrindex = hdr->e_shstrndx; ef->shstrcnt = shdr[shstrindex].sh_size; if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset, shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) { printf("ef_read_entry failed\n"); goto out; } } /* Size up code/data(progbits) and bss(nobits). */ alignmask = 0; max_addralign = 0; mapsize = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; if (shdr[i].sh_addralign > max_addralign) max_addralign = shdr[i].sh_addralign; mapsize += alignmask; mapsize &= ~alignmask; mapsize += shdr[i].sh_size; break; } } /* We know how much space we need for the text/data/bss/etc. */ ef->size = mapsize; if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { printf("posix_memalign failed\n"); goto out; } mapbase = ef->address; /* * Now load code/data(progbits), zero bss(nobits), allocate * space for and load relocs */ pb = 0; rl = 0; ra = 0; alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; mapbase += alignmask; mapbase = (char *)((uintptr_t)mapbase & ~alignmask); ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; if (shdr[i].sh_type == SHT_PROGBITS) { ef->progtab[pb].name = "<>"; if (ef_obj_read(ef, shdr[i].sh_offset, shdr[i].sh_size, ef->progtab[pb].addr) != 0) { printf("failed to read progbits\n"); goto out; } } else { ef->progtab[pb].name = "<>"; bzero(ef->progtab[pb].addr, shdr[i].sh_size); } ef->progtab[pb].size = shdr[i].sh_size; ef->progtab[pb].sec = i; if (ef->shstrtab && shdr[i].sh_name != 0) ef->progtab[pb].name = ef->shstrtab + shdr[i].sh_name; /* Update all symbol values with the offset. */ for (j = 0; j < ef->ddbsymcnt; j++) { es = &ef->ddbsymtab[j]; if (es->st_shndx != i) continue; es->st_value += (Elf_Addr)ef->progtab[pb].addr; } mapbase += shdr[i].sh_size; pb++; break; case SHT_REL: ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); ef->reltab[rl].sec = shdr[i].sh_info; if (ef_obj_read_entry(ef, shdr[i].sh_offset, shdr[i].sh_size, (void**)&ef->reltab[rl].rel) != 0) { printf("ef_read_entry failed\n"); goto out; } rl++; break; case SHT_RELA: ef->relatab[ra].nrela = shdr[i].sh_size / sizeof(Elf_Rela); ef->relatab[ra].sec = shdr[i].sh_info; if (ef_obj_read_entry(ef, shdr[i].sh_offset, shdr[i].sh_size, (void**)&ef->relatab[ra].rela) != 0) { printf("ef_read_entry failed\n"); goto out; } ra++; break; } } error = 0; out: - if (error) + if (error != 0) ef_obj_close(ef); - return error; + return (error); } static int ef_obj_close(elf_file_t ef) { int i; close(ef->ef_fd); if (ef->ef_name) free(ef->ef_name); if (ef->e_shdr != NULL) free(ef->e_shdr); if (ef->size != 0) free(ef->address); if (ef->nprogtab != 0) free(ef->progtab); if (ef->nrel != 0) { for (i = 0; i < ef->nrel; i++) if (ef->reltab[i].rel != NULL) free(ef->reltab[i].rel); free(ef->reltab); } if (ef->nrela != 0) { for (i = 0; i < ef->nrela; i++) if (ef->relatab[i].rela != NULL) free(ef->relatab[i].rela); free(ef->relatab); } if (ef->ddbsymtab != NULL) free(ef->ddbsymtab); if (ef->ddbstrtab != NULL) free(ef->ddbstrtab); if (ef->shstrtab != NULL) free(ef->shstrtab); ef->ef_efile->ef_ops = NULL; ef->ef_efile->ef_ef = NULL; free(ef); - return 0; + return (0); } Index: head/usr.sbin/kldxref/ef_powerpc.c =================================================================== --- head/usr.sbin/kldxref/ef_powerpc.c (revision 328093) +++ head/usr.sbin/kldxref/ef_powerpc.c (revision 328094) @@ -1,76 +1,73 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005 Peter Grehan. * Copyright 1996-1998 John D. Polstra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include "ef.h" -#include - /* * Apply relocations to the values obtained from the file. `relbase' is the * target relocation address of the section, and `dataoff/len' is the region * that is to be relocated, and has been copied to *dest */ int ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase, Elf_Off dataoff, size_t len, void *dest) { - Elf_Addr *where, addend; - Elf_Size rtype, symidx; - const Elf_Rela *rela; + Elf_Addr *where, addend; + Elf_Size rtype; + const Elf_Rela *rela; if (reltype != EF_RELOC_RELA) return (EINVAL); rela = (const Elf_Rela *)reldata; where = (Elf_Addr *) ((Elf_Off)dest - dataoff + rela->r_offset); addend = rela->r_addend; rtype = ELF_R_TYPE(rela->r_info); - symidx = ELF_R_SYM(rela->r_info); if ((char *)where < (char *)dest || (char *)where >= (char *)dest + len) - return (0); + return (0); switch(rtype) { case R_PPC_RELATIVE: /* word32 B + A */ *where = relbase + addend; break; default: - warnx("unhandled relocation type %d", rtype); + warnx("unhandled relocation type %lu", rtype); } return (0); } Index: head/usr.sbin/kldxref/kldxref.c =================================================================== --- head/usr.sbin/kldxref/kldxref.c (revision 328093) +++ head/usr.sbin/kldxref/kldxref.c (revision 328094) @@ -1,718 +1,724 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #define FREEBSD_ELF + #include +#include #include -#include -#include +#include #include #include +#include #include -#include +#include #include "ef.h" #define MAXRECSIZE (64 << 10) /* 64k */ #define check(val) if ((error = (val)) != 0) break -static int dflag; /* do not create a hint file, only write on stdout */ +static bool dflag; /* do not create a hint file, only write on stdout */ static int verbose; static FILE *fxref; /* current hints file */ static const char *xref_file = "linker.hints"; /* * A record is stored in the static buffer recbuf before going to disk. */ static char recbuf[MAXRECSIZE]; static int recpos; /* current write position */ static int reccnt; /* total record written to this file so far */ static void intalign(void) { + recpos = roundup2(recpos, sizeof(int)); } static void record_start(void) { + recpos = 0; memset(recbuf, 0, MAXRECSIZE); } static int record_end(void) { + if (recpos == 0) - return 0; + return (0); reccnt++; intalign(); fwrite(&recpos, sizeof(recpos), 1, fxref); - return fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0; + return (fwrite(recbuf, recpos, 1, fxref) != 1 ? errno : 0); } static int -record_buf(const void *buf, int size) +record_buf(const void *buf, size_t size) { + if (MAXRECSIZE - recpos < size) errx(1, "record buffer overflow"); memcpy(recbuf + recpos, buf, size); recpos += size; - return 0; + return (0); } /* * An int is stored in host order and aligned */ static int record_int(int val) { + intalign(); - return record_buf(&val, sizeof(val)); + return (record_buf(&val, sizeof(val))); } /* * A string is stored as 1-byte length plus data, no padding */ static int record_string(const char *str) { - int len, error; + int error; + size_t len; u_char val; if (dflag) - return 0; + return (0); val = len = strlen(str); if (len > 255) errx(1, "string %s too long", str); error = record_buf(&val, sizeof(val)); - if (error) - return error; - return record_buf(str, len); + if (error != 0) + return (error); + return (record_buf(str, len)); } /* From sys/isa/pnp.c */ static char * pnp_eisaformat(uint32_t id) { uint8_t *data; static char idbuf[8]; const char hextoascii[] = "0123456789abcdef"; id = htole32(id); data = (uint8_t *)&id; idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); idbuf[2] = '@' + (data[1] & 0x1f); idbuf[3] = hextoascii[(data[2] >> 4)]; idbuf[4] = hextoascii[(data[2] & 0xf)]; idbuf[5] = hextoascii[(data[3] >> 4)]; idbuf[6] = hextoascii[(data[3] & 0xf)]; idbuf[7] = 0; - return(idbuf); + return (idbuf); } struct pnp_elt { int pe_kind; /* What kind of entry */ #define TYPE_SZ_MASK 0x0f #define TYPE_FLAGGED 0x10 /* all f's is a wildcard */ #define TYPE_INT 0x20 /* Is a number */ #define TYPE_PAIRED 0x40 #define TYPE_LE 0x80 /* Matches <= this value */ #define TYPE_GE 0x100 /* Matches >= this value */ #define TYPE_MASK 0x200 /* Specifies a mask to follow */ #define TYPE_U8 (1 | TYPE_INT) #define TYPE_V8 (1 | TYPE_INT | TYPE_FLAGGED) #define TYPE_G16 (2 | TYPE_INT | TYPE_GE) #define TYPE_L16 (2 | TYPE_INT | TYPE_LE) #define TYPE_M16 (2 | TYPE_INT | TYPE_MASK) #define TYPE_U16 (2 | TYPE_INT) #define TYPE_V16 (2 | TYPE_INT | TYPE_FLAGGED) #define TYPE_U32 (4 | TYPE_INT) #define TYPE_V32 (4 | TYPE_INT | TYPE_FLAGGED) #define TYPE_W32 (4 | TYPE_INT | TYPE_PAIRED) #define TYPE_D 7 #define TYPE_Z 8 #define TYPE_P 9 #define TYPE_E 10 #define TYPE_T 11 int pe_offset; /* Offset within the element */ char * pe_key; /* pnp key name */ TAILQ_ENTRY(pnp_elt) next; /* Link */ }; typedef TAILQ_HEAD(pnp_head, pnp_elt) pnp_list; /* * this function finds the data from the pnp table, as described by the * the description and creates a new output (new_desc). This output table * is a form that's easier for the agent that's automatically loading the * modules. * * The format output is the simplified string from this routine in the * same basic format as the pnp string, as documented in sys/module.h. * First a string describing the format is output, the a count of the * number of records, then each record. The format string also describes * the length of each entry (though it isn't a fixed length when strings * are present). * * type Output Meaning * I uint32_t Integer equality comparison * J uint32_t Pair of uint16_t fields converted to native byte order. The two fields both must match. * G uint32_t Greater than or equal to * L uint32_t Less than or equal to * M uint32_t Mask of which fields to test. Fields that take up space increment the count. This field must be first, and resets the count. * D string Description of the device this pnp info is for * Z string pnp string must match this * T nothing T fields set pnp values that must be true for * the entire table. * Values are packed the same way that other values are packed in this file. * Strings and int32_t's start on a 32-bit boundary and are padded with 0 * bytes. Objects that are smaller than uint32_t are converted, without * sign extension to uint32_t to simplify parsing downstream. */ static int parse_pnp_list(const char *desc, char **new_desc, pnp_list *list) { - const char *walker = desc, *ep = desc + strlen(desc); + const char *walker, *ep; const char *colon, *semi; struct pnp_elt *elt; char *nd; char type[8], key[32]; int off; + walker = desc; + ep = desc + strlen(desc); off = 0; nd = *new_desc = malloc(strlen(desc) + 1); if (verbose > 1) printf("Converting %s into a list\n", desc); while (walker < ep) { colon = strchr(walker, ':'); semi = strchr(walker, ';'); if (semi != NULL && semi < colon) goto err; if (colon - walker > sizeof(type)) goto err; strncpy(type, walker, colon - walker); type[colon - walker] = '\0'; - if (semi) { + if (semi != NULL) { if (semi - colon >= sizeof(key)) goto err; strncpy(key, colon + 1, semi - colon - 1); key[semi - colon - 1] = '\0'; walker = semi + 1; } else { if (strlen(colon + 1) >= sizeof(key)) goto err; strcpy(key, colon + 1); walker = ep; } if (verbose > 1) printf("Found type %s for name %s\n", type, key); /* Skip pointer place holders */ if (strcmp(type, "P") == 0) { off += sizeof(void *); continue; } /* * Add a node of the appropriate type */ elt = malloc(sizeof(struct pnp_elt) + strlen(key) + 1); TAILQ_INSERT_TAIL(list, elt, next); elt->pe_key = (char *)(elt + 1); elt->pe_offset = off; if (strcmp(type, "U8") == 0) elt->pe_kind = TYPE_U8; else if (strcmp(type, "V8") == 0) elt->pe_kind = TYPE_V8; else if (strcmp(type, "G16") == 0) elt->pe_kind = TYPE_G16; else if (strcmp(type, "L16") == 0) elt->pe_kind = TYPE_L16; else if (strcmp(type, "M16") == 0) elt->pe_kind = TYPE_M16; else if (strcmp(type, "U16") == 0) elt->pe_kind = TYPE_U16; else if (strcmp(type, "V16") == 0) elt->pe_kind = TYPE_V16; else if (strcmp(type, "U32") == 0) elt->pe_kind = TYPE_U32; else if (strcmp(type, "V32") == 0) elt->pe_kind = TYPE_V32; else if (strcmp(type, "W32") == 0) elt->pe_kind = TYPE_W32; else if (strcmp(type, "D") == 0) /* description char * */ elt->pe_kind = TYPE_D; else if (strcmp(type, "Z") == 0) /* char * to match */ elt->pe_kind = TYPE_Z; else if (strcmp(type, "P") == 0) /* Pointer -- ignored */ elt->pe_kind = TYPE_P; else if (strcmp(type, "E") == 0) /* EISA PNP ID, as uint32_t */ elt->pe_kind = TYPE_E; else if (strcmp(type, "T") == 0) elt->pe_kind = TYPE_T; else goto err; /* * Maybe the rounding here needs to be more nuanced and/or somehow * architecture specific. Fortunately, most tables in the system * have sane ordering of types. */ if (elt->pe_kind & TYPE_INT) { elt->pe_offset = roundup2(elt->pe_offset, elt->pe_kind & TYPE_SZ_MASK); off = elt->pe_offset + (elt->pe_kind & TYPE_SZ_MASK); } else if (elt->pe_kind == TYPE_E) { /* Type E stored as Int, displays as string */ elt->pe_offset = roundup2(elt->pe_offset, sizeof(uint32_t)); off = elt->pe_offset + sizeof(uint32_t); } else if (elt->pe_kind == TYPE_T) { /* doesn't actually consume space in the table */ off = elt->pe_offset; } else { elt->pe_offset = roundup2(elt->pe_offset, sizeof(void *)); off = elt->pe_offset + sizeof(void *); } if (elt->pe_kind & TYPE_PAIRED) { char *word, *ctx; for (word = strtok_r(key, "/", &ctx); word; word = strtok_r(NULL, "/", &ctx)) { sprintf(nd, "%c:%s;", elt->pe_kind & TYPE_FLAGGED ? 'J' : 'I', word); nd += strlen(nd); } } else { if (elt->pe_kind & TYPE_FLAGGED) *nd++ = 'J'; else if (elt->pe_kind & TYPE_GE) *nd++ = 'G'; else if (elt->pe_kind & TYPE_LE) *nd++ = 'L'; else if (elt->pe_kind & TYPE_MASK) *nd++ = 'M'; else if (elt->pe_kind & TYPE_INT) *nd++ = 'I'; else if (elt->pe_kind == TYPE_D) *nd++ = 'D'; else if (elt->pe_kind == TYPE_Z || elt->pe_kind == TYPE_E) *nd++ = 'Z'; else if (elt->pe_kind == TYPE_T) *nd++ = 'T'; else errx(1, "Impossible type %x\n", elt->pe_kind); *nd++ = ':'; strcpy(nd, key); nd += strlen(nd); *nd++ = ';'; } } *nd++ = '\0'; - return 0; + return (0); err: errx(1, "Parse error of description string %s", desc); } static int parse_entry(struct mod_metadata *md, const char *cval, struct elf_file *ef, const char *kldname) { struct mod_depend mdp; struct mod_version mdv; struct mod_pnp_match_info pnp; char descr[1024]; - Elf_Off data = (Elf_Off)md->md_data; - int error = 0, i, len; + Elf_Off data; + int error, i; + size_t len; char *walker; void *table; + data = (Elf_Off)md->md_data; + error = 0; record_start(); switch (md->md_type) { case MDT_DEPEND: if (!dflag) break; check(EF_SEG_READ(ef, data, sizeof(mdp), &mdp)); printf(" depends on %s.%d (%d,%d)\n", cval, mdp.md_ver_preferred, mdp.md_ver_minimum, mdp.md_ver_maximum); break; case MDT_VERSION: check(EF_SEG_READ(ef, data, sizeof(mdv), &mdv)); if (dflag) { printf(" interface %s.%d\n", cval, mdv.mv_version); } else { record_int(MDT_VERSION); record_string(cval); record_int(mdv.mv_version); record_string(kldname); } break; case MDT_MODULE: if (dflag) { printf(" module %s\n", cval); } else { record_int(MDT_MODULE); record_string(cval); record_string(kldname); } break; case MDT_PNP_INFO: check(EF_SEG_READ_REL(ef, data, sizeof(pnp), &pnp)); check(EF_SEG_READ(ef, (Elf_Off)pnp.descr, sizeof(descr), descr)); descr[sizeof(descr) - 1] = '\0'; if (dflag) { printf(" pnp info for bus %s format %s %d entries of %d bytes\n", cval, descr, pnp.num_entry, pnp.entry_len); } else { pnp_list list; struct pnp_elt *elt, *elt_tmp; char *new_descr; if (verbose > 1) printf(" pnp info for bus %s format %s %d entries of %d bytes\n", cval, descr, pnp.num_entry, pnp.entry_len); /* * Parse descr to weed out the chaff and to create a list * of offsets to output. */ TAILQ_INIT(&list); parse_pnp_list(descr, &new_descr, &list); record_int(MDT_PNP_INFO); record_string(cval); record_string(new_descr); record_int(pnp.num_entry); len = pnp.num_entry * pnp.entry_len; walker = table = malloc(len); check(EF_SEG_READ_REL(ef, (Elf_Off)pnp.table, len, table)); /* * Walk the list and output things. We've collapsed all the * variant forms of the table down to just ints and strings. */ for (i = 0; i < pnp.num_entry; i++) { TAILQ_FOREACH(elt, &list, next) { uint8_t v1; uint16_t v2; uint32_t v4; int value; char buffer[1024]; if (elt->pe_kind == TYPE_W32) { memcpy(&v4, walker + elt->pe_offset, sizeof(v4)); value = v4 & 0xffff; record_int(value); if (verbose > 1) printf("W32:%#x", value); value = (v4 >> 16) & 0xffff; record_int(value); if (verbose > 1) printf(":%#x;", value); } else if (elt->pe_kind & TYPE_INT) { switch (elt->pe_kind & TYPE_SZ_MASK) { case 1: memcpy(&v1, walker + elt->pe_offset, sizeof(v1)); if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff) value = -1; else value = v1; break; case 2: memcpy(&v2, walker + elt->pe_offset, sizeof(v2)); if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff) value = -1; else value = v2; break; case 4: memcpy(&v4, walker + elt->pe_offset, sizeof(v4)); if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff) value = -1; else value = v4; break; default: errx(1, "Invalid size somehow %#x", elt->pe_kind); } if (verbose > 1) printf("I:%#x;", value); record_int(value); } else if (elt->pe_kind == TYPE_T) { /* Do nothing */ } else { /* E, Z or D -- P already filtered */ if (elt->pe_kind == TYPE_E) { memcpy(&v4, walker + elt->pe_offset, sizeof(v4)); strcpy(buffer, pnp_eisaformat(v4)); } else { char *ptr; ptr = *(char **)(walker + elt->pe_offset); buffer[0] = '\0'; if (ptr != NULL) { EF_SEG_READ(ef, (Elf_Off)ptr, sizeof(buffer), buffer); buffer[sizeof(buffer) - 1] = '\0'; } } if (verbose > 1) printf("%c:%s;", elt->pe_kind == TYPE_E ? 'E' : (elt->pe_kind == TYPE_Z ? 'Z' : 'D'), buffer); record_string(buffer); } } if (verbose > 1) printf("\n"); walker += pnp.entry_len; } /* Now free it */ TAILQ_FOREACH_SAFE(elt, &list, next, elt_tmp) { TAILQ_REMOVE(&list, elt, next); free(elt); } free(table); } break; default: warnx("unknown metadata record %d in file %s", md->md_type, kldname); } if (!error) record_end(); - return error; + return (error); } static int read_kld(char *filename, char *kldname) { struct mod_metadata md; struct elf_file ef; void **p, **orgp; - int error, eftype, nmlen; + int error, eftype; long start, finish, entries; - char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp; + char cval[MAXMODNAME + 1]; if (verbose || dflag) printf("%s\n", filename); error = ef_open(filename, &ef, verbose); - if (error) { + if (error != 0) { error = ef_obj_open(filename, &ef, verbose); - if (error) { + if (error != 0) { if (verbose) warnc(error, "elf_open(%s)", filename); - return error; + return (error); } } eftype = EF_GET_TYPE(&ef); if (eftype != EFT_KLD && eftype != EFT_KERNEL) { EF_CLOSE(&ef); - return 0; + return (0); } - if (!dflag) { - cp = strrchr(kldname, '.'); - nmlen = (cp != NULL) ? cp - kldname : (int)strlen(kldname); - if (nmlen > MAXMODNAME) - nmlen = MAXMODNAME; - strlcpy(kldmodname, kldname, nmlen); -/* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/ - } do { check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish, &entries)); check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries, (void *)&p)); orgp = p; while(entries--) { check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md), &md)); p++; check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); parse_entry(&md, cval, &ef, kldname); } - if (error) + if (error != 0) warnc(error, "error while reading %s", filename); free(orgp); } while(0); EF_CLOSE(&ef); - return error; + return (error); } /* * Create a temp file in directory root, make sure we don't * overflow the buffer for the destination name */ static FILE * maketempfile(char *dest, const char *root) { char *p; int n, fd; p = strrchr(root, '/'); n = p != NULL ? p - root + 1 : 0; if (snprintf(dest, MAXPATHLEN, "%.*slhint.XXXXXX", n, root) >= MAXPATHLEN) { errno = ENAMETOOLONG; - return NULL; + return (NULL); } fd = mkstemp(dest); if (fd < 0) - return NULL; + return (NULL); fchmod(fd, 0644); /* nothing secret in the file */ - return fdopen(fd, "w+"); + return (fdopen(fd, "w+")); } static char xrefname[MAXPATHLEN], tempname[MAXPATHLEN]; static void usage(void) { fprintf(stderr, "%s\n", "usage: kldxref [-Rdv] [-f hintsfile] path ..." ); exit(1); } static int compare(const FTSENT *const *a, const FTSENT *const *b) { + if ((*a)->fts_info == FTS_D && (*b)->fts_info != FTS_D) - return 1; + return (1); if ((*a)->fts_info != FTS_D && (*b)->fts_info == FTS_D) - return -1; - return strcmp((*a)->fts_name, (*b)->fts_name); + return (-1); + return (strcmp((*a)->fts_name, (*b)->fts_name)); } int main(int argc, char *argv[]) { FTS *ftsp; FTSENT *p; int opt, fts_options, ival; struct stat sb; fts_options = FTS_PHYSICAL; while ((opt = getopt(argc, argv, "Rdf:v")) != -1) { switch (opt) { case 'd': /* no hint file, only print on stdout */ - dflag = 1; + dflag = true; break; case 'f': /* use this name instead of linker.hints */ xref_file = optarg; break; case 'v': verbose++; break; case 'R': /* recurse on directories */ fts_options |= FTS_COMFOLLOW; break; default: usage(); /* NOTREACHED */ } } if (argc - optind < 1) usage(); argc -= optind; argv += optind; if (stat(argv[0], &sb) != 0) err(1, "%s", argv[0]); if ((sb.st_mode & S_IFDIR) == 0) { errno = ENOTDIR; err(1, "%s", argv[0]); } ftsp = fts_open(argv, fts_options, compare); if (ftsp == NULL) exit(1); for (;;) { p = fts_read(ftsp); if ((p == NULL || p->fts_info == FTS_D) && fxref) { /* close and rename the current hint file */ fclose(fxref); fxref = NULL; - if (reccnt) { + if (reccnt != 0) { rename(tempname, xrefname); } else { /* didn't find any entry, ignore this file */ unlink(tempname); unlink(xrefname); } } if (p == NULL) break; if (p->fts_info == FTS_D && !dflag) { /* visiting a new directory, create a new hint file */ snprintf(xrefname, sizeof(xrefname), "%s/%s", ftsp->fts_path, xref_file); fxref = maketempfile(tempname, ftsp->fts_path); if (fxref == NULL) err(1, "can't create %s", tempname); ival = 1; fwrite(&ival, sizeof(ival), 1, fxref); reccnt = 0; } /* skip non-files and separate debug files */ if (p->fts_info != FTS_F) continue; if (p->fts_namelen >= 6 && strcmp(p->fts_name + p->fts_namelen - 6, ".debug") == 0) continue; if (p->fts_namelen >= 8 && strcmp(p->fts_name + p->fts_namelen - 8, ".symbols") == 0) continue; read_kld(p->fts_path, p->fts_name); } fts_close(ftsp); - return 0; + return (0); }