| @@ -1,935 +1,935 @@ | | | @@ -1,935 +1,935 @@ |
1 | /* $NetBSD: kern_ksyms.c,v 1.48 2008/12/05 21:38:10 ad Exp $ */ | | 1 | /* $NetBSD: kern_ksyms.c,v 1.49 2009/01/01 19:10:17 pooka Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software developed for The NetBSD Foundation | | 7 | * This code is derived from software developed for The NetBSD Foundation |
8 | * by Andrew Doran. | | 8 | * by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se). | | 33 | * Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se). |
34 | * All rights reserved. | | 34 | * All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. The name of the author may not be used to endorse or promote products | | 44 | * 3. The name of the author may not be used to endorse or promote products |
45 | * derived from this software without specific prior written permission | | 45 | * derived from this software without specific prior written permission |
46 | * | | 46 | * |
47 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 47 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
48 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 48 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
49 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 49 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
50 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 50 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
51 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 51 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
52 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 52 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
53 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 53 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
54 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 54 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
55 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 55 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
57 | */ | | 57 | */ |
58 | | | 58 | |
59 | /* | | 59 | /* |
60 | * Code to deal with in-kernel symbol table management + /dev/ksyms. | | 60 | * Code to deal with in-kernel symbol table management + /dev/ksyms. |
61 | * | | 61 | * |
62 | * For each loaded module the symbol table info is kept track of by a | | 62 | * For each loaded module the symbol table info is kept track of by a |
63 | * struct, placed in a circular list. The first entry is the kernel | | 63 | * struct, placed in a circular list. The first entry is the kernel |
64 | * symbol table. | | 64 | * symbol table. |
65 | */ | | 65 | */ |
66 | | | 66 | |
67 | /* | | 67 | /* |
68 | * TODO: | | 68 | * TODO: |
69 | * | | 69 | * |
70 | * Add support for mmap, poll. | | 70 | * Add support for mmap, poll. |
71 | */ | | 71 | */ |
72 | | | 72 | |
73 | #include <sys/cdefs.h> | | 73 | #include <sys/cdefs.h> |
74 | __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.48 2008/12/05 21:38:10 ad Exp $"); | | 74 | __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.49 2009/01/01 19:10:17 pooka Exp $"); |
75 | | | 75 | |
76 | #ifdef _KERNEL | | 76 | #if defined(_KERNEL) && defined(_KERNEL_OPT) |
77 | #include "opt_ddb.h" | | 77 | #include "opt_ddb.h" |
78 | #include "opt_ddbparam.h" /* for SYMTAB_SPACE */ | | 78 | #include "opt_ddbparam.h" /* for SYMTAB_SPACE */ |
79 | #endif | | 79 | #endif |
80 | | | 80 | |
81 | #define _KSYMS_PRIVATE | | 81 | #define _KSYMS_PRIVATE |
82 | | | 82 | |
83 | #include <sys/param.h> | | 83 | #include <sys/param.h> |
84 | #include <sys/queue.h> | | 84 | #include <sys/queue.h> |
85 | #include <sys/exec.h> | | 85 | #include <sys/exec.h> |
86 | #include <sys/systm.h> | | 86 | #include <sys/systm.h> |
87 | #include <sys/conf.h> | | 87 | #include <sys/conf.h> |
88 | #include <sys/kmem.h> | | 88 | #include <sys/kmem.h> |
89 | #include <sys/proc.h> | | 89 | #include <sys/proc.h> |
90 | #include <sys/atomic.h> | | 90 | #include <sys/atomic.h> |
91 | #include <sys/ksyms.h> | | 91 | #include <sys/ksyms.h> |
92 | | | 92 | |
93 | #include <uvm/uvm_extern.h> | | 93 | #include <uvm/uvm_extern.h> |
94 | | | 94 | |
95 | #ifdef DDB | | 95 | #ifdef DDB |
96 | #include <ddb/db_output.h> | | 96 | #include <ddb/db_output.h> |
97 | #endif | | 97 | #endif |
98 | | | 98 | |
99 | #include "ksyms.h" | | 99 | #include "ksyms.h" |
100 | | | 100 | |
101 | static int ksyms_maxlen; | | 101 | static int ksyms_maxlen; |
102 | static bool ksyms_isopen; | | 102 | static bool ksyms_isopen; |
103 | static bool ksyms_initted; | | 103 | static bool ksyms_initted; |
104 | static struct ksyms_hdr ksyms_hdr; | | 104 | static struct ksyms_hdr ksyms_hdr; |
105 | static kmutex_t ksyms_lock; | | 105 | static kmutex_t ksyms_lock; |
106 | | | 106 | |
107 | void ksymsattach(int); | | 107 | void ksymsattach(int); |
108 | static void ksyms_hdr_init(void *); | | 108 | static void ksyms_hdr_init(void *); |
109 | static void ksyms_sizes_calc(void); | | 109 | static void ksyms_sizes_calc(void); |
110 | | | 110 | |
111 | #ifdef KSYMS_DEBUG | | 111 | #ifdef KSYMS_DEBUG |
112 | #define FOLLOW_CALLS 1 | | 112 | #define FOLLOW_CALLS 1 |
113 | #define FOLLOW_MORE_CALLS 2 | | 113 | #define FOLLOW_MORE_CALLS 2 |
114 | #define FOLLOW_DEVKSYMS 4 | | 114 | #define FOLLOW_DEVKSYMS 4 |
115 | static int ksyms_debug; | | 115 | static int ksyms_debug; |
116 | #endif | | 116 | #endif |
117 | | | 117 | |
118 | #ifdef SYMTAB_SPACE | | 118 | #ifdef SYMTAB_SPACE |
119 | #define SYMTAB_FILLER "|This is the symbol table!" | | 119 | #define SYMTAB_FILLER "|This is the symbol table!" |
120 | | | 120 | |
121 | char db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER; | | 121 | char db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER; |
122 | int db_symtabsize = SYMTAB_SPACE; | | 122 | int db_symtabsize = SYMTAB_SPACE; |
123 | #endif | | 123 | #endif |
124 | | | 124 | |
125 | int ksyms_symsz; | | 125 | int ksyms_symsz; |
126 | int ksyms_strsz; | | 126 | int ksyms_strsz; |
127 | TAILQ_HEAD(, ksyms_symtab) ksyms_symtabs = | | 127 | TAILQ_HEAD(, ksyms_symtab) ksyms_symtabs = |
128 | TAILQ_HEAD_INITIALIZER(ksyms_symtabs); | | 128 | TAILQ_HEAD_INITIALIZER(ksyms_symtabs); |
129 | static struct ksyms_symtab kernel_symtab; | | 129 | static struct ksyms_symtab kernel_symtab; |
130 | | | 130 | |
131 | static int | | 131 | static int |
132 | ksyms_verify(void *symstart, void *strstart) | | 132 | ksyms_verify(void *symstart, void *strstart) |
133 | { | | 133 | { |
134 | #if defined(DIAGNOSTIC) || defined(DEBUG) | | 134 | #if defined(DIAGNOSTIC) || defined(DEBUG) |
135 | if (symstart == NULL) | | 135 | if (symstart == NULL) |
136 | printf("ksyms: Symbol table not found\n"); | | 136 | printf("ksyms: Symbol table not found\n"); |
137 | if (strstart == NULL) | | 137 | if (strstart == NULL) |
138 | printf("ksyms: String table not found\n"); | | 138 | printf("ksyms: String table not found\n"); |
139 | if (symstart == NULL || strstart == NULL) | | 139 | if (symstart == NULL || strstart == NULL) |
140 | printf("ksyms: Perhaps the kernel is stripped?\n"); | | 140 | printf("ksyms: Perhaps the kernel is stripped?\n"); |
141 | #endif | | 141 | #endif |
142 | if (symstart == NULL || strstart == NULL) | | 142 | if (symstart == NULL || strstart == NULL) |
143 | return 0; | | 143 | return 0; |
144 | KASSERT(symstart <= strstart); | | 144 | KASSERT(symstart <= strstart); |
145 | return 1; | | 145 | return 1; |
146 | } | | 146 | } |
147 | | | 147 | |
148 | /* | | 148 | /* |
149 | * Finds a certain symbol name in a certain symbol table. | | 149 | * Finds a certain symbol name in a certain symbol table. |
150 | */ | | 150 | */ |
151 | static Elf_Sym * | | 151 | static Elf_Sym * |
152 | findsym(const char *name, struct ksyms_symtab *table, int type) | | 152 | findsym(const char *name, struct ksyms_symtab *table, int type) |
153 | { | | 153 | { |
154 | Elf_Sym *sym, *maxsym; | | 154 | Elf_Sym *sym, *maxsym; |
155 | int low, mid, high, nglob; | | 155 | int low, mid, high, nglob; |
156 | char *str, *cmp; | | 156 | char *str, *cmp; |
157 | | | 157 | |
158 | sym = table->sd_symstart; | | 158 | sym = table->sd_symstart; |
159 | str = table->sd_strstart - table->sd_usroffset; | | 159 | str = table->sd_strstart - table->sd_usroffset; |
160 | nglob = table->sd_nglob; | | 160 | nglob = table->sd_nglob; |
161 | low = 0; | | 161 | low = 0; |
162 | high = nglob; | | 162 | high = nglob; |
163 | | | 163 | |
164 | /* | | 164 | /* |
165 | * Start with a binary search of all global symbols in this table. | | 165 | * Start with a binary search of all global symbols in this table. |
166 | * Global symbols must have unique names. | | 166 | * Global symbols must have unique names. |
167 | */ | | 167 | */ |
168 | while (low < high) { | | 168 | while (low < high) { |
169 | mid = (low + high) >> 1; | | 169 | mid = (low + high) >> 1; |
170 | cmp = sym[mid].st_name + str; | | 170 | cmp = sym[mid].st_name + str; |
171 | if (cmp[0] < name[0] || strcmp(cmp, name) < 0) { | | 171 | if (cmp[0] < name[0] || strcmp(cmp, name) < 0) { |
172 | low = mid + 1; | | 172 | low = mid + 1; |
173 | } else { | | 173 | } else { |
174 | high = mid; | | 174 | high = mid; |
175 | } | | 175 | } |
176 | } | | 176 | } |
177 | KASSERT(low == high); | | 177 | KASSERT(low == high); |
178 | if (__predict_true(low < nglob && | | 178 | if (__predict_true(low < nglob && |
179 | strcmp(sym[low].st_name + str, name) == 0)) { | | 179 | strcmp(sym[low].st_name + str, name) == 0)) { |
180 | KASSERT(ELF_ST_BIND(sym[low].st_info) == STB_GLOBAL); | | 180 | KASSERT(ELF_ST_BIND(sym[low].st_info) == STB_GLOBAL); |
181 | return &sym[low]; | | 181 | return &sym[low]; |
182 | } | | 182 | } |
183 | | | 183 | |
184 | /* | | 184 | /* |
185 | * Perform a linear search of local symbols (rare). Many local | | 185 | * Perform a linear search of local symbols (rare). Many local |
186 | * symbols with the same name can exist so are not included in | | 186 | * symbols with the same name can exist so are not included in |
187 | * the binary search. | | 187 | * the binary search. |
188 | */ | | 188 | */ |
189 | if (type != KSYMS_EXTERN) { | | 189 | if (type != KSYMS_EXTERN) { |
190 | maxsym = sym + table->sd_symsize / sizeof(Elf_Sym); | | 190 | maxsym = sym + table->sd_symsize / sizeof(Elf_Sym); |
191 | for (sym += nglob; sym < maxsym; sym++) { | | 191 | for (sym += nglob; sym < maxsym; sym++) { |
192 | if (strcmp(name, sym->st_name + str) == 0) { | | 192 | if (strcmp(name, sym->st_name + str) == 0) { |
193 | return sym; | | 193 | return sym; |
194 | } | | 194 | } |
195 | } | | 195 | } |
196 | } | | 196 | } |
197 | return NULL; | | 197 | return NULL; |
198 | } | | 198 | } |
199 | | | 199 | |
200 | /* | | 200 | /* |
201 | * The "attach" is in reality done in ksyms_init(). | | 201 | * The "attach" is in reality done in ksyms_init(). |
202 | */ | | 202 | */ |
203 | void | | 203 | void |
204 | ksymsattach(int arg) | | 204 | ksymsattach(int arg) |
205 | { | | 205 | { |
206 | | | 206 | |
207 | } | | 207 | } |
208 | | | 208 | |
209 | void | | 209 | void |
210 | ksyms_init() | | 210 | ksyms_init() |
211 | { | | 211 | { |
212 | | | 212 | |
213 | mutex_init(&ksyms_lock, MUTEX_DEFAULT, IPL_NONE); | | 213 | mutex_init(&ksyms_lock, MUTEX_DEFAULT, IPL_NONE); |
214 | } | | 214 | } |
215 | | | 215 | |
216 | /* | | 216 | /* |
217 | * Add a symbol table. | | 217 | * Add a symbol table. |
218 | * This is intended for use when the symbol table and its corresponding | | 218 | * This is intended for use when the symbol table and its corresponding |
219 | * string table are easily available. If they are embedded in an ELF | | 219 | * string table are easily available. If they are embedded in an ELF |
220 | * image, use addsymtab_elf() instead. | | 220 | * image, use addsymtab_elf() instead. |
221 | * | | 221 | * |
222 | * name - Symbol's table name. | | 222 | * name - Symbol's table name. |
223 | * symstart, symsize - Address and size of the symbol table. | | 223 | * symstart, symsize - Address and size of the symbol table. |
224 | * strstart, strsize - Address and size of the string table. | | 224 | * strstart, strsize - Address and size of the string table. |
225 | * tab - Symbol table to be updated with this information. | | 225 | * tab - Symbol table to be updated with this information. |
226 | * newstart - Address to which the symbol table has to be copied during | | 226 | * newstart - Address to which the symbol table has to be copied during |
227 | * shrinking. If NULL, it is not moved. | | 227 | * shrinking. If NULL, it is not moved. |
228 | */ | | 228 | */ |
229 | static const char *addsymtab_strstart; | | 229 | static const char *addsymtab_strstart; |
230 | | | 230 | |
231 | static int | | 231 | static int |
232 | addsymtab_compar(const void *a, const void *b) | | 232 | addsymtab_compar(const void *a, const void *b) |
233 | { | | 233 | { |
234 | const Elf_Sym *sa, *sb; | | 234 | const Elf_Sym *sa, *sb; |
235 | | | 235 | |
236 | sa = a; | | 236 | sa = a; |
237 | sb = b; | | 237 | sb = b; |
238 | | | 238 | |
239 | /* | | 239 | /* |
240 | * Split the symbol table into two, with globals at the start | | 240 | * Split the symbol table into two, with globals at the start |
241 | * and locals at the end. | | 241 | * and locals at the end. |
242 | */ | | 242 | */ |
243 | if (ELF_ST_BIND(sa->st_info) != ELF_ST_BIND(sb->st_info)) { | | 243 | if (ELF_ST_BIND(sa->st_info) != ELF_ST_BIND(sb->st_info)) { |
244 | if (ELF_ST_BIND(sa->st_info) == STB_GLOBAL) { | | 244 | if (ELF_ST_BIND(sa->st_info) == STB_GLOBAL) { |
245 | return -1; | | 245 | return -1; |
246 | } | | 246 | } |
247 | if (ELF_ST_BIND(sb->st_info) == STB_GLOBAL) { | | 247 | if (ELF_ST_BIND(sb->st_info) == STB_GLOBAL) { |
248 | return 1; | | 248 | return 1; |
249 | } | | 249 | } |
250 | } | | 250 | } |
251 | | | 251 | |
252 | /* Within each band, sort by name. */ | | 252 | /* Within each band, sort by name. */ |
253 | return strcmp(sa->st_name + addsymtab_strstart, | | 253 | return strcmp(sa->st_name + addsymtab_strstart, |
254 | sb->st_name + addsymtab_strstart); | | 254 | sb->st_name + addsymtab_strstart); |
255 | } | | 255 | } |
256 | | | 256 | |
257 | static void | | 257 | static void |
258 | addsymtab(const char *name, void *symstart, size_t symsize, | | 258 | addsymtab(const char *name, void *symstart, size_t symsize, |
259 | void *strstart, size_t strsize, struct ksyms_symtab *tab, | | 259 | void *strstart, size_t strsize, struct ksyms_symtab *tab, |
260 | void *newstart) | | 260 | void *newstart) |
261 | { | | 261 | { |
262 | Elf_Sym *sym, *nsym, ts; | | 262 | Elf_Sym *sym, *nsym, ts; |
263 | int i, j, n, nglob; | | 263 | int i, j, n, nglob; |
264 | char *str; | | 264 | char *str; |
265 | | | 265 | |
266 | tab->sd_symstart = symstart; | | 266 | tab->sd_symstart = symstart; |
267 | tab->sd_symsize = symsize; | | 267 | tab->sd_symsize = symsize; |
268 | tab->sd_strstart = strstart; | | 268 | tab->sd_strstart = strstart; |
269 | tab->sd_strsize = strsize; | | 269 | tab->sd_strsize = strsize; |
270 | tab->sd_name = name; | | 270 | tab->sd_name = name; |
271 | tab->sd_minsym = UINTPTR_MAX; | | 271 | tab->sd_minsym = UINTPTR_MAX; |
272 | tab->sd_maxsym = 0; | | 272 | tab->sd_maxsym = 0; |
273 | tab->sd_usroffset = 0; | | 273 | tab->sd_usroffset = 0; |
274 | tab->sd_gone = false; | | 274 | tab->sd_gone = false; |
275 | #ifdef KSYMS_DEBUG | | 275 | #ifdef KSYMS_DEBUG |
276 | printf("newstart %p sym %p ksyms_symsz %d str %p strsz %d send %p\n", | | 276 | printf("newstart %p sym %p ksyms_symsz %d str %p strsz %d send %p\n", |
277 | newstart, symstart, symsize, strstart, strsize, | | 277 | newstart, symstart, symsize, strstart, strsize, |
278 | tab->sd_strstart + tab->sd_strsize); | | 278 | tab->sd_strstart + tab->sd_strsize); |
279 | #endif | | 279 | #endif |
280 | | | 280 | |
281 | /* Pack symbol table by removing all file name references. */ | | 281 | /* Pack symbol table by removing all file name references. */ |
282 | sym = tab->sd_symstart; | | 282 | sym = tab->sd_symstart; |
283 | nsym = (Elf_Sym *)newstart; | | 283 | nsym = (Elf_Sym *)newstart; |
284 | str = tab->sd_strstart; | | 284 | str = tab->sd_strstart; |
285 | nglob = 0; | | 285 | nglob = 0; |
286 | for (i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) { | | 286 | for (i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) { |
287 | /* | | 287 | /* |
288 | * Remove useless symbols. | | 288 | * Remove useless symbols. |
289 | * Should actually remove all typeless symbols. | | 289 | * Should actually remove all typeless symbols. |
290 | */ | | 290 | */ |
291 | if (sym[i].st_name == 0) | | 291 | if (sym[i].st_name == 0) |
292 | continue; /* Skip nameless entries */ | | 292 | continue; /* Skip nameless entries */ |
293 | if (sym[i].st_shndx == SHN_UNDEF) | | 293 | if (sym[i].st_shndx == SHN_UNDEF) |
294 | continue; /* Skip external references */ | | 294 | continue; /* Skip external references */ |
295 | if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE) | | 295 | if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE) |
296 | continue; /* Skip filenames */ | | 296 | continue; /* Skip filenames */ |
297 | if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && | | 297 | if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && |
298 | sym[i].st_value == 0 && | | 298 | sym[i].st_value == 0 && |
299 | strcmp(str + sym[i].st_name, "*ABS*") == 0) | | 299 | strcmp(str + sym[i].st_name, "*ABS*") == 0) |
300 | continue; /* XXX */ | | 300 | continue; /* XXX */ |
301 | if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && | | 301 | if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && |
302 | strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0) | | 302 | strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0) |
303 | continue; /* XXX */ | | 303 | continue; /* XXX */ |
304 | | | 304 | |
305 | /* Save symbol. Set it as an absolute offset */ | | 305 | /* Save symbol. Set it as an absolute offset */ |
306 | nsym[n] = sym[i]; | | 306 | nsym[n] = sym[i]; |
307 | nsym[n].st_shndx = SHBSS; | | 307 | nsym[n].st_shndx = SHBSS; |
308 | j = strlen(nsym[n].st_name + str) + 1; | | 308 | j = strlen(nsym[n].st_name + str) + 1; |
309 | if (j > ksyms_maxlen) | | 309 | if (j > ksyms_maxlen) |
310 | ksyms_maxlen = j; | | 310 | ksyms_maxlen = j; |
311 | nglob += (ELF_ST_BIND(nsym[n].st_info) == STB_GLOBAL); | | 311 | nglob += (ELF_ST_BIND(nsym[n].st_info) == STB_GLOBAL); |
312 | | | 312 | |
313 | /* Compute min and max symbols. */ | | 313 | /* Compute min and max symbols. */ |
314 | if (nsym[n].st_value < tab->sd_minsym) { | | 314 | if (nsym[n].st_value < tab->sd_minsym) { |
315 | tab->sd_minsym = nsym[n].st_value; | | 315 | tab->sd_minsym = nsym[n].st_value; |
316 | } | | 316 | } |
317 | if (nsym[n].st_value > tab->sd_maxsym) { | | 317 | if (nsym[n].st_value > tab->sd_maxsym) { |
318 | tab->sd_maxsym = nsym[n].st_value; | | 318 | tab->sd_maxsym = nsym[n].st_value; |
319 | } | | 319 | } |
320 | n++; | | 320 | n++; |
321 | } | | 321 | } |
322 | | | 322 | |
323 | /* Fill the rest of the record, and sort the symbols. */ | | 323 | /* Fill the rest of the record, and sort the symbols. */ |
324 | tab->sd_symstart = nsym; | | 324 | tab->sd_symstart = nsym; |
325 | tab->sd_symsize = n * sizeof(Elf_Sym); | | 325 | tab->sd_symsize = n * sizeof(Elf_Sym); |
326 | tab->sd_nglob = nglob; | | 326 | tab->sd_nglob = nglob; |
327 | addsymtab_strstart = str; | | 327 | addsymtab_strstart = str; |
328 | if (kheapsort(nsym, n, sizeof(Elf_Sym), addsymtab_compar, &ts) != 0) | | 328 | if (kheapsort(nsym, n, sizeof(Elf_Sym), addsymtab_compar, &ts) != 0) |
329 | panic("addsymtab"); | | 329 | panic("addsymtab"); |
330 | | | 330 | |
331 | /* ksymsread() is unlocked, so membar. */ | | 331 | /* ksymsread() is unlocked, so membar. */ |
332 | membar_producer(); | | 332 | membar_producer(); |
333 | TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue); | | 333 | TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue); |
334 | ksyms_sizes_calc(); | | 334 | ksyms_sizes_calc(); |
335 | ksyms_initted = true; | | 335 | ksyms_initted = true; |
336 | } | | 336 | } |
337 | | | 337 | |
338 | /* | | 338 | /* |
339 | * Setup the kernel symbol table stuff. | | 339 | * Setup the kernel symbol table stuff. |
340 | */ | | 340 | */ |
341 | void | | 341 | void |
342 | ksyms_addsyms_elf(int symsize, void *start, void *end) | | 342 | ksyms_addsyms_elf(int symsize, void *start, void *end) |
343 | { | | 343 | { |
344 | int i, j; | | 344 | int i, j; |
345 | Elf_Shdr *shdr; | | 345 | Elf_Shdr *shdr; |
346 | char *symstart = NULL, *strstart = NULL; | | 346 | char *symstart = NULL, *strstart = NULL; |
347 | size_t strsize = 0; | | 347 | size_t strsize = 0; |
348 | Elf_Ehdr *ehdr; | | 348 | Elf_Ehdr *ehdr; |
349 | | | 349 | |
350 | #ifdef SYMTAB_SPACE | | 350 | #ifdef SYMTAB_SPACE |
351 | if (symsize <= 0 && | | 351 | if (symsize <= 0 && |
352 | strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) { | | 352 | strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) { |
353 | symsize = db_symtabsize; | | 353 | symsize = db_symtabsize; |
354 | start = db_symtab; | | 354 | start = db_symtab; |
355 | end = db_symtab + db_symtabsize; | | 355 | end = db_symtab + db_symtabsize; |
356 | } | | 356 | } |
357 | #endif | | 357 | #endif |
358 | if (symsize <= 0) { | | 358 | if (symsize <= 0) { |
359 | printf("[ Kernel symbol table missing! ]\n"); | | 359 | printf("[ Kernel symbol table missing! ]\n"); |
360 | return; | | 360 | return; |
361 | } | | 361 | } |
362 | | | 362 | |
363 | /* Sanity check */ | | 363 | /* Sanity check */ |
364 | if (ALIGNED_POINTER(start, long) == 0) { | | 364 | if (ALIGNED_POINTER(start, long) == 0) { |
365 | printf("[ Kernel symbol table has bad start address %p ]\n", | | 365 | printf("[ Kernel symbol table has bad start address %p ]\n", |
366 | start); | | 366 | start); |
367 | return; | | 367 | return; |
368 | } | | 368 | } |
369 | | | 369 | |
370 | ehdr = (Elf_Ehdr *)start; | | 370 | ehdr = (Elf_Ehdr *)start; |
371 | | | 371 | |
372 | /* check if this is a valid ELF header */ | | 372 | /* check if this is a valid ELF header */ |
373 | /* No reason to verify arch type, the kernel is actually running! */ | | 373 | /* No reason to verify arch type, the kernel is actually running! */ |
374 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || | | 374 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || |
375 | ehdr->e_ident[EI_CLASS] != ELFCLASS || | | 375 | ehdr->e_ident[EI_CLASS] != ELFCLASS || |
376 | ehdr->e_version > 1) { | | 376 | ehdr->e_version > 1) { |
377 | printf("[ Kernel symbol table invalid! ]\n"); | | 377 | printf("[ Kernel symbol table invalid! ]\n"); |
378 | return; /* nothing to do */ | | 378 | return; /* nothing to do */ |
379 | } | | 379 | } |
380 | | | 380 | |
381 | /* Loaded header will be scratched in addsymtab */ | | 381 | /* Loaded header will be scratched in addsymtab */ |
382 | ksyms_hdr_init(start); | | 382 | ksyms_hdr_init(start); |
383 | | | 383 | |
384 | /* Find the symbol table and the corresponding string table. */ | | 384 | /* Find the symbol table and the corresponding string table. */ |
385 | shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff); | | 385 | shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff); |
386 | for (i = 1; i < ehdr->e_shnum; i++) { | | 386 | for (i = 1; i < ehdr->e_shnum; i++) { |
387 | if (shdr[i].sh_type != SHT_SYMTAB) | | 387 | if (shdr[i].sh_type != SHT_SYMTAB) |
388 | continue; | | 388 | continue; |
389 | if (shdr[i].sh_offset == 0) | | 389 | if (shdr[i].sh_offset == 0) |
390 | continue; | | 390 | continue; |
391 | symstart = (uint8_t *)start + shdr[i].sh_offset; | | 391 | symstart = (uint8_t *)start + shdr[i].sh_offset; |
392 | symsize = shdr[i].sh_size; | | 392 | symsize = shdr[i].sh_size; |
393 | j = shdr[i].sh_link; | | 393 | j = shdr[i].sh_link; |
394 | if (shdr[j].sh_offset == 0) | | 394 | if (shdr[j].sh_offset == 0) |
395 | continue; /* Can this happen? */ | | 395 | continue; /* Can this happen? */ |
396 | strstart = (uint8_t *)start + shdr[j].sh_offset; | | 396 | strstart = (uint8_t *)start + shdr[j].sh_offset; |
397 | strsize = shdr[j].sh_size; | | 397 | strsize = shdr[j].sh_size; |
398 | break; | | 398 | break; |
399 | } | | 399 | } |
400 | | | 400 | |
401 | if (!ksyms_verify(symstart, strstart)) | | 401 | if (!ksyms_verify(symstart, strstart)) |
402 | return; | | 402 | return; |
403 | addsymtab("netbsd", symstart, symsize, strstart, strsize, | | 403 | addsymtab("netbsd", symstart, symsize, strstart, strsize, |
404 | &kernel_symtab, start); | | 404 | &kernel_symtab, start); |
405 | | | 405 | |
406 | #ifdef DEBUG | | 406 | #ifdef DEBUG |
407 | printf("Loaded initial symtab at %p, strtab at %p, # entries %ld\n", | | 407 | printf("Loaded initial symtab at %p, strtab at %p, # entries %ld\n", |
408 | kernel_symtab.sd_symstart, kernel_symtab.sd_strstart, | | 408 | kernel_symtab.sd_symstart, kernel_symtab.sd_strstart, |
409 | (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym)); | | 409 | (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym)); |
410 | #endif | | 410 | #endif |
411 | } | | 411 | } |
412 | | | 412 | |
413 | /* | | 413 | /* |
414 | * Setup the kernel symbol table stuff. | | 414 | * Setup the kernel symbol table stuff. |
415 | * Use this when the address of the symbol and string tables are known; | | 415 | * Use this when the address of the symbol and string tables are known; |
416 | * otherwise use ksyms_init with an ELF image. | | 416 | * otherwise use ksyms_init with an ELF image. |
417 | * We need to pass a minimal ELF header which will later be completed by | | 417 | * We need to pass a minimal ELF header which will later be completed by |
418 | * ksyms_hdr_init and handed off to userland through /dev/ksyms. We use | | 418 | * ksyms_hdr_init and handed off to userland through /dev/ksyms. We use |
419 | * a void *rather than a pointer to avoid exposing the Elf_Ehdr type. | | 419 | * a void *rather than a pointer to avoid exposing the Elf_Ehdr type. |
420 | */ | | 420 | */ |
421 | void | | 421 | void |
422 | ksyms_addsyms_explicit(void *ehdr, void *symstart, size_t symsize, | | 422 | ksyms_addsyms_explicit(void *ehdr, void *symstart, size_t symsize, |
423 | void *strstart, size_t strsize) | | 423 | void *strstart, size_t strsize) |
424 | { | | 424 | { |
425 | | | 425 | |
426 | if (!ksyms_verify(symstart, strstart)) | | 426 | if (!ksyms_verify(symstart, strstart)) |
427 | return; | | 427 | return; |
428 | | | 428 | |
429 | ksyms_hdr_init(ehdr); | | 429 | ksyms_hdr_init(ehdr); |
430 | addsymtab("netbsd", symstart, symsize, strstart, strsize, | | 430 | addsymtab("netbsd", symstart, symsize, strstart, strsize, |
431 | &kernel_symtab, symstart); | | 431 | &kernel_symtab, symstart); |
432 | } | | 432 | } |
433 | | | 433 | |
434 | /* | | 434 | /* |
435 | * Get the value associated with a symbol. | | 435 | * Get the value associated with a symbol. |
436 | * "mod" is the module name, or null if any module. | | 436 | * "mod" is the module name, or null if any module. |
437 | * "sym" is the symbol name. | | 437 | * "sym" is the symbol name. |
438 | * "val" is a pointer to the corresponding value, if call succeeded. | | 438 | * "val" is a pointer to the corresponding value, if call succeeded. |
439 | * Returns 0 if success or ENOENT if no such entry. | | 439 | * Returns 0 if success or ENOENT if no such entry. |
440 | * | | 440 | * |
441 | * Call with ksyms_lock, unless known that the symbol table can't change. | | 441 | * Call with ksyms_lock, unless known that the symbol table can't change. |
442 | */ | | 442 | */ |
443 | int | | 443 | int |
444 | ksyms_getval_unlocked(const char *mod, const char *sym, unsigned long *val, | | 444 | ksyms_getval_unlocked(const char *mod, const char *sym, unsigned long *val, |
445 | int type) | | 445 | int type) |
446 | { | | 446 | { |
447 | struct ksyms_symtab *st; | | 447 | struct ksyms_symtab *st; |
448 | Elf_Sym *es; | | 448 | Elf_Sym *es; |
449 | | | 449 | |
450 | #ifdef KSYMS_DEBUG | | 450 | #ifdef KSYMS_DEBUG |
451 | if (ksyms_debug & FOLLOW_CALLS) | | 451 | if (ksyms_debug & FOLLOW_CALLS) |
452 | printf("ksyms_getval_unlocked: mod %s sym %s valp %p\n", | | 452 | printf("ksyms_getval_unlocked: mod %s sym %s valp %p\n", |
453 | mod, sym, val); | | 453 | mod, sym, val); |
454 | #endif | | 454 | #endif |
455 | | | 455 | |
456 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 456 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
457 | if (__predict_false(st->sd_gone)) | | 457 | if (__predict_false(st->sd_gone)) |
458 | continue; | | 458 | continue; |
459 | if (mod != NULL && strcmp(st->sd_name, mod)) | | 459 | if (mod != NULL && strcmp(st->sd_name, mod)) |
460 | continue; | | 460 | continue; |
461 | if ((es = findsym(sym, st, type)) != NULL) { | | 461 | if ((es = findsym(sym, st, type)) != NULL) { |
462 | *val = es->st_value; | | 462 | *val = es->st_value; |
463 | return 0; | | 463 | return 0; |
464 | } | | 464 | } |
465 | } | | 465 | } |
466 | return ENOENT; | | 466 | return ENOENT; |
467 | } | | 467 | } |
468 | | | 468 | |
469 | int | | 469 | int |
470 | ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type) | | 470 | ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type) |
471 | { | | 471 | { |
472 | int rc; | | 472 | int rc; |
473 | | | 473 | |
474 | if (!ksyms_initted) | | 474 | if (!ksyms_initted) |
475 | return ENOENT; | | 475 | return ENOENT; |
476 | | | 476 | |
477 | mutex_enter(&ksyms_lock); | | 477 | mutex_enter(&ksyms_lock); |
478 | rc = ksyms_getval_unlocked(mod, sym, val, type); | | 478 | rc = ksyms_getval_unlocked(mod, sym, val, type); |
479 | mutex_exit(&ksyms_lock); | | 479 | mutex_exit(&ksyms_lock); |
480 | return rc; | | 480 | return rc; |
481 | } | | 481 | } |
482 | | | 482 | |
483 | /* | | 483 | /* |
484 | * Get "mod" and "symbol" associated with an address. | | 484 | * Get "mod" and "symbol" associated with an address. |
485 | * Returns 0 if success or ENOENT if no such entry. | | 485 | * Returns 0 if success or ENOENT if no such entry. |
486 | * | | 486 | * |
487 | * Call with ksyms_lock, unless known that the symbol table can't change. | | 487 | * Call with ksyms_lock, unless known that the symbol table can't change. |
488 | */ | | 488 | */ |
489 | int | | 489 | int |
490 | ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f) | | 490 | ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f) |
491 | { | | 491 | { |
492 | struct ksyms_symtab *st; | | 492 | struct ksyms_symtab *st; |
493 | Elf_Sym *les, *es = NULL; | | 493 | Elf_Sym *les, *es = NULL; |
494 | vaddr_t laddr = 0; | | 494 | vaddr_t laddr = 0; |
495 | const char *lmod = NULL; | | 495 | const char *lmod = NULL; |
496 | char *stable = NULL; | | 496 | char *stable = NULL; |
497 | int type, i, sz; | | 497 | int type, i, sz; |
498 | | | 498 | |
499 | if (!ksyms_initted) | | 499 | if (!ksyms_initted) |
500 | return ENOENT; | | 500 | return ENOENT; |
501 | | | 501 | |
502 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 502 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
503 | if (st->sd_gone) | | 503 | if (st->sd_gone) |
504 | continue; | | 504 | continue; |
505 | if (v < st->sd_minsym || v > st->sd_maxsym) | | 505 | if (v < st->sd_minsym || v > st->sd_maxsym) |
506 | continue; | | 506 | continue; |
507 | sz = st->sd_symsize/sizeof(Elf_Sym); | | 507 | sz = st->sd_symsize/sizeof(Elf_Sym); |
508 | for (i = 0; i < sz; i++) { | | 508 | for (i = 0; i < sz; i++) { |
509 | les = st->sd_symstart + i; | | 509 | les = st->sd_symstart + i; |
510 | type = ELF_ST_TYPE(les->st_info); | | 510 | type = ELF_ST_TYPE(les->st_info); |
511 | | | 511 | |
512 | if ((f & KSYMS_PROC) && (type != STT_FUNC)) | | 512 | if ((f & KSYMS_PROC) && (type != STT_FUNC)) |
513 | continue; | | 513 | continue; |
514 | | | 514 | |
515 | if (type == STT_NOTYPE) | | 515 | if (type == STT_NOTYPE) |
516 | continue; | | 516 | continue; |
517 | | | 517 | |
518 | if (((f & KSYMS_ANY) == 0) && | | 518 | if (((f & KSYMS_ANY) == 0) && |
519 | (type != STT_FUNC) && (type != STT_OBJECT)) | | 519 | (type != STT_FUNC) && (type != STT_OBJECT)) |
520 | continue; | | 520 | continue; |
521 | | | 521 | |
522 | if ((les->st_value <= v) && (les->st_value > laddr)) { | | 522 | if ((les->st_value <= v) && (les->st_value > laddr)) { |
523 | laddr = les->st_value; | | 523 | laddr = les->st_value; |
524 | es = les; | | 524 | es = les; |
525 | lmod = st->sd_name; | | 525 | lmod = st->sd_name; |
526 | stable = st->sd_strstart - st->sd_usroffset; | | 526 | stable = st->sd_strstart - st->sd_usroffset; |
527 | } | | 527 | } |
528 | } | | 528 | } |
529 | } | | 529 | } |
530 | if (es == NULL) | | 530 | if (es == NULL) |
531 | return ENOENT; | | 531 | return ENOENT; |
532 | if ((f & KSYMS_EXACT) && (v != es->st_value)) | | 532 | if ((f & KSYMS_EXACT) && (v != es->st_value)) |
533 | return ENOENT; | | 533 | return ENOENT; |
534 | if (mod) | | 534 | if (mod) |
535 | *mod = lmod; | | 535 | *mod = lmod; |
536 | if (sym) | | 536 | if (sym) |
537 | *sym = stable + es->st_name; | | 537 | *sym = stable + es->st_name; |
538 | return 0; | | 538 | return 0; |
539 | } | | 539 | } |
540 | | | 540 | |
541 | /* | | 541 | /* |
542 | * Add a symbol table from a loadable module. | | 542 | * Add a symbol table from a loadable module. |
543 | */ | | 543 | */ |
544 | void | | 544 | void |
545 | ksyms_modload(const char *name, void *symstart, vsize_t symsize, | | 545 | ksyms_modload(const char *name, void *symstart, vsize_t symsize, |
546 | char *strstart, vsize_t strsize) | | 546 | char *strstart, vsize_t strsize) |
547 | { | | 547 | { |
548 | struct ksyms_symtab *st; | | 548 | struct ksyms_symtab *st; |
549 | | | 549 | |
550 | st = kmem_zalloc(sizeof(*st), KM_SLEEP); | | 550 | st = kmem_zalloc(sizeof(*st), KM_SLEEP); |
551 | mutex_enter(&ksyms_lock); | | 551 | mutex_enter(&ksyms_lock); |
552 | addsymtab(name, symstart, symsize, strstart, strsize, st, symstart); | | 552 | addsymtab(name, symstart, symsize, strstart, strsize, st, symstart); |
553 | mutex_exit(&ksyms_lock); | | 553 | mutex_exit(&ksyms_lock); |
554 | } | | 554 | } |
555 | | | 555 | |
556 | /* | | 556 | /* |
557 | * Remove a symbol table from a loadable module. | | 557 | * Remove a symbol table from a loadable module. |
558 | */ | | 558 | */ |
559 | void | | 559 | void |
560 | ksyms_modunload(const char *name) | | 560 | ksyms_modunload(const char *name) |
561 | { | | 561 | { |
562 | struct ksyms_symtab *st; | | 562 | struct ksyms_symtab *st; |
563 | | | 563 | |
564 | mutex_enter(&ksyms_lock); | | 564 | mutex_enter(&ksyms_lock); |
565 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 565 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
566 | if (st->sd_gone) | | 566 | if (st->sd_gone) |
567 | continue; | | 567 | continue; |
568 | if (strcmp(name, st->sd_name) != 0) | | 568 | if (strcmp(name, st->sd_name) != 0) |
569 | continue; | | 569 | continue; |
570 | st->sd_gone = true; | | 570 | st->sd_gone = true; |
571 | if (!ksyms_isopen) { | | 571 | if (!ksyms_isopen) { |
572 | TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); | | 572 | TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); |
573 | ksyms_sizes_calc(); | | 573 | ksyms_sizes_calc(); |
574 | kmem_free(st, sizeof(*st)); | | 574 | kmem_free(st, sizeof(*st)); |
575 | } | | 575 | } |
576 | break; | | 576 | break; |
577 | } | | 577 | } |
578 | mutex_exit(&ksyms_lock); | | 578 | mutex_exit(&ksyms_lock); |
579 | KASSERT(st != NULL); | | 579 | KASSERT(st != NULL); |
580 | } | | 580 | } |
581 | | | 581 | |
582 | #ifdef DDB | | 582 | #ifdef DDB |
583 | /* | | 583 | /* |
584 | * Keep sifting stuff here, to avoid export of ksyms internals. | | 584 | * Keep sifting stuff here, to avoid export of ksyms internals. |
585 | * | | 585 | * |
586 | * Systems is expected to be quiescent, so no locking done. | | 586 | * Systems is expected to be quiescent, so no locking done. |
587 | */ | | 587 | */ |
588 | int | | 588 | int |
589 | ksyms_sift(char *mod, char *sym, int mode) | | 589 | ksyms_sift(char *mod, char *sym, int mode) |
590 | { | | 590 | { |
591 | struct ksyms_symtab *st; | | 591 | struct ksyms_symtab *st; |
592 | char *sb; | | 592 | char *sb; |
593 | int i, sz; | | 593 | int i, sz; |
594 | | | 594 | |
595 | if (!ksyms_initted) | | 595 | if (!ksyms_initted) |
596 | return ENOENT; | | 596 | return ENOENT; |
597 | | | 597 | |
598 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 598 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
599 | if (st->sd_gone) | | 599 | if (st->sd_gone) |
600 | continue; | | 600 | continue; |
601 | if (mod && strcmp(mod, st->sd_name)) | | 601 | if (mod && strcmp(mod, st->sd_name)) |
602 | continue; | | 602 | continue; |
603 | sb = st->sd_strstart - st->sd_usroffset; | | 603 | sb = st->sd_strstart - st->sd_usroffset; |
604 | | | 604 | |
605 | sz = st->sd_symsize/sizeof(Elf_Sym); | | 605 | sz = st->sd_symsize/sizeof(Elf_Sym); |
606 | for (i = 0; i < sz; i++) { | | 606 | for (i = 0; i < sz; i++) { |
607 | Elf_Sym *les = st->sd_symstart + i; | | 607 | Elf_Sym *les = st->sd_symstart + i; |
608 | char c; | | 608 | char c; |
609 | | | 609 | |
610 | if (strstr(sb + les->st_name, sym) == NULL) | | 610 | if (strstr(sb + les->st_name, sym) == NULL) |
611 | continue; | | 611 | continue; |
612 | | | 612 | |
613 | if (mode == 'F') { | | 613 | if (mode == 'F') { |
614 | switch (ELF_ST_TYPE(les->st_info)) { | | 614 | switch (ELF_ST_TYPE(les->st_info)) { |
615 | case STT_OBJECT: | | 615 | case STT_OBJECT: |
616 | c = '+'; | | 616 | c = '+'; |
617 | break; | | 617 | break; |
618 | case STT_FUNC: | | 618 | case STT_FUNC: |
619 | c = '*'; | | 619 | c = '*'; |
620 | break; | | 620 | break; |
621 | case STT_SECTION: | | 621 | case STT_SECTION: |
622 | c = '&'; | | 622 | c = '&'; |
623 | break; | | 623 | break; |
624 | case STT_FILE: | | 624 | case STT_FILE: |
625 | c = '/'; | | 625 | c = '/'; |
626 | break; | | 626 | break; |
627 | default: | | 627 | default: |
628 | c = ' '; | | 628 | c = ' '; |
629 | break; | | 629 | break; |
630 | } | | 630 | } |
631 | db_printf("%s%c ", sb + les->st_name, c); | | 631 | db_printf("%s%c ", sb + les->st_name, c); |
632 | } else | | 632 | } else |
633 | db_printf("%s ", sb + les->st_name); | | 633 | db_printf("%s ", sb + les->st_name); |
634 | } | | 634 | } |
635 | } | | 635 | } |
636 | return ENOENT; | | 636 | return ENOENT; |
637 | } | | 637 | } |
638 | #endif /* DDB */ | | 638 | #endif /* DDB */ |
639 | | | 639 | |
640 | /* | | 640 | /* |
641 | * In case we exposing the symbol table to the userland using the pseudo- | | 641 | * In case we exposing the symbol table to the userland using the pseudo- |
642 | * device /dev/ksyms, it is easier to provide all the tables as one. | | 642 | * device /dev/ksyms, it is easier to provide all the tables as one. |
643 | * However, it means we have to change all the st_name fields for the | | 643 | * However, it means we have to change all the st_name fields for the |
644 | * symbols so they match the ELF image that the userland will read | | 644 | * symbols so they match the ELF image that the userland will read |
645 | * through the device. | | 645 | * through the device. |
646 | * | | 646 | * |
647 | * The actual (correct) value of st_name is preserved through a global | | 647 | * The actual (correct) value of st_name is preserved through a global |
648 | * offset stored in the symbol table structure. | | 648 | * offset stored in the symbol table structure. |
649 | * | | 649 | * |
650 | * Call with ksyms_lock held. | | 650 | * Call with ksyms_lock held. |
651 | */ | | 651 | */ |
652 | static void | | 652 | static void |
653 | ksyms_sizes_calc(void) | | 653 | ksyms_sizes_calc(void) |
654 | { | | 654 | { |
655 | struct ksyms_symtab *st; | | 655 | struct ksyms_symtab *st; |
656 | int i, delta; | | 656 | int i, delta; |
657 | | | 657 | |
658 | ksyms_symsz = ksyms_strsz = 0; | | 658 | ksyms_symsz = ksyms_strsz = 0; |
659 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 659 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
660 | delta = ksyms_strsz - st->sd_usroffset; | | 660 | delta = ksyms_strsz - st->sd_usroffset; |
661 | if (delta != 0) { | | 661 | if (delta != 0) { |
662 | for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++) | | 662 | for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++) |
663 | st->sd_symstart[i].st_name += delta; | | 663 | st->sd_symstart[i].st_name += delta; |
664 | st->sd_usroffset = ksyms_strsz; | | 664 | st->sd_usroffset = ksyms_strsz; |
665 | } | | 665 | } |
666 | ksyms_symsz += st->sd_symsize; | | 666 | ksyms_symsz += st->sd_symsize; |
667 | ksyms_strsz += st->sd_strsize; | | 667 | ksyms_strsz += st->sd_strsize; |
668 | } | | 668 | } |
669 | } | | 669 | } |
670 | | | 670 | |
671 | static void | | 671 | static void |
672 | ksyms_hdr_init(void *hdraddr) | | 672 | ksyms_hdr_init(void *hdraddr) |
673 | { | | 673 | { |
674 | | | 674 | |
675 | /* Copy the loaded elf exec header */ | | 675 | /* Copy the loaded elf exec header */ |
676 | memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr)); | | 676 | memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr)); |
677 | | | 677 | |
678 | /* Set correct program/section header sizes, offsets and numbers */ | | 678 | /* Set correct program/section header sizes, offsets and numbers */ |
679 | ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]); | | 679 | ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]); |
680 | ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr); | | 680 | ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr); |
681 | ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR; | | 681 | ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR; |
682 | ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]); | | 682 | ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]); |
683 | ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr); | | 683 | ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr); |
684 | ksyms_hdr.kh_ehdr.e_shnum = NSECHDR; | | 684 | ksyms_hdr.kh_ehdr.e_shnum = NSECHDR; |
685 | ksyms_hdr.kh_ehdr.e_shstrndx = SHSTRTAB; | | 685 | ksyms_hdr.kh_ehdr.e_shstrndx = SHSTRTAB; |
686 | | | 686 | |
687 | /* Text/data - fake */ | | 687 | /* Text/data - fake */ |
688 | ksyms_hdr.kh_phdr[0].p_type = PT_LOAD; | | 688 | ksyms_hdr.kh_phdr[0].p_type = PT_LOAD; |
689 | ksyms_hdr.kh_phdr[0].p_memsz = (unsigned long)-1L; | | 689 | ksyms_hdr.kh_phdr[0].p_memsz = (unsigned long)-1L; |
690 | ksyms_hdr.kh_phdr[0].p_flags = PF_R | PF_X | PF_W; | | 690 | ksyms_hdr.kh_phdr[0].p_flags = PF_R | PF_X | PF_W; |
691 | | | 691 | |
692 | /* First section is null */ | | 692 | /* First section is null */ |
693 | | | 693 | |
694 | /* Second section header; ".symtab" */ | | 694 | /* Second section header; ".symtab" */ |
695 | ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */ | | 695 | ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */ |
696 | ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB; | | 696 | ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB; |
697 | ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr); | | 697 | ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr); |
698 | /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */ | | 698 | /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */ |
699 | ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */ | | 699 | ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */ |
700 | ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long); | | 700 | ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long); |
701 | ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym); | | 701 | ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym); |
702 | | | 702 | |
703 | /* Third section header; ".strtab" */ | | 703 | /* Third section header; ".strtab" */ |
704 | ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */ | | 704 | ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */ |
705 | ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB; | | 705 | ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB; |
706 | /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */ | | 706 | /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */ |
707 | /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */ | | 707 | /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */ |
708 | ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char); | | 708 | ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char); |
709 | | | 709 | |
710 | /* Fourth section, ".shstrtab" */ | | 710 | /* Fourth section, ".shstrtab" */ |
711 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */ | | 711 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */ |
712 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB; | | 712 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB; |
713 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset = | | 713 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset = |
714 | offsetof(struct ksyms_hdr, kh_strtab); | | 714 | offsetof(struct ksyms_hdr, kh_strtab); |
715 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ; | | 715 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ; |
716 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char); | | 716 | ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char); |
717 | | | 717 | |
718 | /* Fifth section, ".bss". All symbols reside here. */ | | 718 | /* Fifth section, ".bss". All symbols reside here. */ |
719 | ksyms_hdr.kh_shdr[SHBSS].sh_name = 27; /* This section name offset */ | | 719 | ksyms_hdr.kh_shdr[SHBSS].sh_name = 27; /* This section name offset */ |
720 | ksyms_hdr.kh_shdr[SHBSS].sh_type = SHT_NOBITS; | | 720 | ksyms_hdr.kh_shdr[SHBSS].sh_type = SHT_NOBITS; |
721 | ksyms_hdr.kh_shdr[SHBSS].sh_offset = 0; | | 721 | ksyms_hdr.kh_shdr[SHBSS].sh_offset = 0; |
722 | ksyms_hdr.kh_shdr[SHBSS].sh_size = (unsigned long)-1L; | | 722 | ksyms_hdr.kh_shdr[SHBSS].sh_size = (unsigned long)-1L; |
723 | ksyms_hdr.kh_shdr[SHBSS].sh_addralign = PAGE_SIZE; | | 723 | ksyms_hdr.kh_shdr[SHBSS].sh_addralign = PAGE_SIZE; |
724 | ksyms_hdr.kh_shdr[SHBSS].sh_flags = SHF_ALLOC | SHF_EXECINSTR; | | 724 | ksyms_hdr.kh_shdr[SHBSS].sh_flags = SHF_ALLOC | SHF_EXECINSTR; |
725 | | | 725 | |
726 | /* Set section names */ | | 726 | /* Set section names */ |
727 | strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab", | | 727 | strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab", |
728 | sizeof(ksyms_hdr.kh_strtab) - 1); | | 728 | sizeof(ksyms_hdr.kh_strtab) - 1); |
729 | strlcpy(&ksyms_hdr.kh_strtab[9], ".strtab", | | 729 | strlcpy(&ksyms_hdr.kh_strtab[9], ".strtab", |
730 | sizeof(ksyms_hdr.kh_strtab) - 9); | | 730 | sizeof(ksyms_hdr.kh_strtab) - 9); |
731 | strlcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab", | | 731 | strlcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab", |
732 | sizeof(ksyms_hdr.kh_strtab) - 17); | | 732 | sizeof(ksyms_hdr.kh_strtab) - 17); |
733 | strlcpy(&ksyms_hdr.kh_strtab[27], ".bss", | | 733 | strlcpy(&ksyms_hdr.kh_strtab[27], ".bss", |
734 | sizeof(ksyms_hdr.kh_strtab) - 27); | | 734 | sizeof(ksyms_hdr.kh_strtab) - 27); |
735 | } | | 735 | } |
736 | | | 736 | |
737 | static int | | 737 | static int |
738 | ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l) | | 738 | ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l) |
739 | { | | 739 | { |
740 | | | 740 | |
741 | if (minor(dev) != 0 || !ksyms_initted) | | 741 | if (minor(dev) != 0 || !ksyms_initted) |
742 | return ENXIO; | | 742 | return ENXIO; |
743 | | | 743 | |
744 | /* | | 744 | /* |
745 | * Create a "snapshot" of the kernel symbol table. Setting | | 745 | * Create a "snapshot" of the kernel symbol table. Setting |
746 | * ksyms_isopen will prevent symbol tables from being freed. | | 746 | * ksyms_isopen will prevent symbol tables from being freed. |
747 | */ | | 747 | */ |
748 | mutex_enter(&ksyms_lock); | | 748 | mutex_enter(&ksyms_lock); |
749 | ksyms_hdr.kh_shdr[SYMTAB].sh_size = ksyms_symsz; | | 749 | ksyms_hdr.kh_shdr[SYMTAB].sh_size = ksyms_symsz; |
750 | ksyms_hdr.kh_shdr[SYMTAB].sh_info = ksyms_symsz / sizeof(Elf_Sym); | | 750 | ksyms_hdr.kh_shdr[SYMTAB].sh_info = ksyms_symsz / sizeof(Elf_Sym); |
751 | ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz + | | 751 | ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz + |
752 | ksyms_hdr.kh_shdr[SYMTAB].sh_offset; | | 752 | ksyms_hdr.kh_shdr[SYMTAB].sh_offset; |
753 | ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz; | | 753 | ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz; |
754 | ksyms_isopen = true; | | 754 | ksyms_isopen = true; |
755 | mutex_exit(&ksyms_lock); | | 755 | mutex_exit(&ksyms_lock); |
756 | | | 756 | |
757 | return 0; | | 757 | return 0; |
758 | } | | 758 | } |
759 | | | 759 | |
760 | static int | | 760 | static int |
761 | ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l) | | 761 | ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l) |
762 | { | | 762 | { |
763 | struct ksyms_symtab *st, *next; | | 763 | struct ksyms_symtab *st, *next; |
764 | bool resize; | | 764 | bool resize; |
765 | | | 765 | |
766 | /* Discard refernces to symbol tables. */ | | 766 | /* Discard refernces to symbol tables. */ |
767 | mutex_enter(&ksyms_lock); | | 767 | mutex_enter(&ksyms_lock); |
768 | ksyms_isopen = false; | | 768 | ksyms_isopen = false; |
769 | resize = false; | | 769 | resize = false; |
770 | for (st = TAILQ_FIRST(&ksyms_symtabs); st != NULL; st = next) { | | 770 | for (st = TAILQ_FIRST(&ksyms_symtabs); st != NULL; st = next) { |
771 | next = TAILQ_NEXT(st, sd_queue); | | 771 | next = TAILQ_NEXT(st, sd_queue); |
772 | if (st->sd_gone) { | | 772 | if (st->sd_gone) { |
773 | TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); | | 773 | TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); |
774 | kmem_free(st, sizeof(*st)); | | 774 | kmem_free(st, sizeof(*st)); |
775 | resize = true; | | 775 | resize = true; |
776 | } | | 776 | } |
777 | } | | 777 | } |
778 | if (resize) | | 778 | if (resize) |
779 | ksyms_sizes_calc(); | | 779 | ksyms_sizes_calc(); |
780 | mutex_exit(&ksyms_lock); | | 780 | mutex_exit(&ksyms_lock); |
781 | | | 781 | |
782 | return 0; | | 782 | return 0; |
783 | } | | 783 | } |
784 | | | 784 | |
785 | static int | | 785 | static int |
786 | ksymsread(dev_t dev, struct uio *uio, int ioflag) | | 786 | ksymsread(dev_t dev, struct uio *uio, int ioflag) |
787 | { | | 787 | { |
788 | struct ksyms_symtab *st; | | 788 | struct ksyms_symtab *st; |
789 | size_t filepos, inpos, off; | | 789 | size_t filepos, inpos, off; |
790 | int error; | | 790 | int error; |
791 | | | 791 | |
792 | /* | | 792 | /* |
793 | * First: Copy out the ELF header. XXX Lose if ksymsopen() | | 793 | * First: Copy out the ELF header. XXX Lose if ksymsopen() |
794 | * occurs during read of the header. | | 794 | * occurs during read of the header. |
795 | */ | | 795 | */ |
796 | off = uio->uio_offset; | | 796 | off = uio->uio_offset; |
797 | if (off < sizeof(struct ksyms_hdr)) { | | 797 | if (off < sizeof(struct ksyms_hdr)) { |
798 | error = uiomove((char *)&ksyms_hdr + off, | | 798 | error = uiomove((char *)&ksyms_hdr + off, |
799 | sizeof(struct ksyms_hdr) - off, uio); | | 799 | sizeof(struct ksyms_hdr) - off, uio); |
800 | if (error != 0) | | 800 | if (error != 0) |
801 | return error; | | 801 | return error; |
802 | } | | 802 | } |
803 | | | 803 | |
804 | /* | | 804 | /* |
805 | * Copy out the symbol table. | | 805 | * Copy out the symbol table. |
806 | */ | | 806 | */ |
807 | filepos = sizeof(struct ksyms_hdr); | | 807 | filepos = sizeof(struct ksyms_hdr); |
808 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 808 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
809 | if (uio->uio_resid == 0) | | 809 | if (uio->uio_resid == 0) |
810 | return 0; | | 810 | return 0; |
811 | if (uio->uio_offset <= st->sd_symsize + filepos) { | | 811 | if (uio->uio_offset <= st->sd_symsize + filepos) { |
812 | inpos = uio->uio_offset - filepos; | | 812 | inpos = uio->uio_offset - filepos; |
813 | error = uiomove((char *)st->sd_symstart + inpos, | | 813 | error = uiomove((char *)st->sd_symstart + inpos, |
814 | st->sd_symsize - inpos, uio); | | 814 | st->sd_symsize - inpos, uio); |
815 | if (error != 0) | | 815 | if (error != 0) |
816 | return error; | | 816 | return error; |
817 | } | | 817 | } |
818 | filepos += st->sd_symsize; | | 818 | filepos += st->sd_symsize; |
819 | } | | 819 | } |
820 | | | 820 | |
821 | /* | | 821 | /* |
822 | * Copy out the string table | | 822 | * Copy out the string table |
823 | */ | | 823 | */ |
824 | KASSERT(filepos == sizeof(struct ksyms_hdr) + | | 824 | KASSERT(filepos == sizeof(struct ksyms_hdr) + |
825 | ksyms_hdr.kh_shdr[SYMTAB].sh_size); | | 825 | ksyms_hdr.kh_shdr[SYMTAB].sh_size); |
826 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 826 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
827 | if (uio->uio_resid == 0) | | 827 | if (uio->uio_resid == 0) |
828 | return 0; | | 828 | return 0; |
829 | if (uio->uio_offset <= st->sd_strsize + filepos) { | | 829 | if (uio->uio_offset <= st->sd_strsize + filepos) { |
830 | inpos = uio->uio_offset - filepos; | | 830 | inpos = uio->uio_offset - filepos; |
831 | error = uiomove((char *)st->sd_strstart + inpos, | | 831 | error = uiomove((char *)st->sd_strstart + inpos, |
832 | st->sd_strsize - inpos, uio); | | 832 | st->sd_strsize - inpos, uio); |
833 | if (error != 0) | | 833 | if (error != 0) |
834 | return error; | | 834 | return error; |
835 | } | | 835 | } |
836 | filepos += st->sd_strsize; | | 836 | filepos += st->sd_strsize; |
837 | } | | 837 | } |
838 | | | 838 | |
839 | return 0; | | 839 | return 0; |
840 | } | | 840 | } |
841 | | | 841 | |
842 | static int | | 842 | static int |
843 | ksymswrite(dev_t dev, struct uio *uio, int ioflag) | | 843 | ksymswrite(dev_t dev, struct uio *uio, int ioflag) |
844 | { | | 844 | { |
845 | | | 845 | |
846 | return EROFS; | | 846 | return EROFS; |
847 | } | | 847 | } |
848 | | | 848 | |
849 | static int | | 849 | static int |
850 | ksymsioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l) | | 850 | ksymsioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l) |
851 | { | | 851 | { |
852 | struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data; | | 852 | struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data; |
853 | struct ksyms_symtab *st; | | 853 | struct ksyms_symtab *st; |
854 | Elf_Sym *sym = NULL, copy; | | 854 | Elf_Sym *sym = NULL, copy; |
855 | unsigned long val; | | 855 | unsigned long val; |
856 | int error = 0; | | 856 | int error = 0; |
857 | char *str = NULL; | | 857 | char *str = NULL; |
858 | int len; | | 858 | int len; |
859 | | | 859 | |
860 | /* Read ksyms_maxlen only once while not holding the lock. */ | | 860 | /* Read ksyms_maxlen only once while not holding the lock. */ |
861 | len = ksyms_maxlen; | | 861 | len = ksyms_maxlen; |
862 | | | 862 | |
863 | if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL) { | | 863 | if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL) { |
864 | str = kmem_alloc(len, KM_SLEEP); | | 864 | str = kmem_alloc(len, KM_SLEEP); |
865 | if ((error = copyinstr(kg->kg_name, str, len, NULL)) != 0) { | | 865 | if ((error = copyinstr(kg->kg_name, str, len, NULL)) != 0) { |
866 | kmem_free(str, len); | | 866 | kmem_free(str, len); |
867 | return error; | | 867 | return error; |
868 | } | | 868 | } |
869 | } | | 869 | } |
870 | | | 870 | |
871 | switch (cmd) { | | 871 | switch (cmd) { |
872 | case KIOCGVALUE: | | 872 | case KIOCGVALUE: |
873 | /* | | 873 | /* |
874 | * Use the in-kernel symbol lookup code for fast | | 874 | * Use the in-kernel symbol lookup code for fast |
875 | * retreival of a value. | | 875 | * retreival of a value. |
876 | */ | | 876 | */ |
877 | error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN); | | 877 | error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN); |
878 | if (error == 0) | | 878 | if (error == 0) |
879 | error = copyout(&val, kg->kg_value, sizeof(long)); | | 879 | error = copyout(&val, kg->kg_value, sizeof(long)); |
880 | kmem_free(str, len); | | 880 | kmem_free(str, len); |
881 | break; | | 881 | break; |
882 | | | 882 | |
883 | case KIOCGSYMBOL: | | 883 | case KIOCGSYMBOL: |
884 | /* | | 884 | /* |
885 | * Use the in-kernel symbol lookup code for fast | | 885 | * Use the in-kernel symbol lookup code for fast |
886 | * retreival of a symbol. | | 886 | * retreival of a symbol. |
887 | */ | | 887 | */ |
888 | mutex_enter(&ksyms_lock); | | 888 | mutex_enter(&ksyms_lock); |
889 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { | | 889 | TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { |
890 | if (st->sd_gone) | | 890 | if (st->sd_gone) |
891 | continue; | | 891 | continue; |
892 | if ((sym = findsym(str, st, KSYMS_ANY)) == NULL) | | 892 | if ((sym = findsym(str, st, KSYMS_ANY)) == NULL) |
893 | continue; | | 893 | continue; |
894 | #ifdef notdef | | 894 | #ifdef notdef |
895 | /* Skip if bad binding */ | | 895 | /* Skip if bad binding */ |
896 | if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) { | | 896 | if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) { |
897 | sym = NULL; | | 897 | sym = NULL; |
898 | continue; | | 898 | continue; |
899 | } | | 899 | } |
900 | #endif | | 900 | #endif |
901 | break; | | 901 | break; |
902 | } | | 902 | } |
903 | if (sym != NULL) { | | 903 | if (sym != NULL) { |
904 | memcpy(©, sym, sizeof(copy)); | | 904 | memcpy(©, sym, sizeof(copy)); |
905 | mutex_exit(&ksyms_lock); | | 905 | mutex_exit(&ksyms_lock); |
906 | error = copyout(©, kg->kg_sym, sizeof(Elf_Sym)); | | 906 | error = copyout(©, kg->kg_sym, sizeof(Elf_Sym)); |
907 | } else { | | 907 | } else { |
908 | mutex_exit(&ksyms_lock); | | 908 | mutex_exit(&ksyms_lock); |
909 | error = ENOENT; | | 909 | error = ENOENT; |
910 | } | | 910 | } |
911 | kmem_free(str, len); | | 911 | kmem_free(str, len); |
912 | break; | | 912 | break; |
913 | | | 913 | |
914 | case KIOCGSIZE: | | 914 | case KIOCGSIZE: |
915 | /* | | 915 | /* |
916 | * Get total size of symbol table. | | 916 | * Get total size of symbol table. |
917 | */ | | 917 | */ |
918 | mutex_enter(&ksyms_lock); | | 918 | mutex_enter(&ksyms_lock); |
919 | *(int *)data = ksyms_strsz + ksyms_symsz + | | 919 | *(int *)data = ksyms_strsz + ksyms_symsz + |
920 | sizeof(struct ksyms_hdr); | | 920 | sizeof(struct ksyms_hdr); |
921 | mutex_exit(&ksyms_lock); | | 921 | mutex_exit(&ksyms_lock); |
922 | break; | | 922 | break; |
923 | | | 923 | |
924 | default: | | 924 | default: |
925 | error = ENOTTY; | | 925 | error = ENOTTY; |
926 | break; | | 926 | break; |
927 | } | | 927 | } |
928 | | | 928 | |
929 | return error; | | 929 | return error; |
930 | } | | 930 | } |
931 | | | 931 | |
932 | const struct cdevsw ksyms_cdevsw = { | | 932 | const struct cdevsw ksyms_cdevsw = { |
933 | ksymsopen, ksymsclose, ksymsread, ksymswrite, ksymsioctl, | | 933 | ksymsopen, ksymsclose, ksymsread, ksymswrite, ksymsioctl, |
934 | nullstop, notty, nopoll, nommap, nullkqfilter, D_OTHER | D_MPSAFE | | 934 | nullstop, notty, nopoll, nommap, nullkqfilter, D_OTHER | D_MPSAFE |
935 | }; | | 935 | }; |