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