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