0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/kallsyms.h>
0016 #include <linux/init.h>
0017 #include <linux/seq_file.h>
0018 #include <linux/fs.h>
0019 #include <linux/kdb.h>
0020 #include <linux/err.h>
0021 #include <linux/proc_fs.h>
0022 #include <linux/sched.h> /* for cond_resched */
0023 #include <linux/ctype.h>
0024 #include <linux/slab.h>
0025 #include <linux/filter.h>
0026 #include <linux/ftrace.h>
0027 #include <linux/kprobes.h>
0028 #include <linux/build_bug.h>
0029 #include <linux/compiler.h>
0030 #include <linux/module.h>
0031 #include <linux/kernel.h>
0032 #include <linux/bsearch.h>
0033 #include <linux/btf_ids.h>
0034
0035 #include "kallsyms_internal.h"
0036
0037
0038
0039
0040
0041
0042 static unsigned int kallsyms_expand_symbol(unsigned int off,
0043 char *result, size_t maxlen)
0044 {
0045 int len, skipped_first = 0;
0046 const char *tptr;
0047 const u8 *data;
0048
0049
0050 data = &kallsyms_names[off];
0051 len = *data;
0052 data++;
0053
0054
0055
0056
0057
0058 off += len + 1;
0059
0060
0061
0062
0063
0064 while (len) {
0065 tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
0066 data++;
0067 len--;
0068
0069 while (*tptr) {
0070 if (skipped_first) {
0071 if (maxlen <= 1)
0072 goto tail;
0073 *result = *tptr;
0074 result++;
0075 maxlen--;
0076 } else
0077 skipped_first = 1;
0078 tptr++;
0079 }
0080 }
0081
0082 tail:
0083 if (maxlen)
0084 *result = '\0';
0085
0086
0087 return off;
0088 }
0089
0090
0091
0092
0093
0094 static char kallsyms_get_symbol_type(unsigned int off)
0095 {
0096
0097
0098
0099
0100 return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]];
0101 }
0102
0103
0104
0105
0106
0107
0108 static unsigned int get_symbol_offset(unsigned long pos)
0109 {
0110 const u8 *name;
0111 int i;
0112
0113
0114
0115
0116
0117 name = &kallsyms_names[kallsyms_markers[pos >> 8]];
0118
0119
0120
0121
0122
0123
0124
0125 for (i = 0; i < (pos & 0xFF); i++)
0126 name = name + (*name) + 1;
0127
0128 return name - kallsyms_names;
0129 }
0130
0131 static unsigned long kallsyms_sym_address(int idx)
0132 {
0133 if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
0134 return kallsyms_addresses[idx];
0135
0136
0137 if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
0138 return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
0139
0140
0141 if (kallsyms_offsets[idx] >= 0)
0142 return kallsyms_offsets[idx];
0143
0144
0145 return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
0146 }
0147
0148 static bool cleanup_symbol_name(char *s)
0149 {
0150 char *res;
0151
0152 if (!IS_ENABLED(CONFIG_LTO_CLANG))
0153 return false;
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164 res = strchr(s, '.');
0165 if (res) {
0166 *res = '\0';
0167 return true;
0168 }
0169
0170 if (!IS_ENABLED(CONFIG_CFI_CLANG) ||
0171 !IS_ENABLED(CONFIG_LTO_CLANG_THIN) ||
0172 CONFIG_CLANG_VERSION >= 130000)
0173 return false;
0174
0175
0176
0177
0178
0179
0180 res = strrchr(s, '$');
0181 if (res) {
0182 *res = '\0';
0183 return true;
0184 }
0185
0186 return false;
0187 }
0188
0189
0190 unsigned long kallsyms_lookup_name(const char *name)
0191 {
0192 char namebuf[KSYM_NAME_LEN];
0193 unsigned long i;
0194 unsigned int off;
0195
0196
0197 if (!*name)
0198 return 0;
0199
0200 for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
0201 off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
0202
0203 if (strcmp(namebuf, name) == 0)
0204 return kallsyms_sym_address(i);
0205
0206 if (cleanup_symbol_name(namebuf) && strcmp(namebuf, name) == 0)
0207 return kallsyms_sym_address(i);
0208 }
0209 return module_kallsyms_lookup_name(name);
0210 }
0211
0212
0213
0214
0215
0216 int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
0217 unsigned long),
0218 void *data)
0219 {
0220 char namebuf[KSYM_NAME_LEN];
0221 unsigned long i;
0222 unsigned int off;
0223 int ret;
0224
0225 for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
0226 off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
0227 ret = fn(data, namebuf, NULL, kallsyms_sym_address(i));
0228 if (ret != 0)
0229 return ret;
0230 cond_resched();
0231 }
0232 return 0;
0233 }
0234
0235 static unsigned long get_symbol_pos(unsigned long addr,
0236 unsigned long *symbolsize,
0237 unsigned long *offset)
0238 {
0239 unsigned long symbol_start = 0, symbol_end = 0;
0240 unsigned long i, low, high, mid;
0241
0242
0243 if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
0244 BUG_ON(!kallsyms_addresses);
0245 else
0246 BUG_ON(!kallsyms_offsets);
0247
0248
0249 low = 0;
0250 high = kallsyms_num_syms;
0251
0252 while (high - low > 1) {
0253 mid = low + (high - low) / 2;
0254 if (kallsyms_sym_address(mid) <= addr)
0255 low = mid;
0256 else
0257 high = mid;
0258 }
0259
0260
0261
0262
0263
0264 while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low))
0265 --low;
0266
0267 symbol_start = kallsyms_sym_address(low);
0268
0269
0270 for (i = low + 1; i < kallsyms_num_syms; i++) {
0271 if (kallsyms_sym_address(i) > symbol_start) {
0272 symbol_end = kallsyms_sym_address(i);
0273 break;
0274 }
0275 }
0276
0277
0278 if (!symbol_end) {
0279 if (is_kernel_inittext(addr))
0280 symbol_end = (unsigned long)_einittext;
0281 else if (IS_ENABLED(CONFIG_KALLSYMS_ALL))
0282 symbol_end = (unsigned long)_end;
0283 else
0284 symbol_end = (unsigned long)_etext;
0285 }
0286
0287 if (symbolsize)
0288 *symbolsize = symbol_end - symbol_start;
0289 if (offset)
0290 *offset = addr - symbol_start;
0291
0292 return low;
0293 }
0294
0295
0296
0297
0298 int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
0299 unsigned long *offset)
0300 {
0301 char namebuf[KSYM_NAME_LEN];
0302
0303 if (is_ksym_addr(addr)) {
0304 get_symbol_pos(addr, symbolsize, offset);
0305 return 1;
0306 }
0307 return !!module_address_lookup(addr, symbolsize, offset, NULL, NULL, namebuf) ||
0308 !!__bpf_address_lookup(addr, symbolsize, offset, namebuf);
0309 }
0310
0311 static const char *kallsyms_lookup_buildid(unsigned long addr,
0312 unsigned long *symbolsize,
0313 unsigned long *offset, char **modname,
0314 const unsigned char **modbuildid, char *namebuf)
0315 {
0316 const char *ret;
0317
0318 namebuf[KSYM_NAME_LEN - 1] = 0;
0319 namebuf[0] = 0;
0320
0321 if (is_ksym_addr(addr)) {
0322 unsigned long pos;
0323
0324 pos = get_symbol_pos(addr, symbolsize, offset);
0325
0326 kallsyms_expand_symbol(get_symbol_offset(pos),
0327 namebuf, KSYM_NAME_LEN);
0328 if (modname)
0329 *modname = NULL;
0330 if (modbuildid)
0331 *modbuildid = NULL;
0332
0333 ret = namebuf;
0334 goto found;
0335 }
0336
0337
0338 ret = module_address_lookup(addr, symbolsize, offset,
0339 modname, modbuildid, namebuf);
0340 if (!ret)
0341 ret = bpf_address_lookup(addr, symbolsize,
0342 offset, modname, namebuf);
0343
0344 if (!ret)
0345 ret = ftrace_mod_address_lookup(addr, symbolsize,
0346 offset, modname, namebuf);
0347
0348 found:
0349 cleanup_symbol_name(namebuf);
0350 return ret;
0351 }
0352
0353
0354
0355
0356
0357
0358
0359
0360 const char *kallsyms_lookup(unsigned long addr,
0361 unsigned long *symbolsize,
0362 unsigned long *offset,
0363 char **modname, char *namebuf)
0364 {
0365 return kallsyms_lookup_buildid(addr, symbolsize, offset, modname,
0366 NULL, namebuf);
0367 }
0368
0369 int lookup_symbol_name(unsigned long addr, char *symname)
0370 {
0371 int res;
0372
0373 symname[0] = '\0';
0374 symname[KSYM_NAME_LEN - 1] = '\0';
0375
0376 if (is_ksym_addr(addr)) {
0377 unsigned long pos;
0378
0379 pos = get_symbol_pos(addr, NULL, NULL);
0380
0381 kallsyms_expand_symbol(get_symbol_offset(pos),
0382 symname, KSYM_NAME_LEN);
0383 goto found;
0384 }
0385
0386 res = lookup_module_symbol_name(addr, symname);
0387 if (res)
0388 return res;
0389
0390 found:
0391 cleanup_symbol_name(symname);
0392 return 0;
0393 }
0394
0395 int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
0396 unsigned long *offset, char *modname, char *name)
0397 {
0398 int res;
0399
0400 name[0] = '\0';
0401 name[KSYM_NAME_LEN - 1] = '\0';
0402
0403 if (is_ksym_addr(addr)) {
0404 unsigned long pos;
0405
0406 pos = get_symbol_pos(addr, size, offset);
0407
0408 kallsyms_expand_symbol(get_symbol_offset(pos),
0409 name, KSYM_NAME_LEN);
0410 modname[0] = '\0';
0411 goto found;
0412 }
0413
0414 res = lookup_module_symbol_attrs(addr, size, offset, modname, name);
0415 if (res)
0416 return res;
0417
0418 found:
0419 cleanup_symbol_name(name);
0420 return 0;
0421 }
0422
0423
0424 static int __sprint_symbol(char *buffer, unsigned long address,
0425 int symbol_offset, int add_offset, int add_buildid)
0426 {
0427 char *modname;
0428 const unsigned char *buildid;
0429 const char *name;
0430 unsigned long offset, size;
0431 int len;
0432
0433 address += symbol_offset;
0434 name = kallsyms_lookup_buildid(address, &size, &offset, &modname, &buildid,
0435 buffer);
0436 if (!name)
0437 return sprintf(buffer, "0x%lx", address - symbol_offset);
0438
0439 if (name != buffer)
0440 strcpy(buffer, name);
0441 len = strlen(buffer);
0442 offset -= symbol_offset;
0443
0444 if (add_offset)
0445 len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);
0446
0447 if (modname) {
0448 len += sprintf(buffer + len, " [%s", modname);
0449 #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
0450 if (add_buildid && buildid) {
0451
0452 #if IS_ENABLED(CONFIG_MODULES)
0453 static_assert(sizeof(typeof_member(struct module, build_id)) == 20);
0454 #endif
0455 len += sprintf(buffer + len, " %20phN", buildid);
0456 }
0457 #endif
0458 len += sprintf(buffer + len, "]");
0459 }
0460
0461 return len;
0462 }
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475 int sprint_symbol(char *buffer, unsigned long address)
0476 {
0477 return __sprint_symbol(buffer, address, 0, 1, 0);
0478 }
0479 EXPORT_SYMBOL_GPL(sprint_symbol);
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492 int sprint_symbol_build_id(char *buffer, unsigned long address)
0493 {
0494 return __sprint_symbol(buffer, address, 0, 1, 1);
0495 }
0496 EXPORT_SYMBOL_GPL(sprint_symbol_build_id);
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509 int sprint_symbol_no_offset(char *buffer, unsigned long address)
0510 {
0511 return __sprint_symbol(buffer, address, 0, 0, 0);
0512 }
0513 EXPORT_SYMBOL_GPL(sprint_symbol_no_offset);
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529 int sprint_backtrace(char *buffer, unsigned long address)
0530 {
0531 return __sprint_symbol(buffer, address, -1, 1, 0);
0532 }
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549 int sprint_backtrace_build_id(char *buffer, unsigned long address)
0550 {
0551 return __sprint_symbol(buffer, address, -1, 1, 1);
0552 }
0553
0554
0555 struct kallsym_iter {
0556 loff_t pos;
0557 loff_t pos_arch_end;
0558 loff_t pos_mod_end;
0559 loff_t pos_ftrace_mod_end;
0560 loff_t pos_bpf_end;
0561 unsigned long value;
0562 unsigned int nameoff;
0563 char type;
0564 char name[KSYM_NAME_LEN];
0565 char module_name[MODULE_NAME_LEN];
0566 int exported;
0567 int show_value;
0568 };
0569
0570 int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
0571 char *type, char *name)
0572 {
0573 return -EINVAL;
0574 }
0575
0576 static int get_ksymbol_arch(struct kallsym_iter *iter)
0577 {
0578 int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms,
0579 &iter->value, &iter->type,
0580 iter->name);
0581
0582 if (ret < 0) {
0583 iter->pos_arch_end = iter->pos;
0584 return 0;
0585 }
0586
0587 return 1;
0588 }
0589
0590 static int get_ksymbol_mod(struct kallsym_iter *iter)
0591 {
0592 int ret = module_get_kallsym(iter->pos - iter->pos_arch_end,
0593 &iter->value, &iter->type,
0594 iter->name, iter->module_name,
0595 &iter->exported);
0596 if (ret < 0) {
0597 iter->pos_mod_end = iter->pos;
0598 return 0;
0599 }
0600
0601 return 1;
0602 }
0603
0604
0605
0606
0607
0608
0609 static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter)
0610 {
0611 int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end,
0612 &iter->value, &iter->type,
0613 iter->name, iter->module_name,
0614 &iter->exported);
0615 if (ret < 0) {
0616 iter->pos_ftrace_mod_end = iter->pos;
0617 return 0;
0618 }
0619
0620 return 1;
0621 }
0622
0623 static int get_ksymbol_bpf(struct kallsym_iter *iter)
0624 {
0625 int ret;
0626
0627 strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN);
0628 iter->exported = 0;
0629 ret = bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end,
0630 &iter->value, &iter->type,
0631 iter->name);
0632 if (ret < 0) {
0633 iter->pos_bpf_end = iter->pos;
0634 return 0;
0635 }
0636
0637 return 1;
0638 }
0639
0640
0641
0642
0643
0644
0645 static int get_ksymbol_kprobe(struct kallsym_iter *iter)
0646 {
0647 strlcpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN);
0648 iter->exported = 0;
0649 return kprobe_get_kallsym(iter->pos - iter->pos_bpf_end,
0650 &iter->value, &iter->type,
0651 iter->name) < 0 ? 0 : 1;
0652 }
0653
0654
0655 static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
0656 {
0657 unsigned off = iter->nameoff;
0658
0659 iter->module_name[0] = '\0';
0660 iter->value = kallsyms_sym_address(iter->pos);
0661
0662 iter->type = kallsyms_get_symbol_type(off);
0663
0664 off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name));
0665
0666 return off - iter->nameoff;
0667 }
0668
0669 static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
0670 {
0671 iter->name[0] = '\0';
0672 iter->nameoff = get_symbol_offset(new_pos);
0673 iter->pos = new_pos;
0674 if (new_pos == 0) {
0675 iter->pos_arch_end = 0;
0676 iter->pos_mod_end = 0;
0677 iter->pos_ftrace_mod_end = 0;
0678 iter->pos_bpf_end = 0;
0679 }
0680 }
0681
0682
0683
0684
0685
0686
0687 static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
0688 {
0689 iter->pos = pos;
0690
0691 if ((!iter->pos_arch_end || iter->pos_arch_end > pos) &&
0692 get_ksymbol_arch(iter))
0693 return 1;
0694
0695 if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&
0696 get_ksymbol_mod(iter))
0697 return 1;
0698
0699 if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) &&
0700 get_ksymbol_ftrace_mod(iter))
0701 return 1;
0702
0703 if ((!iter->pos_bpf_end || iter->pos_bpf_end > pos) &&
0704 get_ksymbol_bpf(iter))
0705 return 1;
0706
0707 return get_ksymbol_kprobe(iter);
0708 }
0709
0710
0711 static int update_iter(struct kallsym_iter *iter, loff_t pos)
0712 {
0713
0714 if (pos >= kallsyms_num_syms)
0715 return update_iter_mod(iter, pos);
0716
0717
0718 if (pos != iter->pos)
0719 reset_iter(iter, pos);
0720
0721 iter->nameoff += get_ksymbol_core(iter);
0722 iter->pos++;
0723
0724 return 1;
0725 }
0726
0727 static void *s_next(struct seq_file *m, void *p, loff_t *pos)
0728 {
0729 (*pos)++;
0730
0731 if (!update_iter(m->private, *pos))
0732 return NULL;
0733 return p;
0734 }
0735
0736 static void *s_start(struct seq_file *m, loff_t *pos)
0737 {
0738 if (!update_iter(m->private, *pos))
0739 return NULL;
0740 return m->private;
0741 }
0742
0743 static void s_stop(struct seq_file *m, void *p)
0744 {
0745 }
0746
0747 static int s_show(struct seq_file *m, void *p)
0748 {
0749 void *value;
0750 struct kallsym_iter *iter = m->private;
0751
0752
0753 if (!iter->name[0])
0754 return 0;
0755
0756 value = iter->show_value ? (void *)iter->value : NULL;
0757
0758 if (iter->module_name[0]) {
0759 char type;
0760
0761
0762
0763
0764
0765 type = iter->exported ? toupper(iter->type) :
0766 tolower(iter->type);
0767 seq_printf(m, "%px %c %s\t[%s]\n", value,
0768 type, iter->name, iter->module_name);
0769 } else
0770 seq_printf(m, "%px %c %s\n", value,
0771 iter->type, iter->name);
0772 return 0;
0773 }
0774
0775 static const struct seq_operations kallsyms_op = {
0776 .start = s_start,
0777 .next = s_next,
0778 .stop = s_stop,
0779 .show = s_show
0780 };
0781
0782 #ifdef CONFIG_BPF_SYSCALL
0783
0784 struct bpf_iter__ksym {
0785 __bpf_md_ptr(struct bpf_iter_meta *, meta);
0786 __bpf_md_ptr(struct kallsym_iter *, ksym);
0787 };
0788
0789 static int ksym_prog_seq_show(struct seq_file *m, bool in_stop)
0790 {
0791 struct bpf_iter__ksym ctx;
0792 struct bpf_iter_meta meta;
0793 struct bpf_prog *prog;
0794
0795 meta.seq = m;
0796 prog = bpf_iter_get_info(&meta, in_stop);
0797 if (!prog)
0798 return 0;
0799
0800 ctx.meta = &meta;
0801 ctx.ksym = m ? m->private : NULL;
0802 return bpf_iter_run_prog(prog, &ctx);
0803 }
0804
0805 static int bpf_iter_ksym_seq_show(struct seq_file *m, void *p)
0806 {
0807 return ksym_prog_seq_show(m, false);
0808 }
0809
0810 static void bpf_iter_ksym_seq_stop(struct seq_file *m, void *p)
0811 {
0812 if (!p)
0813 (void) ksym_prog_seq_show(m, true);
0814 else
0815 s_stop(m, p);
0816 }
0817
0818 static const struct seq_operations bpf_iter_ksym_ops = {
0819 .start = s_start,
0820 .next = s_next,
0821 .stop = bpf_iter_ksym_seq_stop,
0822 .show = bpf_iter_ksym_seq_show,
0823 };
0824
0825 static int bpf_iter_ksym_init(void *priv_data, struct bpf_iter_aux_info *aux)
0826 {
0827 struct kallsym_iter *iter = priv_data;
0828
0829 reset_iter(iter, 0);
0830
0831
0832
0833
0834 iter->show_value = kallsyms_show_value(current_cred());
0835
0836 return 0;
0837 }
0838
0839 DEFINE_BPF_ITER_FUNC(ksym, struct bpf_iter_meta *meta, struct kallsym_iter *ksym)
0840
0841 static const struct bpf_iter_seq_info ksym_iter_seq_info = {
0842 .seq_ops = &bpf_iter_ksym_ops,
0843 .init_seq_private = bpf_iter_ksym_init,
0844 .fini_seq_private = NULL,
0845 .seq_priv_size = sizeof(struct kallsym_iter),
0846 };
0847
0848 static struct bpf_iter_reg ksym_iter_reg_info = {
0849 .target = "ksym",
0850 .feature = BPF_ITER_RESCHED,
0851 .ctx_arg_info_size = 1,
0852 .ctx_arg_info = {
0853 { offsetof(struct bpf_iter__ksym, ksym),
0854 PTR_TO_BTF_ID_OR_NULL },
0855 },
0856 .seq_info = &ksym_iter_seq_info,
0857 };
0858
0859 BTF_ID_LIST(btf_ksym_iter_id)
0860 BTF_ID(struct, kallsym_iter)
0861
0862 static int __init bpf_ksym_iter_register(void)
0863 {
0864 ksym_iter_reg_info.ctx_arg_info[0].btf_id = *btf_ksym_iter_id;
0865 return bpf_iter_reg_target(&ksym_iter_reg_info);
0866 }
0867
0868 late_initcall(bpf_ksym_iter_register);
0869
0870 #endif
0871
0872 static inline int kallsyms_for_perf(void)
0873 {
0874 #ifdef CONFIG_PERF_EVENTS
0875 extern int sysctl_perf_event_paranoid;
0876 if (sysctl_perf_event_paranoid <= 1)
0877 return 1;
0878 #endif
0879 return 0;
0880 }
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890 bool kallsyms_show_value(const struct cred *cred)
0891 {
0892 switch (kptr_restrict) {
0893 case 0:
0894 if (kallsyms_for_perf())
0895 return true;
0896 fallthrough;
0897 case 1:
0898 if (security_capable(cred, &init_user_ns, CAP_SYSLOG,
0899 CAP_OPT_NOAUDIT) == 0)
0900 return true;
0901 fallthrough;
0902 default:
0903 return false;
0904 }
0905 }
0906
0907 static int kallsyms_open(struct inode *inode, struct file *file)
0908 {
0909
0910
0911
0912
0913
0914 struct kallsym_iter *iter;
0915 iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter));
0916 if (!iter)
0917 return -ENOMEM;
0918 reset_iter(iter, 0);
0919
0920
0921
0922
0923
0924 iter->show_value = kallsyms_show_value(file->f_cred);
0925 return 0;
0926 }
0927
0928 #ifdef CONFIG_KGDB_KDB
0929 const char *kdb_walk_kallsyms(loff_t *pos)
0930 {
0931 static struct kallsym_iter kdb_walk_kallsyms_iter;
0932 if (*pos == 0) {
0933 memset(&kdb_walk_kallsyms_iter, 0,
0934 sizeof(kdb_walk_kallsyms_iter));
0935 reset_iter(&kdb_walk_kallsyms_iter, 0);
0936 }
0937 while (1) {
0938 if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
0939 return NULL;
0940 ++*pos;
0941
0942 if (kdb_walk_kallsyms_iter.name[0])
0943 return kdb_walk_kallsyms_iter.name;
0944 }
0945 }
0946 #endif
0947
0948 static const struct proc_ops kallsyms_proc_ops = {
0949 .proc_open = kallsyms_open,
0950 .proc_read = seq_read,
0951 .proc_lseek = seq_lseek,
0952 .proc_release = seq_release_private,
0953 };
0954
0955 static int __init kallsyms_init(void)
0956 {
0957 proc_create("kallsyms", 0444, NULL, &kallsyms_proc_ops);
0958 return 0;
0959 }
0960 device_initcall(kallsyms_init);