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/kernel/kallsyms.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  * kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
    3  *
    4  * Rewritten and vastly simplified by Rusty Russell for in-kernel
    5  * module loader:
    6  *   Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
    7  *
    8  * ChangeLog:
    9  *
   10  * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
   11  *      Changed the compression method from stem compression to "table lookup"
   12  *      compression (see scripts/kallsyms.c for a more complete description)
   13  */
   14 #include <linux/kallsyms.h>
   15 #include <linux/module.h>
   16 #include <linux/init.h>
   17 #include <linux/seq_file.h>
   18 #include <linux/fs.h>
   19 #include <linux/kdb.h>
   20 #include <linux/err.h>
   21 #include <linux/proc_fs.h>
   22 #include <linux/sched.h>        /* for cond_resched */
   23 #include <linux/mm.h>
   24 #include <linux/ctype.h>
   25 #include <linux/slab.h>
   26 
   27 #include <asm/sections.h>
   28 
   29 #ifdef CONFIG_KALLSYMS_ALL
   30 #define all_var 1
   31 #else
   32 #define all_var 0
   33 #endif
   34 
   35 /*
   36  * These will be re-linked against their real values
   37  * during the second link stage.
   38  */
   39 extern const unsigned long kallsyms_addresses[] __attribute__((weak));
   40 extern const u8 kallsyms_names[] __attribute__((weak));
   41 
   42 /*
   43  * Tell the compiler that the count isn't in the small data section if the arch
   44  * has one (eg: FRV).
   45  */
   46 extern const unsigned long kallsyms_num_syms
   47 __attribute__((weak, section(".rodata")));
   48 
   49 extern const u8 kallsyms_token_table[] __attribute__((weak));
   50 extern const u16 kallsyms_token_index[] __attribute__((weak));
   51 
   52 extern const unsigned long kallsyms_markers[] __attribute__((weak));
   53 
   54 static inline int is_kernel_inittext(unsigned long addr)
   55 {
   56         if (addr >= (unsigned long)_sinittext
   57             && addr <= (unsigned long)_einittext)
   58                 return 1;
   59         return 0;
   60 }
   61 
   62 static inline int is_kernel_text(unsigned long addr)
   63 {
   64         if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) ||
   65             arch_is_kernel_text(addr))
   66                 return 1;
   67         return in_gate_area_no_mm(addr);
   68 }
   69 
   70 static inline int is_kernel(unsigned long addr)
   71 {
   72         if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
   73                 return 1;
   74         return in_gate_area_no_mm(addr);
   75 }
   76 
   77 static int is_ksym_addr(unsigned long addr)
   78 {
   79         if (all_var)
   80                 return is_kernel(addr);
   81 
   82         return is_kernel_text(addr) || is_kernel_inittext(addr);
   83 }
   84 
   85 /*
   86  * Expand a compressed symbol data into the resulting uncompressed string,
   87  * given the offset to where the symbol is in the compressed stream.
   88  */
   89 static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
   90 {
   91         int len, skipped_first = 0;
   92         const u8 *tptr, *data;
   93 
   94         /* Get the compressed symbol length from the first symbol byte. */
   95         data = &kallsyms_names[off];
   96         len = *data;
   97         data++;
   98 
   99         /*
  100          * Update the offset to return the offset for the next symbol on
  101          * the compressed stream.
  102          */
  103         off += len + 1;
  104 
  105         /*
  106          * For every byte on the compressed symbol data, copy the table
  107          * entry for that byte.
  108          */
  109         while (len) {
  110                 tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
  111                 data++;
  112                 len--;
  113 
  114                 while (*tptr) {
  115                         if (skipped_first) {
  116                                 *result = *tptr;
  117                                 result++;
  118                         } else
  119                                 skipped_first = 1;
  120                         tptr++;
  121                 }
  122         }
  123 
  124         *result = '\0';
  125 
  126         /* Return to offset to the next symbol. */
  127         return off;
  128 }
  129 
  130 /*
  131  * Get symbol type information. This is encoded as a single char at the
  132  * beginning of the symbol name.
  133  */
  134 static char kallsyms_get_symbol_type(unsigned int off)
  135 {
  136         /*
  137          * Get just the first code, look it up in the token table,
  138          * and return the first char from this token.
  139          */
  140         return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]];
  141 }
  142 
  143 
  144 /*
  145  * Find the offset on the compressed stream given and index in the
  146  * kallsyms array.
  147  */
  148 static unsigned int get_symbol_offset(unsigned long pos)
  149 {
  150         const u8 *name;
  151         int i;
  152 
  153         /*
  154          * Use the closest marker we have. We have markers every 256 positions,
  155          * so that should be close enough.
  156          */
  157         name = &kallsyms_names[kallsyms_markers[pos >> 8]];
  158 
  159         /*
  160          * Sequentially scan all the symbols up to the point we're searching
  161          * for. Every symbol is stored in a [<len>][<len> bytes of data] format,
  162          * so we just need to add the len to the current pointer for every
  163          * symbol we wish to skip.
  164          */
  165         for (i = 0; i < (pos & 0xFF); i++)
  166                 name = name + (*name) + 1;
  167 
  168         return name - kallsyms_names;
  169 }
  170 
  171 /* Lookup the address for this symbol. Returns 0 if not found. */
  172 unsigned long kallsyms_lookup_name(const char *name)
  173 {
  174         char namebuf[KSYM_NAME_LEN];
  175         unsigned long i;
  176         unsigned int off;
  177 
  178         for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
  179                 off = kallsyms_expand_symbol(off, namebuf);
  180 
  181                 if (strcmp(namebuf, name) == 0)
  182                         return kallsyms_addresses[i];
  183         }
  184         return module_kallsyms_lookup_name(name);
  185 }
  186 EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
  187 
  188 int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
  189                                       unsigned long),
  190                             void *data)
  191 {
  192         char namebuf[KSYM_NAME_LEN];
  193         unsigned long i;
  194         unsigned int off;
  195         int ret;
  196 
  197         for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
  198                 off = kallsyms_expand_symbol(off, namebuf);
  199                 ret = fn(data, namebuf, NULL, kallsyms_addresses[i]);
  200                 if (ret != 0)
  201                         return ret;
  202         }
  203         return module_kallsyms_on_each_symbol(fn, data);
  204 }
  205 EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol);
  206 
  207 static unsigned long get_symbol_pos(unsigned long addr,
  208                                     unsigned long *symbolsize,
  209                                     unsigned long *offset)
  210 {
  211         unsigned long symbol_start = 0, symbol_end = 0;
  212         unsigned long i, low, high, mid;
  213 
  214         /* This kernel should never had been booted. */
  215         BUG_ON(!kallsyms_addresses);
  216 
  217         /* Do a binary search on the sorted kallsyms_addresses array. */
  218         low = 0;
  219         high = kallsyms_num_syms;
  220 
  221         while (high - low > 1) {
  222                 mid = low + (high - low) / 2;
  223                 if (kallsyms_addresses[mid] <= addr)
  224                         low = mid;
  225                 else
  226                         high = mid;
  227         }
  228 
  229         /*
  230          * Search for the first aliased symbol. Aliased
  231          * symbols are symbols with the same address.
  232          */
  233         while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
  234                 --low;
  235 
  236         symbol_start = kallsyms_addresses[low];
  237 
  238         /* Search for next non-aliased symbol. */
  239         for (i = low + 1; i < kallsyms_num_syms; i++) {
  240                 if (kallsyms_addresses[i] > symbol_start) {
  241                         symbol_end = kallsyms_addresses[i];
  242                         break;
  243                 }
  244         }
  245 
  246         /* If we found no next symbol, we use the end of the section. */
  247         if (!symbol_end) {
  248                 if (is_kernel_inittext(addr))
  249                         symbol_end = (unsigned long)_einittext;
  250                 else if (all_var)
  251                         symbol_end = (unsigned long)_end;
  252                 else
  253                         symbol_end = (unsigned long)_etext;
  254         }
  255 
  256         if (symbolsize)
  257                 *symbolsize = symbol_end - symbol_start;
  258         if (offset)
  259                 *offset = addr - symbol_start;
  260 
  261         return low;
  262 }
  263 
  264 /*
  265  * Lookup an address but don't bother to find any names.
  266  */
  267 int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
  268                                 unsigned long *offset)
  269 {
  270         char namebuf[KSYM_NAME_LEN];
  271         if (is_ksym_addr(addr))
  272                 return !!get_symbol_pos(addr, symbolsize, offset);
  273 
  274         return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf);
  275 }
  276 
  277 /*
  278  * Lookup an address
  279  * - modname is set to NULL if it's in the kernel.
  280  * - We guarantee that the returned name is valid until we reschedule even if.
  281  *   It resides in a module.
  282  * - We also guarantee that modname will be valid until rescheduled.
  283  */
  284 const char *kallsyms_lookup(unsigned long addr,
  285                             unsigned long *symbolsize,
  286                             unsigned long *offset,
  287                             char **modname, char *namebuf)
  288 {
  289         namebuf[KSYM_NAME_LEN - 1] = 0;
  290         namebuf[0] = 0;
  291 
  292         if (is_ksym_addr(addr)) {
  293                 unsigned long pos;
  294 
  295                 pos = get_symbol_pos(addr, symbolsize, offset);
  296                 /* Grab name */
  297                 kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
  298                 if (modname)
  299                         *modname = NULL;
  300                 return namebuf;
  301         }
  302 
  303         /* See if it's in a module. */
  304         return module_address_lookup(addr, symbolsize, offset, modname,
  305                                      namebuf);
  306 }
  307 
  308 int lookup_symbol_name(unsigned long addr, char *symname)
  309 {
  310         symname[0] = '\0';
  311         symname[KSYM_NAME_LEN - 1] = '\0';
  312 
  313         if (is_ksym_addr(addr)) {
  314                 unsigned long pos;
  315 
  316                 pos = get_symbol_pos(addr, NULL, NULL);
  317                 /* Grab name */
  318                 kallsyms_expand_symbol(get_symbol_offset(pos), symname);
  319                 return 0;
  320         }
  321         /* See if it's in a module. */
  322         return lookup_module_symbol_name(addr, symname);
  323 }
  324 
  325 int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
  326                         unsigned long *offset, char *modname, char *name)
  327 {
  328         name[0] = '\0';
  329         name[KSYM_NAME_LEN - 1] = '\0';
  330 
  331         if (is_ksym_addr(addr)) {
  332                 unsigned long pos;
  333 
  334                 pos = get_symbol_pos(addr, size, offset);
  335                 /* Grab name */
  336                 kallsyms_expand_symbol(get_symbol_offset(pos), name);
  337                 modname[0] = '\0';
  338                 return 0;
  339         }
  340         /* See if it's in a module. */
  341         return lookup_module_symbol_attrs(addr, size, offset, modname, name);
  342 }
  343 
  344 /* Look up a kernel symbol and return it in a text buffer. */
  345 static int __sprint_symbol(char *buffer, unsigned long address,
  346                            int symbol_offset, int add_offset)
  347 {
  348         char *modname;
  349         const char *name;
  350         unsigned long offset, size;
  351         int len;
  352 
  353         address += symbol_offset;
  354         name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
  355         if (!name)
  356                 return sprintf(buffer, "0x%lx", address);
  357 
  358         if (name != buffer)
  359                 strcpy(buffer, name);
  360         len = strlen(buffer);
  361         offset -= symbol_offset;
  362 
  363         if (add_offset)
  364                 len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);
  365 
  366         if (modname)
  367                 len += sprintf(buffer + len, " [%s]", modname);
  368 
  369         return len;
  370 }
  371 
  372 /**
  373  * sprint_symbol - Look up a kernel symbol and return it in a text buffer
  374  * @buffer: buffer to be stored
  375  * @address: address to lookup
  376  *
  377  * This function looks up a kernel symbol with @address and stores its name,
  378  * offset, size and module name to @buffer if possible. If no symbol was found,
  379  * just saves its @address as is.
  380  *
  381  * This function returns the number of bytes stored in @buffer.
  382  */
  383 int sprint_symbol(char *buffer, unsigned long address)
  384 {
  385         return __sprint_symbol(buffer, address, 0, 1);
  386 }
  387 EXPORT_SYMBOL_GPL(sprint_symbol);
  388 
  389 /**
  390  * sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer
  391  * @buffer: buffer to be stored
  392  * @address: address to lookup
  393  *
  394  * This function looks up a kernel symbol with @address and stores its name
  395  * and module name to @buffer if possible. If no symbol was found, just saves
  396  * its @address as is.
  397  *
  398  * This function returns the number of bytes stored in @buffer.
  399  */
  400 int sprint_symbol_no_offset(char *buffer, unsigned long address)
  401 {
  402         return __sprint_symbol(buffer, address, 0, 0);
  403 }
  404 EXPORT_SYMBOL_GPL(sprint_symbol_no_offset);
  405 
  406 /**
  407  * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer
  408  * @buffer: buffer to be stored
  409  * @address: address to lookup
  410  *
  411  * This function is for stack backtrace and does the same thing as
  412  * sprint_symbol() but with modified/decreased @address. If there is a
  413  * tail-call to the function marked "noreturn", gcc optimized out code after
  414  * the call so that the stack-saved return address could point outside of the
  415  * caller. This function ensures that kallsyms will find the original caller
  416  * by decreasing @address.
  417  *
  418  * This function returns the number of bytes stored in @buffer.
  419  */
  420 int sprint_backtrace(char *buffer, unsigned long address)
  421 {
  422         return __sprint_symbol(buffer, address, -1, 1);
  423 }
  424 
  425 /* Look up a kernel symbol and print it to the kernel messages. */
  426 void __print_symbol(const char *fmt, unsigned long address)
  427 {
  428         char buffer[KSYM_SYMBOL_LEN];
  429 
  430         sprint_symbol(buffer, address);
  431 
  432         printk(fmt, buffer);
  433 }
  434 EXPORT_SYMBOL(__print_symbol);
  435 
  436 /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
  437 struct kallsym_iter {
  438         loff_t pos;
  439         unsigned long value;
  440         unsigned int nameoff; /* If iterating in core kernel symbols. */
  441         char type;
  442         char name[KSYM_NAME_LEN];
  443         char module_name[MODULE_NAME_LEN];
  444         int exported;
  445 };
  446 
  447 static int get_ksymbol_mod(struct kallsym_iter *iter)
  448 {
  449         if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
  450                                 &iter->type, iter->name, iter->module_name,
  451                                 &iter->exported) < 0)
  452                 return 0;
  453         return 1;
  454 }
  455 
  456 /* Returns space to next name. */
  457 static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
  458 {
  459         unsigned off = iter->nameoff;
  460 
  461         iter->module_name[0] = '\0';
  462         iter->value = kallsyms_addresses[iter->pos];
  463 
  464         iter->type = kallsyms_get_symbol_type(off);
  465 
  466         off = kallsyms_expand_symbol(off, iter->name);
  467 
  468         return off - iter->nameoff;
  469 }
  470 
  471 static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
  472 {
  473         iter->name[0] = '\0';
  474         iter->nameoff = get_symbol_offset(new_pos);
  475         iter->pos = new_pos;
  476 }
  477 
  478 /* Returns false if pos at or past end of file. */
  479 static int update_iter(struct kallsym_iter *iter, loff_t pos)
  480 {
  481         /* Module symbols can be accessed randomly. */
  482         if (pos >= kallsyms_num_syms) {
  483                 iter->pos = pos;
  484                 return get_ksymbol_mod(iter);
  485         }
  486 
  487         /* If we're not on the desired position, reset to new position. */
  488         if (pos != iter->pos)
  489                 reset_iter(iter, pos);
  490 
  491         iter->nameoff += get_ksymbol_core(iter);
  492         iter->pos++;
  493 
  494         return 1;
  495 }
  496 
  497 static void *s_next(struct seq_file *m, void *p, loff_t *pos)
  498 {
  499         (*pos)++;
  500 
  501         if (!update_iter(m->private, *pos))
  502                 return NULL;
  503         return p;
  504 }
  505 
  506 static void *s_start(struct seq_file *m, loff_t *pos)
  507 {
  508         if (!update_iter(m->private, *pos))
  509                 return NULL;
  510         return m->private;
  511 }
  512 
  513 static void s_stop(struct seq_file *m, void *p)
  514 {
  515 }
  516 
  517 static int s_show(struct seq_file *m, void *p)
  518 {
  519         struct kallsym_iter *iter = m->private;
  520 
  521         /* Some debugging symbols have no name.  Ignore them. */
  522         if (!iter->name[0])
  523                 return 0;
  524 
  525         if (iter->module_name[0]) {
  526                 char type;
  527 
  528                 /*
  529                  * Label it "global" if it is exported,
  530                  * "local" if not exported.
  531                  */
  532                 type = iter->exported ? toupper(iter->type) :
  533                                         tolower(iter->type);
  534                 seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
  535                            type, iter->name, iter->module_name);
  536         } else
  537                 seq_printf(m, "%pK %c %s\n", (void *)iter->value,
  538                            iter->type, iter->name);
  539         return 0;
  540 }
  541 
  542 static const struct seq_operations kallsyms_op = {
  543         .start = s_start,
  544         .next = s_next,
  545         .stop = s_stop,
  546         .show = s_show
  547 };
  548 
  549 static int kallsyms_open(struct inode *inode, struct file *file)
  550 {
  551         /*
  552          * We keep iterator in m->private, since normal case is to
  553          * s_start from where we left off, so we avoid doing
  554          * using get_symbol_offset for every symbol.
  555          */
  556         struct kallsym_iter *iter;
  557         int ret;
  558 
  559         iter = kmalloc(sizeof(*iter), GFP_KERNEL);
  560         if (!iter)
  561                 return -ENOMEM;
  562         reset_iter(iter, 0);
  563 
  564         ret = seq_open(file, &kallsyms_op);
  565         if (ret == 0)
  566                 ((struct seq_file *)file->private_data)->private = iter;
  567         else
  568                 kfree(iter);
  569         return ret;
  570 }
  571 
  572 #ifdef  CONFIG_KGDB_KDB
  573 const char *kdb_walk_kallsyms(loff_t *pos)
  574 {
  575         static struct kallsym_iter kdb_walk_kallsyms_iter;
  576         if (*pos == 0) {
  577                 memset(&kdb_walk_kallsyms_iter, 0,
  578                        sizeof(kdb_walk_kallsyms_iter));
  579                 reset_iter(&kdb_walk_kallsyms_iter, 0);
  580         }
  581         while (1) {
  582                 if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
  583                         return NULL;
  584                 ++*pos;
  585                 /* Some debugging symbols have no name.  Ignore them. */
  586                 if (kdb_walk_kallsyms_iter.name[0])
  587                         return kdb_walk_kallsyms_iter.name;
  588         }
  589 }
  590 #endif  /* CONFIG_KGDB_KDB */
  591 
  592 static const struct file_operations kallsyms_operations = {
  593         .open = kallsyms_open,
  594         .read = seq_read,
  595         .llseek = seq_lseek,
  596         .release = seq_release_private,
  597 };
  598 
  599 static int __init kallsyms_init(void)
  600 {
  601         proc_create("kallsyms", 0444, NULL, &kallsyms_operations);
  602         return 0;
  603 }
  604 device_initcall(kallsyms_init);

Cache object: e96fab8d3090ec1e0f4b4da17a54719c


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