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