xref: /openbsd-src/sys/dev/ksyms.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: ksyms.c,v 1.25 2014/07/08 17:19:25 deraadt 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 extern char *esym;				/* end of symbol table */
42 #if defined(__sparc64__) || defined(__mips__)
43 extern char *ssym;				/* end of kernel */
44 #else
45 extern long end;				/* end of kernel */
46 #endif
47 
48 static caddr_t ksym_head;
49 static caddr_t ksym_syms;
50 static size_t ksym_head_size;
51 static size_t ksym_syms_size;
52 
53 void	ksymsattach(int);
54 
55 /*
56  * We assume __LDPGSZ is a multiple of PAGE_SIZE (it is)
57  */
58 
59 /*ARGSUSED*/
60 void
61 ksymsattach(int num)
62 {
63 
64 #if defined(__sparc64__) || defined(__mips__)
65 	if (esym <= ssym) {
66 		printf("/dev/ksyms: Symbol table not valid.\n");
67 		return;
68 	}
69 #else
70 	if (esym <= (char *)&end) {
71 		printf("/dev/ksyms: Symbol table not valid.\n");
72 		return;
73 	}
74 #endif
75 
76 #ifdef _NLIST_DO_ELF
77 	do {
78 #if defined(__sparc64__) || defined(__mips__)
79 		caddr_t symtab = ssym;
80 #else
81 		caddr_t symtab = (caddr_t)&end;
82 #endif
83 		Elf_Ehdr *elf;
84 		Elf_Shdr *shdr;
85 		int i;
86 
87 		elf = (Elf_Ehdr *)symtab;
88 		if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
89 		    elf->e_ident[EI_CLASS] != ELFCLASS ||
90 		    elf->e_machine != ELF_TARG_MACH)
91 			break;
92 
93 		shdr = (Elf_Shdr *)&symtab[elf->e_shoff];
94 		for (i = 0; i < elf->e_shnum; i++) {
95 			if (shdr[i].sh_type == SHT_SYMTAB) {
96 				break;
97 			}
98 		}
99 
100 		/*
101 		 * No symbol table found.
102 		 */
103 		if (i == elf->e_shnum)
104 			break;
105 
106 		/*
107 		 * No additional header.
108 		 */
109 		ksym_head_size = 0;
110 		ksym_syms = symtab;
111 		ksym_syms_size = (size_t)(esym - symtab);
112 
113 		return;
114 	} while (0);
115 #endif
116 }
117 
118 /*ARGSUSED*/
119 int
120 ksymsopen(dev_t dev, int flag, int mode, struct proc *p)
121 {
122 
123 	/* There are no non-zero minor devices */
124 	if (minor(dev) != 0)
125 		return (ENXIO);
126 
127 	/* This device is read-only */
128 	if ((flag & FWRITE))
129 		return (EPERM);
130 
131 	/* ksym_syms must be initialized */
132 	if (ksym_syms == NULL)
133 		return (ENXIO);
134 
135 	return (0);
136 }
137 
138 /*ARGSUSED*/
139 int
140 ksymsclose(dev_t dev, int flag, int mode, struct proc *p)
141 {
142 
143 	return (0);
144 }
145 
146 /*ARGSUSED*/
147 int
148 ksymsread(dev_t dev, struct uio *uio, int flags)
149 {
150 	int error;
151 	size_t len;
152 	caddr_t v;
153 	size_t off;
154 
155 	if (uio->uio_offset < 0)
156 		return (EINVAL);
157 
158 	while (uio->uio_resid > 0) {
159 		if (uio->uio_offset >= ksym_head_size + ksym_syms_size)
160 			break;
161 
162 		if (uio->uio_offset < ksym_head_size) {
163 			v = ksym_head + uio->uio_offset;
164 			len = ksym_head_size - uio->uio_offset;
165 		} else {
166 			off = uio->uio_offset - ksym_head_size;
167 			v = ksym_syms + off;
168 			len = ksym_syms_size - off;
169 		}
170 
171 		if (len > uio->uio_resid)
172 			len = uio->uio_resid;
173 
174 		if ((error = uiomove(v, len, uio)) != 0)
175 			return (error);
176 	}
177 
178 	return (0);
179 }
180