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