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