The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_ksyms.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_ksyms.c,v 1.41.4.2 2010/02/14 13:35:43 bouyer 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  *      Consider replacing patricia tree with simpler binary search
   71  *      for symbol tables.
   72  *
   73  *      Add support for mmap, poll.
   74  */
   75 
   76 #include <sys/cdefs.h>
   77 __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.41.4.2 2010/02/14 13:35:43 bouyer Exp $");
   78 
   79 #ifdef _KERNEL
   80 #include "opt_ddb.h"
   81 #include "opt_ddbparam.h"       /* for SYMTAB_SPACE */
   82 #endif
   83 
   84 #define _KSYMS_PRIVATE
   85 
   86 #include <sys/param.h>
   87 #include <sys/errno.h>
   88 #include <sys/queue.h>
   89 #include <sys/exec.h>
   90 #include <sys/systm.h>
   91 #include <sys/conf.h>
   92 #include <sys/malloc.h>
   93 #include <sys/kmem.h>
   94 #include <sys/proc.h>
   95 #include <sys/module.h>
   96 #include <sys/atomic.h>
   97 #include <sys/ksyms.h>
   98 
   99 #include <lib/libkern/libkern.h>
  100 
  101 #ifdef DDB
  102 #include <ddb/db_output.h>
  103 #endif
  104 
  105 #include "ksyms.h"
  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 TAILQ_HEAD(, ksyms_symtab) ksyms_symtabs =
  134     TAILQ_HEAD_INITIALIZER(ksyms_symtabs);
  135 static struct ksyms_symtab kernel_symtab;
  136 
  137 /*
  138  * Patricia-tree-based lookup structure for the in-kernel global symbols.
  139  * Based on a design by Mikael Sundstrom, msm@sm.luth.se.
  140  */
  141 struct ptree {
  142         int16_t bitno;
  143         int16_t lr[2];
  144 } *symb;
  145 static int16_t baseidx;
  146 static int treex = 1;
  147 
  148 #define P_BIT(key, bit) ((key[bit >> 3] >> (bit & 7)) & 1)
  149 #define STRING(idx) (kernel_symtab.sd_symstart[idx].st_name + \
  150                         kernel_symtab.sd_strstart)
  151 
  152 static int
  153 ksyms_verify(void *symstart, void *strstart)
  154 {
  155 #if defined(DIAGNOSTIC) || defined(DEBUG)
  156         if (symstart == NULL)
  157                 printf("ksyms: Symbol table not found\n");
  158         if (strstart == NULL)
  159                 printf("ksyms: String table not found\n");
  160         if (symstart == NULL || strstart == NULL)
  161                 printf("ksyms: Perhaps the kernel is stripped?\n");
  162 #endif
  163         if (symstart == NULL || strstart == NULL)
  164                 return 0;
  165         KASSERT(symstart <= strstart);
  166         return 1;
  167 }
  168 
  169 /*
  170  * Walk down the tree until a terminal node is found.
  171  */
  172 static int
  173 symbol_traverse(const char *key)
  174 {
  175         int16_t nb, rbit = baseidx;
  176 
  177         while (rbit > 0) {
  178                 nb = symb[rbit].bitno;
  179                 rbit = symb[rbit].lr[P_BIT(key, nb)];
  180         }
  181         return -rbit;
  182 }
  183 
  184 static int
  185 ptree_add(char *key, int val)
  186 {
  187         int idx;
  188         int nix, cix, bit, rbit, sb, lastrbit, svbit = 0, ix;
  189         char *m, *k;
  190 
  191         if (baseidx == 0) {
  192                 baseidx = -val;
  193                 return 0; /* First element */
  194         }
  195 
  196         /* Get string to match against */
  197         idx = symbol_traverse(key);
  198 
  199         /* Find first mismatching bit */
  200         m = STRING(idx);
  201         k = key;
  202         if (strcmp(m, k) == 0)
  203                 return 1;
  204 
  205         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += 8)
  206                 ;
  207         ix = ffs((int)*m ^ (int)*k) - 1;
  208         cix += ix;
  209 
  210         /* Create new node */
  211         nix = treex++;
  212         bit = P_BIT(key, cix);
  213         symb[nix].bitno = cix;
  214         symb[nix].lr[bit] = -val;
  215 
  216         /* Find where to insert node */
  217         rbit = baseidx;
  218         lastrbit = 0;
  219         for (;;) {
  220                 if (rbit < 0)
  221                         break;
  222                 sb = symb[rbit].bitno;
  223                 if (sb > cix)
  224                         break;
  225                 if (sb == cix)
  226                         printf("symb[rbit].bitno == cix!!!\n");
  227                 lastrbit = rbit;
  228                 svbit = P_BIT(key, sb);
  229                 rbit = symb[rbit].lr[svbit];
  230         }
  231 
  232         /* Do the actual insertion */
  233         if (lastrbit == 0) {
  234                 /* first element */
  235                 symb[nix].lr[!bit] = baseidx;
  236                 baseidx = nix;
  237         } else {
  238                 symb[nix].lr[!bit] = rbit;
  239                 symb[lastrbit].lr[svbit] = nix;
  240         }
  241         return 0;
  242 }
  243 
  244 static int
  245 ptree_find(const char *key)
  246 {
  247         int idx;
  248 
  249         if (baseidx == 0)
  250                 return 0;
  251         idx = symbol_traverse(key);
  252 
  253         if (strcmp(key, STRING(idx)) == 0)
  254                 return idx;
  255         return 0;
  256 }
  257 
  258 static void
  259 ptree_gen(char *off, struct ksyms_symtab *tab)
  260 {
  261         Elf_Sym *sym;
  262         int i, nsym;
  263 
  264         if (off != NULL)
  265                 symb = (struct ptree *)ALIGN(off);
  266         else
  267                 symb = malloc((tab->sd_symsize/sizeof(Elf_Sym)) *
  268                     sizeof(struct ptree), M_DEVBUF, M_WAITOK);
  269         symb--; /* sym index won't be 0 */
  270 
  271         sym = tab->sd_symstart;
  272         if ((nsym = tab->sd_symsize/sizeof(Elf_Sym)) > INT16_MAX) {
  273                 printf("Too many symbols for tree, skipping %d symbols\n",
  274                     nsym-INT16_MAX);
  275                 nsym = INT16_MAX;
  276         }
  277         for (i = 1; i < nsym; i++) {
  278                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  279                         continue;
  280                 ptree_add(tab->sd_strstart+sym[i].st_name, i);
  281                 if (tab->sd_minsym == NULL ||
  282                     sym[i].st_value < tab->sd_minsym->st_value)
  283                         tab->sd_minsym = &sym[i];
  284                 if (tab->sd_maxsym == NULL ||
  285                     sym[i].st_value > tab->sd_maxsym->st_value)
  286                         tab->sd_maxsym = &sym[i];
  287         }
  288 }
  289 
  290 /*
  291  * Finds a certain symbol name in a certain symbol table.
  292  */
  293 static Elf_Sym *
  294 findsym(const char *name, struct ksyms_symtab *table)
  295 {
  296         Elf_Sym *start = table->sd_symstart;
  297         int i, sz = table->sd_symsize/sizeof(Elf_Sym);
  298         char *np;
  299         char *realstart = table->sd_strstart - table->sd_usroffset;
  300 
  301         if (table == &kernel_symtab && (i = ptree_find(name)) != 0)
  302                 return &start[i];
  303 
  304         for (i = 0; i < sz; i++) {
  305                 np = realstart + start[i].st_name;
  306                 if (name[0] == np[0] && name[1] == np[1] &&
  307                     strcmp(name, np) == 0)
  308                         return &start[i];
  309         }
  310         return NULL;
  311 }
  312 
  313 /*
  314  * The "attach" is in reality done in ksyms_init().
  315  */
  316 void
  317 ksymsattach(int arg)
  318 {
  319         if (baseidx == 0)
  320                 ptree_gen(0, &kernel_symtab);
  321 }
  322 
  323 /*
  324  * Add a symbol table.
  325  * This is intended for use when the symbol table and its corresponding
  326  * string table are easily available.  If they are embedded in an ELF
  327  * image, use addsymtab_elf() instead.
  328  *
  329  * name - Symbol's table name.
  330  * symstart, symsize - Address and size of the symbol table.
  331  * strstart, strsize - Address and size of the string table.
  332  * tab - Symbol table to be updated with this information.
  333  * newstart - Address to which the symbol table has to be copied during
  334  *            shrinking.  If NULL, it is not moved.
  335  */
  336 static void
  337 addsymtab(const char *name, void *symstart, size_t symsize,
  338           void *strstart, size_t strsize, struct ksyms_symtab *tab,
  339           void *newstart)
  340 {
  341         Elf_Sym *sym, *nsym;
  342         int i, j, n;
  343         char *str;
  344 
  345         tab->sd_symstart = symstart;
  346         tab->sd_symsize = symsize;
  347         tab->sd_strstart = strstart;
  348         tab->sd_strsize = strsize;
  349         tab->sd_name = name;
  350         tab->sd_minsym = NULL;
  351         tab->sd_maxsym = NULL;
  352         tab->sd_usroffset = 0;
  353         tab->sd_gone = false;
  354         tab->sd_malloc = false; /* XXXLKM */
  355 #ifdef KSYMS_DEBUG
  356         printf("newstart %p sym %p ksyms_symsz %d str %p strsz %d send %p\n",
  357             newstart, symstart, symsize, strstart, strsize,
  358             tab->sd_strstart + tab->sd_strsize);
  359 #endif
  360 
  361         /* Pack symbol table by removing all file name references. */
  362         sym = tab->sd_symstart;
  363         nsym = (Elf_Sym *)newstart;
  364         str = tab->sd_strstart;
  365         for (i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
  366                 /*
  367                  * Remove useless symbols.
  368                  * Should actually remove all typeless symbols.
  369                  */
  370                 if (sym[i].st_name == 0)
  371                         continue; /* Skip nameless entries */
  372                 if (sym[i].st_shndx == SHN_UNDEF)
  373                         continue; /* Skip external references */
  374                 if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE)
  375                         continue; /* Skip filenames */
  376                 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
  377                     sym[i].st_value == 0 &&
  378                     strcmp(str + sym[i].st_name, "*ABS*") == 0)
  379                         continue; /* XXX */
  380                 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
  381                     strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0)
  382                         continue; /* XXX */
  383 
  384                 /* Save symbol. Set it as an absolute offset */
  385                 nsym[n] = sym[i];
  386                 nsym[n].st_shndx = SHN_ABS;
  387                 j = strlen(nsym[n].st_name + tab->sd_strstart) + 1;
  388                 if (j > ksyms_maxlen)
  389                         ksyms_maxlen = j;
  390                 n++;
  391 
  392         }
  393         tab->sd_symstart = nsym;
  394         tab->sd_symsize = n * sizeof(Elf_Sym);
  395         /* ksymsread() is unlocked, so membar. */
  396         membar_producer();
  397         TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue);
  398         ksyms_sizes_calc();
  399         ksyms_initted = true;
  400 }
  401 
  402 void
  403 ksyms_init_finalize()
  404 {
  405         mutex_init(&ksyms_lock, MUTEX_DEFAULT, IPL_NONE);
  406 }
  407 
  408 /*
  409  * Setup the kernel symbol table stuff.
  410  */
  411 void
  412 ksyms_init(int symsize, void *start, void *end)
  413 {
  414         int i, j;
  415         Elf_Shdr *shdr;
  416         char *symstart = NULL, *strstart = NULL;
  417         size_t strsize = 0;
  418         Elf_Ehdr *ehdr;
  419 
  420 #ifdef SYMTAB_SPACE
  421         if (symsize <= 0 &&
  422             strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) {
  423                 symsize = db_symtabsize;
  424                 start = db_symtab;
  425                 end = db_symtab + db_symtabsize;
  426         }
  427 #endif
  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         if (!ksyms_verify(symstart, strstart))
  472                 return;
  473         addsymtab("netbsd", symstart, symsize, strstart, strsize,
  474             &kernel_symtab, start);
  475 
  476 #ifdef DEBUG
  477         aprint_normal("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
  478             kernel_symtab.sd_symstart, kernel_symtab.sd_strstart,
  479             (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym));
  480 #endif
  481 }
  482 
  483 /*
  484  * Setup the kernel symbol table stuff.
  485  * Use this when the address of the symbol and string tables are known;
  486  * otherwise use ksyms_init with an ELF image.
  487  * We need to pass a minimal ELF header which will later be completed by
  488  * ksyms_hdr_init and handed off to userland through /dev/ksyms.  We use
  489  * a void *rather than a pointer to avoid exposing the Elf_Ehdr type.
  490  */
  491 void
  492 ksyms_init_explicit(void *ehdr, void *symstart, size_t symsize,
  493                     void *strstart, size_t strsize)
  494 {
  495 
  496         if (!ksyms_verify(symstart, strstart))
  497                 return;
  498 
  499         ksyms_hdr_init(ehdr);
  500         addsymtab("netbsd", symstart, symsize, strstart, strsize,
  501             &kernel_symtab, symstart);
  502 }
  503 
  504 /*
  505  * Get the value associated with a symbol.
  506  * "mod" is the module name, or null if any module.
  507  * "sym" is the symbol name.
  508  * "val" is a pointer to the corresponding value, if call succeeded.
  509  * Returns 0 if success or ENOENT if no such entry.
  510  *
  511  * Call with ksyms_lock, unless known that the symbol table can't change.
  512  */
  513 int
  514 ksyms_getval_unlocked(const char *mod, const char *sym, unsigned long *val,
  515     int type)
  516 {
  517         struct ksyms_symtab *st;
  518         Elf_Sym *es;
  519 
  520         if (!ksyms_initted)
  521                 return ENOENT;
  522 
  523 #ifdef KSYMS_DEBUG
  524         if (ksyms_debug & FOLLOW_CALLS)
  525                 printf("ksyms_getval_unlocked: mod %s sym %s valp %p\n",
  526                     mod, sym, val);
  527 #endif
  528 
  529         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  530                 if (st->sd_gone)
  531                         continue;
  532                 if (mod && strcmp(st->sd_name, mod))
  533                         continue;
  534                 if ((es = findsym(sym, st)) == NULL)
  535                         continue;
  536                 if (es->st_shndx == SHN_UNDEF)
  537                         continue;
  538 
  539                 /* Skip if bad binding */
  540                 if (type == KSYMS_EXTERN &&
  541                     ELF_ST_BIND(es->st_info) != STB_GLOBAL)
  542                         continue;
  543 
  544                 if (val)
  545                         *val = es->st_value;
  546                 return 0;
  547         }
  548         return ENOENT;
  549 }
  550 
  551 int
  552 ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type)
  553 {
  554         int rc;
  555 
  556         mutex_enter(&ksyms_lock);
  557         rc = ksyms_getval_unlocked(mod, sym, val, type);
  558         mutex_exit(&ksyms_lock);
  559         return rc;
  560 }
  561 
  562 
  563 /*
  564  * Get "mod" and "symbol" associated with an address.
  565  * Returns 0 if success or ENOENT if no such entry.
  566  *
  567  * Call with ksyms_lock, unless known that the symbol table can't change.
  568  */
  569 int
  570 ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f)
  571 {
  572         struct ksyms_symtab *st;
  573         Elf_Sym *les, *es = NULL;
  574         vaddr_t laddr = 0;
  575         const char *lmod = NULL;
  576         char *stable = NULL;
  577         int type, i, sz;
  578 
  579         if (!ksyms_initted)
  580                 return ENOENT;
  581 
  582         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  583                 if (st->sd_gone)
  584                         continue;
  585                 if (st->sd_minsym != NULL && v < st->sd_minsym->st_value)
  586                         continue;
  587                 if (st->sd_maxsym != NULL && v > st->sd_maxsym->st_value)
  588                         continue;
  589                 sz = st->sd_symsize/sizeof(Elf_Sym);
  590                 for (i = 0; i < sz; i++) {
  591                         les = st->sd_symstart + i;
  592                         type = ELF_ST_TYPE(les->st_info);
  593 
  594                         if ((f & KSYMS_PROC) && (type != STT_FUNC))
  595                                 continue;
  596 
  597                         if (type == STT_NOTYPE)
  598                                 continue;
  599 
  600                         if (((f & KSYMS_ANY) == 0) &&
  601                             (type != STT_FUNC) && (type != STT_OBJECT))
  602                                 continue;
  603 
  604                         if ((les->st_value <= v) && (les->st_value > laddr)) {
  605                                 laddr = les->st_value;
  606                                 es = les;
  607                                 lmod = st->sd_name;
  608                                 stable = st->sd_strstart - st->sd_usroffset;
  609                         }
  610                 }
  611         }
  612         if (es == NULL)
  613                 return ENOENT;
  614         if ((f & KSYMS_EXACT) && (v != es->st_value))
  615                 return ENOENT;
  616         if (mod)
  617                 *mod = lmod;
  618         if (sym)
  619                 *sym = stable + es->st_name;
  620         return 0;
  621 }
  622 
  623 /*
  624  * Temporary work structure for dynamic loaded symbol tables.
  625  *
  626  * XXX REMOVE WHEN LKMS GO.
  627  */
  628 struct syminfo {
  629         size_t cursyms;
  630         size_t curnamep;
  631         size_t maxsyms;
  632         size_t maxnamep;
  633         Elf_Sym *syms;
  634         char *symnames;
  635 };
  636 
  637 /*
  638  * Add a symbol to the temporary save area for symbols.
  639  *
  640  * XXX REMOVE WHEN LKMS GO.
  641  */
  642 static void
  643 addsym(struct syminfo *info, const Elf_Sym *sym, const char *name,
  644        const char *mod)
  645 {
  646         int len, mlen;
  647 
  648 #ifdef KSYMS_DEBUG
  649         if (ksyms_debug & FOLLOW_MORE_CALLS)
  650                 printf("addsym: name %s val %lx\n", name, (long)sym->st_value);
  651 #endif
  652         len = strlen(name) + 1;
  653         if (mod)
  654                 mlen = 1 + strlen(mod);
  655         else
  656                 mlen = 0;
  657         if (info->cursyms == info->maxsyms ||
  658             (len + mlen + info->curnamep) > info->maxnamep) {
  659                 printf("addsym: too many symbols, skipping '%s'\n", name);
  660                 return;
  661         }
  662         strlcpy(&info->symnames[info->curnamep], name,
  663             info->maxnamep - info->curnamep);
  664         if (mlen) {
  665                 info->symnames[info->curnamep + len - 1] = '.';
  666                 strlcpy(&info->symnames[info->curnamep + len], mod,
  667                     info->maxnamep - (info->curnamep + len));
  668                 len += mlen;
  669         }
  670         info->syms[info->cursyms] = *sym;
  671         info->syms[info->cursyms].st_name = info->curnamep;
  672         info->curnamep += len;
  673         if (len > ksyms_maxlen)
  674                 ksyms_maxlen = len;
  675         info->cursyms++;
  676 }
  677 
  678 /*
  679  * XXX REMOVE WHEN LKMS GO.
  680  */
  681 static int
  682 specialsym(const char *symname)
  683 {
  684 
  685         return  !strcmp(symname, "_bss_start") ||
  686             !strcmp(symname, "__bss_start") ||
  687             !strcmp(symname, "_bss_end__") ||
  688             !strcmp(symname, "__bss_end__") ||
  689             !strcmp(symname, "_edata") ||
  690             !strcmp(symname, "_end") ||
  691             !strcmp(symname, "__end") ||
  692             !strcmp(symname, "__end__") ||
  693             !strncmp(symname, "__start_link_set_", 17) ||
  694             !strncmp(symname, "__stop_link_set_", 16);
  695 }
  696 
  697 /*
  698  * Adds a symbol table.
  699  * "name" is the module name, "start" and "size" is where the symbol table
  700  * is located, and "type" is in which binary format the symbol table is.
  701  * New memory for keeping the symbol table is allocated in this function.
  702  * Returns 0 if success and EEXIST if the module name is in use.
  703  *
  704  * XXX REMOVE WHEN LKMS GO.
  705  */
  706 int
  707 ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
  708                 char *strstart, vsize_t strsize)
  709 {
  710         Elf_Sym *sym = symstart;
  711         struct ksyms_symtab *st;
  712         unsigned long rval;
  713         int i;
  714         char *name;
  715         struct syminfo info;
  716 
  717 #ifdef KSYMS_DEBUG
  718         if (ksyms_debug & FOLLOW_CALLS)
  719                 printf("ksyms_addsymtab: mod %s symsize %lx strsize %lx\n",
  720                     mod, symsize, strsize);
  721 #endif
  722 
  723         mutex_enter(&ksyms_lock);
  724 
  725         /* Check if this symtab already loaded */
  726         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  727                 if (st->sd_gone)
  728                         continue;
  729                 if (strcmp(mod, st->sd_name) == 0) {
  730                         mutex_exit(&ksyms_lock);
  731                         return EEXIST;
  732                 }
  733         }
  734 
  735         /*
  736          * XXX - Only add a symbol if it do not exist already.
  737          * This is because of a flaw in the current LKM implementation,
  738          * these loops will be removed once the in-kernel linker is in place.
  739          */
  740         memset(&info, 0, sizeof(info));
  741         for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
  742                 char * const symname = strstart + sym[i].st_name;
  743                 if (sym[i].st_name == 0)
  744                         continue; /* Just ignore */
  745 
  746                 /* check validity of the symbol */
  747                 /* XXX - save local symbols if DDB */
  748                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  749                         continue;
  750 
  751                 /* Check if the symbol exists */
  752                 if (ksyms_getval_unlocked(NULL, symname, &rval, KSYMS_EXTERN)
  753                     == 0) {
  754                         /* Check (and complain) about differing values */
  755                         if (sym[i].st_value != rval &&
  756                             sym[i].st_shndx != SHN_UNDEF) {
  757                                 if (specialsym(symname)) {
  758                                         info.maxsyms++;
  759                                         info.maxnamep += strlen(symname) + 1 +
  760                                             strlen(mod) + 1;
  761                                 } else {
  762                                         printf("%s: symbol '%s' redeclared with"
  763                                             " different value (%lx != %lx)\n",
  764                                             mod, symname,
  765                                             rval, (long)sym[i].st_value);
  766                                 }
  767                         }
  768                 } else {
  769                         /*
  770                          * Count this symbol
  771                          */
  772                         info.maxsyms++;
  773                         info.maxnamep += strlen(symname) + 1;
  774                 }
  775         }
  776 
  777         /*
  778          * Now that we know the sizes, malloc the structures.
  779          */
  780         info.syms = malloc(sizeof(Elf_Sym)*info.maxsyms, M_DEVBUF, M_WAITOK);
  781         info.symnames = malloc(info.maxnamep, M_DEVBUF, M_WAITOK);
  782 
  783         /*
  784          * Now that we have the symbols, actually fill in the structures.
  785          */
  786         for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
  787                 char * const symname = strstart + sym[i].st_name;
  788                 if (sym[i].st_name == 0)
  789                         continue; /* Just ignore */
  790 
  791                 /* check validity of the symbol */
  792                 /* XXX - save local symbols if DDB */
  793                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  794                         continue;
  795 
  796                 /* Check if the symbol exists */
  797                 if (ksyms_getval_unlocked(NULL, symname, &rval, KSYMS_EXTERN)
  798                     == 0) {
  799                         if ((sym[i].st_value != rval) && specialsym(symname)) {
  800                                 addsym(&info, &sym[i], symname, mod);
  801                         }
  802                 } else
  803                         /* Ok, save this symbol */
  804                         addsym(&info, &sym[i], symname, NULL);
  805         }
  806 
  807         st = kmem_zalloc(sizeof(*st), KM_SLEEP);
  808         i = strlen(mod) + 1;
  809         name = malloc(i, M_DEVBUF, M_WAITOK);
  810         strlcpy(name, mod, i);
  811         st->sd_name = name;
  812         st->sd_symstart = info.syms;
  813         st->sd_symsize = sizeof(Elf_Sym)*info.maxsyms;
  814         st->sd_strstart = info.symnames;
  815         st->sd_strsize = info.maxnamep;
  816         st->sd_malloc = true;
  817 
  818         /* Make them absolute references */
  819         sym = st->sd_symstart;
  820         for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
  821                 sym[i].st_shndx = SHN_ABS;
  822 
  823         /* ksymsread() is unlocked, so membar. */
  824         membar_producer();
  825         TAILQ_INSERT_TAIL(&ksyms_symtabs, st, sd_queue);
  826         ksyms_sizes_calc();
  827         mutex_exit(&ksyms_lock);
  828 
  829         return 0;
  830 }
  831 
  832 /*
  833  * Remove a symbol table specified by name.
  834  * Returns 0 if success, EBUSY if device open and ENOENT if no such name.
  835  *
  836  * XXX REMOVE WHEN LKMS GO.
  837  */
  838 int
  839 ksyms_delsymtab(const char *mod)
  840 {
  841         struct ksyms_symtab *st;
  842 
  843         mutex_enter(&ksyms_lock);
  844         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  845                 if (st->sd_gone)
  846                         continue;
  847                 if (strcmp(mod, st->sd_name) != 0)
  848                         continue;
  849                 if (ksyms_isopen) {
  850                         st->sd_gone = true;
  851                         mutex_exit(&ksyms_lock);
  852                         return 0;
  853                 } 
  854                 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
  855                 ksyms_sizes_calc();
  856                 mutex_exit(&ksyms_lock);
  857                 KASSERT(st->sd_malloc);
  858                 free(st->sd_symstart, M_DEVBUF);
  859                 free(st->sd_strstart, M_DEVBUF);
  860                 /* XXXUNCONST LINTED - const castaway */
  861                 free(__UNCONST(st->sd_name), M_DEVBUF);
  862                 kmem_free(st, sizeof(*st));
  863                 return 0;
  864         }
  865         mutex_exit(&ksyms_lock);
  866         return ENOENT;
  867 }
  868 
  869 /*
  870  * Add a symbol table from a loadable module.
  871  */
  872 void
  873 ksyms_modload(const char *name, void *symstart, vsize_t symsize,
  874               char *strstart, vsize_t strsize)
  875 {
  876         struct ksyms_symtab *st;
  877 
  878         st = kmem_zalloc(sizeof(*st), KM_SLEEP);
  879         mutex_enter(&ksyms_lock);
  880         addsymtab(name, symstart, symsize, strstart, strsize, st, symstart);
  881         mutex_exit(&ksyms_lock);
  882 }
  883 
  884 /*
  885  * Remove a symbol table from a loadable module.
  886  */
  887 void
  888 ksyms_modunload(const char *name)
  889 {
  890         struct ksyms_symtab *st;
  891 
  892         mutex_enter(&ksyms_lock);
  893         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  894                 if (st->sd_gone)
  895                         continue;
  896                 if (strcmp(name, st->sd_name) != 0)
  897                         continue;
  898                 KASSERT(!st->sd_malloc);        /* XXXLKM */
  899                 st->sd_gone = true;
  900                 if (!ksyms_isopen) {
  901                         TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
  902                         ksyms_sizes_calc();
  903                         kmem_free(st, sizeof(*st));
  904                 }
  905                 break;
  906         }
  907         mutex_exit(&ksyms_lock);
  908         KASSERT(st != NULL);
  909 }
  910 
  911 #ifdef DDB
  912 /*
  913  * Keep sifting stuff here, to avoid export of ksyms internals.
  914  *
  915  * Systems is expected to be quiescent, so no locking done.
  916  */
  917 int
  918 ksyms_sift(char *mod, char *sym, int mode)
  919 {
  920         struct ksyms_symtab *st;
  921         char *sb;
  922         int i, sz;
  923 
  924         if (!ksyms_initted)
  925                 return ENOENT;
  926 
  927         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  928                 if (st->sd_gone)
  929                         continue;
  930                 if (mod && strcmp(mod, st->sd_name))
  931                         continue;
  932                 sb = st->sd_strstart - st->sd_usroffset;
  933 
  934                 sz = st->sd_symsize/sizeof(Elf_Sym);
  935                 for (i = 0; i < sz; i++) {
  936                         Elf_Sym *les = st->sd_symstart + i;
  937                         char c;
  938 
  939                         if (strstr(sb + les->st_name, sym) == NULL)
  940                                 continue;
  941 
  942                         if (mode == 'F') {
  943                                 switch (ELF_ST_TYPE(les->st_info)) {
  944                                 case STT_OBJECT:
  945                                         c = '+';
  946                                         break;
  947                                 case STT_FUNC:
  948                                         c = '*';
  949                                         break;
  950                                 case STT_SECTION:
  951                                         c = '&';
  952                                         break;
  953                                 case STT_FILE:
  954                                         c = '/';
  955                                         break;
  956                                 default:
  957                                         c = ' ';
  958                                         break;
  959                                 }
  960                                 db_printf("%s%c ", sb + les->st_name, c);
  961                         } else
  962                                 db_printf("%s ", sb + les->st_name);
  963                 }
  964         }
  965         return ENOENT;
  966 }
  967 #endif /* DDB */
  968 
  969 /*
  970  * In case we exposing the symbol table to the userland using the pseudo-
  971  * device /dev/ksyms, it is easier to provide all the tables as one.
  972  * However, it means we have to change all the st_name fields for the
  973  * symbols so they match the ELF image that the userland will read
  974  * through the device.
  975  *
  976  * The actual (correct) value of st_name is preserved through a global
  977  * offset stored in the symbol table structure.
  978  *
  979  * Call with ksyms_lock held.
  980  */
  981 static void
  982 ksyms_sizes_calc(void)
  983 {
  984         struct ksyms_symtab *st;
  985         int i, delta;
  986 
  987         ksyms_symsz = ksyms_strsz = 0;
  988         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
  989                 delta = ksyms_strsz - st->sd_usroffset;
  990                 if (delta != 0) {
  991                         for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
  992                                 st->sd_symstart[i].st_name += delta;
  993                         st->sd_usroffset = ksyms_strsz;
  994                 }
  995                 ksyms_symsz += st->sd_symsize;
  996                 ksyms_strsz += st->sd_strsize;
  997         }
  998 }
  999 
 1000 static void
 1001 ksyms_hdr_init(void *hdraddr)
 1002 {
 1003 
 1004         /* Copy the loaded elf exec header */
 1005         memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr));
 1006 
 1007         /* Set correct program/section header sizes, offsets and numbers */
 1008         ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]);
 1009         ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr);
 1010         ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR;
 1011         ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]);
 1012         ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr);
 1013         ksyms_hdr.kh_ehdr.e_shnum = NSECHDR;
 1014         ksyms_hdr.kh_ehdr.e_shstrndx = NSECHDR - 1; /* Last section */
 1015 
 1016         /* Text */
 1017         ksyms_hdr.kh_phdr[0].p_type = PT_LOAD;
 1018         ksyms_hdr.kh_phdr[0].p_memsz = (unsigned long)-1L;
 1019         ksyms_hdr.kh_phdr[0].p_flags = PF_R | PF_X;
 1020 
 1021         /* Data */
 1022         ksyms_hdr.kh_phdr[1].p_type = PT_LOAD;
 1023         ksyms_hdr.kh_phdr[1].p_memsz = (unsigned long)-1L;
 1024         ksyms_hdr.kh_phdr[1].p_flags = PF_R | PF_W | PF_X;
 1025 
 1026         /* First section is null */
 1027 
 1028         /* Second section header; ".symtab" */
 1029         ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */
 1030         ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB;
 1031         ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr);
 1032 /*      ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */
 1033         ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */
 1034         ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long);
 1035         ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym);
 1036 
 1037         /* Third section header; ".strtab" */
 1038         ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */
 1039         ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB;
 1040 /*      ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */
 1041 /*      ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */
 1042         ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char);
 1043 
 1044         /* Fourth section, ".shstrtab" */
 1045         ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */
 1046         ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB;
 1047         ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset =
 1048             offsetof(struct ksyms_hdr, kh_strtab);
 1049         ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ;
 1050         ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char);
 1051 
 1052         /* Set section names */
 1053         strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab",
 1054             sizeof(ksyms_hdr.kh_strtab) - 1);
 1055         strlcpy(&ksyms_hdr.kh_strtab[9], ".strtab",
 1056             sizeof(ksyms_hdr.kh_strtab) - 9);
 1057         strlcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab",
 1058             sizeof(ksyms_hdr.kh_strtab) - 17);
 1059 }
 1060 
 1061 static int
 1062 ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l)
 1063 {
 1064 
 1065         if (minor(dev) != 0 || !ksyms_initted)
 1066                 return ENXIO;
 1067 
 1068         /*
 1069          * Create a "snapshot" of the kernel symbol table.  Setting
 1070          * ksyms_isopen will prevent symbol tables from being freed.
 1071          */
 1072         mutex_enter(&ksyms_lock);
 1073         ksyms_hdr.kh_shdr[SYMTAB].sh_size = ksyms_symsz;
 1074         ksyms_hdr.kh_shdr[SYMTAB].sh_info = ksyms_symsz / sizeof(Elf_Sym);
 1075         ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz +
 1076             ksyms_hdr.kh_shdr[SYMTAB].sh_offset;
 1077         ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz;
 1078         ksyms_isopen = true;
 1079         mutex_exit(&ksyms_lock);
 1080 
 1081         return 0;
 1082 }
 1083 
 1084 static int
 1085 ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l)
 1086 {
 1087         struct ksyms_symtab *st, *next;
 1088         bool resize;
 1089 
 1090         /* Discard refernces to symbol tables. */
 1091         mutex_enter(&ksyms_lock);
 1092         ksyms_isopen = false;
 1093         resize = false;
 1094         for (st = TAILQ_FIRST(&ksyms_symtabs); st != NULL; st = next) {
 1095                 next = TAILQ_NEXT(st, sd_queue);
 1096                 if (st->sd_gone) {
 1097                         TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
 1098                         kmem_free(st, sizeof(*st));
 1099                         if (st->sd_malloc) {    /* XXXLKM */
 1100                                 free(st->sd_symstart, M_DEVBUF);
 1101                                 free(st->sd_strstart, M_DEVBUF);
 1102                                 /* XXXUNCONST LINTED - const castaway */
 1103                                 free(__UNCONST(st->sd_name), M_DEVBUF);
 1104                         }
 1105                         resize = true;
 1106                 }
 1107         }
 1108         if (resize)
 1109                 ksyms_sizes_calc();
 1110         mutex_exit(&ksyms_lock);
 1111 
 1112         return 0;
 1113 }
 1114 
 1115 static int
 1116 ksymsread(dev_t dev, struct uio *uio, int ioflag)
 1117 {
 1118         struct ksyms_symtab *st;
 1119         size_t filepos, inpos, off;
 1120         int error;
 1121 
 1122         /*
 1123          * First: Copy out the ELF header.   XXX Lose if ksymsopen()
 1124          * occurs during read of the header.
 1125          */
 1126         off = uio->uio_offset;
 1127         if (off < sizeof(struct ksyms_hdr)) {
 1128                 error = uiomove((char *)&ksyms_hdr + off,
 1129                     sizeof(struct ksyms_hdr) - off, uio);
 1130                 if (error != 0)
 1131                         return error;
 1132         }
 1133 
 1134         /*
 1135          * Copy out the symbol table.
 1136          */
 1137         filepos = sizeof(struct ksyms_hdr);
 1138         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
 1139                 if (uio->uio_resid == 0)
 1140                         return 0;
 1141                 if (uio->uio_offset <= st->sd_symsize + filepos) {
 1142                         inpos = uio->uio_offset - filepos;
 1143                         error = uiomove((char *)st->sd_symstart + inpos,
 1144                            st->sd_symsize - inpos, uio);
 1145                         if (error != 0)
 1146                                 return error;
 1147                 }
 1148                 filepos += st->sd_symsize;
 1149         }
 1150 
 1151         /*
 1152          * Copy out the string table
 1153          */
 1154         KASSERT(filepos == sizeof(struct ksyms_hdr) +
 1155             ksyms_hdr.kh_shdr[SYMTAB].sh_size);
 1156         TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
 1157                 if (uio->uio_resid == 0)
 1158                         return 0;
 1159                 if (uio->uio_offset <= st->sd_strsize + filepos) {
 1160                         inpos = uio->uio_offset - filepos;
 1161                         error = uiomove((char *)st->sd_strstart + inpos,
 1162                            st->sd_strsize - inpos, uio);
 1163                         if (error != 0)
 1164                                 return error;
 1165                 }
 1166                 filepos += st->sd_strsize;
 1167         }
 1168 
 1169         return 0;
 1170 }
 1171 
 1172 static int
 1173 ksymswrite(dev_t dev, struct uio *uio, int ioflag)
 1174 {
 1175 
 1176         return EROFS;
 1177 }
 1178 
 1179 static int
 1180 ksymsioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l)
 1181 {
 1182         struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data;
 1183         struct ksyms_symtab *st;
 1184         Elf_Sym *sym = NULL, copy;
 1185         unsigned long val;
 1186         int error = 0;
 1187         char *str = NULL;
 1188         int len;
 1189 
 1190         /* Read ksyms_maxlen only once while not holding the lock. */
 1191         len = ksyms_maxlen;
 1192 
 1193         if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL) {
 1194                 str = kmem_alloc(len, KM_SLEEP);
 1195                 if ((error = copyinstr(kg->kg_name, str, len, NULL)) != 0) {
 1196                         kmem_free(str, len);
 1197                         return error;
 1198                 }
 1199         }
 1200 
 1201         switch (cmd) {
 1202         case KIOCGVALUE:
 1203                 /*
 1204                  * Use the in-kernel symbol lookup code for fast
 1205                  * retreival of a value.
 1206                  */
 1207                 error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN);
 1208                 if (error == 0)
 1209                         error = copyout(&val, kg->kg_value, sizeof(long));
 1210                 kmem_free(str, len);
 1211                 break;
 1212 
 1213         case KIOCGSYMBOL:
 1214                 /*
 1215                  * Use the in-kernel symbol lookup code for fast
 1216                  * retreival of a symbol.
 1217                  */
 1218                 mutex_enter(&ksyms_lock);
 1219                 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
 1220                         if (st->sd_gone)
 1221                                 continue;
 1222                         if ((sym = findsym(str, st)) == NULL)
 1223                                 continue;
 1224 #ifdef notdef
 1225                         /* Skip if bad binding */
 1226                         if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
 1227                                 sym = NULL;
 1228                                 continue;
 1229                         }
 1230 #endif
 1231                         break;
 1232                 }
 1233                 if (sym != NULL) {
 1234                         memcpy(&copy, sym, sizeof(copy));
 1235                         mutex_exit(&ksyms_lock);
 1236                         error = copyout(&copy, kg->kg_sym, sizeof(Elf_Sym));
 1237                 } else {
 1238                         mutex_exit(&ksyms_lock);
 1239                         error = ENOENT;
 1240                 }
 1241                 kmem_free(str, len);
 1242                 break;
 1243 
 1244         case KIOCGSIZE:
 1245                 /*
 1246                  * Get total size of symbol table.
 1247                  */
 1248                 mutex_enter(&ksyms_lock);
 1249                 *(int *)data = ksyms_strsz + ksyms_symsz +
 1250                     sizeof(struct ksyms_hdr);
 1251                 mutex_exit(&ksyms_lock);
 1252                 break;
 1253 
 1254         default:
 1255                 error = ENOTTY;
 1256                 break;
 1257         }
 1258 
 1259         return error;
 1260 }
 1261 
 1262 const struct cdevsw ksyms_cdevsw = {
 1263         ksymsopen, ksymsclose, ksymsread, ksymswrite, ksymsioctl,
 1264         nullstop, notty, nopoll, nommap, nullkqfilter, D_OTHER | D_MPSAFE
 1265 };

Cache object: 69ed25ae016d8f863ffb6715fddc364d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.