OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [tags/] [linux-2.6/] [linux-2.6.24_orig/] [kernel/] [kallsyms.c] - Blame information for rev 5

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.