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