Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us