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