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 /*
    2  * Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se).
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * Code to deal with in-kernel symbol table management + /dev/ksyms.
   30  *
   31  * For each loaded module the symbol table info is kept track of by a
   32  * struct, placed in a circular list. The first entry is the kernel
   33  * symbol table.
   34  */
   35 
   36 /*
   37  * TODO:
   38  *      Change the ugly way of adding new symbols (comes with linker)
   39  *      Add kernel locking stuff.
   40  *      (Ev) add support for poll.
   41  *      (Ev) fix support for mmap.
   42  *
   43  *      Export ksyms internal logic for use in post-mortem debuggers?
   44  *        Need to move struct symtab to ksyms.h for that.
   45  */
   46 
   47 #include <sys/cdefs.h>
   48 __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.31 2006/11/06 13:35:35 jmmv Exp $");
   49 
   50 #ifdef _KERNEL
   51 #include "opt_ddb.h"
   52 #include "opt_ddbparam.h"       /* for SYMTAB_SPACE */
   53 #endif
   54 
   55 #include <sys/param.h>
   56 #include <sys/errno.h>
   57 #include <sys/queue.h>
   58 #include <sys/exec.h>
   59 #include <sys/systm.h>
   60 #include <sys/conf.h>
   61 #include <sys/device.h>
   62 #include <sys/malloc.h>
   63 #include <sys/proc.h>
   64 
   65 #include <machine/elf_machdep.h> /* XXX */
   66 #define ELFSIZE ARCH_ELFSIZE
   67 
   68 #include <sys/exec_elf.h>
   69 #include <sys/ksyms.h>
   70 
   71 #include <lib/libkern/libkern.h>
   72 
   73 #ifdef DDB
   74 #include <ddb/db_output.h>
   75 #endif
   76 
   77 #include "ksyms.h"
   78 
   79 static int ksymsinited = 0;
   80 
   81 #if NKSYMS
   82 static void ksyms_hdr_init(caddr_t hdraddr);
   83 static void ksyms_sizes_calc(void);
   84 static int ksyms_isopen;
   85 static int ksyms_maxlen;
   86 #endif
   87 
   88 #ifdef KSYMS_DEBUG
   89 #define FOLLOW_CALLS            1
   90 #define FOLLOW_MORE_CALLS       2
   91 #define FOLLOW_DEVKSYMS         4
   92 static int ksyms_debug;
   93 #endif
   94 
   95 #ifdef SYMTAB_SPACE
   96 #define         SYMTAB_FILLER   "|This is the symbol table!"
   97 
   98 char            db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER;
   99 int             db_symtabsize = SYMTAB_SPACE;
  100 #endif
  101 
  102 /*
  103  * Store the different symbol tables in a double-linked list.
  104  */
  105 struct symtab {
  106         CIRCLEQ_ENTRY(symtab) sd_queue;
  107         const char *sd_name;    /* Name of this table */
  108         Elf_Sym *sd_symstart;   /* Address of symbol table */
  109         caddr_t sd_strstart;    /* Adderss of corresponding string table */
  110         int sd_usroffset;       /* Real address for userspace */
  111         int sd_symsize;         /* Size in bytes of symbol table */
  112         int sd_strsize;         /* Size of string table */
  113         int *sd_symnmoff;       /* Used when calculating the name offset */
  114 };
  115 
  116 static CIRCLEQ_HEAD(, symtab) symtab_queue =
  117     CIRCLEQ_HEAD_INITIALIZER(symtab_queue);
  118 
  119 static struct symtab kernel_symtab;
  120 
  121 #define USE_PTREE
  122 #ifdef USE_PTREE
  123 /*
  124  * Patricia-tree-based lookup structure for the in-kernel global symbols.
  125  * Based on a design by Mikael Sundstrom, msm@sm.luth.se.
  126  */
  127 struct ptree {
  128         int16_t bitno;
  129         int16_t lr[2];
  130 } *symb;
  131 static int16_t baseidx;
  132 static int treex = 1;
  133 
  134 #define P_BIT(key, bit) ((key[bit >> 3] >> (bit & 7)) & 1)
  135 #define STRING(idx) kernel_symtab.sd_symstart[idx].st_name + \
  136                         kernel_symtab.sd_strstart
  137 
  138 /*
  139  * Walk down the tree until a terminal node is found.
  140  */
  141 static int
  142 symbol_traverse(const char *key)
  143 {
  144         int16_t nb, rbit = baseidx;
  145 
  146         while (rbit > 0) {
  147                 nb = symb[rbit].bitno;
  148                 rbit = symb[rbit].lr[P_BIT(key, nb)];
  149         }
  150         return -rbit;
  151 }
  152 
  153 static int
  154 ptree_add(char *key, int val)
  155 {
  156         int idx;
  157         int nix, cix, bit, rbit, sb, lastrbit, svbit = 0, ix;
  158         char *m, *k;
  159 
  160         if (baseidx == 0) {
  161                 baseidx = -val;
  162                 return 0; /* First element */
  163         }
  164 
  165         /* Get string to match against */
  166         idx = symbol_traverse(key);
  167 
  168         /* Find first mismatching bit */
  169         m = STRING(idx);
  170         k = key;
  171         if (strcmp(m, k) == 0)
  172                 return 1;
  173 
  174         for (cix = 0; *m && *k && *m == *k; m++, k++, cix += 8)
  175                 ;
  176         ix = ffs((int)*m ^ (int)*k) - 1;
  177         cix += ix;
  178 
  179         /* Create new node */
  180         nix = treex++;
  181         bit = P_BIT(key, cix);
  182         symb[nix].bitno = cix;
  183         symb[nix].lr[bit] = -val;
  184 
  185         /* Find where to insert node */
  186         rbit = baseidx;
  187         lastrbit = 0;
  188         for (;;) {
  189                 if (rbit < 0)
  190                         break;
  191                 sb = symb[rbit].bitno;
  192                 if (sb > cix)
  193                         break;
  194                 if (sb == cix)
  195                         printf("symb[rbit].bitno == cix!!!\n");
  196                 lastrbit = rbit;
  197                 svbit = P_BIT(key, sb);
  198                 rbit = symb[rbit].lr[svbit];
  199         }
  200 
  201         /* Do the actual insertion */
  202         if (lastrbit == 0) {
  203                 /* first element */
  204                 symb[nix].lr[!bit] = baseidx;
  205                 baseidx = nix;
  206         } else {
  207                 symb[nix].lr[!bit] = rbit;
  208                 symb[lastrbit].lr[svbit] = nix;
  209         }
  210         return 0;
  211 }
  212 
  213 static int
  214 ptree_find(const char *key)
  215 {
  216         int idx;
  217 
  218         if (baseidx == 0)
  219                 return 0;
  220         idx = symbol_traverse(key);
  221 
  222         if (strcmp(key, STRING(idx)) == 0)
  223                 return idx;
  224         return 0;
  225 }
  226 
  227 static void
  228 ptree_gen(char *off, struct symtab *tab)
  229 {
  230         Elf_Sym *sym;
  231         int i, nsym;
  232 
  233         if (off != NULL)
  234                 symb = (struct ptree *)ALIGN(off);
  235         else
  236                 symb = malloc((tab->sd_symsize/sizeof(Elf_Sym)) *
  237                     sizeof(struct ptree), M_DEVBUF, M_WAITOK);
  238         symb--; /* sym index won't be 0 */
  239 
  240         sym = tab->sd_symstart;
  241         if ((nsym = tab->sd_symsize/sizeof(Elf_Sym)) > INT16_MAX) {
  242                 printf("Too many symbols for tree, skipping %d symbols\n",
  243                     nsym-INT16_MAX);
  244                 nsym = INT16_MAX;
  245         }
  246         for (i = 1; i < nsym; i++) {
  247                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  248                         continue;
  249                 ptree_add(tab->sd_strstart+sym[i].st_name, i);
  250         }
  251 }
  252 #endif /* USE_PTREE */
  253 
  254 /*
  255  * Finds a certain symbol name in a certain symbol table.
  256  */
  257 static Elf_Sym *
  258 findsym(const char *name, struct symtab *table)
  259 {
  260         Elf_Sym *start = table->sd_symstart;
  261         int i, sz = table->sd_symsize/sizeof(Elf_Sym);
  262         char *np;
  263         caddr_t realstart = table->sd_strstart - table->sd_usroffset;
  264 
  265 #ifdef USE_PTREE
  266         if (table == &kernel_symtab && (i = ptree_find(name)) != 0)
  267                 return &start[i];
  268 #endif
  269 
  270         for (i = 0; i < sz; i++) {
  271                 np = realstart + start[i].st_name;
  272                 if (name[0] == np[0] && name[1] == np[1] &&
  273                     strcmp(name, np) == 0)
  274                         return &start[i];
  275         }
  276         return NULL;
  277 }
  278 
  279 /*
  280  * The "attach" is in reality done in ksyms_init().
  281  */
  282 void ksymsattach(int);
  283 void
  284 ksymsattach(int arg)
  285 {
  286 
  287 #ifdef USE_PTREE
  288         if (baseidx == 0)
  289                 ptree_gen(0, &kernel_symtab);
  290 #endif
  291 
  292 }
  293 
  294 /*
  295  * Add a symbol table.
  296  * This is intended for use when the symbol table and its corresponding
  297  * string table are easily available.  If they are embedded in an ELF
  298  * image, use addsymtab_elf() instead.
  299  *
  300  * name - Symbol's table name.
  301  * symstart, symsize - Address and size of the symbol table.
  302  * strstart, strsize - Address and size of the string table.
  303  * tab - Symbol table to be updated with this information.
  304  * newstart - Address to which the symbol table has to be copied during
  305  *            shrinking.  If NULL, it is not moved.
  306  */
  307 static void
  308 addsymtab(const char *name,
  309     caddr_t symstart, size_t symsize,
  310     caddr_t strstart, size_t strsize,
  311     struct symtab *tab,
  312     caddr_t newstart)
  313 {
  314         caddr_t send;
  315         Elf_Sym *sym, *nsym;
  316         int i, n, g;
  317         char *str;
  318 
  319         if (newstart == NULL)
  320                 newstart = symstart;
  321         KASSERT(newstart <= symstart && symstart <= strstart);
  322 
  323         tab->sd_symstart = (Elf_Sym *)symstart;
  324         tab->sd_symsize = symsize;
  325         tab->sd_strstart = strstart;
  326         tab->sd_strsize = strsize;
  327         tab->sd_name = name;
  328         send = tab->sd_strstart + tab->sd_strsize;
  329 
  330 #ifdef KSYMS_DEBUG
  331         printf("newstart %p sym %p symsz %d str %p strsz %d send %p\n",
  332             newstart, symstart, symsize, strstart, strsize, send);
  333 #endif
  334 
  335         /*
  336          * Pack symbol table by removing all file name references
  337          * and overwrite the elf header.
  338          */
  339         sym = tab->sd_symstart;
  340         nsym = (Elf_Sym *)newstart;
  341         str = tab->sd_strstart;
  342         for (g = i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
  343                 if (i == 0) {
  344                         nsym[n++] = sym[i];
  345                         continue;
  346                 }
  347                 /*
  348                  * Remove useless symbols.
  349                  * Should actually remove all typeless symbols.
  350                  */
  351                 if (sym[i].st_name == 0)
  352                         continue; /* Skip nameless entries */
  353                 if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE)
  354                         continue; /* Skip filenames */
  355                 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
  356                     sym[i].st_value == 0 &&
  357                     strcmp(str + sym[i].st_name, "*ABS*") == 0)
  358                         continue; /* XXX */
  359                 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
  360                     strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0)
  361                         continue; /* XXX */
  362 
  363 #ifndef DDB
  364                 /* Only need global symbols */
  365                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  366                         continue;
  367 #endif
  368 
  369                 /* Save symbol. Set it as an absolute offset */
  370                 nsym[n] = sym[i];
  371                 nsym[n].st_shndx = SHN_ABS;
  372                 if (ELF_ST_BIND(nsym[n].st_info) == STB_GLOBAL)
  373                         g++;
  374 #if NKSYMS
  375                 {
  376                         int j;
  377                         j = strlen(nsym[n].st_name + tab->sd_strstart) + 1;
  378                         if (j > ksyms_maxlen)
  379                                 ksyms_maxlen = j;
  380                 }
  381 #endif
  382                 n++;
  383 
  384         }
  385         tab->sd_symstart = nsym;
  386         tab->sd_symsize = n * sizeof(Elf_Sym);
  387 
  388 #ifdef notyet
  389         /*
  390          * Remove left-over strings.
  391          */
  392         sym = tab->sd_symstart;
  393         str = (caddr_t)tab->sd_symstart + tab->sd_symsize;
  394         str[0] = 0;
  395         n = 1;
  396         for (i = 1; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
  397                 strcpy(str + n, tab->sd_strstart + sym[i].st_name);
  398                 sym[i].st_name = n;
  399                 n += strlen(str+n) + 1;
  400         }
  401         tab->sd_strstart = str;
  402         tab->sd_strsize = n;
  403 
  404 #ifdef KSYMS_DEBUG
  405         printf("str %p strsz %d send %p\n", str, n, send);
  406 #endif
  407 #endif
  408 
  409         CIRCLEQ_INSERT_HEAD(&symtab_queue, tab, sd_queue);
  410 
  411 #ifdef notyet
  412 #ifdef USE_PTREE
  413         /* Try to use the freed space, if possible */
  414         if (send - str - n > g * sizeof(struct ptree))
  415                 ptree_gen(str + n, tab);
  416 #endif
  417 #endif
  418 }
  419 
  420 /*
  421  * Add a symbol table named name.
  422  * This is intended for use when the kernel loader enters the table.
  423  */
  424 static void
  425 addsymtab_elf(const char *name, Elf_Ehdr *ehdr, struct symtab *tab)
  426 {
  427         int i, j;
  428         caddr_t start = (caddr_t)ehdr;
  429         Elf_Shdr *shdr;
  430         caddr_t symstart = NULL, strstart = NULL;
  431         size_t symsize = 0, strsize = 0;
  432 
  433         /* Find the symbol table and the corresponding string table. */
  434         shdr = (Elf_Shdr *)(start + ehdr->e_shoff);
  435         for (i = 1; i < ehdr->e_shnum; i++) {
  436                 if (shdr[i].sh_type != SHT_SYMTAB)
  437                         continue;
  438                 if (shdr[i].sh_offset == 0)
  439                         continue;
  440                 symstart = start + shdr[i].sh_offset;
  441                 symsize = shdr[i].sh_size;
  442                 j = shdr[i].sh_link;
  443                 if (shdr[j].sh_offset == 0)
  444                         continue; /* Can this happen? */
  445                 strstart = start + shdr[j].sh_offset;
  446                 strsize = shdr[j].sh_size;
  447                 break;
  448         }
  449 
  450         KASSERT(symstart != NULL && strstart != NULL);
  451 
  452         addsymtab(name, symstart, symsize, strstart, strsize, tab, start);
  453 }
  454 
  455 /*
  456  * Setup the kernel symbol table stuff.
  457  */
  458 void
  459 ksyms_init(int symsize, void *start, void *end)
  460 {
  461         Elf_Ehdr *ehdr;
  462 
  463 #ifdef SYMTAB_SPACE
  464         if (symsize <= 0 &&
  465             strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) {
  466                 symsize = db_symtabsize;
  467                 start = db_symtab;
  468                 end = db_symtab + db_symtabsize;
  469         }
  470 #endif
  471         if (symsize <= 0) {
  472                 printf("[ Kernel symbol table missing! ]\n");
  473                 return;
  474         }
  475 
  476         /* Sanity check */
  477         if (ALIGNED_POINTER(start, long) == 0) {
  478                 printf("[ Kernel symbol table has bad start address %p ]\n",
  479                     start);
  480                 return;
  481         }
  482 
  483         ehdr = (Elf_Ehdr *)start;
  484 
  485         /* check if this is a valid ELF header */
  486         /* No reason to verify arch type, the kernel is actually running! */
  487         if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
  488             ehdr->e_ident[EI_CLASS] != ELFCLASS ||
  489             ehdr->e_version > 1) {
  490 #ifdef notyet /* DDB */
  491                 if (ddb_init(symsize, start, end))
  492                         return; /* old-style symbol table */
  493 #endif
  494                 printf("[ Kernel symbol table invalid! ]\n");
  495                 return; /* nothing to do */
  496         }
  497 
  498 #if NKSYMS
  499         /* Loaded header will be scratched in addsymtab */
  500         ksyms_hdr_init(start);
  501 #endif
  502 
  503         addsymtab_elf("netbsd", ehdr, &kernel_symtab);
  504 
  505 #if NKSYMS
  506         ksyms_sizes_calc();
  507 #endif
  508 
  509         ksymsinited = 1;
  510 
  511 #ifdef DEBUG
  512         printf("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
  513             kernel_symtab.sd_symstart, kernel_symtab.sd_strstart,
  514             (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym));
  515 #endif
  516 }
  517 
  518 /*
  519  * Setup the kernel symbol table stuff.
  520  * Use this when the address of the symbol and string tables are known;
  521  * otherwise use ksyms_init with an ELF image.
  522  * We need to pass a minimal ELF header which will later be completed by
  523  * ksyms_hdr_init and handed off to userland through /dev/ksyms.  We use
  524  * a caddr_t rather than a pointer to avoid exposing the Elf_Ehdr type.
  525  */
  526 void
  527 ksyms_init_explicit(caddr_t ehdr, caddr_t symstart, size_t symsize,
  528     caddr_t strstart, size_t strsize)
  529 {
  530 
  531         KASSERT(symstart != NULL);
  532         KASSERT(strstart != NULL);
  533         KASSERT(symstart <= strstart);
  534 
  535 #if NKSYMS
  536         ksyms_hdr_init(ehdr);
  537 #endif
  538 
  539         addsymtab("netbsd", symstart, symsize, strstart, strsize,
  540             &kernel_symtab, NULL);
  541 
  542 #if NKSYMS
  543         ksyms_sizes_calc();
  544 #endif
  545 
  546         ksymsinited = 1;
  547 }
  548 
  549 /*
  550  * Get the value associated with a symbol.
  551  * "mod" is the module name, or null if any module.
  552  * "sym" is the symbol name.
  553  * "val" is a pointer to the corresponding value, if call succeeded.
  554  * Returns 0 if success or ENOENT if no such entry.
  555  */
  556 int
  557 ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type)
  558 {
  559         struct symtab *st;
  560         Elf_Sym *es;
  561 
  562         if (ksymsinited == 0)
  563                 return ENOENT;
  564 
  565 #ifdef KSYMS_DEBUG
  566         if (ksyms_debug & FOLLOW_CALLS)
  567                 printf("ksyms_getval: mod %s sym %s valp %p\n", mod, sym, val);
  568 #endif
  569 
  570         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  571                 if (mod && strcmp(st->sd_name, mod))
  572                         continue;
  573                 if ((es = findsym(sym, st)) == NULL)
  574                         continue;
  575 
  576                 /* Skip if bad binding */
  577                 if (type == KSYMS_EXTERN &&
  578                     ELF_ST_BIND(es->st_info) != STB_GLOBAL)
  579                         continue;
  580 
  581                 if (val)
  582                         *val = es->st_value;
  583                 return 0;
  584         }
  585         return ENOENT;
  586 }
  587 
  588 /*
  589  * Get "mod" and "symbol" associated with an address.
  590  * Returns 0 if success or ENOENT if no such entry.
  591  */
  592 int
  593 ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f)
  594 {
  595         struct symtab *st;
  596         Elf_Sym *les, *es = NULL;
  597         vaddr_t laddr = 0;
  598         const char *lmod = NULL;
  599         char *stable = NULL;
  600         int type, i, sz;
  601 
  602         if (ksymsinited == 0)
  603                 return ENOENT;
  604 
  605         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  606                 sz = st->sd_symsize/sizeof(Elf_Sym);
  607                 for (i = 0; i < sz; i++) {
  608                         les = st->sd_symstart + i;
  609                         type = ELF_ST_TYPE(les->st_info);
  610 
  611                         if ((f & KSYMS_PROC) && (type != STT_FUNC))
  612                                 continue;
  613 
  614                         if (type == STT_NOTYPE)
  615                                 continue;
  616 
  617                         if (((f & KSYMS_ANY) == 0) &&
  618                             (type != STT_FUNC) && (type != STT_OBJECT))
  619                                 continue;
  620 
  621                         if ((les->st_value <= v) && (les->st_value > laddr)) {
  622                                 laddr = les->st_value;
  623                                 es = les;
  624                                 lmod = st->sd_name;
  625                                 stable = st->sd_strstart - st->sd_usroffset;
  626                         }
  627                 }
  628         }
  629         if (es == NULL)
  630                 return ENOENT;
  631         if ((f & KSYMS_EXACT) && (v != es->st_value))
  632                 return ENOENT;
  633         if (mod)
  634                 *mod = lmod;
  635         if (sym)
  636                 *sym = stable + es->st_name;
  637         return 0;
  638 }
  639 
  640 #if NKSYMS
  641 static int symsz, strsz;
  642 
  643 /*
  644  * In case we exposing the symbol table to the userland using the pseudo-
  645  * device /dev/ksyms, it is easier to provide all the tables as one.
  646  * However, it means we have to change all the st_name fields for the
  647  * symbols so they match the ELF image that the userland will read
  648  * through the device.
  649  *
  650  * The actual (correct) value of st_name is preserved through a global
  651  * offset stored in the symbol table structure.
  652  */
  653 
  654 static void
  655 ksyms_sizes_calc(void)
  656 {
  657         struct symtab *st;
  658         int i;
  659 
  660         symsz = strsz = 0;
  661         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  662                 if (st != &kernel_symtab) {
  663                         for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
  664                                 st->sd_symstart[i].st_name =
  665                                     strsz + st->sd_symnmoff[i];
  666                         st->sd_usroffset = strsz;
  667                 }
  668                 symsz += st->sd_symsize;
  669                 strsz += st->sd_strsize;
  670         }
  671 }
  672 #endif /* NKSYMS */
  673 
  674 /*
  675  * Temporary work structure for dynamic loaded symbol tables.
  676  * Will go away when in-kernel linker is in place.
  677  */
  678 
  679 struct syminfo {
  680         size_t cursyms;
  681         size_t curnamep;
  682         size_t maxsyms;
  683         size_t maxnamep;
  684         Elf_Sym *syms;
  685         int *symnmoff;
  686         char *symnames;
  687 };
  688 
  689 
  690 /*
  691  * Add a symbol to the temporary save area for symbols.
  692  * This routine will go away when the in-kernel linker is in place.
  693  */
  694 static void
  695 addsym(struct syminfo *info, const Elf_Sym *sym, const char *name,
  696        const char *mod)
  697 {
  698         int len, mlen;
  699 
  700 #ifdef KSYMS_DEBUG
  701         if (ksyms_debug & FOLLOW_MORE_CALLS)
  702                 printf("addsym: name %s val %lx\n", name, (long)sym->st_value);
  703 #endif
  704         len = strlen(name) + 1;
  705         if (mod)
  706                 mlen = 1 + strlen(mod);
  707         else
  708                 mlen = 0;
  709         if (info->cursyms == info->maxsyms ||
  710             (len + mlen + info->curnamep) > info->maxnamep) {
  711                 printf("addsym: too many symbols, skipping '%s'\n", name);
  712                 return;
  713         }
  714         strlcpy(&info->symnames[info->curnamep], name,
  715             info->maxnamep - info->curnamep);
  716         if (mlen) {
  717                 info->symnames[info->curnamep + len - 1] = '.';
  718                 strlcpy(&info->symnames[info->curnamep + len], mod,
  719                     info->maxnamep - (info->curnamep + len));
  720                 len += mlen;
  721         }
  722         info->syms[info->cursyms] = *sym;
  723         info->syms[info->cursyms].st_name = info->curnamep;
  724         info->symnmoff[info->cursyms] = info->curnamep;
  725         info->curnamep += len;
  726 #if NKSYMS
  727         if (len > ksyms_maxlen)
  728                 ksyms_maxlen = len;
  729 #endif
  730         info->cursyms++;
  731 }
  732 /*
  733  * Adds a symbol table.
  734  * "name" is the module name, "start" and "size" is where the symbol table
  735  * is located, and "type" is in which binary format the symbol table is.
  736  * New memory for keeping the symbol table is allocated in this function.
  737  * Returns 0 if success and EEXIST if the module name is in use.
  738  */
  739 static int
  740 specialsym(const char *symname)
  741 {
  742         return  !strcmp(symname, "_bss_start") ||
  743                 !strcmp(symname, "__bss_start") ||
  744                 !strcmp(symname, "_bss_end__") ||
  745                 !strcmp(symname, "__bss_end__") ||
  746                 !strcmp(symname, "_edata") ||
  747                 !strcmp(symname, "_end") ||
  748                 !strcmp(symname, "__end") ||
  749                 !strcmp(symname, "__end__") ||
  750                 !strncmp(symname, "__start_link_set_", 17) ||
  751                 !strncmp(symname, "__stop_link_set_", 16);
  752 }
  753 
  754 int
  755 ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
  756     char *strstart, vsize_t strsize)
  757 {
  758         Elf_Sym *sym = symstart;
  759         struct symtab *st;
  760         unsigned long rval;
  761         int i;
  762         char *name;
  763         struct syminfo info;
  764 
  765 #ifdef KSYMS_DEBUG
  766         if (ksyms_debug & FOLLOW_CALLS)
  767                 printf("ksyms_addsymtab: mod %s symsize %lx strsize %lx\n",
  768                     mod, symsize, strsize);
  769 #endif
  770 
  771 #if NKSYMS
  772         /*
  773          * Do not try to add a symbol table while someone is reading
  774          * from /dev/ksyms.
  775          */
  776         while (ksyms_isopen != 0)
  777                 tsleep(&ksyms_isopen, PWAIT, "ksyms", 0);
  778 #endif
  779 
  780         /* Check if this symtab already loaded */
  781         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  782                 if (strcmp(mod, st->sd_name) == 0)
  783                         return EEXIST;
  784         }
  785 
  786         /*
  787          * XXX - Only add a symbol if it do not exist already.
  788          * This is because of a flaw in the current LKM implementation,
  789          * these loops will be removed once the in-kernel linker is in place.
  790          */
  791         memset(&info, 0, sizeof(info));
  792         for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
  793                 char * const symname = strstart + sym[i].st_name;
  794                 if (sym[i].st_name == 0)
  795                         continue; /* Just ignore */
  796 
  797                 /* check validity of the symbol */
  798                 /* XXX - save local symbols if DDB */
  799                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  800                         continue;
  801 
  802                 /* Check if the symbol exists */
  803                 if (ksyms_getval(NULL, symname, &rval, KSYMS_EXTERN) == 0) {
  804                         /* Check (and complain) about differing values */
  805                         if (sym[i].st_value != rval) {
  806                                 if (specialsym(symname)) {
  807                                         info.maxsyms++;
  808                                         info.maxnamep += strlen(symname) + 1 +
  809                                             strlen(mod) + 1;
  810                                 } else {
  811                                         printf("%s: symbol '%s' redeclared with"
  812                                             " different value (%lx != %lx)\n",
  813                                             mod, symname,
  814                                             rval, (long)sym[i].st_value);
  815                                 }
  816                         }
  817                 } else {
  818                         /*
  819                          * Count this symbol
  820                          */
  821                         info.maxsyms++;
  822                         info.maxnamep += strlen(symname) + 1;
  823                 }
  824         }
  825 
  826         /*
  827          * Now that we know the sizes, malloc the structures.
  828          */
  829         info.syms = malloc(sizeof(Elf_Sym)*info.maxsyms, M_DEVBUF, M_WAITOK);
  830         info.symnames = malloc(info.maxnamep, M_DEVBUF, M_WAITOK);
  831         info.symnmoff = malloc(sizeof(int)*info.maxsyms, M_DEVBUF, M_WAITOK);
  832 
  833         /*
  834          * Now that we have the symbols, actually fill in the structures.
  835          */
  836         for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
  837                 char * const symname = strstart + sym[i].st_name;
  838                 if (sym[i].st_name == 0)
  839                         continue; /* Just ignore */
  840 
  841                 /* check validity of the symbol */
  842                 /* XXX - save local symbols if DDB */
  843                 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
  844                         continue;
  845 
  846                 /* Check if the symbol exists */
  847                 if (ksyms_getval(NULL, symname, &rval, KSYMS_EXTERN) == 0) {
  848                         if ((sym[i].st_value != rval) && specialsym(symname)) {
  849                                 addsym(&info, &sym[i], symname, mod);
  850                         }
  851                 } else
  852                         /* Ok, save this symbol */
  853                         addsym(&info, &sym[i], symname, NULL);
  854         }
  855 
  856         st = malloc(sizeof(struct symtab), M_DEVBUF, M_WAITOK);
  857         i = strlen(mod) + 1;
  858         name = malloc(i, M_DEVBUF, M_WAITOK);
  859         strlcpy(name, mod, i);
  860         st->sd_name = name;
  861         st->sd_symnmoff = info.symnmoff;
  862         st->sd_symstart = info.syms;
  863         st->sd_symsize = sizeof(Elf_Sym)*info.maxsyms;
  864         st->sd_strstart = info.symnames;
  865         st->sd_strsize = info.maxnamep;
  866 
  867         /* Make them absolute references */
  868         sym = st->sd_symstart;
  869         for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
  870                 sym[i].st_shndx = SHN_ABS;
  871 
  872         CIRCLEQ_INSERT_TAIL(&symtab_queue, st, sd_queue);
  873 #if NKSYMS
  874         ksyms_sizes_calc();
  875 #endif
  876         return 0;
  877 }
  878 
  879 /*
  880  * Remove a symbol table specified by name.
  881  * Returns 0 if success, EBUSY if device open and ENOENT if no such name.
  882  */
  883 int
  884 ksyms_delsymtab(const char *mod)
  885 {
  886         struct symtab *st;
  887         int found = 0;
  888 
  889 #if NKSYMS
  890         /*
  891          * Do not try to delete a symbol table while someone is reading
  892          * from /dev/ksyms.
  893          */
  894         while (ksyms_isopen != 0)
  895                 tsleep(&ksyms_isopen, PWAIT, "ksyms", 0);
  896 #endif
  897 
  898         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  899                 if (strcmp(mod, st->sd_name) == 0) {
  900                         found = 1;
  901                         break;
  902                 }
  903         }
  904         if (found == 0)
  905                 return ENOENT;
  906         CIRCLEQ_REMOVE(&symtab_queue, st, sd_queue);
  907         free(st->sd_symstart, M_DEVBUF);
  908         free(st->sd_strstart, M_DEVBUF);
  909         free(st->sd_symnmoff, M_DEVBUF);
  910         /* XXXUNCONST LINTED - const castaway */
  911         free(__UNCONST(st->sd_name), M_DEVBUF);
  912         free(st, M_DEVBUF);
  913 #if NKSYMS
  914         ksyms_sizes_calc();
  915 #endif
  916         return 0;
  917 }
  918 
  919 int
  920 ksyms_rensymtab(const char *old, const char *new)
  921 {
  922         struct symtab *st, *oldst = NULL;
  923         char *newstr;
  924 
  925         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  926                 if (strcmp(old, st->sd_name) == 0)
  927                         oldst = st;
  928                 if (strcmp(new, st->sd_name) == 0)
  929                         return (EEXIST);
  930         }
  931         if (oldst == NULL)
  932                 return (ENOENT);
  933 
  934         newstr = malloc(strlen(new)+1, M_DEVBUF, M_WAITOK);
  935         if (!newstr)
  936                 return (ENOMEM);
  937         strcpy(newstr, new);
  938         /*XXXUNCONST*/
  939         free(__UNCONST(oldst->sd_name), M_DEVBUF);
  940         oldst->sd_name = newstr;
  941 
  942         return (0);
  943 }
  944 
  945 #ifdef DDB
  946 /*
  947  * Keep sifting stuff here, to avoid export of ksyms internals.
  948  */
  949 int
  950 ksyms_sift(char *mod, char *sym, int mode)
  951 {
  952         struct symtab *st;
  953         char *sb;
  954         int i, sz;
  955 
  956         if (ksymsinited == 0)
  957                 return ENOENT;
  958 
  959         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
  960                 if (mod && strcmp(mod, st->sd_name))
  961                         continue;
  962                 sb = st->sd_strstart;
  963 
  964                 sz = st->sd_symsize/sizeof(Elf_Sym);
  965                 for (i = 0; i < sz; i++) {
  966                         Elf_Sym *les = st->sd_symstart + i;
  967                         char c;
  968 
  969                         if (strstr(sb + les->st_name - st->sd_usroffset, sym)
  970                             == NULL)
  971                                 continue;
  972 
  973                         if (mode == 'F') {
  974                                 switch (ELF_ST_TYPE(les->st_info)) {
  975                                 case STT_OBJECT:
  976                                         c = '+';
  977                                         break;
  978                                 case STT_FUNC:
  979                                         c = '*';
  980                                         break;
  981                                 case STT_SECTION:
  982                                         c = '&';
  983                                         break;
  984                                 case STT_FILE:
  985                                         c = '/';
  986                                         break;
  987                                 default:
  988                                         c = ' ';
  989                                         break;
  990                                 }
  991                                 db_printf("%s%c ", sb + les->st_name -
  992                                     st->sd_usroffset, c);
  993                         } else
  994                                 db_printf("%s ", sb + les->st_name -
  995                                     st->sd_usroffset);
  996                 }
  997         }
  998         return ENOENT;
  999 }
 1000 #endif /* DDB */
 1001 
 1002 #if NKSYMS
 1003 /*
 1004  * Static allocated ELF header.
 1005  * Basic info is filled in at attach, sizes at open.
 1006  */
 1007 #define SYMTAB          1
 1008 #define STRTAB          2
 1009 #define SHSTRTAB        3
 1010 #define NSECHDR         4
 1011 
 1012 #define NPRGHDR         2
 1013 #define SHSTRSIZ        28
 1014 
 1015 static struct ksyms_hdr {
 1016         Elf_Ehdr        kh_ehdr;
 1017         Elf_Phdr        kh_phdr[NPRGHDR];
 1018         Elf_Shdr        kh_shdr[NSECHDR];
 1019         char            kh_strtab[SHSTRSIZ];
 1020 } ksyms_hdr;
 1021 
 1022 
 1023 static void
 1024 ksyms_hdr_init(caddr_t hdraddr)
 1025 {
 1026 
 1027         /* Copy the loaded elf exec header */
 1028         memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr));
 1029 
 1030         /* Set correct program/section header sizes, offsets and numbers */
 1031         ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]);
 1032         ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr);
 1033         ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR;
 1034         ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]);
 1035         ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr);
 1036         ksyms_hdr.kh_ehdr.e_shnum = NSECHDR;
 1037         ksyms_hdr.kh_ehdr.e_shstrndx = NSECHDR - 1; /* Last section */
 1038 
 1039         /*
 1040          * Keep program headers zeroed (unused).
 1041          * The section headers are hand-crafted.
 1042          * First section is section zero.
 1043          */
 1044 
 1045         /* Second section header; ".symtab" */
 1046         ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */
 1047         ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB;
 1048         ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr);
 1049 /*      ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */
 1050         ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */
 1051         ksyms_hdr.kh_shdr[SYMTAB].sh_info = 0; /* XXX */
 1052         ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long);
 1053         ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym);
 1054 
 1055         /* Third section header; ".strtab" */
 1056         ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */
 1057         ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB;
 1058 /*      ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */
 1059 /*      ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */
 1060 /*      ksyms_hdr.kh_shdr[STRTAB].sh_link = kept zero */
 1061         ksyms_hdr.kh_shdr[STRTAB].sh_info = 0;
 1062         ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char);
 1063         ksyms_hdr.kh_shdr[STRTAB].sh_entsize = 0;
 1064 
 1065         /* Fourth section, ".shstrtab" */
 1066         ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */
 1067         ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB;
 1068         ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset =
 1069             offsetof(struct ksyms_hdr, kh_strtab);
 1070         ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ;
 1071         ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char);
 1072 
 1073         /* Set section names */
 1074         strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab",
 1075             sizeof(ksyms_hdr.kh_strtab) - 1);
 1076         strlcpy(&ksyms_hdr.kh_strtab[9], ".strtab",
 1077             sizeof(ksyms_hdr.kh_strtab) - 9);
 1078         strlcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab",
 1079             sizeof(ksyms_hdr.kh_strtab) - 17);
 1080 };
 1081 
 1082 static int
 1083 ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l)
 1084 {
 1085 
 1086         if (minor(dev))
 1087                 return ENXIO;
 1088         if (ksymsinited == 0)
 1089                 return ENXIO;
 1090 
 1091         ksyms_hdr.kh_shdr[SYMTAB].sh_size = symsz;
 1092         ksyms_hdr.kh_shdr[STRTAB].sh_offset = symsz +
 1093             ksyms_hdr.kh_shdr[SYMTAB].sh_offset;
 1094         ksyms_hdr.kh_shdr[STRTAB].sh_size = strsz;
 1095         ksyms_isopen = 1;
 1096 
 1097 #ifdef KSYMS_DEBUG
 1098         if (ksyms_debug & FOLLOW_DEVKSYMS)
 1099                 printf("ksymsopen: symsz 0x%x strsz 0x%x\n", symsz, strsz);
 1100 #endif
 1101 
 1102         return 0;
 1103 }
 1104 
 1105 static int
 1106 ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l)
 1107 {
 1108 
 1109 #ifdef KSYMS_DEBUG
 1110         if (ksyms_debug & FOLLOW_DEVKSYMS)
 1111                 printf("ksymsclose\n");
 1112 #endif
 1113 
 1114         ksyms_isopen = 0;
 1115         wakeup(&ksyms_isopen);
 1116         return 0;
 1117 }
 1118 
 1119 #define HDRSIZ  sizeof(struct ksyms_hdr)
 1120 
 1121 static int
 1122 ksymsread(dev_t dev, struct uio *uio, int ioflag)
 1123 {
 1124         struct symtab *st;
 1125         size_t filepos, inpos, off;
 1126 
 1127 #ifdef KSYMS_DEBUG
 1128         if (ksyms_debug & FOLLOW_DEVKSYMS)
 1129                 printf("ksymsread: offset 0x%llx resid 0x%zx\n",
 1130                     (long long)uio->uio_offset, uio->uio_resid);
 1131 #endif
 1132 
 1133         off = uio->uio_offset;
 1134         if (off >= (strsz + symsz + HDRSIZ))
 1135                 return 0; /* End of symtab */
 1136         /*
 1137          * First: Copy out the ELF header.
 1138          */
 1139         if (off < HDRSIZ)
 1140                 uiomove((char *)&ksyms_hdr + off, HDRSIZ - off, uio);
 1141 
 1142         /*
 1143          * Copy out the symbol table.
 1144          */
 1145         filepos = HDRSIZ;
 1146         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
 1147                 if (uio->uio_resid == 0)
 1148                         return 0;
 1149                 if (uio->uio_offset <= st->sd_symsize + filepos) {
 1150                         inpos = uio->uio_offset - filepos;
 1151                         uiomove((char *)st->sd_symstart + inpos,
 1152                            st->sd_symsize - inpos, uio);
 1153                 }
 1154                 filepos += st->sd_symsize;
 1155         }
 1156 
 1157         if (filepos != HDRSIZ + symsz)
 1158                 panic("ksymsread: unsunc");
 1159 
 1160         /*
 1161          * Copy out the string table
 1162          */
 1163         CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
 1164                 if (uio->uio_resid == 0)
 1165                         return 0;
 1166                 if (uio->uio_offset <= st->sd_strsize + filepos) {
 1167                         inpos = uio->uio_offset - filepos;
 1168                         uiomove((char *)st->sd_strstart + inpos,
 1169                            st->sd_strsize - inpos, uio);
 1170                 }
 1171                 filepos += st->sd_strsize;
 1172         }
 1173         return 0;
 1174 }
 1175 
 1176 static int
 1177 ksymswrite(dev_t dev, struct uio *uio, int ioflag)
 1178 {
 1179 
 1180         return EROFS;
 1181 }
 1182 
 1183 static int
 1184 ksymsioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct lwp *l)
 1185 {
 1186         struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data;
 1187         struct symtab *st;
 1188         Elf_Sym *sym = NULL;
 1189         unsigned long val;
 1190         int error = 0;
 1191         char *str = NULL;
 1192 
 1193         if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL)
 1194                 str = malloc(ksyms_maxlen, M_DEVBUF, M_WAITOK);
 1195 
 1196         switch (cmd) {
 1197         case KIOCGVALUE:
 1198                 /*
 1199                  * Use the in-kernel symbol lookup code for fast
 1200                  * retreival of a value.
 1201                  */
 1202                 if ((error = copyinstr(kg->kg_name, str, ksyms_maxlen, NULL)))
 1203                         break;
 1204                 if ((error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN)))
 1205                         break;
 1206                 error = copyout(&val, kg->kg_value, sizeof(long));
 1207                 break;
 1208 
 1209         case KIOCGSYMBOL:
 1210                 /*
 1211                  * Use the in-kernel symbol lookup code for fast
 1212                  * retreival of a symbol.
 1213                  */
 1214                 if ((error = copyinstr(kg->kg_name, str, ksyms_maxlen, NULL)))
 1215                         break;
 1216                 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
 1217                         if ((sym = findsym(str, st)) == NULL) /* from userland */
 1218                                 continue;
 1219 
 1220                         /* Skip if bad binding */
 1221                         if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
 1222                                 sym = NULL;
 1223                                 continue;
 1224                         }
 1225                         break;
 1226                 }
 1227                 /*
 1228                  * XXX which value of sym->st_name should be returned?  The real
 1229                  * one, or the one that matches what reading /dev/ksyms get?
 1230                  *
 1231                  * Currently, we're returning the /dev/ksyms one.
 1232                  */
 1233                 if (sym != NULL)
 1234                         error = copyout(sym, kg->kg_sym, sizeof(Elf_Sym));
 1235                 else
 1236                         error = ENOENT;
 1237                 break;
 1238 
 1239         case KIOCGSIZE:
 1240                 /*
 1241                  * Get total size of symbol table.
 1242                  */
 1243                 *(int *)data = strsz + symsz + HDRSIZ;
 1244                 break;
 1245 
 1246         default:
 1247                 error = ENOTTY;
 1248                 break;
 1249         }
 1250 
 1251         if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL)
 1252                 free(str, M_DEVBUF);
 1253 
 1254         return error;
 1255 }
 1256 
 1257 const struct cdevsw ksyms_cdevsw = {
 1258         ksymsopen, ksymsclose, ksymsread, ksymswrite, ksymsioctl,
 1259             nullstop, notty, nopoll, nommap, nullkqfilter, DV_DULL
 1260 };
 1261 #endif /* NKSYMS */

Cache object: 8c92f709bcd9b92f9e275ba61c797d84


[ 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.