xref: /openbsd/sys/dev/ksyms.c (revision 97c974cd)
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