1 /* $OpenBSD: ksyms.c,v 1.20 2010/12/26 15:41:00 miod 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/buf.h> 30 #include <sys/exec.h> 31 #include <sys/systm.h> 32 #include <sys/uio.h> 33 #include <sys/malloc.h> 34 #include <sys/fcntl.h> 35 #include <sys/conf.h> 36 37 #include <uvm/uvm_extern.h> 38 39 #ifdef _NLIST_DO_ELF 40 #include <sys/exec_elf.h> 41 #endif 42 43 #include <machine/cpu.h> 44 45 extern char *esym; /* end of symbol table */ 46 #if defined(__sparc64__) || defined(__mips__) 47 extern char *ssym; /* end of kernel */ 48 #else 49 extern long end; /* end of kernel */ 50 #endif 51 52 static caddr_t ksym_head; 53 static caddr_t ksym_syms; 54 static size_t ksym_head_size; 55 static size_t ksym_syms_size; 56 57 void ksymsattach(int); 58 59 /* 60 * We assume __LDPGSZ is a multiple of PAGE_SIZE (it is) 61 */ 62 63 /*ARGSUSED*/ 64 void 65 ksymsattach(num) 66 int num; 67 { 68 69 #if defined(__sparc64__) || defined(__mips__) 70 if (esym <= ssym) { 71 printf("/dev/ksyms: Symbol table not valid.\n"); 72 return; 73 } 74 #else 75 if (esym <= (char *)&end) { 76 printf("/dev/ksyms: Symbol table not valid.\n"); 77 return; 78 } 79 #endif 80 81 #ifdef _NLIST_DO_ELF 82 do { 83 #if defined(__sparc64__) || defined(__mips__) 84 caddr_t symtab = ssym; 85 #else 86 caddr_t symtab = (caddr_t)&end; 87 #endif 88 Elf_Ehdr *elf; 89 Elf_Shdr *shdr; 90 int i; 91 92 elf = (Elf_Ehdr *)symtab; 93 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 94 elf->e_ident[EI_CLASS] != ELFCLASS || 95 elf->e_machine != ELF_TARG_MACH) 96 break; 97 98 shdr = (Elf_Shdr *)&symtab[elf->e_shoff]; 99 for (i = 0; i < elf->e_shnum; i++) { 100 if (shdr[i].sh_type == SHT_SYMTAB) { 101 break; 102 } 103 } 104 105 /* 106 * No symbol table found. 107 */ 108 if (i == elf->e_shnum) 109 break; 110 111 /* 112 * No additional header. 113 */ 114 ksym_head_size = 0; 115 ksym_syms = symtab; 116 ksym_syms_size = (size_t)(esym - symtab); 117 118 return; 119 } while (0); 120 #endif 121 122 #ifdef _NLIST_DO_AOUT 123 { 124 /* 125 * a.out header. 126 * Fake up a struct exec. 127 * We only fill in the following non-zero entries: 128 * a_text - fake text segment (struct exec only) 129 * a_syms - size of symbol table 130 */ 131 caddr_t symtab = (char *)(&end + 1); 132 struct exec *k1; 133 134 ksym_head_size = __LDPGSZ; 135 ksym_head = malloc(ksym_head_size, M_DEVBUF, M_NOWAIT | M_ZERO); 136 if (ksym_head == NULL) { 137 printf("failed to allocate memory for /dev/ksyms\n"); 138 return; 139 } 140 141 k1 = (struct exec *)ksym_head; 142 143 N_SETMAGIC(*k1, ZMAGIC, MID_MACHINE, 0); 144 k1->a_text = __LDPGSZ; 145 k1->a_syms = end; 146 147 ksym_syms = symtab; 148 ksym_syms_size = (size_t)(esym - symtab); 149 } 150 #endif 151 } 152 153 /*ARGSUSED*/ 154 int 155 ksymsopen(dev, flag, mode, p) 156 dev_t dev; 157 int flag, mode; 158 struct proc *p; 159 { 160 161 /* There are no non-zero minor devices */ 162 if (minor(dev) != 0) 163 return (ENXIO); 164 165 /* This device is read-only */ 166 if ((flag & FWRITE)) 167 return (EPERM); 168 169 /* ksym_syms must be initialized */ 170 if (ksym_syms == NULL) 171 return (ENXIO); 172 173 return (0); 174 } 175 176 /*ARGSUSED*/ 177 int 178 ksymsclose(dev, flag, mode, p) 179 dev_t dev; 180 int flag, mode; 181 struct proc *p; 182 { 183 184 return (0); 185 } 186 187 /*ARGSUSED*/ 188 int 189 ksymsread(dev, uio, flags) 190 dev_t dev; 191 struct uio *uio; 192 int flags; 193 { 194 int error; 195 size_t len; 196 caddr_t v; 197 size_t off; 198 199 while (uio->uio_resid > 0) { 200 if (uio->uio_offset >= ksym_head_size + ksym_syms_size) 201 break; 202 203 if (uio->uio_offset < ksym_head_size) { 204 v = ksym_head + uio->uio_offset; 205 len = ksym_head_size - uio->uio_offset; 206 } else { 207 off = uio->uio_offset - ksym_head_size; 208 v = ksym_syms + off; 209 len = ksym_syms_size - off; 210 } 211 212 if (len > uio->uio_resid) 213 len = uio->uio_resid; 214 215 if ((error = uiomove(v, len, uio)) != 0) 216 return (error); 217 } 218 219 return (0); 220 } 221 222 /* XXX - not yet */ 223 #if 0 224 paddr_t 225 ksymsmmap(dev, off, prot) 226 dev_t dev; 227 off_t off; 228 int prot; 229 { 230 vaddr_t va; 231 paddr_t pa; 232 233 if (off < 0) 234 return (-1); 235 if (off >= ksym_head_size + ksym_syms_size) 236 return (-1); 237 238 if ((vaddr_t)off < ksym_head_size) { 239 va = (vaddr_t)ksym_head + off; 240 } else { 241 va = (vaddr_t)ksym_syms + off; 242 } 243 244 if (pmap_extract(pmap_kernel, va, &pa) == FALSE) 245 panic("ksymsmmap: unmapped page"); 246 247 return (pa); 248 } 249 #endif 250