diff options
Diffstat (limited to 'kernel/kallsyms.c')
| -rw-r--r-- | kernel/kallsyms.c | 134 |
1 files changed, 78 insertions, 56 deletions
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 374faf9bfdc7..3a29dbe7898e 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
| @@ -30,12 +30,16 @@ | |||
| 30 | #define all_var 0 | 30 | #define all_var 0 |
| 31 | #endif | 31 | #endif |
| 32 | 32 | ||
| 33 | /* These will be re-linked against their real values during the second link stage */ | 33 | /* |
| 34 | * These will be re-linked against their real values | ||
| 35 | * during the second link stage. | ||
| 36 | */ | ||
| 34 | extern const unsigned long kallsyms_addresses[] __attribute__((weak)); | 37 | extern const unsigned long kallsyms_addresses[] __attribute__((weak)); |
| 35 | extern const u8 kallsyms_names[] __attribute__((weak)); | 38 | extern const u8 kallsyms_names[] __attribute__((weak)); |
| 36 | 39 | ||
| 37 | /* tell the compiler that the count isn't in the small data section if the arch | 40 | /* |
| 38 | * has one (eg: FRV) | 41 | * Tell the compiler that the count isn't in the small data section if the arch |
| 42 | * has one (eg: FRV). | ||
| 39 | */ | 43 | */ |
| 40 | extern const unsigned long kallsyms_num_syms | 44 | extern const unsigned long kallsyms_num_syms |
| 41 | __attribute__((weak, section(".rodata"))); | 45 | __attribute__((weak, section(".rodata"))); |
| @@ -75,31 +79,37 @@ static int is_ksym_addr(unsigned long addr) | |||
| 75 | return is_kernel_text(addr) || is_kernel_inittext(addr); | 79 | return is_kernel_text(addr) || is_kernel_inittext(addr); |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | /* expand a compressed symbol data into the resulting uncompressed string, | 82 | /* |
| 79 | given the offset to where the symbol is in the compressed stream */ | 83 | * Expand a compressed symbol data into the resulting uncompressed string, |
| 84 | * given the offset to where the symbol is in the compressed stream. | ||
| 85 | */ | ||
| 80 | static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) | 86 | static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) |
| 81 | { | 87 | { |
| 82 | int len, skipped_first = 0; | 88 | int len, skipped_first = 0; |
| 83 | const u8 *tptr, *data; | 89 | const u8 *tptr, *data; |
| 84 | 90 | ||
| 85 | /* get the compressed symbol length from the first symbol byte */ | 91 | /* Get the compressed symbol length from the first symbol byte. */ |
| 86 | data = &kallsyms_names[off]; | 92 | data = &kallsyms_names[off]; |
| 87 | len = *data; | 93 | len = *data; |
| 88 | data++; | 94 | data++; |
| 89 | 95 | ||
| 90 | /* update the offset to return the offset for the next symbol on | 96 | /* |
| 91 | * the compressed stream */ | 97 | * Update the offset to return the offset for the next symbol on |
| 98 | * the compressed stream. | ||
| 99 | */ | ||
| 92 | off += len + 1; | 100 | off += len + 1; |
| 93 | 101 | ||
| 94 | /* for every byte on the compressed symbol data, copy the table | 102 | /* |
| 95 | entry for that byte */ | 103 | * For every byte on the compressed symbol data, copy the table |
| 96 | while(len) { | 104 | * entry for that byte. |
| 97 | tptr = &kallsyms_token_table[ kallsyms_token_index[*data] ]; | 105 | */ |
| 106 | while (len) { | ||
| 107 | tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; | ||
| 98 | data++; | 108 | data++; |
| 99 | len--; | 109 | len--; |
| 100 | 110 | ||
| 101 | while (*tptr) { | 111 | while (*tptr) { |
| 102 | if(skipped_first) { | 112 | if (skipped_first) { |
| 103 | *result = *tptr; | 113 | *result = *tptr; |
| 104 | result++; | 114 | result++; |
| 105 | } else | 115 | } else |
| @@ -110,36 +120,46 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) | |||
| 110 | 120 | ||
| 111 | *result = '\0'; | 121 | *result = '\0'; |
| 112 | 122 | ||
| 113 | /* return to offset to the next symbol */ | 123 | /* Return to offset to the next symbol. */ |
| 114 | return off; | 124 | return off; |
| 115 | } | 125 | } |
| 116 | 126 | ||
| 117 | /* get symbol type information. This is encoded as a single char at the | 127 | /* |
| 118 | * begining of the symbol name */ | 128 | * Get symbol type information. This is encoded as a single char at the |
| 129 | * beginning of the symbol name. | ||
| 130 | */ | ||
| 119 | static char kallsyms_get_symbol_type(unsigned int off) | 131 | static char kallsyms_get_symbol_type(unsigned int off) |
| 120 | { | 132 | { |
| 121 | /* get just the first code, look it up in the token table, and return the | 133 | /* |
| 122 | * first char from this token */ | 134 | * Get just the first code, look it up in the token table, |
| 123 | return kallsyms_token_table[ kallsyms_token_index[ kallsyms_names[off+1] ] ]; | 135 | * and return the first char from this token. |
| 136 | */ | ||
| 137 | return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]]; | ||
| 124 | } | 138 | } |
| 125 | 139 | ||
| 126 | 140 | ||
| 127 | /* find the offset on the compressed stream given and index in the | 141 | /* |
| 128 | * kallsyms array */ | 142 | * Find the offset on the compressed stream given and index in the |
| 143 | * kallsyms array. | ||
| 144 | */ | ||
| 129 | static unsigned int get_symbol_offset(unsigned long pos) | 145 | static unsigned int get_symbol_offset(unsigned long pos) |
| 130 | { | 146 | { |
| 131 | const u8 *name; | 147 | const u8 *name; |
| 132 | int i; | 148 | int i; |
| 133 | 149 | ||
| 134 | /* use the closest marker we have. We have markers every 256 positions, | 150 | /* |
| 135 | * so that should be close enough */ | 151 | * Use the closest marker we have. We have markers every 256 positions, |
| 136 | name = &kallsyms_names[ kallsyms_markers[pos>>8] ]; | 152 | * so that should be close enough. |
| 153 | */ | ||
| 154 | name = &kallsyms_names[kallsyms_markers[pos >> 8]]; | ||
| 137 | 155 | ||
| 138 | /* sequentially scan all the symbols up to the point we're searching for. | 156 | /* |
| 139 | * Every symbol is stored in a [<len>][<len> bytes of data] format, so we | 157 | * Sequentially scan all the symbols up to the point we're searching |
| 140 | * just need to add the len to the current pointer for every symbol we | 158 | * for. Every symbol is stored in a [<len>][<len> bytes of data] format, |
| 141 | * wish to skip */ | 159 | * so we just need to add the len to the current pointer for every |
| 142 | for(i = 0; i < (pos&0xFF); i++) | 160 | * symbol we wish to skip. |
| 161 | */ | ||
| 162 | for (i = 0; i < (pos & 0xFF); i++) | ||
| 143 | name = name + (*name) + 1; | 163 | name = name + (*name) + 1; |
| 144 | 164 | ||
| 145 | return name - kallsyms_names; | 165 | return name - kallsyms_names; |
| @@ -190,7 +210,7 @@ static unsigned long get_symbol_pos(unsigned long addr, | |||
| 190 | /* This kernel should never had been booted. */ | 210 | /* This kernel should never had been booted. */ |
| 191 | BUG_ON(!kallsyms_addresses); | 211 | BUG_ON(!kallsyms_addresses); |
| 192 | 212 | ||
| 193 | /* do a binary search on the sorted kallsyms_addresses array */ | 213 | /* Do a binary search on the sorted kallsyms_addresses array. */ |
| 194 | low = 0; | 214 | low = 0; |
| 195 | high = kallsyms_num_syms; | 215 | high = kallsyms_num_syms; |
| 196 | 216 | ||
| @@ -203,15 +223,15 @@ static unsigned long get_symbol_pos(unsigned long addr, | |||
| 203 | } | 223 | } |
| 204 | 224 | ||
| 205 | /* | 225 | /* |
| 206 | * search for the first aliased symbol. Aliased | 226 | * Search for the first aliased symbol. Aliased |
| 207 | * symbols are symbols with the same address | 227 | * symbols are symbols with the same address. |
| 208 | */ | 228 | */ |
| 209 | while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low]) | 229 | while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low]) |
| 210 | --low; | 230 | --low; |
| 211 | 231 | ||
| 212 | symbol_start = kallsyms_addresses[low]; | 232 | symbol_start = kallsyms_addresses[low]; |
| 213 | 233 | ||
| 214 | /* Search for next non-aliased symbol */ | 234 | /* Search for next non-aliased symbol. */ |
| 215 | for (i = low + 1; i < kallsyms_num_syms; i++) { | 235 | for (i = low + 1; i < kallsyms_num_syms; i++) { |
| 216 | if (kallsyms_addresses[i] > symbol_start) { | 236 | if (kallsyms_addresses[i] > symbol_start) { |
| 217 | symbol_end = kallsyms_addresses[i]; | 237 | symbol_end = kallsyms_addresses[i]; |
| @@ -219,7 +239,7 @@ static unsigned long get_symbol_pos(unsigned long addr, | |||
| 219 | } | 239 | } |
| 220 | } | 240 | } |
| 221 | 241 | ||
| 222 | /* if we found no next symbol, we use the end of the section */ | 242 | /* If we found no next symbol, we use the end of the section. */ |
| 223 | if (!symbol_end) { | 243 | if (!symbol_end) { |
| 224 | if (is_kernel_inittext(addr)) | 244 | if (is_kernel_inittext(addr)) |
| 225 | symbol_end = (unsigned long)_einittext; | 245 | symbol_end = (unsigned long)_einittext; |
| @@ -252,10 +272,10 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, | |||
| 252 | 272 | ||
| 253 | /* | 273 | /* |
| 254 | * Lookup an address | 274 | * Lookup an address |
| 255 | * - modname is set to NULL if it's in the kernel | 275 | * - modname is set to NULL if it's in the kernel. |
| 256 | * - we guarantee that the returned name is valid until we reschedule even if | 276 | * - We guarantee that the returned name is valid until we reschedule even if. |
| 257 | * it resides in a module | 277 | * It resides in a module. |
| 258 | * - we also guarantee that modname will be valid until rescheduled | 278 | * - We also guarantee that modname will be valid until rescheduled. |
| 259 | */ | 279 | */ |
| 260 | const char *kallsyms_lookup(unsigned long addr, | 280 | const char *kallsyms_lookup(unsigned long addr, |
| 261 | unsigned long *symbolsize, | 281 | unsigned long *symbolsize, |
| @@ -276,7 +296,7 @@ const char *kallsyms_lookup(unsigned long addr, | |||
| 276 | return namebuf; | 296 | return namebuf; |
| 277 | } | 297 | } |
| 278 | 298 | ||
| 279 | /* see if it's in a module */ | 299 | /* See if it's in a module. */ |
| 280 | return module_address_lookup(addr, symbolsize, offset, modname, | 300 | return module_address_lookup(addr, symbolsize, offset, modname, |
| 281 | namebuf); | 301 | namebuf); |
| 282 | } | 302 | } |
| @@ -294,7 +314,7 @@ int lookup_symbol_name(unsigned long addr, char *symname) | |||
| 294 | kallsyms_expand_symbol(get_symbol_offset(pos), symname); | 314 | kallsyms_expand_symbol(get_symbol_offset(pos), symname); |
| 295 | return 0; | 315 | return 0; |
| 296 | } | 316 | } |
| 297 | /* see if it's in a module */ | 317 | /* See if it's in a module. */ |
| 298 | return lookup_module_symbol_name(addr, symname); | 318 | return lookup_module_symbol_name(addr, symname); |
| 299 | } | 319 | } |
| 300 | 320 | ||
| @@ -313,7 +333,7 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, | |||
| 313 | modname[0] = '\0'; | 333 | modname[0] = '\0'; |
| 314 | return 0; | 334 | return 0; |
| 315 | } | 335 | } |
| 316 | /* see if it's in a module */ | 336 | /* See if it's in a module. */ |
| 317 | return lookup_module_symbol_attrs(addr, size, offset, modname, name); | 337 | return lookup_module_symbol_attrs(addr, size, offset, modname, name); |
| 318 | } | 338 | } |
| 319 | 339 | ||
| @@ -342,6 +362,7 @@ int sprint_symbol(char *buffer, unsigned long address) | |||
| 342 | 362 | ||
| 343 | return len; | 363 | return len; |
| 344 | } | 364 | } |
| 365 | EXPORT_SYMBOL_GPL(sprint_symbol); | ||
| 345 | 366 | ||
| 346 | /* Look up a kernel symbol and print it to the kernel messages. */ | 367 | /* Look up a kernel symbol and print it to the kernel messages. */ |
| 347 | void __print_symbol(const char *fmt, unsigned long address) | 368 | void __print_symbol(const char *fmt, unsigned long address) |
| @@ -352,13 +373,13 @@ void __print_symbol(const char *fmt, unsigned long address) | |||
| 352 | 373 | ||
| 353 | printk(fmt, buffer); | 374 | printk(fmt, buffer); |
| 354 | } | 375 | } |
| 376 | EXPORT_SYMBOL(__print_symbol); | ||
| 355 | 377 | ||
| 356 | /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ | 378 | /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ |
| 357 | struct kallsym_iter | 379 | struct kallsym_iter { |
| 358 | { | ||
| 359 | loff_t pos; | 380 | loff_t pos; |
| 360 | unsigned long value; | 381 | unsigned long value; |
| 361 | unsigned int nameoff; /* If iterating in core kernel symbols */ | 382 | unsigned int nameoff; /* If iterating in core kernel symbols. */ |
| 362 | char type; | 383 | char type; |
| 363 | char name[KSYM_NAME_LEN]; | 384 | char name[KSYM_NAME_LEN]; |
| 364 | char module_name[MODULE_NAME_LEN]; | 385 | char module_name[MODULE_NAME_LEN]; |
| @@ -404,7 +425,7 @@ static int update_iter(struct kallsym_iter *iter, loff_t pos) | |||
| 404 | iter->pos = pos; | 425 | iter->pos = pos; |
| 405 | return get_ksymbol_mod(iter); | 426 | return get_ksymbol_mod(iter); |
| 406 | } | 427 | } |
| 407 | 428 | ||
| 408 | /* If we're not on the desired position, reset to new position. */ | 429 | /* If we're not on the desired position, reset to new position. */ |
| 409 | if (pos != iter->pos) | 430 | if (pos != iter->pos) |
| 410 | reset_iter(iter, pos); | 431 | reset_iter(iter, pos); |
| @@ -439,23 +460,25 @@ static int s_show(struct seq_file *m, void *p) | |||
| 439 | { | 460 | { |
| 440 | struct kallsym_iter *iter = m->private; | 461 | struct kallsym_iter *iter = m->private; |
| 441 | 462 | ||
| 442 | /* Some debugging symbols have no name. Ignore them. */ | 463 | /* Some debugging symbols have no name. Ignore them. */ |
| 443 | if (!iter->name[0]) | 464 | if (!iter->name[0]) |
| 444 | return 0; | 465 | return 0; |
| 445 | 466 | ||
| 446 | if (iter->module_name[0]) { | 467 | if (iter->module_name[0]) { |
| 447 | char type; | 468 | char type; |
| 448 | 469 | ||
| 449 | /* Label it "global" if it is exported, | 470 | /* |
| 450 | * "local" if not exported. */ | 471 | * Label it "global" if it is exported, |
| 472 | * "local" if not exported. | ||
| 473 | */ | ||
| 451 | type = iter->exported ? toupper(iter->type) : | 474 | type = iter->exported ? toupper(iter->type) : |
| 452 | tolower(iter->type); | 475 | tolower(iter->type); |
| 453 | seq_printf(m, "%0*lx %c %s\t[%s]\n", | 476 | seq_printf(m, "%0*lx %c %s\t[%s]\n", |
| 454 | (int)(2*sizeof(void*)), | 477 | (int)(2 * sizeof(void *)), |
| 455 | iter->value, type, iter->name, iter->module_name); | 478 | iter->value, type, iter->name, iter->module_name); |
| 456 | } else | 479 | } else |
| 457 | seq_printf(m, "%0*lx %c %s\n", | 480 | seq_printf(m, "%0*lx %c %s\n", |
| 458 | (int)(2*sizeof(void*)), | 481 | (int)(2 * sizeof(void *)), |
| 459 | iter->value, iter->type, iter->name); | 482 | iter->value, iter->type, iter->name); |
| 460 | return 0; | 483 | return 0; |
| 461 | } | 484 | } |
| @@ -469,9 +492,11 @@ static const struct seq_operations kallsyms_op = { | |||
| 469 | 492 | ||
| 470 | static int kallsyms_open(struct inode *inode, struct file *file) | 493 | static int kallsyms_open(struct inode *inode, struct file *file) |
| 471 | { | 494 | { |
| 472 | /* We keep iterator in m->private, since normal case is to | 495 | /* |
| 496 | * We keep iterator in m->private, since normal case is to | ||
| 473 | * s_start from where we left off, so we avoid doing | 497 | * s_start from where we left off, so we avoid doing |
| 474 | * using get_symbol_offset for every symbol */ | 498 | * using get_symbol_offset for every symbol. |
| 499 | */ | ||
| 475 | struct kallsym_iter *iter; | 500 | struct kallsym_iter *iter; |
| 476 | int ret; | 501 | int ret; |
| 477 | 502 | ||
| @@ -500,7 +525,4 @@ static int __init kallsyms_init(void) | |||
| 500 | proc_create("kallsyms", 0444, NULL, &kallsyms_operations); | 525 | proc_create("kallsyms", 0444, NULL, &kallsyms_operations); |
| 501 | return 0; | 526 | return 0; |
| 502 | } | 527 | } |
| 503 | __initcall(kallsyms_init); | 528 | device_initcall(kallsyms_init); |
| 504 | |||
| 505 | EXPORT_SYMBOL(__print_symbol); | ||
| 506 | EXPORT_SYMBOL_GPL(sprint_symbol); | ||
