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