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 } 245 178 246 /* !! 179 int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, 247 * Iterate over all symbols in vmlinux. For s !! 180 unsigned long), 248 * module_kallsyms_on_each_symbol instead. << 249 */ << 250 int kallsyms_on_each_symbol(int (*fn)(void *, << 251 void *data) 181 void *data) 252 { 182 { 253 char namebuf[KSYM_NAME_LEN]; 183 char namebuf[KSYM_NAME_LEN]; 254 unsigned long i; 184 unsigned long i; 255 unsigned int off; 185 unsigned int off; 256 int ret; 186 int ret; 257 187 258 for (i = 0, off = 0; i < kallsyms_num_ 188 for (i = 0, off = 0; i < kallsyms_num_syms; i++) { 259 off = kallsyms_expand_symbol(o 189 off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); 260 ret = fn(data, namebuf, kallsy !! 190 ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); 261 if (ret != 0) 191 if (ret != 0) 262 return ret; 192 return ret; 263 cond_resched(); << 264 } 193 } 265 return 0; !! 194 return module_kallsyms_on_each_symbol(fn, data); 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 } << 282 << 283 return ret; << 284 } 195 } 285 196 286 static unsigned long get_symbol_pos(unsigned l 197 static unsigned long get_symbol_pos(unsigned long addr, 287 unsigned l 198 unsigned long *symbolsize, 288 unsigned l 199 unsigned long *offset) 289 { 200 { 290 unsigned long symbol_start = 0, symbol 201 unsigned long symbol_start = 0, symbol_end = 0; 291 unsigned long i, low, high, mid; 202 unsigned long i, low, high, mid; 292 203 293 /* Do a binary search on the sorted ka !! 204 /* This kernel should never had been booted. */ >> 205 if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) >> 206 BUG_ON(!kallsyms_addresses); >> 207 else >> 208 BUG_ON(!kallsyms_offsets); >> 209 >> 210 /* Do a binary search on the sorted kallsyms_addresses array. */ 294 low = 0; 211 low = 0; 295 high = kallsyms_num_syms; 212 high = kallsyms_num_syms; 296 213 297 while (high - low > 1) { 214 while (high - low > 1) { 298 mid = low + (high - low) / 2; 215 mid = low + (high - low) / 2; 299 if (kallsyms_sym_address(mid) 216 if (kallsyms_sym_address(mid) <= addr) 300 low = mid; 217 low = mid; 301 else 218 else 302 high = mid; 219 high = mid; 303 } 220 } 304 221 305 /* 222 /* 306 * Search for the first aliased symbol 223 * Search for the first aliased symbol. Aliased 307 * symbols are symbols with the same a 224 * symbols are symbols with the same address. 308 */ 225 */ 309 while (low && kallsyms_sym_address(low 226 while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low)) 310 --low; 227 --low; 311 228 312 symbol_start = kallsyms_sym_address(lo 229 symbol_start = kallsyms_sym_address(low); 313 230 314 /* Search for next non-aliased symbol. 231 /* Search for next non-aliased symbol. */ 315 for (i = low + 1; i < kallsyms_num_sym 232 for (i = low + 1; i < kallsyms_num_syms; i++) { 316 if (kallsyms_sym_address(i) > 233 if (kallsyms_sym_address(i) > symbol_start) { 317 symbol_end = kallsyms_ 234 symbol_end = kallsyms_sym_address(i); 318 break; 235 break; 319 } 236 } 320 } 237 } 321 238 322 /* If we found no next symbol, we use 239 /* If we found no next symbol, we use the end of the section. */ 323 if (!symbol_end) { 240 if (!symbol_end) { 324 if (is_kernel_inittext(addr)) 241 if (is_kernel_inittext(addr)) 325 symbol_end = (unsigned 242 symbol_end = (unsigned long)_einittext; 326 else if (IS_ENABLED(CONFIG_KAL 243 else if (IS_ENABLED(CONFIG_KALLSYMS_ALL)) 327 symbol_end = (unsigned 244 symbol_end = (unsigned long)_end; 328 else 245 else 329 symbol_end = (unsigned 246 symbol_end = (unsigned long)_etext; 330 } 247 } 331 248 332 if (symbolsize) 249 if (symbolsize) 333 *symbolsize = symbol_end - sym 250 *symbolsize = symbol_end - symbol_start; 334 if (offset) 251 if (offset) 335 *offset = addr - symbol_start; 252 *offset = addr - symbol_start; 336 253 337 return low; 254 return low; 338 } 255 } 339 256 340 /* 257 /* 341 * Lookup an address but don't bother to find 258 * Lookup an address but don't bother to find any names. 342 */ 259 */ 343 int kallsyms_lookup_size_offset(unsigned long 260 int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, 344 unsigned long 261 unsigned long *offset) 345 { 262 { 346 char namebuf[KSYM_NAME_LEN]; 263 char namebuf[KSYM_NAME_LEN]; 347 264 348 if (is_ksym_addr(addr)) { 265 if (is_ksym_addr(addr)) { 349 get_symbol_pos(addr, symbolsiz 266 get_symbol_pos(addr, symbolsize, offset); 350 return 1; 267 return 1; 351 } 268 } 352 return !!module_address_lookup(addr, s !! 269 return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) || 353 !!__bpf_address_lookup(addr, sy 270 !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); 354 } 271 } 355 272 356 static int kallsyms_lookup_buildid(unsigned lo !! 273 /* 357 unsigned long *symbols !! 274 * Lookup an address 358 unsigned long *offset, !! 275 * - modname is set to NULL if it's in the kernel. 359 const unsigned char ** !! 276 * - We guarantee that the returned name is valid until we reschedule even if. >> 277 * It resides in a module. >> 278 * - We also guarantee that modname will be valid until rescheduled. >> 279 */ >> 280 const char *kallsyms_lookup(unsigned long addr, >> 281 unsigned long *symbolsize, >> 282 unsigned long *offset, >> 283 char **modname, char *namebuf) 360 { 284 { 361 int ret; !! 285 const char *ret; 362 286 363 namebuf[KSYM_NAME_LEN - 1] = 0; 287 namebuf[KSYM_NAME_LEN - 1] = 0; 364 namebuf[0] = 0; 288 namebuf[0] = 0; 365 289 366 if (is_ksym_addr(addr)) { 290 if (is_ksym_addr(addr)) { 367 unsigned long pos; 291 unsigned long pos; 368 292 369 pos = get_symbol_pos(addr, sym 293 pos = get_symbol_pos(addr, symbolsize, offset); 370 /* Grab name */ 294 /* Grab name */ 371 kallsyms_expand_symbol(get_sym 295 kallsyms_expand_symbol(get_symbol_offset(pos), 372 namebuf 296 namebuf, KSYM_NAME_LEN); 373 if (modname) 297 if (modname) 374 *modname = NULL; 298 *modname = NULL; 375 if (modbuildid) !! 299 return namebuf; 376 *modbuildid = NULL; << 377 << 378 return strlen(namebuf); << 379 } 300 } 380 301 381 /* See if it's in a module or a BPF JI 302 /* See if it's in a module or a BPF JITed image. */ 382 ret = module_address_lookup(addr, symb 303 ret = module_address_lookup(addr, symbolsize, offset, 383 modname, m !! 304 modname, namebuf); 384 if (!ret) 305 if (!ret) 385 ret = bpf_address_lookup(addr, 306 ret = bpf_address_lookup(addr, symbolsize, 386 offse 307 offset, modname, namebuf); 387 308 388 if (!ret) 309 if (!ret) 389 ret = ftrace_mod_address_looku 310 ret = ftrace_mod_address_lookup(addr, symbolsize, 390 311 offset, modname, namebuf); 391 << 392 return ret; 312 return ret; 393 } 313 } 394 314 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 315 int lookup_symbol_name(unsigned long addr, char *symname) 417 { 316 { 418 symname[0] = '\0'; 317 symname[0] = '\0'; 419 symname[KSYM_NAME_LEN - 1] = '\0'; 318 symname[KSYM_NAME_LEN - 1] = '\0'; 420 319 421 if (is_ksym_addr(addr)) { 320 if (is_ksym_addr(addr)) { 422 unsigned long pos; 321 unsigned long pos; 423 322 424 pos = get_symbol_pos(addr, NUL 323 pos = get_symbol_pos(addr, NULL, NULL); 425 /* Grab name */ 324 /* Grab name */ 426 kallsyms_expand_symbol(get_sym 325 kallsyms_expand_symbol(get_symbol_offset(pos), 427 symname 326 symname, KSYM_NAME_LEN); 428 return 0; 327 return 0; 429 } 328 } 430 /* See if it's in a module. */ 329 /* See if it's in a module. */ 431 return lookup_module_symbol_name(addr, 330 return lookup_module_symbol_name(addr, symname); 432 } 331 } 433 332 >> 333 int lookup_symbol_attrs(unsigned long addr, unsigned long *size, >> 334 unsigned long *offset, char *modname, char *name) >> 335 { >> 336 name[0] = '\0'; >> 337 name[KSYM_NAME_LEN - 1] = '\0'; >> 338 >> 339 if (is_ksym_addr(addr)) { >> 340 unsigned long pos; >> 341 >> 342 pos = get_symbol_pos(addr, size, offset); >> 343 /* Grab name */ >> 344 kallsyms_expand_symbol(get_symbol_offset(pos), >> 345 name, KSYM_NAME_LEN); >> 346 modname[0] = '\0'; >> 347 return 0; >> 348 } >> 349 /* See if it's in a module. */ >> 350 return lookup_module_symbol_attrs(addr, size, offset, modname, name); >> 351 } >> 352 434 /* Look up a kernel symbol and return it in a 353 /* Look up a kernel symbol and return it in a text buffer. */ 435 static int __sprint_symbol(char *buffer, unsig 354 static int __sprint_symbol(char *buffer, unsigned long address, 436 int symbol_offset, !! 355 int symbol_offset, int add_offset) 437 { 356 { 438 char *modname; 357 char *modname; 439 const unsigned char *buildid; !! 358 const char *name; 440 unsigned long offset, size; 359 unsigned long offset, size; 441 int len; 360 int len; 442 361 443 address += symbol_offset; 362 address += symbol_offset; 444 len = kallsyms_lookup_buildid(address, !! 363 name = kallsyms_lookup(address, &size, &offset, &modname, buffer); 445 buffer) !! 364 if (!name) 446 if (!len) << 447 return sprintf(buffer, "0x%lx" 365 return sprintf(buffer, "0x%lx", address - symbol_offset); 448 366 >> 367 if (name != buffer) >> 368 strcpy(buffer, name); >> 369 len = strlen(buffer); 449 offset -= symbol_offset; 370 offset -= symbol_offset; 450 371 451 if (add_offset) 372 if (add_offset) 452 len += sprintf(buffer + len, " 373 len += sprintf(buffer + len, "+%#lx/%#lx", offset, size); 453 374 454 if (modname) { !! 375 if (modname) 455 len += sprintf(buffer + len, " !! 376 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 377 468 return len; 378 return len; 469 } 379 } 470 380 471 /** 381 /** 472 * sprint_symbol - Look up a kernel symbol and 382 * sprint_symbol - Look up a kernel symbol and return it in a text buffer 473 * @buffer: buffer to be stored 383 * @buffer: buffer to be stored 474 * @address: address to lookup 384 * @address: address to lookup 475 * 385 * 476 * This function looks up a kernel symbol with 386 * This function looks up a kernel symbol with @address and stores its name, 477 * offset, size and module name to @buffer if 387 * offset, size and module name to @buffer if possible. If no symbol was found, 478 * just saves its @address as is. 388 * just saves its @address as is. 479 * 389 * 480 * This function returns the number of bytes s 390 * This function returns the number of bytes stored in @buffer. 481 */ 391 */ 482 int sprint_symbol(char *buffer, unsigned long 392 int sprint_symbol(char *buffer, unsigned long address) 483 { 393 { 484 return __sprint_symbol(buffer, address !! 394 return __sprint_symbol(buffer, address, 0, 1); 485 } 395 } 486 EXPORT_SYMBOL_GPL(sprint_symbol); 396 EXPORT_SYMBOL_GPL(sprint_symbol); 487 397 488 /** 398 /** 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 399 * sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer 507 * @buffer: buffer to be stored 400 * @buffer: buffer to be stored 508 * @address: address to lookup 401 * @address: address to lookup 509 * 402 * 510 * This function looks up a kernel symbol with 403 * This function looks up a kernel symbol with @address and stores its name 511 * and module name to @buffer if possible. If 404 * and module name to @buffer if possible. If no symbol was found, just saves 512 * its @address as is. 405 * its @address as is. 513 * 406 * 514 * This function returns the number of bytes s 407 * This function returns the number of bytes stored in @buffer. 515 */ 408 */ 516 int sprint_symbol_no_offset(char *buffer, unsi 409 int sprint_symbol_no_offset(char *buffer, unsigned long address) 517 { 410 { 518 return __sprint_symbol(buffer, address !! 411 return __sprint_symbol(buffer, address, 0, 0); 519 } 412 } 520 EXPORT_SYMBOL_GPL(sprint_symbol_no_offset); 413 EXPORT_SYMBOL_GPL(sprint_symbol_no_offset); 521 414 522 /** 415 /** 523 * sprint_backtrace - Look up a backtrace symb 416 * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer 524 * @buffer: buffer to be stored 417 * @buffer: buffer to be stored 525 * @address: address to lookup 418 * @address: address to lookup 526 * 419 * 527 * This function is for stack backtrace and do 420 * This function is for stack backtrace and does the same thing as 528 * sprint_symbol() but with modified/decreased 421 * sprint_symbol() but with modified/decreased @address. If there is a 529 * tail-call to the function marked "noreturn" 422 * tail-call to the function marked "noreturn", gcc optimized out code after 530 * the call so that the stack-saved return add 423 * the call so that the stack-saved return address could point outside of the 531 * caller. This function ensures that kallsyms 424 * caller. This function ensures that kallsyms will find the original caller 532 * by decreasing @address. 425 * by decreasing @address. 533 * 426 * 534 * This function returns the number of bytes s 427 * This function returns the number of bytes stored in @buffer. 535 */ 428 */ 536 int sprint_backtrace(char *buffer, unsigned lo 429 int sprint_backtrace(char *buffer, unsigned long address) 537 { 430 { 538 return __sprint_symbol(buffer, address !! 431 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 } 432 } 560 433 561 /* To avoid using get_symbol_offset for every 434 /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ 562 struct kallsym_iter { 435 struct kallsym_iter { 563 loff_t pos; 436 loff_t pos; >> 437 loff_t pos_arch_end; 564 loff_t pos_mod_end; 438 loff_t pos_mod_end; 565 loff_t pos_ftrace_mod_end; 439 loff_t pos_ftrace_mod_end; 566 loff_t pos_bpf_end; << 567 unsigned long value; 440 unsigned long value; 568 unsigned int nameoff; /* If iterating 441 unsigned int nameoff; /* If iterating in core kernel symbols. */ 569 char type; 442 char type; 570 char name[KSYM_NAME_LEN]; 443 char name[KSYM_NAME_LEN]; 571 char module_name[MODULE_NAME_LEN]; 444 char module_name[MODULE_NAME_LEN]; 572 int exported; 445 int exported; 573 int show_value; 446 int show_value; 574 }; 447 }; 575 448 >> 449 int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value, >> 450 char *type, char *name) >> 451 { >> 452 return -EINVAL; >> 453 } >> 454 >> 455 static int get_ksymbol_arch(struct kallsym_iter *iter) >> 456 { >> 457 int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms, >> 458 &iter->value, &iter->type, >> 459 iter->name); >> 460 >> 461 if (ret < 0) { >> 462 iter->pos_arch_end = iter->pos; >> 463 return 0; >> 464 } >> 465 >> 466 return 1; >> 467 } >> 468 576 static int get_ksymbol_mod(struct kallsym_iter 469 static int get_ksymbol_mod(struct kallsym_iter *iter) 577 { 470 { 578 int ret = module_get_kallsym(iter->pos !! 471 int ret = module_get_kallsym(iter->pos - iter->pos_arch_end, 579 &iter->va 472 &iter->value, &iter->type, 580 iter->nam 473 iter->name, iter->module_name, 581 &iter->ex 474 &iter->exported); 582 if (ret < 0) { 475 if (ret < 0) { 583 iter->pos_mod_end = iter->pos; 476 iter->pos_mod_end = iter->pos; 584 return 0; 477 return 0; 585 } 478 } 586 479 587 return 1; 480 return 1; 588 } 481 } 589 482 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 483 static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter) 596 { 484 { 597 int ret = ftrace_mod_get_kallsym(iter- 485 int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end, 598 &iter 486 &iter->value, &iter->type, 599 iter- 487 iter->name, iter->module_name, 600 &iter 488 &iter->exported); 601 if (ret < 0) { 489 if (ret < 0) { 602 iter->pos_ftrace_mod_end = ite 490 iter->pos_ftrace_mod_end = iter->pos; 603 return 0; 491 return 0; 604 } 492 } 605 493 606 return 1; 494 return 1; 607 } 495 } 608 496 609 static int get_ksymbol_bpf(struct kallsym_iter 497 static int get_ksymbol_bpf(struct kallsym_iter *iter) 610 { 498 { 611 int ret; !! 499 strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN); 612 << 613 strscpy(iter->module_name, "bpf", MODU << 614 iter->exported = 0; 500 iter->exported = 0; 615 ret = bpf_get_kallsym(iter->pos - iter !! 501 return bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end, 616 &iter->value, &i !! 502 &iter->value, &iter->type, 617 iter->name); !! 503 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 } 504 } 639 505 640 /* Returns space to next name. */ 506 /* Returns space to next name. */ 641 static unsigned long get_ksymbol_core(struct k 507 static unsigned long get_ksymbol_core(struct kallsym_iter *iter) 642 { 508 { 643 unsigned off = iter->nameoff; 509 unsigned off = iter->nameoff; 644 510 645 iter->module_name[0] = '\0'; 511 iter->module_name[0] = '\0'; 646 iter->value = kallsyms_sym_address(ite 512 iter->value = kallsyms_sym_address(iter->pos); 647 513 648 iter->type = kallsyms_get_symbol_type( 514 iter->type = kallsyms_get_symbol_type(off); 649 515 650 off = kallsyms_expand_symbol(off, iter 516 off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name)); 651 517 652 return off - iter->nameoff; 518 return off - iter->nameoff; 653 } 519 } 654 520 655 static void reset_iter(struct kallsym_iter *it 521 static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) 656 { 522 { 657 iter->name[0] = '\0'; 523 iter->name[0] = '\0'; 658 iter->nameoff = get_symbol_offset(new_ 524 iter->nameoff = get_symbol_offset(new_pos); 659 iter->pos = new_pos; 525 iter->pos = new_pos; 660 if (new_pos == 0) { 526 if (new_pos == 0) { >> 527 iter->pos_arch_end = 0; 661 iter->pos_mod_end = 0; 528 iter->pos_mod_end = 0; 662 iter->pos_ftrace_mod_end = 0; 529 iter->pos_ftrace_mod_end = 0; 663 iter->pos_bpf_end = 0; << 664 } 530 } 665 } 531 } 666 532 667 /* 533 /* 668 * The end position (last + 1) of each additio 534 * The end position (last + 1) of each additional kallsyms section is recorded 669 * in iter->pos_..._end as each section is add 535 * in iter->pos_..._end as each section is added, and so can be used to 670 * determine which get_ksymbol_...() function 536 * determine which get_ksymbol_...() function to call next. 671 */ 537 */ 672 static int update_iter_mod(struct kallsym_iter 538 static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) 673 { 539 { 674 iter->pos = pos; 540 iter->pos = pos; 675 541 >> 542 if ((!iter->pos_arch_end || iter->pos_arch_end > pos) && >> 543 get_ksymbol_arch(iter)) >> 544 return 1; >> 545 676 if ((!iter->pos_mod_end || iter->pos_m 546 if ((!iter->pos_mod_end || iter->pos_mod_end > pos) && 677 get_ksymbol_mod(iter)) 547 get_ksymbol_mod(iter)) 678 return 1; 548 return 1; 679 549 680 if ((!iter->pos_ftrace_mod_end || iter 550 if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) && 681 get_ksymbol_ftrace_mod(iter)) 551 get_ksymbol_ftrace_mod(iter)) 682 return 1; 552 return 1; 683 553 684 if ((!iter->pos_bpf_end || iter->pos_b !! 554 return get_ksymbol_bpf(iter); 685 get_ksymbol_bpf(iter)) << 686 return 1; << 687 << 688 return get_ksymbol_kprobe(iter); << 689 } 555 } 690 556 691 /* Returns false if pos at or past end of file 557 /* Returns false if pos at or past end of file. */ 692 static int update_iter(struct kallsym_iter *it 558 static int update_iter(struct kallsym_iter *iter, loff_t pos) 693 { 559 { 694 /* Module symbols can be accessed rand 560 /* Module symbols can be accessed randomly. */ 695 if (pos >= kallsyms_num_syms) 561 if (pos >= kallsyms_num_syms) 696 return update_iter_mod(iter, p 562 return update_iter_mod(iter, pos); 697 563 698 /* If we're not on the desired positio 564 /* If we're not on the desired position, reset to new position. */ 699 if (pos != iter->pos) 565 if (pos != iter->pos) 700 reset_iter(iter, pos); 566 reset_iter(iter, pos); 701 567 702 iter->nameoff += get_ksymbol_core(iter 568 iter->nameoff += get_ksymbol_core(iter); 703 iter->pos++; 569 iter->pos++; 704 570 705 return 1; 571 return 1; 706 } 572 } 707 573 708 static void *s_next(struct seq_file *m, void * 574 static void *s_next(struct seq_file *m, void *p, loff_t *pos) 709 { 575 { 710 (*pos)++; 576 (*pos)++; 711 577 712 if (!update_iter(m->private, *pos)) 578 if (!update_iter(m->private, *pos)) 713 return NULL; 579 return NULL; 714 return p; 580 return p; 715 } 581 } 716 582 717 static void *s_start(struct seq_file *m, loff_ 583 static void *s_start(struct seq_file *m, loff_t *pos) 718 { 584 { 719 if (!update_iter(m->private, *pos)) 585 if (!update_iter(m->private, *pos)) 720 return NULL; 586 return NULL; 721 return m->private; 587 return m->private; 722 } 588 } 723 589 724 static void s_stop(struct seq_file *m, void *p 590 static void s_stop(struct seq_file *m, void *p) 725 { 591 { 726 } 592 } 727 593 728 static int s_show(struct seq_file *m, void *p) 594 static int s_show(struct seq_file *m, void *p) 729 { 595 { 730 void *value; 596 void *value; 731 struct kallsym_iter *iter = m->private 597 struct kallsym_iter *iter = m->private; 732 598 733 /* Some debugging symbols have no name 599 /* Some debugging symbols have no name. Ignore them. */ 734 if (!iter->name[0]) 600 if (!iter->name[0]) 735 return 0; 601 return 0; 736 602 737 value = iter->show_value ? (void *)ite 603 value = iter->show_value ? (void *)iter->value : NULL; 738 604 739 if (iter->module_name[0]) { 605 if (iter->module_name[0]) { 740 char type; 606 char type; 741 607 742 /* 608 /* 743 * Label it "global" if it is 609 * Label it "global" if it is exported, 744 * "local" if not exported. 610 * "local" if not exported. 745 */ 611 */ 746 type = iter->exported ? touppe 612 type = iter->exported ? toupper(iter->type) : 747 tolowe 613 tolower(iter->type); 748 seq_printf(m, "%px %c %s\t[%s] 614 seq_printf(m, "%px %c %s\t[%s]\n", value, 749 type, iter->name, i 615 type, iter->name, iter->module_name); 750 } else 616 } else 751 seq_printf(m, "%px %c %s\n", v 617 seq_printf(m, "%px %c %s\n", value, 752 iter->type, iter->n 618 iter->type, iter->name); 753 return 0; 619 return 0; 754 } 620 } 755 621 756 static const struct seq_operations kallsyms_op 622 static const struct seq_operations kallsyms_op = { 757 .start = s_start, 623 .start = s_start, 758 .next = s_next, 624 .next = s_next, 759 .stop = s_stop, 625 .stop = s_stop, 760 .show = s_show 626 .show = s_show 761 }; 627 }; 762 628 763 #ifdef CONFIG_BPF_SYSCALL !! 629 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 { << 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 { 630 { 808 struct kallsym_iter *iter = priv_data; !! 631 #ifdef CONFIG_PERF_EVENTS 809 !! 632 extern int sysctl_perf_event_paranoid; 810 reset_iter(iter, 0); !! 633 if (sysctl_perf_event_paranoid <= 1) 811 !! 634 return 1; 812 /* cache here as in kallsyms_open() ca !! 635 #endif 813 * credentials to tell BPF iterators i << 814 */ << 815 iter->show_value = kallsyms_show_value << 816 << 817 return 0; 636 return 0; 818 } 637 } 819 638 820 DEFINE_BPF_ITER_FUNC(ksym, struct bpf_iter_met !! 639 /* 821 !! 640 * We show kallsyms information even to normal users if we've enabled 822 static const struct bpf_iter_seq_info ksym_ite !! 641 * kernel profiling and are explicitly not paranoid (so kptr_restrict 823 .seq_ops = &bpf_iter_ks !! 642 * is clear, and sysctl_perf_event_paranoid isn't set). 824 .init_seq_private = bpf_iter_ksy !! 643 * 825 .fini_seq_private = NULL, !! 644 * Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to 826 .seq_priv_size = sizeof(struc !! 645 * block even that). 827 }; !! 646 */ 828 !! 647 bool kallsyms_show_value(const struct cred *cred) 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 { 648 { 845 ksym_iter_reg_info.ctx_arg_info[0].btf !! 649 switch (kptr_restrict) { 846 return bpf_iter_reg_target(&ksym_iter_ !! 650 case 0: >> 651 if (kallsyms_for_perf()) >> 652 return true; >> 653 /* fallthrough */ >> 654 case 1: >> 655 if (security_capable(cred, &init_user_ns, CAP_SYSLOG, >> 656 CAP_OPT_NOAUDIT) == 0) >> 657 return true; >> 658 /* fallthrough */ >> 659 default: >> 660 return false; >> 661 } 847 } 662 } 848 << 849 late_initcall(bpf_ksym_iter_register); << 850 << 851 #endif /* CONFIG_BPF_SYSCALL */ << 852 663 853 static int kallsyms_open(struct inode *inode, 664 static int kallsyms_open(struct inode *inode, struct file *file) 854 { 665 { 855 /* 666 /* 856 * We keep iterator in m->private, sin 667 * We keep iterator in m->private, since normal case is to 857 * s_start from where we left off, so 668 * s_start from where we left off, so we avoid doing 858 * using get_symbol_offset for every s 669 * using get_symbol_offset for every symbol. 859 */ 670 */ 860 struct kallsym_iter *iter; 671 struct kallsym_iter *iter; 861 iter = __seq_open_private(file, &kalls 672 iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter)); 862 if (!iter) 673 if (!iter) 863 return -ENOMEM; 674 return -ENOMEM; 864 reset_iter(iter, 0); 675 reset_iter(iter, 0); 865 676 866 /* 677 /* 867 * Instead of checking this on every s 678 * Instead of checking this on every s_show() call, cache 868 * the result here at open time. 679 * the result here at open time. 869 */ 680 */ 870 iter->show_value = kallsyms_show_value 681 iter->show_value = kallsyms_show_value(file->f_cred); 871 return 0; 682 return 0; 872 } 683 } 873 684 874 #ifdef CONFIG_KGDB_KDB 685 #ifdef CONFIG_KGDB_KDB 875 const char *kdb_walk_kallsyms(loff_t *pos) 686 const char *kdb_walk_kallsyms(loff_t *pos) 876 { 687 { 877 static struct kallsym_iter kdb_walk_ka 688 static struct kallsym_iter kdb_walk_kallsyms_iter; 878 if (*pos == 0) { 689 if (*pos == 0) { 879 memset(&kdb_walk_kallsyms_iter 690 memset(&kdb_walk_kallsyms_iter, 0, 880 sizeof(kdb_walk_kallsym 691 sizeof(kdb_walk_kallsyms_iter)); 881 reset_iter(&kdb_walk_kallsyms_ 692 reset_iter(&kdb_walk_kallsyms_iter, 0); 882 } 693 } 883 while (1) { 694 while (1) { 884 if (!update_iter(&kdb_walk_kal 695 if (!update_iter(&kdb_walk_kallsyms_iter, *pos)) 885 return NULL; 696 return NULL; 886 ++*pos; 697 ++*pos; 887 /* Some debugging symbols have 698 /* Some debugging symbols have no name. Ignore them. */ 888 if (kdb_walk_kallsyms_iter.nam 699 if (kdb_walk_kallsyms_iter.name[0]) 889 return kdb_walk_kallsy 700 return kdb_walk_kallsyms_iter.name; 890 } 701 } 891 } 702 } 892 #endif /* CONFIG_KGDB_KDB */ 703 #endif /* CONFIG_KGDB_KDB */ 893 704 894 static const struct proc_ops kallsyms_proc_ops 705 static const struct proc_ops kallsyms_proc_ops = { 895 .proc_open = kallsyms_open, 706 .proc_open = kallsyms_open, 896 .proc_read = seq_read, 707 .proc_read = seq_read, 897 .proc_lseek = seq_lseek, 708 .proc_lseek = seq_lseek, 898 .proc_release = seq_release_private, 709 .proc_release = seq_release_private, 899 }; 710 }; 900 711 901 static int __init kallsyms_init(void) 712 static int __init kallsyms_init(void) 902 { 713 { 903 proc_create("kallsyms", 0444, NULL, &k 714 proc_create("kallsyms", 0444, NULL, &kallsyms_proc_ops); 904 return 0; 715 return 0; 905 } 716 } 906 device_initcall(kallsyms_init); 717 device_initcall(kallsyms_init); 907 718
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.