Root/kernel/kallsyms.c

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

Archive Download this file



interactive