1 // SPDX-License-Identifier: GPL-2.0-only << 2 /* 1 /* 3 * kallsyms.c: in-kernel printing of symbolic 2 * kallsyms.c: in-kernel printing of symbolic oopses and stack traces. 4 * 3 * 5 * Rewritten and vastly simplified by Rusty Ru 4 * Rewritten and vastly simplified by Rusty Russell for in-kernel 6 * module loader: 5 * module loader: 7 * Copyright 2002 Rusty Russell <rusty@rustc 6 * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation 8 * !! 7 * Stem compression by Andi Kleen. 9 * ChangeLog: << 10 * << 11 * (25/Aug/2004) Paulo Marques <pmarques@grupo << 12 * Changed the compression method from st << 13 * compression (see scripts/kallsyms.c fo << 14 */ 8 */ 15 #include <linux/kallsyms.h> 9 #include <linux/kallsyms.h> >> 10 #include <linux/module.h> 16 #include <linux/init.h> 11 #include <linux/init.h> 17 #include <linux/seq_file.h> 12 #include <linux/seq_file.h> 18 #include <linux/fs.h> 13 #include <linux/fs.h> 19 #include <linux/kdb.h> << 20 #include <linux/err.h> 14 #include <linux/err.h> 21 #include <linux/proc_fs.h> 15 #include <linux/proc_fs.h> 22 #include <linux/sched.h> /* for cond_re << 23 #include <linux/ctype.h> << 24 #include <linux/slab.h> << 25 #include <linux/filter.h> << 26 #include <linux/ftrace.h> << 27 #include <linux/kprobes.h> << 28 #include <linux/build_bug.h> << 29 #include <linux/compiler.h> << 30 #include <linux/module.h> << 31 #include <linux/kernel.h> << 32 #include <linux/bsearch.h> << 33 #include <linux/btf_ids.h> << 34 << 35 #include "kallsyms_internal.h" << 36 << 37 /* << 38 * Expand a compressed symbol data into the re << 39 * if uncompressed string is too long (>= maxl << 40 * given the offset to where the symbol is in << 41 */ << 42 static unsigned int kallsyms_expand_symbol(uns << 43 cha << 44 { << 45 int len, skipped_first = 0; << 46 const char *tptr; << 47 const u8 *data; << 48 << 49 /* Get the compressed symbol length fr << 50 data = &kallsyms_names[off]; << 51 len = *data; << 52 data++; << 53 off++; << 54 << 55 /* If MSB is 1, it is a "big" symbol, << 56 if ((len & 0x80) != 0) { << 57 len = (len & 0x7F) | (*data << << 58 data++; << 59 off++; << 60 } << 61 << 62 /* << 63 * Update the offset to return the off << 64 * the compressed stream. << 65 */ << 66 off += len; << 67 << 68 /* << 69 * For every byte on the compressed sy << 70 * entry for that byte. << 71 */ << 72 while (len) { << 73 tptr = &kallsyms_token_table[k << 74 data++; << 75 len--; << 76 << 77 while (*tptr) { << 78 if (skipped_first) { << 79 if (maxlen <= << 80 goto t << 81 *result = *tpt << 82 result++; << 83 maxlen--; << 84 } else << 85 skipped_first << 86 tptr++; << 87 } << 88 } << 89 << 90 tail: << 91 if (maxlen) << 92 *result = '\0'; << 93 << 94 /* Return to offset to the next symbol << 95 return off; << 96 } << 97 << 98 /* << 99 * Get symbol type information. This is encode << 100 * beginning of the symbol name. << 101 */ << 102 static char kallsyms_get_symbol_type(unsigned << 103 { << 104 /* << 105 * Get just the first code, look it up << 106 * and return the first char from this << 107 */ << 108 return kallsyms_token_table[kallsyms_t << 109 } << 110 << 111 << 112 /* << 113 * Find the offset on the compressed stream gi << 114 * kallsyms array. << 115 */ << 116 static unsigned int get_symbol_offset(unsigned << 117 { << 118 const u8 *name; << 119 int i, len; << 120 << 121 /* << 122 * Use the closest marker we have. We << 123 * so that should be close enough. << 124 */ << 125 name = &kallsyms_names[kallsyms_marker << 126 << 127 /* << 128 * Sequentially scan all the symbols u << 129 * for. Every symbol is stored in a [< << 130 * so we just need to add the len to t << 131 * symbol we wish to skip. << 132 */ << 133 for (i = 0; i < (pos & 0xFF); i++) { << 134 len = *name; << 135 << 136 /* << 137 * If MSB is 1, it is a "big" << 138 * the next byte (and skip it, << 139 */ << 140 if ((len & 0x80) != 0) << 141 len = ((len & 0x7F) | << 142 << 143 name = name + len + 1; << 144 } << 145 << 146 return name - kallsyms_names; << 147 } << 148 16 149 unsigned long kallsyms_sym_address(int idx) !! 17 /* These will be re-linked against their real values during the second link stage */ 150 { !! 18 extern unsigned long kallsyms_addresses[] __attribute__((weak)); 151 /* values are unsigned offsets if --ab !! 19 extern unsigned long kallsyms_num_syms __attribute__((weak)); 152 if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLU !! 20 extern char kallsyms_names[] __attribute__((weak)); 153 return kallsyms_relative_base << 154 << 155 /* ...otherwise, positive offsets are << 156 if (kallsyms_offsets[idx] >= 0) << 157 return kallsyms_offsets[idx]; << 158 << 159 /* ...and negative offsets are relativ << 160 return kallsyms_relative_base - 1 - ka << 161 } << 162 21 163 static unsigned int get_symbol_seq(int index) !! 22 /* Defined by the linker script. */ 164 { !! 23 extern char _stext[], _etext[], _sinittext[], _einittext[]; 165 unsigned int i, seq = 0; << 166 << 167 for (i = 0; i < 3; i++) << 168 seq = (seq << 8) | kallsyms_se << 169 << 170 return seq; << 171 } << 172 24 173 static int kallsyms_lookup_names(const char *n !! 25 static inline int is_kernel_inittext(unsigned long addr) 174 unsigned int << 175 unsigned int << 176 { 26 { 177 int ret; !! 27 if (addr >= (unsigned long)_sinittext 178 int low, mid, high; !! 28 && addr <= (unsigned long)_einittext) 179 unsigned int seq, off; !! 29 return 1; 180 char namebuf[KSYM_NAME_LEN]; << 181 << 182 low = 0; << 183 high = kallsyms_num_syms - 1; << 184 << 185 while (low <= high) { << 186 mid = low + (high - low) / 2; << 187 seq = get_symbol_seq(mid); << 188 off = get_symbol_offset(seq); << 189 kallsyms_expand_symbol(off, na << 190 ret = strcmp(name, namebuf); << 191 if (ret > 0) << 192 low = mid + 1; << 193 else if (ret < 0) << 194 high = mid - 1; << 195 else << 196 break; << 197 } << 198 << 199 if (low > high) << 200 return -ESRCH; << 201 << 202 low = mid; << 203 while (low) { << 204 seq = get_symbol_seq(low - 1); << 205 off = get_symbol_offset(seq); << 206 kallsyms_expand_symbol(off, na << 207 if (strcmp(name, namebuf)) << 208 break; << 209 low--; << 210 } << 211 *start = low; << 212 << 213 if (end) { << 214 high = mid; << 215 while (high < kallsyms_num_sym << 216 seq = get_symbol_seq(h << 217 off = get_symbol_offse << 218 kallsyms_expand_symbol << 219 if (strcmp(name, nameb << 220 break; << 221 high++; << 222 } << 223 *end = high; << 224 } << 225 << 226 return 0; 30 return 0; 227 } 31 } 228 32 229 /* Lookup the address for this symbol. Returns !! 33 static inline int is_kernel_text(unsigned long addr) 230 unsigned long kallsyms_lookup_name(const char << 231 { 34 { 232 int ret; !! 35 if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) 233 unsigned int i; !! 36 return 1; 234 << 235 /* Skip the search for empty string. * << 236 if (!*name) << 237 return 0; << 238 << 239 ret = kallsyms_lookup_names(name, &i, << 240 if (!ret) << 241 return kallsyms_sym_address(ge << 242 << 243 return module_kallsyms_lookup_name(nam << 244 } << 245 << 246 /* << 247 * Iterate over all symbols in vmlinux. For s << 248 * module_kallsyms_on_each_symbol instead. << 249 */ << 250 int kallsyms_on_each_symbol(int (*fn)(void *, << 251 void *data) << 252 { << 253 char namebuf[KSYM_NAME_LEN]; << 254 unsigned long i; << 255 unsigned int off; << 256 int ret; << 257 << 258 for (i = 0, off = 0; i < kallsyms_num_ << 259 off = kallsyms_expand_symbol(o << 260 ret = fn(data, namebuf, kallsy << 261 if (ret != 0) << 262 return ret; << 263 cond_resched(); << 264 } << 265 return 0; 37 return 0; 266 } 38 } 267 39 268 int kallsyms_on_each_match_symbol(int (*fn)(vo !! 40 /* Lookup an address. modname is set to NULL if it's in the kernel. */ 269 const char * !! 41 const char *kallsyms_lookup(unsigned long addr, >> 42 unsigned long *symbolsize, >> 43 unsigned long *offset, >> 44 char **modname, char *namebuf) 270 { 45 { 271 int ret; !! 46 unsigned long i, best = 0; 272 unsigned int i, start, end; << 273 47 274 ret = kallsyms_lookup_names(name, &sta !! 48 /* This kernel should never had been booted. */ 275 if (ret) !! 49 BUG_ON(!kallsyms_addresses); 276 return 0; << 277 << 278 for (i = start; !ret && i <= end; i++) << 279 ret = fn(data, kallsyms_sym_ad << 280 cond_resched(); << 281 } << 282 50 283 return ret; !! 51 namebuf[127] = 0; 284 } !! 52 namebuf[0] = 0; 285 53 286 static unsigned long get_symbol_pos(unsigned l !! 54 if (is_kernel_text(addr) || is_kernel_inittext(addr)) { 287 unsigned l !! 55 unsigned long symbol_end; 288 unsigned l !! 56 char *name = kallsyms_names; 289 { !! 57 290 unsigned long symbol_start = 0, symbol !! 58 /* They're sorted, we could be clever here, but who cares? */ 291 unsigned long i, low, high, mid; !! 59 for (i = 0; i < kallsyms_num_syms; i++) { 292 !! 60 if (kallsyms_addresses[i] > kallsyms_addresses[best] && 293 /* Do a binary search on the sorted ka !! 61 kallsyms_addresses[i] <= addr) 294 low = 0; !! 62 best = i; 295 high = kallsyms_num_syms; !! 63 } 296 << 297 while (high - low > 1) { << 298 mid = low + (high - low) / 2; << 299 if (kallsyms_sym_address(mid) << 300 low = mid; << 301 else << 302 high = mid; << 303 } << 304 64 305 /* !! 65 /* Grab name */ 306 * Search for the first aliased symbol !! 66 for (i = 0; i <= best; i++) { 307 * symbols are symbols with the same a !! 67 unsigned prefix = *name++; 308 */ !! 68 strncpy(namebuf + prefix, name, 127 - prefix); 309 while (low && kallsyms_sym_address(low !! 69 name += strlen(name) + 1; 310 --low; << 311 << 312 symbol_start = kallsyms_sym_address(lo << 313 << 314 /* Search for next non-aliased symbol. << 315 for (i = low + 1; i < kallsyms_num_sym << 316 if (kallsyms_sym_address(i) > << 317 symbol_end = kallsyms_ << 318 break; << 319 } 70 } 320 } << 321 71 322 /* If we found no next symbol, we use !! 72 /* Base symbol size on next symbol. */ 323 if (!symbol_end) { !! 73 if (best + 1 < kallsyms_num_syms) 324 if (is_kernel_inittext(addr)) !! 74 symbol_end = kallsyms_addresses[best + 1]; >> 75 else if (is_kernel_inittext(addr)) 325 symbol_end = (unsigned 76 symbol_end = (unsigned long)_einittext; 326 else if (IS_ENABLED(CONFIG_KAL << 327 symbol_end = (unsigned << 328 else 77 else 329 symbol_end = (unsigned 78 symbol_end = (unsigned long)_etext; 330 } << 331 << 332 if (symbolsize) << 333 *symbolsize = symbol_end - sym << 334 if (offset) << 335 *offset = addr - symbol_start; << 336 << 337 return low; << 338 } << 339 << 340 /* << 341 * Lookup an address but don't bother to find << 342 */ << 343 int kallsyms_lookup_size_offset(unsigned long << 344 unsigned long << 345 { << 346 char namebuf[KSYM_NAME_LEN]; << 347 << 348 if (is_ksym_addr(addr)) { << 349 get_symbol_pos(addr, symbolsiz << 350 return 1; << 351 } << 352 return !!module_address_lookup(addr, s << 353 !!__bpf_address_lookup(addr, sy << 354 } << 355 << 356 static int kallsyms_lookup_buildid(unsigned lo << 357 unsigned long *symbols << 358 unsigned long *offset, << 359 const unsigned char ** << 360 { << 361 int ret; << 362 << 363 namebuf[KSYM_NAME_LEN - 1] = 0; << 364 namebuf[0] = 0; << 365 << 366 if (is_ksym_addr(addr)) { << 367 unsigned long pos; << 368 << 369 pos = get_symbol_pos(addr, sym << 370 /* Grab name */ << 371 kallsyms_expand_symbol(get_sym << 372 namebuf << 373 if (modname) << 374 *modname = NULL; << 375 if (modbuildid) << 376 *modbuildid = NULL; << 377 79 378 return strlen(namebuf); !! 80 *symbolsize = symbol_end - kallsyms_addresses[best]; >> 81 *modname = NULL; >> 82 *offset = addr - kallsyms_addresses[best]; >> 83 return namebuf; 379 } 84 } 380 85 381 /* See if it's in a module or a BPF JI !! 86 return module_address_lookup(addr, symbolsize, offset, modname); 382 ret = module_address_lookup(addr, symb << 383 modname, m << 384 if (!ret) << 385 ret = bpf_address_lookup(addr, << 386 offse << 387 << 388 if (!ret) << 389 ret = ftrace_mod_address_looku << 390 << 391 << 392 return ret; << 393 } << 394 << 395 /* << 396 * Lookup an address << 397 * - modname is set to NULL if it's in the ker << 398 * - We guarantee that the returned name is va << 399 * It resides in a module. << 400 * - We also guarantee that modname will be va << 401 */ << 402 const char *kallsyms_lookup(unsigned long addr << 403 unsigned long *sym << 404 unsigned long *off << 405 char **modname, ch << 406 { << 407 int ret = kallsyms_lookup_buildid(addr << 408 NULL << 409 << 410 if (!ret) << 411 return NULL; << 412 << 413 return namebuf; << 414 } << 415 << 416 int lookup_symbol_name(unsigned long addr, cha << 417 { << 418 symname[0] = '\0'; << 419 symname[KSYM_NAME_LEN - 1] = '\0'; << 420 << 421 if (is_ksym_addr(addr)) { << 422 unsigned long pos; << 423 << 424 pos = get_symbol_pos(addr, NUL << 425 /* Grab name */ << 426 kallsyms_expand_symbol(get_sym << 427 symname << 428 return 0; << 429 } << 430 /* See if it's in a module. */ << 431 return lookup_module_symbol_name(addr, << 432 } 87 } 433 88 434 /* Look up a kernel symbol and return it in a !! 89 /* Replace "%s" in format with address, or returns -errno. */ 435 static int __sprint_symbol(char *buffer, unsig !! 90 void __print_symbol(const char *fmt, unsigned long address) 436 int symbol_offset, << 437 { 91 { 438 char *modname; 92 char *modname; 439 const unsigned char *buildid; !! 93 const char *name; 440 unsigned long offset, size; 94 unsigned long offset, size; 441 int len; !! 95 char namebuf[128]; 442 96 443 address += symbol_offset; !! 97 name = kallsyms_lookup(address, &size, &offset, &modname, namebuf); 444 len = kallsyms_lookup_buildid(address, << 445 buffer) << 446 if (!len) << 447 return sprintf(buffer, "0x%lx" << 448 98 449 offset -= symbol_offset; !! 99 if (!name) { >> 100 char addrstr[sizeof("0x%lx") + (BITS_PER_LONG*3/10)]; 450 101 451 if (add_offset) !! 102 sprintf(addrstr, "0x%lx", address); 452 len += sprintf(buffer + len, " !! 103 printk(fmt, addrstr); 453 !! 104 return; 454 if (modname) { << 455 len += sprintf(buffer + len, " << 456 #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) << 457 if (add_buildid && buildid) { << 458 /* build ID should mat << 459 #if IS_ENABLED(CONFIG_MODULES) << 460 static_assert(sizeof(t << 461 #endif << 462 len += sprintf(buffer << 463 } << 464 #endif << 465 len += sprintf(buffer + len, " << 466 } 105 } 467 106 468 return len; !! 107 if (modname) { 469 } !! 108 /* This is pretty small. */ 470 !! 109 char buffer[sizeof("%s+%#lx/%#lx [%s]") 471 /** !! 110 + strlen(name) + 2*(BITS_PER_LONG*3/10) 472 * sprint_symbol - Look up a kernel symbol and !! 111 + strlen(modname)]; 473 * @buffer: buffer to be stored << 474 * @address: address to lookup << 475 * << 476 * This function looks up a kernel symbol with << 477 * offset, size and module name to @buffer if << 478 * just saves its @address as is. << 479 * << 480 * This function returns the number of bytes s << 481 */ << 482 int sprint_symbol(char *buffer, unsigned long << 483 { << 484 return __sprint_symbol(buffer, address << 485 } << 486 EXPORT_SYMBOL_GPL(sprint_symbol); << 487 << 488 /** << 489 * sprint_symbol_build_id - Look up a kernel s << 490 * @buffer: buffer to be stored << 491 * @address: address to lookup << 492 * << 493 * This function looks up a kernel symbol with << 494 * offset, size, module name and module build << 495 * symbol was found, just saves its @address a << 496 * << 497 * This function returns the number of bytes s << 498 */ << 499 int sprint_symbol_build_id(char *buffer, unsig << 500 { << 501 return __sprint_symbol(buffer, address << 502 } << 503 EXPORT_SYMBOL_GPL(sprint_symbol_build_id); << 504 112 505 /** !! 113 sprintf(buffer, "%s+%#lx/%#lx [%s]", 506 * sprint_symbol_no_offset - Look up a kernel !! 114 name, offset, size, modname); 507 * @buffer: buffer to be stored !! 115 printk(fmt, buffer); 508 * @address: address to lookup !! 116 } else { 509 * !! 117 char buffer[sizeof("%s+%#lx/%#lx") 510 * This function looks up a kernel symbol with !! 118 + strlen(name) + 2*(BITS_PER_LONG*3/10)]; 511 * and module name to @buffer if possible. If << 512 * its @address as is. << 513 * << 514 * This function returns the number of bytes s << 515 */ << 516 int sprint_symbol_no_offset(char *buffer, unsi << 517 { << 518 return __sprint_symbol(buffer, address << 519 } << 520 EXPORT_SYMBOL_GPL(sprint_symbol_no_offset); << 521 119 522 /** !! 120 sprintf(buffer, "%s+%#lx/%#lx", name, offset, size); 523 * sprint_backtrace - Look up a backtrace symb !! 121 printk(fmt, buffer); 524 * @buffer: buffer to be stored !! 122 } 525 * @address: address to lookup << 526 * << 527 * This function is for stack backtrace and do << 528 * sprint_symbol() but with modified/decreased << 529 * tail-call to the function marked "noreturn" << 530 * the call so that the stack-saved return add << 531 * caller. This function ensures that kallsyms << 532 * by decreasing @address. << 533 * << 534 * This function returns the number of bytes s << 535 */ << 536 int sprint_backtrace(char *buffer, unsigned lo << 537 { << 538 return __sprint_symbol(buffer, address << 539 } 123 } 540 124 541 /** !! 125 /* To avoid O(n^2) iteration, we carry prefix along. */ 542 * sprint_backtrace_build_id - Look up a backt !! 126 struct kallsym_iter 543 * @buffer: buffer to be stored << 544 * @address: address to lookup << 545 * << 546 * This function is for stack backtrace and do << 547 * sprint_symbol() but with modified/decreased << 548 * tail-call to the function marked "noreturn" << 549 * the call so that the stack-saved return add << 550 * caller. This function ensures that kallsyms << 551 * by decreasing @address. This function also << 552 * the @buffer if @address is within a kernel << 553 * << 554 * This function returns the number of bytes s << 555 */ << 556 int sprint_backtrace_build_id(char *buffer, un << 557 { 127 { 558 return __sprint_symbol(buffer, address << 559 } << 560 << 561 /* To avoid using get_symbol_offset for every << 562 struct kallsym_iter { << 563 loff_t pos; 128 loff_t pos; 564 loff_t pos_mod_end; !! 129 struct module *owner; 565 loff_t pos_ftrace_mod_end; << 566 loff_t pos_bpf_end; << 567 unsigned long value; 130 unsigned long value; 568 unsigned int nameoff; /* If iterating !! 131 unsigned int nameoff; /* If iterating in core kernel symbols */ 569 char type; 132 char type; 570 char name[KSYM_NAME_LEN]; !! 133 char name[128]; 571 char module_name[MODULE_NAME_LEN]; << 572 int exported; << 573 int show_value; << 574 }; 134 }; 575 135 576 static int get_ksymbol_mod(struct kallsym_iter !! 136 /* Only label it "global" if it is exported. */ >> 137 static void upcase_if_global(struct kallsym_iter *iter) 577 { 138 { 578 int ret = module_get_kallsym(iter->pos !! 139 if (is_exported(iter->name, iter->owner)) 579 &iter->va !! 140 iter->type += 'A' - 'a'; 580 iter->nam << 581 &iter->ex << 582 if (ret < 0) { << 583 iter->pos_mod_end = iter->pos; << 584 return 0; << 585 } << 586 << 587 return 1; << 588 } 141 } 589 142 590 /* !! 143 static int get_ksymbol_mod(struct kallsym_iter *iter) 591 * ftrace_mod_get_kallsym() may also get symbo << 592 * purposes. In that case "__builtin__ftrace" << 593 * though "__builtin__ftrace" is not a module. << 594 */ << 595 static int get_ksymbol_ftrace_mod(struct kalls << 596 { 144 { 597 int ret = ftrace_mod_get_kallsym(iter- !! 145 iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms, 598 &iter !! 146 &iter->value, 599 iter- !! 147 &iter->type, iter->name); 600 &iter !! 148 if (iter->owner == NULL) 601 if (ret < 0) { << 602 iter->pos_ftrace_mod_end = ite << 603 return 0; 149 return 0; 604 } << 605 150 >> 151 upcase_if_global(iter); 606 return 1; 152 return 1; 607 } 153 } 608 154 609 static int get_ksymbol_bpf(struct kallsym_iter !! 155 static void get_ksymbol_core(struct kallsym_iter *iter) 610 { 156 { 611 int ret; !! 157 unsigned stemlen; 612 158 613 strscpy(iter->module_name, "bpf", MODU !! 159 /* First char of each symbol name indicates prefix length 614 iter->exported = 0; !! 160 shared with previous name (stem compression). */ 615 ret = bpf_get_kallsym(iter->pos - iter !! 161 stemlen = kallsyms_names[iter->nameoff++]; 616 &iter->value, &i << 617 iter->name); << 618 if (ret < 0) { << 619 iter->pos_bpf_end = iter->pos; << 620 return 0; << 621 } << 622 162 623 return 1; !! 163 strlcpy(iter->name+stemlen, kallsyms_names+iter->nameoff, 128-stemlen); 624 } !! 164 iter->nameoff += strlen(kallsyms_names + iter->nameoff) + 1; >> 165 iter->owner = NULL; >> 166 iter->value = kallsyms_addresses[iter->pos]; >> 167 iter->type = 't'; 625 168 626 /* !! 169 upcase_if_global(iter); 627 * This uses "__builtin__kprobes" as a module << 628 * allocated for kprobes' purposes, even thoug << 629 * module. << 630 */ << 631 static int get_ksymbol_kprobe(struct kallsym_i << 632 { << 633 strscpy(iter->module_name, "__builtin_ << 634 iter->exported = 0; << 635 return kprobe_get_kallsym(iter->pos - << 636 &iter->value << 637 iter->name) << 638 } 170 } 639 171 640 /* Returns space to next name. */ !! 172 static void reset_iter(struct kallsym_iter *iter) 641 static unsigned long get_ksymbol_core(struct k << 642 { << 643 unsigned off = iter->nameoff; << 644 << 645 iter->module_name[0] = '\0'; << 646 iter->value = kallsyms_sym_address(ite << 647 << 648 iter->type = kallsyms_get_symbol_type( << 649 << 650 off = kallsyms_expand_symbol(off, iter << 651 << 652 return off - iter->nameoff; << 653 } << 654 << 655 static void reset_iter(struct kallsym_iter *it << 656 { 173 { 657 iter->name[0] = '\0'; 174 iter->name[0] = '\0'; 658 iter->nameoff = get_symbol_offset(new_ !! 175 iter->nameoff = 0; 659 iter->pos = new_pos; !! 176 iter->pos = 0; 660 if (new_pos == 0) { << 661 iter->pos_mod_end = 0; << 662 iter->pos_ftrace_mod_end = 0; << 663 iter->pos_bpf_end = 0; << 664 } << 665 } << 666 << 667 /* << 668 * The end position (last + 1) of each additio << 669 * in iter->pos_..._end as each section is add << 670 * determine which get_ksymbol_...() function << 671 */ << 672 static int update_iter_mod(struct kallsym_iter << 673 { << 674 iter->pos = pos; << 675 << 676 if ((!iter->pos_mod_end || iter->pos_m << 677 get_ksymbol_mod(iter)) << 678 return 1; << 679 << 680 if ((!iter->pos_ftrace_mod_end || iter << 681 get_ksymbol_ftrace_mod(iter)) << 682 return 1; << 683 << 684 if ((!iter->pos_bpf_end || iter->pos_b << 685 get_ksymbol_bpf(iter)) << 686 return 1; << 687 << 688 return get_ksymbol_kprobe(iter); << 689 } 177 } 690 178 691 /* Returns false if pos at or past end of file 179 /* Returns false if pos at or past end of file. */ 692 static int update_iter(struct kallsym_iter *it 180 static int update_iter(struct kallsym_iter *iter, loff_t pos) 693 { 181 { 694 /* Module symbols can be accessed rand 182 /* Module symbols can be accessed randomly. */ 695 if (pos >= kallsyms_num_syms) !! 183 if (pos >= kallsyms_num_syms) { 696 return update_iter_mod(iter, p !! 184 iter->pos = pos; 697 !! 185 return get_ksymbol_mod(iter); 698 /* If we're not on the desired positio !! 186 } 699 if (pos != iter->pos) !! 187 700 reset_iter(iter, pos); !! 188 /* If we're past the desired position, reset to start. */ 701 !! 189 if (pos < iter->pos) 702 iter->nameoff += get_ksymbol_core(iter !! 190 reset_iter(iter); 703 iter->pos++; !! 191 704 !! 192 /* We need to iterate through the previous symbols: can be slow */ >> 193 for (; iter->pos != pos; iter->pos++) { >> 194 get_ksymbol_core(iter); >> 195 cond_resched(); >> 196 } 705 return 1; 197 return 1; 706 } 198 } 707 199 708 static void *s_next(struct seq_file *m, void * 200 static void *s_next(struct seq_file *m, void *p, loff_t *pos) 709 { 201 { 710 (*pos)++; 202 (*pos)++; 711 203 712 if (!update_iter(m->private, *pos)) 204 if (!update_iter(m->private, *pos)) 713 return NULL; 205 return NULL; 714 return p; 206 return p; 715 } 207 } 716 208 717 static void *s_start(struct seq_file *m, loff_ 209 static void *s_start(struct seq_file *m, loff_t *pos) 718 { 210 { 719 if (!update_iter(m->private, *pos)) 211 if (!update_iter(m->private, *pos)) 720 return NULL; 212 return NULL; 721 return m->private; 213 return m->private; 722 } 214 } 723 215 724 static void s_stop(struct seq_file *m, void *p 216 static void s_stop(struct seq_file *m, void *p) 725 { 217 { 726 } 218 } 727 219 728 static int s_show(struct seq_file *m, void *p) 220 static int s_show(struct seq_file *m, void *p) 729 { 221 { 730 void *value; << 731 struct kallsym_iter *iter = m->private 222 struct kallsym_iter *iter = m->private; 732 223 733 /* Some debugging symbols have no name !! 224 /* Some debugging symbols have no name. Ignore them. */ 734 if (!iter->name[0]) 225 if (!iter->name[0]) 735 return 0; 226 return 0; 736 227 737 value = iter->show_value ? (void *)ite !! 228 if (iter->owner) 738 !! 229 seq_printf(m, "%0*lx %c %s\t[%s]\n", 739 if (iter->module_name[0]) { !! 230 (int)(2*sizeof(void*)), 740 char type; !! 231 iter->value, iter->type, iter->name, 741 !! 232 module_name(iter->owner)); 742 /* !! 233 else 743 * Label it "global" if it is !! 234 seq_printf(m, "%0*lx %c %s\n", 744 * "local" if not exported. !! 235 (int)(2*sizeof(void*)), 745 */ !! 236 iter->value, iter->type, iter->name); 746 type = iter->exported ? touppe << 747 tolowe << 748 seq_printf(m, "%px %c %s\t[%s] << 749 type, iter->name, i << 750 } else << 751 seq_printf(m, "%px %c %s\n", v << 752 iter->type, iter->n << 753 return 0; 237 return 0; 754 } 238 } 755 239 756 static const struct seq_operations kallsyms_op !! 240 struct seq_operations kallsyms_op = { 757 .start = s_start, 241 .start = s_start, 758 .next = s_next, 242 .next = s_next, 759 .stop = s_stop, 243 .stop = s_stop, 760 .show = s_show 244 .show = s_show 761 }; 245 }; 762 246 763 #ifdef CONFIG_BPF_SYSCALL << 764 << 765 struct bpf_iter__ksym { << 766 __bpf_md_ptr(struct bpf_iter_meta *, m << 767 __bpf_md_ptr(struct kallsym_iter *, ks << 768 }; << 769 << 770 static int ksym_prog_seq_show(struct seq_file << 771 { << 772 struct bpf_iter__ksym ctx; << 773 struct bpf_iter_meta meta; << 774 struct bpf_prog *prog; << 775 << 776 meta.seq = m; << 777 prog = bpf_iter_get_info(&meta, in_sto << 778 if (!prog) << 779 return 0; << 780 << 781 ctx.meta = &meta; << 782 ctx.ksym = m ? m->private : NULL; << 783 return bpf_iter_run_prog(prog, &ctx); << 784 } << 785 << 786 static int bpf_iter_ksym_seq_show(struct seq_f << 787 { << 788 return ksym_prog_seq_show(m, false); << 789 } << 790 << 791 static void bpf_iter_ksym_seq_stop(struct seq_ << 792 { << 793 if (!p) << 794 (void) ksym_prog_seq_show(m, t << 795 else << 796 s_stop(m, p); << 797 } << 798 << 799 static const struct seq_operations bpf_iter_ks << 800 .start = s_start, << 801 .next = s_next, << 802 .stop = bpf_iter_ksym_seq_stop, << 803 .show = bpf_iter_ksym_seq_show, << 804 }; << 805 << 806 static int bpf_iter_ksym_init(void *priv_data, << 807 { << 808 struct kallsym_iter *iter = priv_data; << 809 << 810 reset_iter(iter, 0); << 811 << 812 /* cache here as in kallsyms_open() ca << 813 * credentials to tell BPF iterators i << 814 */ << 815 iter->show_value = kallsyms_show_value << 816 << 817 return 0; << 818 } << 819 << 820 DEFINE_BPF_ITER_FUNC(ksym, struct bpf_iter_met << 821 << 822 static const struct bpf_iter_seq_info ksym_ite << 823 .seq_ops = &bpf_iter_ks << 824 .init_seq_private = bpf_iter_ksy << 825 .fini_seq_private = NULL, << 826 .seq_priv_size = sizeof(struc << 827 }; << 828 << 829 static struct bpf_iter_reg ksym_iter_reg_info << 830 .target = "ksym", << 831 .feature = BPF_ITER_RES << 832 .ctx_arg_info_size = 1, << 833 .ctx_arg_info = { << 834 { offsetof(struct bpf_iter__ks << 835 PTR_TO_BTF_ID_OR_NULL }, << 836 }, << 837 .seq_info = &ksym_iter_s << 838 }; << 839 << 840 BTF_ID_LIST(btf_ksym_iter_id) << 841 BTF_ID(struct, kallsym_iter) << 842 << 843 static int __init bpf_ksym_iter_register(void) << 844 { << 845 ksym_iter_reg_info.ctx_arg_info[0].btf << 846 return bpf_iter_reg_target(&ksym_iter_ << 847 } << 848 << 849 late_initcall(bpf_ksym_iter_register); << 850 << 851 #endif /* CONFIG_BPF_SYSCALL */ << 852 << 853 static int kallsyms_open(struct inode *inode, 247 static int kallsyms_open(struct inode *inode, struct file *file) 854 { 248 { 855 /* !! 249 /* We keep iterator in m->private, since normal case is to 856 * We keep iterator in m->private, sin !! 250 * s_start from where we left off, so we avoid O(N^2). */ 857 * s_start from where we left off, so << 858 * using get_symbol_offset for every s << 859 */ << 860 struct kallsym_iter *iter; 251 struct kallsym_iter *iter; 861 iter = __seq_open_private(file, &kalls !! 252 int ret; >> 253 >> 254 iter = kmalloc(sizeof(*iter), GFP_KERNEL); 862 if (!iter) 255 if (!iter) 863 return -ENOMEM; 256 return -ENOMEM; 864 reset_iter(iter, 0); !! 257 reset_iter(iter); 865 258 866 /* !! 259 ret = seq_open(file, &kallsyms_op); 867 * Instead of checking this on every s !! 260 if (ret == 0) 868 * the result here at open time. !! 261 ((struct seq_file *)file->private_data)->private = iter; 869 */ !! 262 else 870 iter->show_value = kallsyms_show_value !! 263 kfree(iter); 871 return 0; !! 264 return ret; 872 } 265 } 873 266 874 #ifdef CONFIG_KGDB_KDB !! 267 static int kallsyms_release(struct inode *inode, struct file *file) 875 const char *kdb_walk_kallsyms(loff_t *pos) << 876 { 268 { 877 static struct kallsym_iter kdb_walk_ka !! 269 struct seq_file *m = (struct seq_file *)file->private_data; 878 if (*pos == 0) { !! 270 kfree(m->private); 879 memset(&kdb_walk_kallsyms_iter !! 271 return seq_release(inode, file); 880 sizeof(kdb_walk_kallsym << 881 reset_iter(&kdb_walk_kallsyms_ << 882 } << 883 while (1) { << 884 if (!update_iter(&kdb_walk_kal << 885 return NULL; << 886 ++*pos; << 887 /* Some debugging symbols have << 888 if (kdb_walk_kallsyms_iter.nam << 889 return kdb_walk_kallsy << 890 } << 891 } 272 } 892 #endif /* CONFIG_KGDB_KDB */ << 893 273 894 static const struct proc_ops kallsyms_proc_ops !! 274 static struct file_operations kallsyms_operations = { 895 .proc_open = kallsyms_open, !! 275 .open = kallsyms_open, 896 .proc_read = seq_read, !! 276 .read = seq_read, 897 .proc_lseek = seq_lseek, !! 277 .llseek = seq_lseek, 898 .proc_release = seq_release_private, !! 278 .release = kallsyms_release, 899 }; 279 }; 900 280 901 static int __init kallsyms_init(void) !! 281 int __init kallsyms_init(void) 902 { 282 { 903 proc_create("kallsyms", 0444, NULL, &k !! 283 struct proc_dir_entry *entry; >> 284 >> 285 entry = create_proc_entry("kallsyms", 0444, NULL); >> 286 if (entry) >> 287 entry->proc_fops = &kallsyms_operations; 904 return 0; 288 return 0; 905 } 289 } 906 device_initcall(kallsyms_init); !! 290 __initcall(kallsyms_init); >> 291 >> 292 EXPORT_SYMBOL(kallsyms_lookup); >> 293 EXPORT_SYMBOL(__print_symbol); 907 294
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.