1 /* $OpenBSD: ksyms.c,v 1.12 2002/03/14 01:26:52 millert 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 * 3. The name of the authors may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/buf.h> 32 #include <sys/exec.h> 33 #include <sys/systm.h> 34 #include <sys/uio.h> 35 #include <sys/malloc.h> 36 #include <sys/fcntl.h> 37 38 #ifdef _NLIST_DO_ELF 39 #include <sys/exec_elf.h> 40 #endif 41 42 #include <machine/cpu.h> 43 44 #include <uvm/uvm_extern.h> 45 46 extern char *esym; /* end of symbol table */ 47 #ifdef __sparc64__ 48 extern char *ssym; /* end of kernel */ 49 #else 50 extern long end; /* end of kernel */ 51 #endif 52 53 static caddr_t ksym_head; 54 static caddr_t ksym_syms; 55 static size_t ksym_head_size; 56 static size_t ksym_syms_size; 57 58 void ksymsattach(int); 59 int ksymsopen(dev_t, int, int); 60 int ksymsclose(dev_t, int, int); 61 int ksymsread(dev_t, struct uio *, int); 62 63 /* 64 * We assume __LDPGSZ is a multiple of PAGE_SIZE (it is) 65 */ 66 67 /*ARGSUSED*/ 68 void 69 ksymsattach(num) 70 int num; 71 { 72 73 #ifdef __sparc64__ 74 if (esym <= ssym) { 75 printf("/dev/ksyms: Symbol table not valid.\n"); 76 return; 77 } 78 #else 79 if (esym <= (char *)&end) { 80 printf("/dev/ksyms: Symbol table not valid.\n"); 81 return; 82 } 83 #endif 84 85 #ifdef _NLIST_DO_ELF 86 do { 87 #ifdef __sparc64__ 88 caddr_t symtab = ssym; 89 #else 90 caddr_t symtab = (caddr_t)&end; 91 #endif 92 Elf_Ehdr *elf; 93 Elf_Shdr *shdr; 94 int i; 95 96 elf = (Elf_Ehdr *)symtab; 97 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 98 elf->e_ident[EI_CLASS] != ELFCLASS || 99 elf->e_machine != ELF_TARG_MACH) 100 break; 101 102 shdr = (Elf_Shdr *)&symtab[elf->e_shoff]; 103 for (i = 0; i < elf->e_shnum; i++) { 104 if (shdr[i].sh_type == SHT_SYMTAB) { 105 break; 106 } 107 } 108 109 /* 110 * No symbol table found. 111 */ 112 if (i == elf->e_shnum) 113 break; 114 115 /* 116 * No additional header. 117 */ 118 ksym_head_size = 0; 119 ksym_syms = symtab; 120 ksym_syms_size = (size_t)(esym - symtab); 121 122 return; 123 } while (0); 124 #endif 125 126 #ifdef _NLIST_DO_AOUT 127 { 128 /* 129 * a.out header. 130 * Fake up a struct exec. 131 * We only fill in the following non-zero entries: 132 * a_text - fake text segment (struct exec only) 133 * a_syms - size of symbol table 134 */ 135 caddr_t symtab = (char *)(&end + 1); 136 struct exec *k1; 137 138 ksym_head_size = __LDPGSZ; 139 ksym_head = malloc(ksym_head_size, M_DEVBUF, M_NOWAIT); 140 if (ksym_head == NULL) { 141 printf("failed to allocate memory for /dev/ksyms\n"); 142 return; 143 } 144 bzero(ksym_head, ksym_head_size); 145 146 k1 = (struct exec *)ksym_head; 147 148 N_SETMAGIC(*k1, ZMAGIC, MID_MACHINE, 0); 149 k1->a_text = __LDPGSZ; 150 k1->a_syms = end; 151 152 ksym_syms = symtab; 153 ksym_syms_size = (size_t)(esym - symtab); 154 } 155 #endif 156 } 157 158 /*ARGSUSED*/ 159 int 160 ksymsopen(dev, flag, mode) 161 dev_t dev; 162 int flag, mode; 163 { 164 165 /* There are no non-zero minor devices */ 166 if (minor(dev) != 0) 167 return (ENXIO); 168 169 /* This device is read-only */ 170 if ((flag & FWRITE)) 171 return (EPERM); 172 173 /* ksym_syms must be initialized */ 174 if (ksym_syms == NULL) 175 return (ENXIO); 176 177 return (0); 178 } 179 180 /*ARGSUSED*/ 181 int 182 ksymsclose(dev, flag, mode) 183 dev_t dev; 184 int flag, mode; 185 { 186 187 return (0); 188 } 189 190 /*ARGSUSED*/ 191 int 192 ksymsread(dev, uio, flags) 193 dev_t dev; 194 struct uio *uio; 195 int flags; 196 { 197 int error; 198 size_t len; 199 caddr_t v; 200 size_t off; 201 202 while (uio->uio_resid > 0) { 203 if (uio->uio_offset >= ksym_head_size + ksym_syms_size) 204 break; 205 206 if (uio->uio_offset < ksym_head_size) { 207 v = ksym_head + uio->uio_offset; 208 len = ksym_head_size - uio->uio_offset; 209 } else { 210 off = uio->uio_offset - ksym_head_size; 211 v = ksym_syms + off; 212 len = ksym_syms_size - off; 213 } 214 215 if (len > uio->uio_resid) 216 len = uio->uio_resid; 217 218 if ((error = uiomove(v, len, uio)) != 0) 219 return (error); 220 } 221 222 return (0); 223 } 224 225 /* XXX - not yet */ 226 #if 0 227 paddr_t 228 ksymsmmap(dev, off, prot) 229 dev_t dev; 230 off_t off; 231 int prot; 232 { 233 vaddr_t va; 234 paddr_t pa; 235 236 if (off < 0) 237 return (-1); 238 if (off >= ksym_head_size + ksym_syms_size) 239 return (-1); 240 241 if ((vaddr_t)off < ksym_head_size) { 242 va = (vaddr_t)ksym_head + off; 243 } else { 244 va = (vaddr_t)ksym_syms + off; 245 } 246 247 if (pmap_extract(pmap_kernel, va, &pa) == FALSE) 248 panic("ksymsmmap: unmapped page"); 249 250 return atop(pa); 251 } 252 #endif 253