]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
kallsyms: provide symbol sizes in /proc/kallmodsyms
authorNick Alcock <nick.alcock@oracle.com>
Fri, 29 Jun 2012 20:06:28 +0000 (21:06 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:40:25 +0000 (22:40 +0100)
For modules, we can simply extract these sizes from the module symtab; for core
kernel symbols, we must do subtraction as get_symbol_pos() did: this is now
abstracted into a new get_symbol_size().

Because /proc/kallmodsyms contains *all* symbols, where get_symbol_pos() was
normally only called for a small subset of symbols, this exercises this code
like never before, and has revealed a bug: the size of __per_cpu_end was being
returned as a ludicrously vast value, because the next symbol after
__per_cpu_end is far up the address space, in the kernel proper. Fixing this by
forcing a size of zero for __per_cpu_end is easy enough.

Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
include/linux/kallsyms.h
include/linux/module.h
kernel/kallsyms.c
kernel/module.c

index 8472c3dbace993f9b3ad0b0a90f3f48c27b2c0d7..d3ca092837256dfa40b7f8c29b398d547d1bd0fa 100644 (file)
@@ -22,11 +22,12 @@ struct kallsym_iter {
        loff_t pos;
        unsigned long value;
        unsigned int nameoff; /* If iterating in core kernel symbols. */
+       unsigned long size;
+       int builtin_module;
+       int exported;
        char type;
        char name[KSYM_NAME_LEN];
        char module_name[MODULE_NAME_LEN];
-       int builtin_module;
-       int exported;
 };
 
 /* Lookup the address for a symbol. Returns 0 if not found. */
index dc5f02be0980d482774bbe7379a02a9eaed7e6fb..192471649d981dd4f7d084b8819ade439f67db44 100644 (file)
@@ -448,7 +448,8 @@ bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
 /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
    symnum out of range. */
 int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
-                       char *name, char *module_name, int *exported);
+                      char *name, char *module_name, unsigned long *size,
+                      int *exported);
 
 /* Look for this name: can be of form module:name. */
 unsigned long module_kallsyms_lookup_name(const char *name);
@@ -595,8 +596,8 @@ static inline int lookup_module_symbol_attrs(unsigned long addr, unsigned long *
 }
 
 static inline int module_get_kallsym(unsigned int symnum, unsigned long *value,
-                                       char *type, char *name,
-                                       char *module_name, int *exported)
+                                    char *type, char *name, char *module_name,
+                                    unsigned long *size, int *exported)
 {
        return -ERANGE;
 }
index cf4b3a7e6a06e88ee6fe73ea6f122da1a7f5e9ec..c3cf2a24f29bafcd72f7dc349370a7ea8a92c915 100644 (file)
@@ -214,12 +214,58 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
 }
 EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol);
 
+static unsigned long get_symbol_size(unsigned long kallsyms_addr)
+{
+       unsigned long size = 0;
+       unsigned long sym_addr = kallsyms_addresses[kallsyms_addr];
+       unsigned long used_i = 0;
+       unsigned long used_i_addr = 0;
+
+       /*
+        * __per_cpu_end always has size zero.
+        */
+       if (sym_addr == (unsigned long)__per_cpu_end)
+               return 0;
+
+       /*
+        * Search for next non-aliased symbol.  Aliased symbols are symbols with
+        * the same address.
+        */
+       if (kallsyms_addr < (kallsyms_num_syms - 1)) {
+               unsigned long i;
+
+               for (i = kallsyms_addr + 1; i < kallsyms_num_syms; i++)
+                       if (kallsyms_addresses[i] > sym_addr) {
+                               size = kallsyms_addresses[i] - sym_addr;
+                               used_i = i;
+                               used_i_addr = kallsyms_addresses[i];
+                               break;
+                       }
+       }
+
+       /* If we found no next symbol, we use the end of the section. */
+       if (!size) {
+               unsigned long symbol_end;
+
+               if (is_kernel_inittext(sym_addr))
+                       symbol_end = (unsigned long)_einittext;
+               else if (all_var)
+                       symbol_end = (unsigned long)_end;
+               else
+                       symbol_end = (unsigned long)_etext;
+
+               size = symbol_end - sym_addr;
+       }
+
+       return size;
+}
+
+
 static unsigned long get_symbol_pos(unsigned long addr,
                                    unsigned long *symbolsize,
                                    unsigned long *offset)
 {
-       unsigned long symbol_start = 0, symbol_end = 0;
-       unsigned long i, low, high, mid;
+       unsigned long low, high, mid;
 
        /* This kernel should never had been booted. */
        BUG_ON(!kallsyms_addresses);
@@ -237,36 +283,15 @@ static unsigned long get_symbol_pos(unsigned long addr,
        }
 
        /*
-        * Search for the first aliased symbol. Aliased
-        * symbols are symbols with the same address.
+        * Search for the first aliased symbol.
         */
        while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
                --low;
 
-       symbol_start = kallsyms_addresses[low];
-
-       /* Search for next non-aliased symbol. */
-       for (i = low + 1; i < kallsyms_num_syms; i++) {
-               if (kallsyms_addresses[i] > symbol_start) {
-                       symbol_end = kallsyms_addresses[i];
-                       break;
-               }
-       }
-
-       /* If we found no next symbol, we use the end of the section. */
-       if (!symbol_end) {
-               if (is_kernel_inittext(addr))
-                       symbol_end = (unsigned long)_einittext;
-               else if (all_var)
-                       symbol_end = (unsigned long)_end;
-               else
-                       symbol_end = (unsigned long)_etext;
-       }
-
        if (symbolsize)
-               *symbolsize = symbol_end - symbol_start;
+               *symbolsize = get_symbol_size(low);
        if (offset)
-               *offset = addr - symbol_start;
+               *offset = addr - kallsyms_addresses[low];
 
        return low;
 }
@@ -451,8 +476,8 @@ static int get_ksymbol_mod(struct kallsym_iter *iter)
 {
        iter->builtin_module = 0;
        if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
-                               &iter->type, iter->name, iter->module_name,
-                               &iter->exported) < 0)
+                              &iter->type, iter->name, iter->module_name,
+                              &iter->size, &iter->exported) < 0)
                return 0;
        return 1;
 }
@@ -473,6 +498,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
        iter->exported = 0;
        iter->value = kallsyms_addresses[iter->pos];
 
+       iter->size = get_symbol_size(iter->pos);
        iter->type = kallsyms_get_symbol_type(off);
 
        off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name));
@@ -547,12 +573,18 @@ static int s_show_internal(struct seq_file *m, void *p, int builtin_modules)
                 */
                type = iter->exported ? toupper(iter->type) :
                                        tolower(iter->type);
-               seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
-                          type, iter->name, iter->module_name);
-       } else {
+               if (builtin_modules)
+                       seq_printf(m, "%pK %lx %c %s\t[%s]\n", (void *)iter->value,
+                                  iter->size, type, iter->name, iter->module_name);
+               else
+                       seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
+                                  type, iter->name, iter->module_name);
+       } else if (builtin_modules)
+               seq_printf(m, "%pK %lx %c %s\n", (void *)iter->value,
+                          iter->size, iter->type, iter->name);
+       else
                seq_printf(m, "%pK %c %s\n", (void *)iter->value,
                           iter->type, iter->name);
-       }
        return 0;
 }
 
index 656aaedf5bd2eb12e9959e034e38dd263b9565b7..c55b12485b4341bb08ec6b122075e70484e892ed 100644 (file)
@@ -3602,7 +3602,7 @@ out:
 }
 
 int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
-                       char *name, char *module_name, int *exported)
+                      char *name, char *module_name, unsigned long *size, int *exported)
 {
        struct module *mod;
 
@@ -3617,6 +3617,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                                KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, *value, mod);
+                       *size = mod->symtab[symnum].st_size;
                        preempt_enable();
                        return 0;
                }