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