/* $OpenBSD: ksyms.c,v 1.26 2014/12/22 02:55:48 deraadt Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * Copyright (c) 2001 Artur Grabowski * 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 ``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 AUTHORS 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. */ #include #include #include #include #include #include #include #include #ifdef _NLIST_DO_ELF #include #endif extern char *esym; /* end of symbol table */ #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) extern char *ssym; /* end of kernel */ #else extern long end; /* end of kernel */ #endif static caddr_t ksym_head; static caddr_t ksym_syms; static size_t ksym_head_size; static size_t ksym_syms_size; void ksymsattach(int); /* * We assume __LDPGSZ is a multiple of PAGE_SIZE (it is) */ /*ARGSUSED*/ void ksymsattach(int num) { #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) if (esym <= ssym) { printf("/dev/ksyms: Symbol table not valid.\n"); return; } #else if (esym <= (char *)&end) { printf("/dev/ksyms: Symbol table not valid.\n"); return; } #endif #ifdef _NLIST_DO_ELF do { #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) caddr_t symtab = ssym; #else caddr_t symtab = (caddr_t)&end; #endif Elf_Ehdr *elf; Elf_Shdr *shdr; int i; elf = (Elf_Ehdr *)symtab; if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || elf->e_ident[EI_CLASS] != ELFCLASS || elf->e_machine != ELF_TARG_MACH) break; shdr = (Elf_Shdr *)&symtab[elf->e_shoff]; for (i = 0; i < elf->e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { break; } } /* * No symbol table found. */ if (i == elf->e_shnum) break; /* * No additional header. */ ksym_head_size = 0; ksym_syms = symtab; ksym_syms_size = (size_t)(esym - symtab); return; } while (0); #endif } /*ARGSUSED*/ int ksymsopen(dev_t dev, int flag, int mode, struct proc *p) { /* There are no non-zero minor devices */ if (minor(dev) != 0) return (ENXIO); /* This device is read-only */ if ((flag & FWRITE)) return (EPERM); /* ksym_syms must be initialized */ if (ksym_syms == NULL) return (ENXIO); return (0); } /*ARGSUSED*/ int ksymsclose(dev_t dev, int flag, int mode, struct proc *p) { return (0); } /*ARGSUSED*/ int ksymsread(dev_t dev, struct uio *uio, int flags) { int error; size_t len; caddr_t v; size_t off; if (uio->uio_offset < 0) return (EINVAL); while (uio->uio_resid > 0) { if (uio->uio_offset >= ksym_head_size + ksym_syms_size) break; if (uio->uio_offset < ksym_head_size) { v = ksym_head + uio->uio_offset; len = ksym_head_size - uio->uio_offset; } else { off = uio->uio_offset - ksym_head_size; v = ksym_syms + off; len = ksym_syms_size - off; } if (len > uio->uio_resid) len = uio->uio_resid; if ((error = uiomove(v, len, uio)) != 0) return (error); } return (0); }