1 /* $NetBSD: kern_ksyms.c,v 1.51 2009/03/15 17:14:40 cegger Exp $ */
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software developed for The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se).
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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
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.
60 * Code to deal with in-kernel symbol table management + /dev/ksyms.
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
70 * Add support for mmap, poll.
73 #include <sys/cdefs.h>
74 __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.51 2009/03/15 17:14:40 cegger Exp $");
76 #if defined(_KERNEL) && defined(_KERNEL_OPT)
78 #include "opt_ddbparam.h" /* for SYMTAB_SPACE */
81 #define _KSYMS_PRIVATE
83 #include <sys/param.h>
84 #include <sys/queue.h>
86 #include <sys/systm.h>
90 #include <sys/atomic.h>
91 #include <sys/ksyms.h>
93 #include <uvm/uvm_extern.h>
96 #include <ddb/db_output.h>
101 static int ksyms_maxlen
;
102 static bool ksyms_isopen
;
103 static bool ksyms_initted
;
104 static struct ksyms_hdr ksyms_hdr
;
105 static kmutex_t ksyms_lock
;
107 void ksymsattach(int);
108 static void ksyms_hdr_init(void *);
109 static void ksyms_sizes_calc(void);
112 #define FOLLOW_CALLS 1
113 #define FOLLOW_MORE_CALLS 2
114 #define FOLLOW_DEVKSYMS 4
115 static int ksyms_debug
;
119 #define SYMTAB_FILLER "|This is the symbol table!"
121 char db_symtab
[SYMTAB_SPACE
] = SYMTAB_FILLER
;
122 int db_symtabsize
= SYMTAB_SPACE
;
127 TAILQ_HEAD(, ksyms_symtab
) ksyms_symtabs
=
128 TAILQ_HEAD_INITIALIZER(ksyms_symtabs
);
129 static struct ksyms_symtab kernel_symtab
;
132 ksyms_verify(void *symstart
, void *strstart
)
134 #if defined(DIAGNOSTIC) || defined(DEBUG)
135 if (symstart
== NULL
)
136 printf("ksyms: Symbol table not found\n");
137 if (strstart
== NULL
)
138 printf("ksyms: String table not found\n");
139 if (symstart
== NULL
|| strstart
== NULL
)
140 printf("ksyms: Perhaps the kernel is stripped?\n");
142 if (symstart
== NULL
|| strstart
== NULL
)
148 * Finds a certain symbol name in a certain symbol table.
151 findsym(const char *name
, struct ksyms_symtab
*table
, int type
)
153 Elf_Sym
*sym
, *maxsym
;
154 int low
, mid
, high
, nglob
;
157 sym
= table
->sd_symstart
;
158 str
= table
->sd_strstart
- table
->sd_usroffset
;
159 nglob
= table
->sd_nglob
;
164 * Start with a binary search of all global symbols in this table.
165 * Global symbols must have unique names.
168 mid
= (low
+ high
) >> 1;
169 cmp
= sym
[mid
].st_name
+ str
;
170 if (cmp
[0] < name
[0] || strcmp(cmp
, name
) < 0) {
176 KASSERT(low
== high
);
177 if (__predict_true(low
< nglob
&&
178 strcmp(sym
[low
].st_name
+ str
, name
) == 0)) {
179 KASSERT(ELF_ST_BIND(sym
[low
].st_info
) == STB_GLOBAL
);
184 * Perform a linear search of local symbols (rare). Many local
185 * symbols with the same name can exist so are not included in
188 if (type
!= KSYMS_EXTERN
) {
189 maxsym
= sym
+ table
->sd_symsize
/ sizeof(Elf_Sym
);
190 for (sym
+= nglob
; sym
< maxsym
; sym
++) {
191 if (strcmp(name
, sym
->st_name
+ str
) == 0) {
200 * The "attach" is in reality done in ksyms_init().
213 if (!ksyms_initted
&&
214 strncmp(db_symtab
, SYMTAB_FILLER
, sizeof(SYMTAB_FILLER
))) {
215 ksyms_addsyms_elf(db_symtabsize
, db_symtab
,
216 db_symtab
+ db_symtabsize
);
220 mutex_init(&ksyms_lock
, MUTEX_DEFAULT
, IPL_NONE
);
224 * Add a symbol table.
225 * This is intended for use when the symbol table and its corresponding
226 * string table are easily available. If they are embedded in an ELF
227 * image, use addsymtab_elf() instead.
229 * name - Symbol's table name.
230 * symstart, symsize - Address and size of the symbol table.
231 * strstart, strsize - Address and size of the string table.
232 * tab - Symbol table to be updated with this information.
233 * newstart - Address to which the symbol table has to be copied during
234 * shrinking. If NULL, it is not moved.
236 static const char *addsymtab_strstart
;
239 addsymtab_compar(const void *a
, const void *b
)
241 const Elf_Sym
*sa
, *sb
;
247 * Split the symbol table into two, with globals at the start
248 * and locals at the end.
250 if (ELF_ST_BIND(sa
->st_info
) != ELF_ST_BIND(sb
->st_info
)) {
251 if (ELF_ST_BIND(sa
->st_info
) == STB_GLOBAL
) {
254 if (ELF_ST_BIND(sb
->st_info
) == STB_GLOBAL
) {
259 /* Within each band, sort by name. */
260 return strcmp(sa
->st_name
+ addsymtab_strstart
,
261 sb
->st_name
+ addsymtab_strstart
);
265 addsymtab(const char *name
, void *symstart
, size_t symsize
,
266 void *strstart
, size_t strsize
, struct ksyms_symtab
*tab
,
269 Elf_Sym
*sym
, *nsym
, ts
;
273 tab
->sd_symstart
= symstart
;
274 tab
->sd_symsize
= symsize
;
275 tab
->sd_strstart
= strstart
;
276 tab
->sd_strsize
= strsize
;
278 tab
->sd_minsym
= UINTPTR_MAX
;
280 tab
->sd_usroffset
= 0;
281 tab
->sd_gone
= false;
283 printf("newstart %p sym %p ksyms_symsz %d str %p strsz %d send %p\n",
284 newstart
, symstart
, symsize
, strstart
, strsize
,
285 tab
->sd_strstart
+ tab
->sd_strsize
);
288 /* Pack symbol table by removing all file name references. */
289 sym
= tab
->sd_symstart
;
290 nsym
= (Elf_Sym
*)newstart
;
291 str
= tab
->sd_strstart
;
293 for (i
= n
= 0; i
< tab
->sd_symsize
/sizeof(Elf_Sym
); i
++) {
295 * Remove useless symbols.
296 * Should actually remove all typeless symbols.
298 if (sym
[i
].st_name
== 0)
299 continue; /* Skip nameless entries */
300 if (sym
[i
].st_shndx
== SHN_UNDEF
)
301 continue; /* Skip external references */
302 if (ELF_ST_TYPE(sym
[i
].st_info
) == STT_FILE
)
303 continue; /* Skip filenames */
304 if (ELF_ST_TYPE(sym
[i
].st_info
) == STT_NOTYPE
&&
305 sym
[i
].st_value
== 0 &&
306 strcmp(str
+ sym
[i
].st_name
, "*ABS*") == 0)
308 if (ELF_ST_TYPE(sym
[i
].st_info
) == STT_NOTYPE
&&
309 strcmp(str
+ sym
[i
].st_name
, "gcc2_compiled.") == 0)
312 /* Save symbol. Set it as an absolute offset */
314 nsym
[n
].st_shndx
= SHBSS
;
315 j
= strlen(nsym
[n
].st_name
+ str
) + 1;
316 if (j
> ksyms_maxlen
)
318 nglob
+= (ELF_ST_BIND(nsym
[n
].st_info
) == STB_GLOBAL
);
320 /* Compute min and max symbols. */
321 if (nsym
[n
].st_value
< tab
->sd_minsym
) {
322 tab
->sd_minsym
= nsym
[n
].st_value
;
324 if (nsym
[n
].st_value
> tab
->sd_maxsym
) {
325 tab
->sd_maxsym
= nsym
[n
].st_value
;
330 /* Fill the rest of the record, and sort the symbols. */
331 tab
->sd_symstart
= nsym
;
332 tab
->sd_symsize
= n
* sizeof(Elf_Sym
);
333 tab
->sd_nglob
= nglob
;
334 addsymtab_strstart
= str
;
335 if (kheapsort(nsym
, n
, sizeof(Elf_Sym
), addsymtab_compar
, &ts
) != 0)
338 /* ksymsread() is unlocked, so membar. */
340 TAILQ_INSERT_TAIL(&ksyms_symtabs
, tab
, sd_queue
);
342 ksyms_initted
= true;
346 * Setup the kernel symbol table stuff.
349 ksyms_addsyms_elf(int symsize
, void *start
, void *end
)
353 char *symstart
= NULL
, *strstart
= NULL
;
358 printf("[ Kernel symbol table missing! ]\n");
363 if (ALIGNED_POINTER(start
, long) == 0) {
364 printf("[ Kernel symbol table has bad start address %p ]\n",
369 ehdr
= (Elf_Ehdr
*)start
;
371 /* check if this is a valid ELF header */
372 /* No reason to verify arch type, the kernel is actually running! */
373 if (memcmp(ehdr
->e_ident
, ELFMAG
, SELFMAG
) ||
374 ehdr
->e_ident
[EI_CLASS
] != ELFCLASS
||
375 ehdr
->e_version
> 1) {
376 printf("[ Kernel symbol table invalid! ]\n");
377 return; /* nothing to do */
380 /* Loaded header will be scratched in addsymtab */
381 ksyms_hdr_init(start
);
383 /* Find the symbol table and the corresponding string table. */
384 shdr
= (Elf_Shdr
*)((uint8_t *)start
+ ehdr
->e_shoff
);
385 for (i
= 1; i
< ehdr
->e_shnum
; i
++) {
386 if (shdr
[i
].sh_type
!= SHT_SYMTAB
)
388 if (shdr
[i
].sh_offset
== 0)
390 symstart
= (uint8_t *)start
+ shdr
[i
].sh_offset
;
391 symsize
= shdr
[i
].sh_size
;
393 if (shdr
[j
].sh_offset
== 0)
394 continue; /* Can this happen? */
395 strstart
= (uint8_t *)start
+ shdr
[j
].sh_offset
;
396 strsize
= shdr
[j
].sh_size
;
400 if (!ksyms_verify(symstart
, strstart
))
402 addsymtab("netbsd", symstart
, symsize
, strstart
, strsize
,
403 &kernel_symtab
, start
);
406 printf("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
407 kernel_symtab
.sd_symstart
, kernel_symtab
.sd_strstart
,
408 (long)kernel_symtab
.sd_symsize
/sizeof(Elf_Sym
));
413 * Setup the kernel symbol table stuff.
414 * Use this when the address of the symbol and string tables are known;
415 * otherwise use ksyms_init with an ELF image.
416 * We need to pass a minimal ELF header which will later be completed by
417 * ksyms_hdr_init and handed off to userland through /dev/ksyms. We use
418 * a void *rather than a pointer to avoid exposing the Elf_Ehdr type.
421 ksyms_addsyms_explicit(void *ehdr
, void *symstart
, size_t symsize
,
422 void *strstart
, size_t strsize
)
425 if (!ksyms_verify(symstart
, strstart
))
428 ksyms_hdr_init(ehdr
);
429 addsymtab("netbsd", symstart
, symsize
, strstart
, strsize
,
430 &kernel_symtab
, symstart
);
434 * Get the value associated with a symbol.
435 * "mod" is the module name, or null if any module.
436 * "sym" is the symbol name.
437 * "val" is a pointer to the corresponding value, if call succeeded.
438 * Returns 0 if success or ENOENT if no such entry.
440 * Call with ksyms_lock, unless known that the symbol table can't change.
443 ksyms_getval_unlocked(const char *mod
, const char *sym
, unsigned long *val
,
446 struct ksyms_symtab
*st
;
450 if (ksyms_debug
& FOLLOW_CALLS
)
451 printf("ksyms_getval_unlocked: mod %s sym %s valp %p\n",
455 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
456 if (__predict_false(st
->sd_gone
))
458 if (mod
!= NULL
&& strcmp(st
->sd_name
, mod
))
460 if ((es
= findsym(sym
, st
, type
)) != NULL
) {
469 ksyms_getval(const char *mod
, const char *sym
, unsigned long *val
, int type
)
476 mutex_enter(&ksyms_lock
);
477 rc
= ksyms_getval_unlocked(mod
, sym
, val
, type
);
478 mutex_exit(&ksyms_lock
);
483 * Get "mod" and "symbol" associated with an address.
484 * Returns 0 if success or ENOENT if no such entry.
486 * Call with ksyms_lock, unless known that the symbol table can't change.
489 ksyms_getname(const char **mod
, const char **sym
, vaddr_t v
, int f
)
491 struct ksyms_symtab
*st
;
492 Elf_Sym
*les
, *es
= NULL
;
494 const char *lmod
= NULL
;
501 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
504 if (v
< st
->sd_minsym
|| v
> st
->sd_maxsym
)
506 sz
= st
->sd_symsize
/sizeof(Elf_Sym
);
507 for (i
= 0; i
< sz
; i
++) {
508 les
= st
->sd_symstart
+ i
;
509 type
= ELF_ST_TYPE(les
->st_info
);
511 if ((f
& KSYMS_PROC
) && (type
!= STT_FUNC
))
514 if (type
== STT_NOTYPE
)
517 if (((f
& KSYMS_ANY
) == 0) &&
518 (type
!= STT_FUNC
) && (type
!= STT_OBJECT
))
521 if ((les
->st_value
<= v
) && (les
->st_value
> laddr
)) {
522 laddr
= les
->st_value
;
525 stable
= st
->sd_strstart
- st
->sd_usroffset
;
531 if ((f
& KSYMS_EXACT
) && (v
!= es
->st_value
))
536 *sym
= stable
+ es
->st_name
;
541 * Add a symbol table from a loadable module.
544 ksyms_modload(const char *name
, void *symstart
, vsize_t symsize
,
545 char *strstart
, vsize_t strsize
)
547 struct ksyms_symtab
*st
;
549 st
= kmem_zalloc(sizeof(*st
), KM_SLEEP
);
550 mutex_enter(&ksyms_lock
);
551 addsymtab(name
, symstart
, symsize
, strstart
, strsize
, st
, symstart
);
552 mutex_exit(&ksyms_lock
);
556 * Remove a symbol table from a loadable module.
559 ksyms_modunload(const char *name
)
561 struct ksyms_symtab
*st
;
563 mutex_enter(&ksyms_lock
);
564 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
567 if (strcmp(name
, st
->sd_name
) != 0)
571 TAILQ_REMOVE(&ksyms_symtabs
, st
, sd_queue
);
573 kmem_free(st
, sizeof(*st
));
577 mutex_exit(&ksyms_lock
);
583 * Keep sifting stuff here, to avoid export of ksyms internals.
585 * Systems is expected to be quiescent, so no locking done.
588 ksyms_sift(char *mod
, char *sym
, int mode
)
590 struct ksyms_symtab
*st
;
597 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
600 if (mod
&& strcmp(mod
, st
->sd_name
))
602 sb
= st
->sd_strstart
- st
->sd_usroffset
;
604 sz
= st
->sd_symsize
/sizeof(Elf_Sym
);
605 for (i
= 0; i
< sz
; i
++) {
606 Elf_Sym
*les
= st
->sd_symstart
+ i
;
609 if (strstr(sb
+ les
->st_name
, sym
) == NULL
)
613 switch (ELF_ST_TYPE(les
->st_info
)) {
630 db_printf("%s%c ", sb
+ les
->st_name
, c
);
632 db_printf("%s ", sb
+ les
->st_name
);
640 * In case we exposing the symbol table to the userland using the pseudo-
641 * device /dev/ksyms, it is easier to provide all the tables as one.
642 * However, it means we have to change all the st_name fields for the
643 * symbols so they match the ELF image that the userland will read
644 * through the device.
646 * The actual (correct) value of st_name is preserved through a global
647 * offset stored in the symbol table structure.
649 * Call with ksyms_lock held.
652 ksyms_sizes_calc(void)
654 struct ksyms_symtab
*st
;
657 ksyms_symsz
= ksyms_strsz
= 0;
658 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
659 delta
= ksyms_strsz
- st
->sd_usroffset
;
661 for (i
= 0; i
< st
->sd_symsize
/sizeof(Elf_Sym
); i
++)
662 st
->sd_symstart
[i
].st_name
+= delta
;
663 st
->sd_usroffset
= ksyms_strsz
;
665 ksyms_symsz
+= st
->sd_symsize
;
666 ksyms_strsz
+= st
->sd_strsize
;
671 ksyms_hdr_init(void *hdraddr
)
674 /* Copy the loaded elf exec header */
675 memcpy(&ksyms_hdr
.kh_ehdr
, hdraddr
, sizeof(Elf_Ehdr
));
677 /* Set correct program/section header sizes, offsets and numbers */
678 ksyms_hdr
.kh_ehdr
.e_phoff
= offsetof(struct ksyms_hdr
, kh_phdr
[0]);
679 ksyms_hdr
.kh_ehdr
.e_phentsize
= sizeof(Elf_Phdr
);
680 ksyms_hdr
.kh_ehdr
.e_phnum
= NPRGHDR
;
681 ksyms_hdr
.kh_ehdr
.e_shoff
= offsetof(struct ksyms_hdr
, kh_shdr
[0]);
682 ksyms_hdr
.kh_ehdr
.e_shentsize
= sizeof(Elf_Shdr
);
683 ksyms_hdr
.kh_ehdr
.e_shnum
= NSECHDR
;
684 ksyms_hdr
.kh_ehdr
.e_shstrndx
= SHSTRTAB
;
686 /* Text/data - fake */
687 ksyms_hdr
.kh_phdr
[0].p_type
= PT_LOAD
;
688 ksyms_hdr
.kh_phdr
[0].p_memsz
= (unsigned long)-1L;
689 ksyms_hdr
.kh_phdr
[0].p_flags
= PF_R
| PF_X
| PF_W
;
691 /* First section is null */
693 /* Second section header; ".symtab" */
694 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_name
= 1; /* Section 3 offset */
695 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_type
= SHT_SYMTAB
;
696 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_offset
= sizeof(struct ksyms_hdr
);
697 /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */
698 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_link
= 2; /* Corresponding strtab */
699 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_addralign
= sizeof(long);
700 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_entsize
= sizeof(Elf_Sym
);
702 /* Third section header; ".strtab" */
703 ksyms_hdr
.kh_shdr
[STRTAB
].sh_name
= 9; /* Section 3 offset */
704 ksyms_hdr
.kh_shdr
[STRTAB
].sh_type
= SHT_STRTAB
;
705 /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */
706 /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */
707 ksyms_hdr
.kh_shdr
[STRTAB
].sh_addralign
= sizeof(char);
709 /* Fourth section, ".shstrtab" */
710 ksyms_hdr
.kh_shdr
[SHSTRTAB
].sh_name
= 17; /* This section name offset */
711 ksyms_hdr
.kh_shdr
[SHSTRTAB
].sh_type
= SHT_STRTAB
;
712 ksyms_hdr
.kh_shdr
[SHSTRTAB
].sh_offset
=
713 offsetof(struct ksyms_hdr
, kh_strtab
);
714 ksyms_hdr
.kh_shdr
[SHSTRTAB
].sh_size
= SHSTRSIZ
;
715 ksyms_hdr
.kh_shdr
[SHSTRTAB
].sh_addralign
= sizeof(char);
717 /* Fifth section, ".bss". All symbols reside here. */
718 ksyms_hdr
.kh_shdr
[SHBSS
].sh_name
= 27; /* This section name offset */
719 ksyms_hdr
.kh_shdr
[SHBSS
].sh_type
= SHT_NOBITS
;
720 ksyms_hdr
.kh_shdr
[SHBSS
].sh_offset
= 0;
721 ksyms_hdr
.kh_shdr
[SHBSS
].sh_size
= (unsigned long)-1L;
722 ksyms_hdr
.kh_shdr
[SHBSS
].sh_addralign
= PAGE_SIZE
;
723 ksyms_hdr
.kh_shdr
[SHBSS
].sh_flags
= SHF_ALLOC
| SHF_EXECINSTR
;
725 /* Set section names */
726 strlcpy(&ksyms_hdr
.kh_strtab
[1], ".symtab",
727 sizeof(ksyms_hdr
.kh_strtab
) - 1);
728 strlcpy(&ksyms_hdr
.kh_strtab
[9], ".strtab",
729 sizeof(ksyms_hdr
.kh_strtab
) - 9);
730 strlcpy(&ksyms_hdr
.kh_strtab
[17], ".shstrtab",
731 sizeof(ksyms_hdr
.kh_strtab
) - 17);
732 strlcpy(&ksyms_hdr
.kh_strtab
[27], ".bss",
733 sizeof(ksyms_hdr
.kh_strtab
) - 27);
737 ksymsopen(dev_t dev
, int oflags
, int devtype
, struct lwp
*l
)
740 if (minor(dev
) != 0 || !ksyms_initted
)
744 * Create a "snapshot" of the kernel symbol table. Setting
745 * ksyms_isopen will prevent symbol tables from being freed.
747 mutex_enter(&ksyms_lock
);
748 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_size
= ksyms_symsz
;
749 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_info
= ksyms_symsz
/ sizeof(Elf_Sym
);
750 ksyms_hdr
.kh_shdr
[STRTAB
].sh_offset
= ksyms_symsz
+
751 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_offset
;
752 ksyms_hdr
.kh_shdr
[STRTAB
].sh_size
= ksyms_strsz
;
754 mutex_exit(&ksyms_lock
);
760 ksymsclose(dev_t dev
, int oflags
, int devtype
, struct lwp
*l
)
762 struct ksyms_symtab
*st
, *next
;
765 /* Discard refernces to symbol tables. */
766 mutex_enter(&ksyms_lock
);
767 ksyms_isopen
= false;
769 for (st
= TAILQ_FIRST(&ksyms_symtabs
); st
!= NULL
; st
= next
) {
770 next
= TAILQ_NEXT(st
, sd_queue
);
772 TAILQ_REMOVE(&ksyms_symtabs
, st
, sd_queue
);
773 kmem_free(st
, sizeof(*st
));
779 mutex_exit(&ksyms_lock
);
785 ksymsread(dev_t dev
, struct uio
*uio
, int ioflag
)
787 struct ksyms_symtab
*st
;
788 size_t filepos
, inpos
, off
;
792 * First: Copy out the ELF header. XXX Lose if ksymsopen()
793 * occurs during read of the header.
795 off
= uio
->uio_offset
;
796 if (off
< sizeof(struct ksyms_hdr
)) {
797 error
= uiomove((char *)&ksyms_hdr
+ off
,
798 sizeof(struct ksyms_hdr
) - off
, uio
);
804 * Copy out the symbol table.
806 filepos
= sizeof(struct ksyms_hdr
);
807 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
808 if (uio
->uio_resid
== 0)
810 if (uio
->uio_offset
<= st
->sd_symsize
+ filepos
) {
811 inpos
= uio
->uio_offset
- filepos
;
812 error
= uiomove((char *)st
->sd_symstart
+ inpos
,
813 st
->sd_symsize
- inpos
, uio
);
817 filepos
+= st
->sd_symsize
;
821 * Copy out the string table
823 KASSERT(filepos
== sizeof(struct ksyms_hdr
) +
824 ksyms_hdr
.kh_shdr
[SYMTAB
].sh_size
);
825 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
826 if (uio
->uio_resid
== 0)
828 if (uio
->uio_offset
<= st
->sd_strsize
+ filepos
) {
829 inpos
= uio
->uio_offset
- filepos
;
830 error
= uiomove((char *)st
->sd_strstart
+ inpos
,
831 st
->sd_strsize
- inpos
, uio
);
835 filepos
+= st
->sd_strsize
;
842 ksymswrite(dev_t dev
, struct uio
*uio
, int ioflag
)
849 ksymsioctl(dev_t dev
, u_long cmd
, void *data
, int fflag
, struct lwp
*l
)
851 struct ksyms_gsymbol
*kg
= (struct ksyms_gsymbol
*)data
;
852 struct ksyms_symtab
*st
;
853 Elf_Sym
*sym
= NULL
, copy
;
859 /* Read ksyms_maxlen only once while not holding the lock. */
862 if (cmd
== KIOCGVALUE
|| cmd
== KIOCGSYMBOL
) {
863 str
= kmem_alloc(len
, KM_SLEEP
);
864 if ((error
= copyinstr(kg
->kg_name
, str
, len
, NULL
)) != 0) {
873 * Use the in-kernel symbol lookup code for fast
874 * retreival of a value.
876 error
= ksyms_getval(NULL
, str
, &val
, KSYMS_EXTERN
);
878 error
= copyout(&val
, kg
->kg_value
, sizeof(long));
884 * Use the in-kernel symbol lookup code for fast
885 * retreival of a symbol.
887 mutex_enter(&ksyms_lock
);
888 TAILQ_FOREACH(st
, &ksyms_symtabs
, sd_queue
) {
891 if ((sym
= findsym(str
, st
, KSYMS_ANY
)) == NULL
)
894 /* Skip if bad binding */
895 if (ELF_ST_BIND(sym
->st_info
) != STB_GLOBAL
) {
903 memcpy(©
, sym
, sizeof(copy
));
904 mutex_exit(&ksyms_lock
);
905 error
= copyout(©
, kg
->kg_sym
, sizeof(Elf_Sym
));
907 mutex_exit(&ksyms_lock
);
915 * Get total size of symbol table.
917 mutex_enter(&ksyms_lock
);
918 *(int *)data
= ksyms_strsz
+ ksyms_symsz
+
919 sizeof(struct ksyms_hdr
);
920 mutex_exit(&ksyms_lock
);
931 const struct cdevsw ksyms_cdevsw
= {
932 ksymsopen
, ksymsclose
, ksymsread
, ksymswrite
, ksymsioctl
,
933 nullstop
, notty
, nopoll
, nommap
, nullkqfilter
, D_OTHER
| D_MPSAFE