"Fossies" - the Fresh Open Source Software Archive

Member "modutils-2.4.27/example/kallsyms.c" (1 Mar 2002, 8091 Bytes) of package /linux/misc/old/modutils-2.4.27.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "kallsyms.c" see the Fossies "Dox" file reference documentation.

    1 /* An example of using kallsyms data in a kernel debugger.
    2 
    3    Copyright 2000 Keith Owens <kaos@ocs.com.au> April 2000
    4 
    5    This file is part of the Linux modutils.
    6 
    7    This program is free software; you can redistribute it and/or modify it
    8    under the terms of the GNU General Public License as published by the
    9    Free Software Foundation; either version 2 of the License, or (at your
   10    option) any later version.
   11 
   12    This program is distributed in the hope that it will be useful, but
   13    WITHOUT ANY WARRANTY; without even the implied warranty of
   14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15    General Public License for more details.
   16 
   17    You should have received a copy of the GNU General Public License
   18    along with this program; if not, write to the Free Software Foundation,
   19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   20   */
   21 
   22 /*
   23    This code uses the list of all kernel and module symbols to :-
   24 
   25    * Find any non-stack symbol in a kernel or module.  Symbols do
   26      not have to be exported for debugging.
   27 
   28    * Convert an address to the module (or kernel) that owns it, the
   29      section it is in and the nearest symbol.  This finds all non-stack
   30      symbols, not just exported ones.
   31 
   32    You need modutils >= 2.3.11 and a kernel with the kallsyms patch
   33    which was compiled with CONFIG_KALLSYMS.
   34  */
   35 
   36 #include <linux/elf.h>
   37 #include <linux/kernel.h>
   38 #include <linux/module.h>
   39 #include <linux/string.h>
   40 #include <linux/kallsyms.h>
   41 
   42 /* These external symbols are only available on kernels compiled with
   43  * CONFIG_KALLSYMS.
   44  */
   45 
   46 extern const char __start___kallsyms[];
   47 extern const char __stop___kallsyms[];
   48 
   49 static struct module *local_module_list;
   50 
   51 static void get_module_list(void)
   52 {
   53     const struct kallsyms_header    *ka_hdr;
   54     const struct kallsyms_section   *ka_sec;
   55     const struct kallsyms_symbol    *ka_sym;
   56     const char          *ka_str;
   57     int i;
   58     const char *p;
   59 
   60     if (__start___kallsyms >= __stop___kallsyms)
   61         return;
   62     ka_hdr = (struct kallsyms_header *)__start___kallsyms;
   63     ka_sec = (struct kallsyms_section *)
   64         ((char *)(ka_hdr) + ka_hdr->section_off);
   65     ka_sym = (struct kallsyms_symbol *)
   66         ((char *)(ka_hdr) + ka_hdr->symbol_off);
   67     ka_str =
   68         ((char *)(ka_hdr) + ka_hdr->string_off);
   69 
   70     for (i = 0; i < ka_hdr->symbols; kallsyms_next_sym(ka_hdr, ka_sym), ++i) {
   71         p = ka_str + ka_sym->name_off;
   72         if (strcmp(p, "module_list") == 0) {
   73             if (ka_sym->symbol_addr)
   74                 local_module_list = *((struct module **)(ka_sym->symbol_addr));
   75             break;
   76         }
   77     }
   78 }
   79 
   80 static void __inline__ do_first_time(void)
   81 {
   82     static int first_time = 1;
   83     if (first_time)
   84         get_module_list();
   85     first_time = 0;
   86 }
   87 
   88 /* A symbol can appear in more than one module.  A token is used to
   89  * restart the scan at the next module, set the token to 0 for the
   90  * first scan of each symbol.
   91  */
   92 
   93 int kallsyms_symbol_to_address(
   94     const char   *name,     /* Name to lookup */
   95     unsigned long    *token,    /* Which module to start at */
   96     const char  **mod_name, /* Set to module name */
   97     unsigned long    *mod_start,    /* Set to start address of module */
   98     unsigned long    *mod_end,  /* Set to end address of module */
   99     const char  **sec_name, /* Set to section name */
  100     unsigned long    *sec_start,    /* Set to start address of section */
  101     unsigned long    *sec_end,  /* Set to end address of section */
  102     const char  **sym_name, /* Set to full symbol name */
  103     unsigned long    *sym_start,    /* Set to start address of symbol */
  104     unsigned long    *sym_end   /* Set to end address of symbol */
  105     )
  106 {
  107     const struct kallsyms_header    *ka_hdr = NULL; /* stupid gcc */
  108     const struct kallsyms_section   *ka_sec;
  109     const struct kallsyms_symbol    *ka_sym = NULL;
  110     const char          *ka_str = NULL;
  111     const struct module *m;
  112     int i = 0, l;
  113     const char *p, *pt_R;
  114     char *p2;
  115 
  116     do_first_time();
  117 
  118     /* Restart? */
  119     m = local_module_list;
  120     if (token && *token) {
  121         for (; m; m = m->next)
  122             if ((unsigned long)m == *token)
  123                 break;
  124         if (m)
  125             m = m->next;
  126     }
  127 
  128     for (; m; m = m->next) {
  129         if (!mod_member_present(m, kallsyms_start) ||
  130             !mod_member_present(m, kallsyms_end) ||
  131             m->kallsyms_start >= m->kallsyms_end)
  132             continue;
  133         ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
  134         ka_sym = (struct kallsyms_symbol *)
  135             ((char *)(ka_hdr) + ka_hdr->symbol_off);
  136         ka_str =
  137             ((char *)(ka_hdr) + ka_hdr->string_off);
  138         for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
  139             p = ka_str + ka_sym->name_off;
  140             if (strcmp(p, name) == 0)
  141                 break;
  142             /* Unversioned requests match versioned names */
  143             if (!(pt_R = strstr(p, "_R")))
  144                 continue;
  145             l = strlen(pt_R);
  146             if (l < 10)
  147                 continue;   /* Not _R.*xxxxxxxx */
  148             (void)simple_strtoul(pt_R+l-8, &p2, 16);
  149             if (*p2)
  150                 continue;   /* Not _R.*xxxxxxxx */
  151             if (strncmp(p, name, pt_R-p) == 0)
  152                 break;  /* Match with version */
  153         }
  154         if (i < ka_hdr->symbols)
  155             break;
  156     }
  157 
  158     if (token)
  159         *token = (unsigned long)m;
  160     if (!m)
  161         return(0);  /* not found */
  162 
  163     ka_sec = (const struct kallsyms_section *)
  164         ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off);
  165     *mod_name = *(m->name) ? m->name : "kernel";
  166     *mod_start = ka_hdr->start;
  167     *mod_end = ka_hdr->end;
  168     *sec_name = ka_sec->name_off + ka_str;
  169     *sec_start = ka_sec->start;
  170     *sec_end = ka_sec->start + ka_sec->size;
  171     *sym_name = ka_sym->name_off + ka_str;
  172     *sym_start = ka_sym->symbol_addr;
  173     if (i < ka_hdr->symbols-1) {
  174         const struct kallsyms_symbol *ka_symn = ka_sym;
  175         kallsyms_next_sym(ka_hdr, ka_symn);
  176         *sym_end = ka_symn->symbol_addr;
  177     }
  178     else
  179         *sym_end = *sec_end;
  180     return(1);
  181 }
  182 
  183 int kallsyms_address_to_symbol(
  184     unsigned long     address,  /* Address to lookup */
  185     const char  **mod_name, /* Set to module name */
  186     unsigned long    *mod_start,    /* Set to start address of module */
  187     unsigned long    *mod_end,  /* Set to end address of module */
  188     const char  **sec_name, /* Set to section name */
  189     unsigned long    *sec_start,    /* Set to start address of section */
  190     unsigned long    *sec_end,  /* Set to end address of section */
  191     const char  **sym_name, /* Set to full symbol name */
  192     unsigned long    *sym_start,    /* Set to start address of symbol */
  193     unsigned long    *sym_end   /* Set to end address of symbol */
  194     )
  195 {
  196     const struct kallsyms_header    *ka_hdr = NULL; /* stupid gcc */
  197     const struct kallsyms_section   *ka_sec = NULL;
  198     const struct kallsyms_symbol    *ka_sym;
  199     const char          *ka_str;
  200     const struct module *m;
  201     int i;
  202     unsigned long end;
  203 
  204     do_first_time();
  205 
  206     for (m = local_module_list; m; m = m->next) {
  207         if (!mod_member_present(m, kallsyms_start) ||
  208             !mod_member_present(m, kallsyms_end) ||
  209             m->kallsyms_start >= m->kallsyms_end)
  210             continue;
  211         ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
  212         ka_sec = (const struct kallsyms_section *)
  213             ((char *)ka_hdr + ka_hdr->section_off);
  214         /* Is the address in any section in this module? */
  215         for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
  216             if (ka_sec->start <= address &&
  217                 (ka_sec->start + ka_sec->size) > address)
  218                 break;
  219         }
  220         if (i < ka_hdr->sections)
  221             break;  /* Found a matching section */
  222     }
  223 
  224     if (!m)
  225         return(0);  /* not found */
  226 
  227     ka_sym = (struct kallsyms_symbol *)
  228         ((char *)(ka_hdr) + ka_hdr->symbol_off);
  229     ka_str =
  230         ((char *)(ka_hdr) + ka_hdr->string_off);
  231     *mod_name = *(m->name) ? m->name : "kernel";
  232     *mod_start = ka_hdr->start;
  233     *mod_end = ka_hdr->end;
  234     *sec_name = ka_sec->name_off + ka_str;
  235     *sec_start = ka_sec->start;
  236     *sec_end = ka_sec->start + ka_sec->size;
  237     *sym_name = *sec_name;      /* In case we find no matching symbol */
  238     *sym_start = *sec_start;
  239     *sym_end = *sec_end;
  240 
  241     for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
  242         if (ka_sym->symbol_addr > address)
  243             continue;
  244         if (i < ka_hdr->symbols-1) {
  245             const struct kallsyms_symbol *ka_symn = ka_sym;
  246             kallsyms_next_sym(ka_hdr, ka_symn);
  247             end = ka_symn->symbol_addr;
  248         }
  249         else
  250             end = *sec_end;
  251         if (end <= address)
  252             continue;
  253         if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off
  254             != (char *)ka_sec)
  255             continue;   /* wrong section */
  256         *sym_name = ka_str + ka_sym->name_off;
  257         *sym_start = ka_sym->symbol_addr;
  258         *sym_end = end;
  259         break;
  260     }
  261     return(1);
  262 }