~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to kernel/kallsyms.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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
        buffer += len;
 
362
        offset -= symbol_offset;
 
363
 
 
364
        if (modname)
 
365
                len += sprintf(buffer, "+%#lx/%#lx [%s]", offset, size, modname);
 
366
        else
 
367
                len += sprintf(buffer, "+%#lx/%#lx", offset, size);
 
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);
 
386
}
 
387
 
 
388
EXPORT_SYMBOL_GPL(sprint_symbol);
 
389
 
 
390
/**
 
391
 * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer
 
392
 * @buffer: buffer to be stored
 
393
 * @address: address to lookup
 
394
 *
 
395
 * This function is for stack backtrace and does the same thing as
 
396
 * sprint_symbol() but with modified/decreased @address. If there is a
 
397
 * tail-call to the function marked "noreturn", gcc optimized out code after
 
398
 * the call so that the stack-saved return address could point outside of the
 
399
 * caller. This function ensures that kallsyms will find the original caller
 
400
 * by decreasing @address.
 
401
 *
 
402
 * This function returns the number of bytes stored in @buffer.
 
403
 */
 
404
int sprint_backtrace(char *buffer, unsigned long address)
 
405
{
 
406
        return __sprint_symbol(buffer, address, -1);
 
407
}
 
408
 
 
409
/* Look up a kernel symbol and print it to the kernel messages. */
 
410
void __print_symbol(const char *fmt, unsigned long address)
 
411
{
 
412
        char buffer[KSYM_SYMBOL_LEN];
 
413
 
 
414
        sprint_symbol(buffer, address);
 
415
 
 
416
        printk(fmt, buffer);
 
417
}
 
418
EXPORT_SYMBOL(__print_symbol);
 
419
 
 
420
/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
 
421
struct kallsym_iter {
 
422
        loff_t pos;
 
423
        unsigned long value;
 
424
        unsigned int nameoff; /* If iterating in core kernel symbols. */
 
425
        char type;
 
426
        char name[KSYM_NAME_LEN];
 
427
        char module_name[MODULE_NAME_LEN];
 
428
        int exported;
 
429
};
 
430
 
 
431
static int get_ksymbol_mod(struct kallsym_iter *iter)
 
432
{
 
433
        if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
 
434
                                &iter->type, iter->name, iter->module_name,
 
435
                                &iter->exported) < 0)
 
436
                return 0;
 
437
        return 1;
 
438
}
 
439
 
 
440
/* Returns space to next name. */
 
441
static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
 
442
{
 
443
        unsigned off = iter->nameoff;
 
444
 
 
445
        iter->module_name[0] = '\0';
 
446
        iter->value = kallsyms_addresses[iter->pos];
 
447
 
 
448
        iter->type = kallsyms_get_symbol_type(off);
 
449
 
 
450
        off = kallsyms_expand_symbol(off, iter->name);
 
451
 
 
452
        return off - iter->nameoff;
 
453
}
 
454
 
 
455
static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
 
456
{
 
457
        iter->name[0] = '\0';
 
458
        iter->nameoff = get_symbol_offset(new_pos);
 
459
        iter->pos = new_pos;
 
460
}
 
461
 
 
462
/* Returns false if pos at or past end of file. */
 
463
static int update_iter(struct kallsym_iter *iter, loff_t pos)
 
464
{
 
465
        /* Module symbols can be accessed randomly. */
 
466
        if (pos >= kallsyms_num_syms) {
 
467
                iter->pos = pos;
 
468
                return get_ksymbol_mod(iter);
 
469
        }
 
470
 
 
471
        /* If we're not on the desired position, reset to new position. */
 
472
        if (pos != iter->pos)
 
473
                reset_iter(iter, pos);
 
474
 
 
475
        iter->nameoff += get_ksymbol_core(iter);
 
476
        iter->pos++;
 
477
 
 
478
        return 1;
 
479
}
 
480
 
 
481
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 
482
{
 
483
        (*pos)++;
 
484
 
 
485
        if (!update_iter(m->private, *pos))
 
486
                return NULL;
 
487
        return p;
 
488
}
 
489
 
 
490
static void *s_start(struct seq_file *m, loff_t *pos)
 
491
{
 
492
        if (!update_iter(m->private, *pos))
 
493
                return NULL;
 
494
        return m->private;
 
495
}
 
496
 
 
497
static void s_stop(struct seq_file *m, void *p)
 
498
{
 
499
}
 
500
 
 
501
static int s_show(struct seq_file *m, void *p)
 
502
{
 
503
        struct kallsym_iter *iter = m->private;
 
504
 
 
505
        /* Some debugging symbols have no name.  Ignore them. */
 
506
        if (!iter->name[0])
 
507
                return 0;
 
508
 
 
509
        if (iter->module_name[0]) {
 
510
                char type;
 
511
 
 
512
                /*
 
513
                 * Label it "global" if it is exported,
 
514
                 * "local" if not exported.
 
515
                 */
 
516
                type = iter->exported ? toupper(iter->type) :
 
517
                                        tolower(iter->type);
 
518
                seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
 
519
                           type, iter->name, iter->module_name);
 
520
        } else
 
521
                seq_printf(m, "%pK %c %s\n", (void *)iter->value,
 
522
                           iter->type, iter->name);
 
523
        return 0;
 
524
}
 
525
 
 
526
static const struct seq_operations kallsyms_op = {
 
527
        .start = s_start,
 
528
        .next = s_next,
 
529
        .stop = s_stop,
 
530
        .show = s_show
 
531
};
 
532
 
 
533
static int kallsyms_open(struct inode *inode, struct file *file)
 
534
{
 
535
        /*
 
536
         * We keep iterator in m->private, since normal case is to
 
537
         * s_start from where we left off, so we avoid doing
 
538
         * using get_symbol_offset for every symbol.
 
539
         */
 
540
        struct kallsym_iter *iter;
 
541
        int ret;
 
542
 
 
543
        iter = kmalloc(sizeof(*iter), GFP_KERNEL);
 
544
        if (!iter)
 
545
                return -ENOMEM;
 
546
        reset_iter(iter, 0);
 
547
 
 
548
        ret = seq_open(file, &kallsyms_op);
 
549
        if (ret == 0)
 
550
                ((struct seq_file *)file->private_data)->private = iter;
 
551
        else
 
552
                kfree(iter);
 
553
        return ret;
 
554
}
 
555
 
 
556
#ifdef  CONFIG_KGDB_KDB
 
557
const char *kdb_walk_kallsyms(loff_t *pos)
 
558
{
 
559
        static struct kallsym_iter kdb_walk_kallsyms_iter;
 
560
        if (*pos == 0) {
 
561
                memset(&kdb_walk_kallsyms_iter, 0,
 
562
                       sizeof(kdb_walk_kallsyms_iter));
 
563
                reset_iter(&kdb_walk_kallsyms_iter, 0);
 
564
        }
 
565
        while (1) {
 
566
                if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
 
567
                        return NULL;
 
568
                ++*pos;
 
569
                /* Some debugging symbols have no name.  Ignore them. */
 
570
                if (kdb_walk_kallsyms_iter.name[0])
 
571
                        return kdb_walk_kallsyms_iter.name;
 
572
        }
 
573
}
 
574
#endif  /* CONFIG_KGDB_KDB */
 
575
 
 
576
static const struct file_operations kallsyms_operations = {
 
577
        .open = kallsyms_open,
 
578
        .read = seq_read,
 
579
        .llseek = seq_lseek,
 
580
        .release = seq_release_private,
 
581
};
 
582
 
 
583
static int __init kallsyms_init(void)
 
584
{
 
585
        proc_create("kallsyms", 0444, NULL, &kallsyms_operations);
 
586
        return 0;
 
587
}
 
588
device_initcall(kallsyms_init);