1 /* $OpenBSD: ksyms.c,v 1.28 2015/03/14 03:38:46 jsg Exp $ */ 2 /* 3 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> 4 * Copyright (c) 2001 Artur Grabowski <art@openbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 * THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/exec.h> 30 #include <sys/systm.h> 31 #include <sys/uio.h> 32 #include <sys/malloc.h> 33 #include <sys/fcntl.h> 34 #include <sys/conf.h> 35 36 #ifdef _NLIST_DO_ELF 37 #include <sys/exec_elf.h> 38 #endif 39 40 extern char *esym; /* end of symbol table */ 41 #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) 42 extern char *ssym; /* end of kernel */ 43 #else 44 extern long end; /* end of kernel */ 45 #endif 46 47 static caddr_t ksym_head; 48 static caddr_t ksym_syms; 49 static size_t ksym_head_size; 50 static size_t ksym_syms_size; 51 52 void ksymsattach(int); 53 54 /* 55 * We assume __LDPGSZ is a multiple of PAGE_SIZE (it is) 56 */ 57 58 /*ARGSUSED*/ 59 void 60 ksymsattach(int num) 61 { 62 63 #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) 64 if (esym <= ssym) { 65 printf("/dev/ksyms: Symbol table not valid.\n"); 66 return; 67 } 68 #else 69 if (esym <= (char *)&end) { 70 printf("/dev/ksyms: Symbol table not valid.\n"); 71 return; 72 } 73 #endif 74 75 #ifdef _NLIST_DO_ELF 76 do { 77 #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) 78 caddr_t symtab = ssym; 79 #else 80 caddr_t symtab = (caddr_t)&end; 81 #endif 82 Elf_Ehdr *elf; 83 Elf_Shdr *shdr; 84 int i; 85 86 elf = (Elf_Ehdr *)symtab; 87 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 88 elf->e_ident[EI_CLASS] != ELFCLASS || 89 elf->e_machine != ELF_TARG_MACH) 90 break; 91 92 shdr = (Elf_Shdr *)&symtab[elf->e_shoff]; 93 for (i = 0; i < elf->e_shnum; i++) { 94 if (shdr[i].sh_type == SHT_SYMTAB) { 95 break; 96 } 97 } 98 99 /* 100 * No symbol table found. 101 */ 102 if (i == elf->e_shnum) 103 break; 104 105 /* 106 * No additional header. 107 */ 108 ksym_head_size = 0; 109 ksym_syms = symtab; 110 ksym_syms_size = (size_t)(esym - symtab); 111 112 return; 113 } while (0); 114 #endif 115 } 116 117 /*ARGSUSED*/ 118 int 119 ksymsopen(dev_t dev, int flag, int mode, struct proc *p) 120 { 121 122 /* There are no non-zero minor devices */ 123 if (minor(dev) != 0) 124 return (ENXIO); 125 126 /* This device is read-only */ 127 if ((flag & FWRITE)) 128 return (EPERM); 129 130 /* ksym_syms must be initialized */ 131 if (ksym_syms == NULL) 132 return (ENXIO); 133 134 return (0); 135 } 136 137 /*ARGSUSED*/ 138 int 139 ksymsclose(dev_t dev, int flag, int mode, struct proc *p) 140 { 141 142 return (0); 143 } 144 145 /*ARGSUSED*/ 146 int 147 ksymsread(dev_t dev, struct uio *uio, int flags) 148 { 149 int error; 150 size_t len; 151 caddr_t v; 152 size_t off; 153 154 if (uio->uio_offset < 0) 155 return (EINVAL); 156 157 while (uio->uio_resid > 0) { 158 if (uio->uio_offset >= ksym_head_size + ksym_syms_size) 159 break; 160 161 if (uio->uio_offset < ksym_head_size) { 162 v = ksym_head + uio->uio_offset; 163 len = ksym_head_size - uio->uio_offset; 164 } else { 165 off = uio->uio_offset - ksym_head_size; 166 v = ksym_syms + off; 167 len = ksym_syms_size - off; 168 } 169 170 if (len > uio->uio_resid) 171 len = uio->uio_resid; 172 173 if ((error = uiomovei(v, len, uio)) != 0) 174 return (error); 175 } 176 177 return (0); 178 } 179