* 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (40 commits) tracing: Separate raw syscall from syscall tracer ring-buffer-benchmark: Add parameters to set produce/consumer priorities tracing, function tracer: Clean up strstrip() usage ring-buffer benchmark: Run producer/consumer threads at nice +19 tracing: Remove the stale include/trace/power.h tracing: Only print objcopy version warning once from recordmcount tracing: Prevent build warning: 'ftrace_graph_buf' defined but not used ring-buffer: Move access to commit_page up into function used tracing: do not disable interrupts for trace_clock_local ring-buffer: Add multiple iterations between benchmark timestamps kprobes: Sanitize struct kretprobe_instance allocations tracing: Fix to use __always_unused attribute compiler: Introduce __always_unused tracing: Exit with error if a weak function is used in recordmcount.pl tracing: Move conditional into update_funcs() in recordmcount.pl tracing: Add regex for weak functions in recordmcount.pl tracing: Move mcount section search to front of loop in recordmcount.pl tracing: Fix objcopy revision check in recordmcount.pl tracing: Check absolute path of input file in recordmcount.pl tracing: Correct the check for number of arguments in recordmcount.pl ...
Unified · Split
| @@ -778,6 +778,13 @@ and is between 256 and 4096 characters. It is defined in the file · 777 unmodified lines | ||
| 778 | 778 | by the set_ftrace_notrace file in the debugfs |
| 779 | 779 | tracing directory. |
| 780 | 780 | |
| 781 | + ftrace_graph_filter=[function-list] | |
| 782 | + [FTRACE] Limit the top level callers functions traced | |
| 783 | + by the function graph tracer at boot up. | |
| 784 | + function-list is a comma separated list of functions | |
| 785 | + that can be changed at run time by the | |
| 786 | + set_graph_function file in the debugfs tracing directory. | |
| 787 | + | |
| 781 | 788 | gamecon.map[2|3]= |
| 782 | 789 | [HW,JOY] Multisystem joystick and NES/SNES/PSX pad |
| 783 | 790 | support via parallel port (up to 5 devices per port) |
| @@ -213,10 +213,19 @@ If you can't trace NMI functions, then skip this option. · 212 unmodified lines | ||
| 213 | 213 | <details to be filled> |
| 214 | 214 | |
| 215 | 215 | |
| 216 | −HAVE_FTRACE_SYSCALLS | |
| 216 | +HAVE_SYSCALL_TRACEPOINTS | |
| 217 | 217 | --------------------- |
| 218 | 218 | |
| 219 | −<details to be filled> | |
| 219 | +You need very few things to get the syscalls tracing in an arch. | |
| 220 | + | |
| 221 | +- Have a NR_syscalls variable in <asm/unistd.h> that provides the number | |
| 222 | + of syscalls supported by the arch. | |
| 223 | +- Implement arch_syscall_addr() that resolves a syscall address from a | |
| 224 | + syscall number. | |
| 225 | +- Support the TIF_SYSCALL_TRACEPOINT thread flags | |
| 226 | +- Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace | |
| 227 | + in the ptrace syscalls tracing path. | |
| 228 | +- Tag this arch as HAVE_SYSCALL_TRACEPOINTS. | |
| 220 | 229 | |
| 221 | 230 | |
| 222 | 231 | HAVE_FTRACE_MCOUNT_RECORD |
| @@ -379,6 +379,7 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exc · 378 unmodified lines | ||
| 379 | 379 | PHONY += scripts_basic |
| 380 | 380 | scripts_basic: |
| 381 | 381 | $(Q)$(MAKE) $(build)=scripts/basic |
| 382 | + $(Q)rm -f .tmp_quiet_recordmcount | |
| 382 | 383 | |
| 383 | 384 | # To avoid any implicit rule to kick in, define an empty command. |
| 384 | 385 | scripts/basic/%: scripts_basic ; |
| @@ -203,73 +203,10 @@ out: · 202 unmodified lines | ||
| 203 | 203 | |
| 204 | 204 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 205 | 205 | |
| 206 | −extern unsigned long __start_syscalls_metadata[]; | |
| 207 | −extern unsigned long __stop_syscalls_metadata[]; | |
| 208 | 206 | extern unsigned int sys_call_table[]; |
| 209 | 207 | |
| 210 | −static struct syscall_metadata **syscalls_metadata; | |
| 211 | − | |
| 212 | −struct syscall_metadata *syscall_nr_to_meta(int nr) | |
| 213 | −{ | |
| 214 | − if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | |
| 215 | − return NULL; | |
| 216 | − | |
| 217 | − return syscalls_metadata[nr]; | |
| 218 | −} | |
| 219 | − | |
| 220 | −int syscall_name_to_nr(char *name) | |
| 221 | −{ | |
| 222 | − int i; | |
| 223 | − | |
| 224 | − if (!syscalls_metadata) | |
| 225 | − return -1; | |
| 226 | − for (i = 0; i < NR_syscalls; i++) | |
| 227 | − if (syscalls_metadata[i]) | |
| 228 | − if (!strcmp(syscalls_metadata[i]->name, name)) | |
| 229 | − return i; | |
| 230 | − return -1; | |
| 231 | −} | |
| 232 | − | |
| 233 | −void set_syscall_enter_id(int num, int id) | |
| 234 | −{ | |
| 235 | − syscalls_metadata[num]->enter_id = id; | |
| 236 | −} | |
| 237 | − | |
| 238 | −void set_syscall_exit_id(int num, int id) | |
| 208 | +unsigned long __init arch_syscall_addr(int nr) | |
| 239 | 209 | { |
| 240 | − syscalls_metadata[num]->exit_id = id; | |
| 241 | −} | |
| 242 | − | |
| 243 | −static struct syscall_metadata *find_syscall_meta(unsigned long syscall) | |
| 244 | −{ | |
| 245 | − struct syscall_metadata *start; | |
| 246 | − struct syscall_metadata *stop; | |
| 247 | − char str[KSYM_SYMBOL_LEN]; | |
| 248 | − | |
| 249 | − start = (struct syscall_metadata *)__start_syscalls_metadata; | |
| 250 | − stop = (struct syscall_metadata *)__stop_syscalls_metadata; | |
| 251 | − kallsyms_lookup(syscall, NULL, NULL, NULL, str); | |
| 252 | − | |
| 253 | − for ( ; start < stop; start++) { | |
| 254 | − if (start->name && !strcmp(start->name + 3, str + 3)) | |
| 255 | − return start; | |
| 256 | − } | |
| 257 | − return NULL; | |
| 258 | −} | |
| 259 | − | |
| 260 | −static int __init arch_init_ftrace_syscalls(void) | |
| 261 | −{ | |
| 262 | − struct syscall_metadata *meta; | |
| 263 | − int i; | |
| 264 | − syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls, | |
| 265 | − GFP_KERNEL); | |
| 266 | − if (!syscalls_metadata) | |
| 267 | − return -ENOMEM; | |
| 268 | − for (i = 0; i < NR_syscalls; i++) { | |
| 269 | − meta = find_syscall_meta((unsigned long)sys_call_table[i]); | |
| 270 | − syscalls_metadata[i] = meta; | |
| 271 | − } | |
| 272 | − return 0; | |
| 210 | + return (unsigned long)sys_call_table[nr]; | |
| 273 | 211 | } |
| 274 | −arch_initcall(arch_init_ftrace_syscalls); | |
| 275 | 212 | #endif |
| @@ -1185,17 +1185,14 @@ END(ftrace_graph_caller) · 1184 unmodified lines | ||
| 1185 | 1185 | |
| 1186 | 1186 | .globl return_to_handler |
| 1187 | 1187 | return_to_handler: |
| 1188 | − pushl $0 | |
| 1189 | 1188 | pushl %eax |
| 1190 | − pushl %ecx | |
| 1191 | 1189 | pushl %edx |
| 1192 | 1190 | movl %ebp, %eax |
| 1193 | 1191 | call ftrace_return_to_handler |
| 1194 | − movl %eax, 0xc(%esp) | |
| 1192 | + movl %eax, %ecx | |
| 1195 | 1193 | popl %edx |
| 1196 | − popl %ecx | |
| 1197 | 1194 | popl %eax |
| 1198 | − ret | |
| 1195 | + jmp *%ecx | |
| 1199 | 1196 | #endif |
| 1200 | 1197 | |
| 1201 | 1198 | .section .rodata,"a" |
| @@ -155,11 +155,11 @@ GLOBAL(return_to_handler) · 154 unmodified lines | ||
| 155 | 155 | |
| 156 | 156 | call ftrace_return_to_handler |
| 157 | 157 | |
| 158 | − movq %rax, 16(%rsp) | |
| 158 | + movq %rax, %rdi | |
| 159 | 159 | movq 8(%rsp), %rdx |
| 160 | 160 | movq (%rsp), %rax |
| 161 | − addq $16, %rsp | |
| 162 | − retq | |
| 161 | + addq $24, %rsp | |
| 162 | + jmp *%rdi | |
| 163 | 163 | #endif |
| 164 | 164 | |
| 165 | 165 | |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | * the dangers of modifying code on the run. |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 13 | + | |
| 12 | 14 | #include <linux/spinlock.h> |
| 13 | 15 | #include <linux/hardirq.h> |
| 14 | 16 | #include <linux/uaccess.h> |
| @@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data) · 321 unmodified lines | ||
| 336 | 338 | |
| 337 | 339 | switch (faulted) { |
| 338 | 340 | case 0: |
| 339 | − pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); | |
| 341 | + pr_info("converting mcount calls to 0f 1f 44 00 00\n"); | |
| 340 | 342 | memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); |
| 341 | 343 | break; |
| 342 | 344 | case 1: |
| 343 | − pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); | |
| 345 | + pr_info("converting mcount calls to 66 66 66 66 90\n"); | |
| 344 | 346 | memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); |
| 345 | 347 | break; |
| 346 | 348 | case 2: |
| 347 | − pr_info("ftrace: converting mcount calls to jmp . + 5\n"); | |
| 349 | + pr_info("converting mcount calls to jmp . + 5\n"); | |
| 348 | 350 | memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); |
| 349 | 351 | break; |
| 350 | 352 | } |
| @@ -468,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, · 117 unmodified lines | ||
| 468 | 470 | |
| 469 | 471 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 470 | 472 | |
| 471 | −extern unsigned long __start_syscalls_metadata[]; | |
| 472 | −extern unsigned long __stop_syscalls_metadata[]; | |
| 473 | 473 | extern unsigned long *sys_call_table; |
| 474 | 474 | |
| 475 | −static struct syscall_metadata **syscalls_metadata; | |
| 476 | − | |
| 477 | −static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) | |
| 478 | −{ | |
| 479 | − struct syscall_metadata *start; | |
| 480 | − struct syscall_metadata *stop; | |
| 481 | − char str[KSYM_SYMBOL_LEN]; | |
| 482 | − | |
| 483 | − | |
| 484 | − start = (struct syscall_metadata *)__start_syscalls_metadata; | |
| 485 | − stop = (struct syscall_metadata *)__stop_syscalls_metadata; | |
| 486 | − kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str); | |
| 487 | − | |
| 488 | − for ( ; start < stop; start++) { | |
| 489 | − if (start->name && !strcmp(start->name, str)) | |
| 490 | − return start; | |
| 491 | − } | |
| 492 | − return NULL; | |
| 493 | −} | |
| 494 | − | |
| 495 | −struct syscall_metadata *syscall_nr_to_meta(int nr) | |
| 496 | −{ | |
| 497 | − if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | |
| 498 | − return NULL; | |
| 499 | − | |
| 500 | − return syscalls_metadata[nr]; | |
| 501 | −} | |
| 502 | − | |
| 503 | −int syscall_name_to_nr(char *name) | |
| 475 | +unsigned long __init arch_syscall_addr(int nr) | |
| 504 | 476 | { |
| 505 | − int i; | |
| 506 | − | |
| 507 | − if (!syscalls_metadata) | |
| 508 | − return -1; | |
| 509 | − | |
| 510 | − for (i = 0; i < NR_syscalls; i++) { | |
| 511 | − if (syscalls_metadata[i]) { | |
| 512 | − if (!strcmp(syscalls_metadata[i]->name, name)) | |
| 513 | − return i; | |
| 514 | − } | |
| 515 | − } | |
| 516 | − return -1; | |
| 517 | −} | |
| 518 | − | |
| 519 | −void set_syscall_enter_id(int num, int id) | |
| 520 | −{ | |
| 521 | − syscalls_metadata[num]->enter_id = id; | |
| 522 | −} | |
| 523 | − | |
| 524 | −void set_syscall_exit_id(int num, int id) | |
| 525 | −{ | |
| 526 | − syscalls_metadata[num]->exit_id = id; | |
| 527 | −} | |
| 528 | − | |
| 529 | −static int __init arch_init_ftrace_syscalls(void) | |
| 530 | −{ | |
| 531 | − int i; | |
| 532 | − struct syscall_metadata *meta; | |
| 533 | − unsigned long **psys_syscall_table = &sys_call_table; | |
| 534 | − | |
| 535 | − syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | |
| 536 | − NR_syscalls, GFP_KERNEL); | |
| 537 | − if (!syscalls_metadata) { | |
| 538 | − WARN_ON(1); | |
| 539 | − return -ENOMEM; | |
| 540 | − } | |
| 541 | − | |
| 542 | − for (i = 0; i < NR_syscalls; i++) { | |
| 543 | − meta = find_syscall_meta(psys_syscall_table[i]); | |
| 544 | − syscalls_metadata[i] = meta; | |
| 545 | − } | |
| 546 | − return 0; | |
| 477 | + return (unsigned long)(&sys_call_table)[nr]; | |
| 547 | 478 | } |
| 548 | −arch_initcall(arch_init_ftrace_syscalls); | |
| 549 | 479 | #endif |
| @@ -1,12 +1,13 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi> |
| 3 | 3 | */ |
| 4 | + | |
| 5 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 6 | + | |
| 4 | 7 | #include <linux/module.h> |
| 5 | 8 | #include <linux/io.h> |
| 6 | 9 | #include <linux/mmiotrace.h> |
| 7 | 10 | |
| 8 | −#define MODULE_NAME "testmmiotrace" | |
| 9 | − | |
| 10 | 11 | static unsigned long mmio_address; |
| 11 | 12 | module_param(mmio_address, ulong, 0); |
| 12 | 13 | MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " |
| @@ -30,7 +31,7 @@ static unsigned v32(unsigned i) · 17 unmodified lines | ||
| 30 | 31 | static void do_write_test(void __iomem *p) |
| 31 | 32 | { |
| 32 | 33 | unsigned int i; |
| 33 | − pr_info(MODULE_NAME ": write test.\n"); | |
| 34 | + pr_info("write test.\n"); | |
| 34 | 35 | mmiotrace_printk("Write test.\n"); |
| 35 | 36 | |
| 36 | 37 | for (i = 0; i < 256; i++) |
| @@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p) · 10 unmodified lines | ||
| 47 | 48 | { |
| 48 | 49 | unsigned int i; |
| 49 | 50 | unsigned errs[3] = { 0 }; |
| 50 | − pr_info(MODULE_NAME ": read test.\n"); | |
| 51 | + pr_info("read test.\n"); | |
| 51 | 52 | mmiotrace_printk("Read test.\n"); |
| 52 | 53 | |
| 53 | 54 | for (i = 0; i < 256; i++) |
| @@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p) · 14 unmodified lines | ||
| 68 | 69 | |
| 69 | 70 | static void do_read_far_test(void __iomem *p) |
| 70 | 71 | { |
| 71 | − pr_info(MODULE_NAME ": read far test.\n"); | |
| 72 | + pr_info("read far test.\n"); | |
| 72 | 73 | mmiotrace_printk("Read far test.\n"); |
| 73 | 74 | |
| 74 | 75 | ioread32(p + read_far); |
| @@ -78,7 +79,7 @@ static void do_test(unsigned long size) · 3 unmodified lines | ||
| 78 | 79 | { |
| 79 | 80 | void __iomem *p = ioremap_nocache(mmio_address, size); |
| 80 | 81 | if (!p) { |
| 81 | − pr_err(MODULE_NAME ": could not ioremap, aborting.\n"); | |
| 82 | + pr_err("could not ioremap, aborting.\n"); | |
| 82 | 83 | return; |
| 83 | 84 | } |
| 84 | 85 | mmiotrace_printk("ioremap returned %p.\n", p); |
| @@ -94,24 +95,22 @@ static int __init init(void) · 9 unmodified lines | ||
| 94 | 95 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); |
| 95 | 96 | |
| 96 | 97 | if (mmio_address == 0) { |
| 97 | − pr_err(MODULE_NAME ": you have to use the module argument " | |
| 98 | − "mmio_address.\n"); | |
| 99 | − pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS" | |
| 100 | − " YOU REALLY KNOW WHAT YOU ARE DOING!\n"); | |
| 98 | + pr_err("you have to use the module argument mmio_address.\n"); | |
| 99 | + pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n"); | |
| 101 | 100 | return -ENXIO; |
| 102 | 101 | } |
| 103 | 102 | |
| 104 | − pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI " | |
| 105 | − "address space, and writing 16 kB of rubbish in there.\n", | |
| 106 | − size >> 10, mmio_address); | |
| 103 | + pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, " | |
| 104 | + "and writing 16 kB of rubbish in there.\n", | |
| 105 | + size >> 10, mmio_address); | |
| 107 | 106 | do_test(size); |
| 108 | − pr_info(MODULE_NAME ": All done.\n"); | |
| 107 | + pr_info("All done.\n"); | |
| 109 | 108 | return 0; |
| 110 | 109 | } |
| 111 | 110 | |
| 112 | 111 | static void __exit cleanup(void) |
| 113 | 112 | { |
| 114 | − pr_debug(MODULE_NAME ": unloaded.\n"); | |
| 113 | + pr_debug("unloaded.\n"); | |
| 115 | 114 | } |
| 116 | 115 | |
| 117 | 116 | module_init(init); |
| @@ -79,6 +79,7 @@ · 78 unmodified lines | ||
| 79 | 79 | #define noinline __attribute__((noinline)) |
| 80 | 80 | #define __attribute_const__ __attribute__((__const__)) |
| 81 | 81 | #define __maybe_unused __attribute__((unused)) |
| 82 | +#define __always_unused __attribute__((unused)) | |
| 82 | 83 | |
| 83 | 84 | #define __gcc_header(x) #x |
| 84 | 85 | #define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) |
| @@ -218,6 +218,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); · 217 unmodified lines | ||
| 218 | 218 | # define __maybe_unused /* unimplemented */ |
| 219 | 219 | #endif |
| 220 | 220 | |
| 221 | +#ifndef __always_unused | |
| 222 | +# define __always_unused /* unimplemented */ | |
| 223 | +#endif | |
| 224 | + | |
| 221 | 225 | #ifndef noinline |
| 222 | 226 | #define noinline |
| 223 | 227 | #endif |
| @@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task) · 23 unmodified lines | ||
| 24 | 24 | return 0; |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | −extern void __lockfunc lock_kernel(void) __acquires(kernel_lock); | |
| 28 | −extern void __lockfunc unlock_kernel(void) __releases(kernel_lock); | |
| 27 | +extern void __lockfunc | |
| 28 | +_lock_kernel(const char *func, const char *file, int line) | |
| 29 | +__acquires(kernel_lock); | |
| 30 | + | |
| 31 | +extern void __lockfunc | |
| 32 | +_unlock_kernel(const char *func, const char *file, int line) | |
| 33 | +__releases(kernel_lock); | |
| 34 | + | |
| 35 | +#define lock_kernel() do { \ | |
| 36 | + _lock_kernel(__func__, __FILE__, __LINE__); \ | |
| 37 | +} while (0) | |
| 38 | + | |
| 39 | +#define unlock_kernel() do { \ | |
| 40 | + _unlock_kernel(__func__, __FILE__, __LINE__); \ | |
| 41 | +} while (0) | |
| 29 | 42 | |
| 30 | 43 | /* |
| 31 | 44 | * Various legacy drivers don't really need the BKL in a specific |
| @@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void) · 9 unmodified lines | ||
| 41 | 54 | |
| 42 | 55 | #else |
| 43 | 56 | |
| 44 | −#define lock_kernel() do { } while(0) | |
| 45 | −#define unlock_kernel() do { } while(0) | |
| 57 | +#define lock_kernel() | |
| 58 | +#define unlock_kernel() | |
| 46 | 59 | #define release_kernel_lock(task) do { } while(0) |
| 47 | 60 | #define cycle_kernel_lock() do { } while(0) |
| 48 | 61 | #define reacquire_kernel_lock(task) 0 |
| @@ -0,0 +1,61 @@ | ||
| 1 | +#undef TRACE_SYSTEM | |
| 2 | +#define TRACE_SYSTEM bkl | |
| 3 | + | |
| 4 | +#if !defined(_TRACE_BKL_H) || defined(TRACE_HEADER_MULTI_READ) | |
| 5 | +#define _TRACE_BKL_H | |
| 6 | + | |
| 7 | +#include <linux/tracepoint.h> | |
| 8 | + | |
| 9 | +TRACE_EVENT(lock_kernel, | |
| 10 | + | |
| 11 | + TP_PROTO(const char *func, const char *file, int line), | |
| 12 | + | |
| 13 | + TP_ARGS(func, file, line), | |
| 14 | + | |
| 15 | + TP_STRUCT__entry( | |
| 16 | + __field( int, lock_depth ) | |
| 17 | + __field_ext( const char *, func, FILTER_PTR_STRING ) | |
| 18 | + __field_ext( const char *, file, FILTER_PTR_STRING ) | |
| 19 | + __field( int, line ) | |
| 20 | + ), | |
| 21 | + | |
| 22 | + TP_fast_assign( | |
| 23 | + /* We want to record the lock_depth after lock is acquired */ | |
| 24 | + __entry->lock_depth = current->lock_depth + 1; | |
| 25 | + __entry->func = func; | |
| 26 | + __entry->file = file; | |
| 27 | + __entry->line = line; | |
| 28 | + ), | |
| 29 | + | |
| 30 | + TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, | |
| 31 | + __entry->file, __entry->line, __entry->func) | |
| 32 | +); | |
| 33 | + | |
| 34 | +TRACE_EVENT(unlock_kernel, | |
| 35 | + | |
| 36 | + TP_PROTO(const char *func, const char *file, int line), | |
| 37 | + | |
| 38 | + TP_ARGS(func, file, line), | |
| 39 | + | |
| 40 | + TP_STRUCT__entry( | |
| 41 | + __field(int, lock_depth) | |
| 42 | + __field(const char *, func) | |
| 43 | + __field(const char *, file) | |
| 44 | + __field(int, line) | |
| 45 | + ), | |
| 46 | + | |
| 47 | + TP_fast_assign( | |
| 48 | + __entry->lock_depth = current->lock_depth; | |
| 49 | + __entry->func = func; | |
| 50 | + __entry->file = file; | |
| 51 | + __entry->line = line; | |
| 52 | + ), | |
| 53 | + | |
| 54 | + TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, | |
| 55 | + __entry->file, __entry->line, __entry->func) | |
| 56 | +); | |
| 57 | + | |
| 58 | +#endif /* _TRACE_BKL_H */ | |
| 59 | + | |
| 60 | +/* This part must be outside protection */ | |
| 61 | +#include <trace/define_trace.h> | |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | #undef TRACE_SYSTEM |
| 2 | −#define TRACE_SYSTEM syscalls | |
| 2 | +#define TRACE_SYSTEM raw_syscalls | |
| 3 | +#define TRACE_INCLUDE_FILE syscalls | |
| 3 | 4 | |
| 4 | 5 | #if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ) |
| 5 | 6 | #define _TRACE_EVENTS_SYSCALLS_H |
| @@ -1,32 +0,0 @@ | ||
| 1 | −#ifndef _TRACE_POWER_H | |
| 2 | −#define _TRACE_POWER_H | |
| 3 | − | |
| 4 | −#include <linux/ktime.h> | |
| 5 | −#include <linux/tracepoint.h> | |
| 6 | − | |
| 7 | −enum { | |
| 8 | − POWER_NONE = 0, | |
| 9 | − POWER_CSTATE = 1, | |
| 10 | − POWER_PSTATE = 2, | |
| 11 | −}; | |
| 12 | − | |
| 13 | −struct power_trace { | |
| 14 | − ktime_t stamp; | |
| 15 | − ktime_t end; | |
| 16 | − int type; | |
| 17 | − int state; | |
| 18 | −}; | |
| 19 | − | |
| 20 | −DECLARE_TRACE(power_start, | |
| 21 | − TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state), | |
| 22 | − TP_ARGS(it, type, state)); | |
| 23 | − | |
| 24 | −DECLARE_TRACE(power_mark, | |
| 25 | − TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state), | |
| 26 | − TP_ARGS(it, type, state)); | |
| 27 | − | |
| 28 | −DECLARE_TRACE(power_end, | |
| 29 | − TP_PROTO(struct power_trace *it), | |
| 30 | − TP_ARGS(it)); | |
| 31 | − | |
| 32 | −#endif /* _TRACE_POWER_H */ | |
| @@ -33,7 +33,7 @@ struct syscall_metadata { · 32 unmodified lines | ||
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | 35 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 36 | −extern struct syscall_metadata *syscall_nr_to_meta(int nr); | |
| 36 | +extern unsigned long arch_syscall_addr(int nr); | |
| 37 | 37 | extern int syscall_name_to_nr(char *name); |
| 38 | 38 | void set_syscall_enter_id(int num, int id); |
| 39 | 39 | void set_syscall_exit_id(int num, int id); |
| @@ -1014,9 +1014,9 @@ int __kprobes register_kretprobe(struct kretprobe *rp) · 1013 unmodified lines | ||
| 1014 | 1014 | /* Pre-allocate memory for max kretprobe instances */ |
| 1015 | 1015 | if (rp->maxactive <= 0) { |
| 1016 | 1016 | #ifdef CONFIG_PREEMPT |
| 1017 | − rp->maxactive = max(10, 2 * NR_CPUS); | |
| 1017 | + rp->maxactive = max(10, 2 * num_possible_cpus()); | |
| 1018 | 1018 | #else |
| 1019 | − rp->maxactive = NR_CPUS; | |
| 1019 | + rp->maxactive = num_possible_cpus(); | |
| 1020 | 1020 | #endif |
| 1021 | 1021 | } |
| 1022 | 1022 | spin_lock_init(&rp->lock); |
| @@ -60,6 +60,13 @@ static int last_ftrace_enabled; · 59 unmodified lines | ||
| 60 | 60 | /* Quick disabling of function tracer. */ |
| 61 | 61 | int function_trace_stop; |
| 62 | 62 | |
| 63 | +/* List for set_ftrace_pid's pids. */ | |
| 64 | +LIST_HEAD(ftrace_pids); | |
| 65 | +struct ftrace_pid { | |
| 66 | + struct list_head list; | |
| 67 | + struct pid *pid; | |
| 68 | +}; | |
| 69 | + | |
| 63 | 70 | /* |
| 64 | 71 | * ftrace_disabled is set when an anomaly is discovered. |
| 65 | 72 | * ftrace_disabled is much stronger than ftrace_enabled. |
| @@ -78,6 +85,10 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; · 12 unmodified lines | ||
| 78 | 85 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
| 79 | 86 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
| 80 | 87 | |
| 88 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| 89 | +static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | |
| 90 | +#endif | |
| 91 | + | |
| 81 | 92 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
| 82 | 93 | { |
| 83 | 94 | struct ftrace_ops *op = ftrace_list; |
| @@ -155,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) · 71 unmodified lines | ||
| 155 | 166 | else |
| 156 | 167 | func = ftrace_list_func; |
| 157 | 168 | |
| 158 | − if (ftrace_pid_trace) { | |
| 169 | + if (!list_empty(&ftrace_pids)) { | |
| 159 | 170 | set_ftrace_pid_function(func); |
| 160 | 171 | func = ftrace_pid_func; |
| 161 | 172 | } |
| @@ -203,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) · 41 unmodified lines | ||
| 203 | 214 | if (ftrace_list->next == &ftrace_list_end) { |
| 204 | 215 | ftrace_func_t func = ftrace_list->func; |
| 205 | 216 | |
| 206 | − if (ftrace_pid_trace) { | |
| 217 | + if (!list_empty(&ftrace_pids)) { | |
| 207 | 218 | set_ftrace_pid_function(func); |
| 208 | 219 | func = ftrace_pid_func; |
| 209 | 220 | } |
| @@ -231,7 +242,7 @@ static void ftrace_update_pid_func(void) · 21 unmodified lines | ||
| 231 | 242 | func = __ftrace_trace_function; |
| 232 | 243 | #endif |
| 233 | 244 | |
| 234 | − if (ftrace_pid_trace) { | |
| 245 | + if (!list_empty(&ftrace_pids)) { | |
| 235 | 246 | set_ftrace_pid_function(func); |
| 236 | 247 | func = ftrace_pid_func; |
| 237 | 248 | } else { |
| @@ -821,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer) · 583 unmodified lines | ||
| 821 | 832 | } |
| 822 | 833 | #endif /* CONFIG_FUNCTION_PROFILER */ |
| 823 | 834 | |
| 824 | −/* set when tracing only a pid */ | |
| 825 | −struct pid *ftrace_pid_trace; | |
| 826 | 835 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; |
| 827 | 836 | |
| 828 | 837 | #ifdef CONFIG_DYNAMIC_FTRACE |
| @@ -1261,12 +1270,34 @@ static int ftrace_update_code(struct module *mod) · 432 unmodified lines | ||
| 1261 | 1270 | ftrace_new_addrs = p->newlist; |
| 1262 | 1271 | p->flags = 0L; |
| 1263 | 1272 | |
| 1264 | − /* convert record (i.e, patch mcount-call with NOP) */ | |
| 1265 | − if (ftrace_code_disable(mod, p)) { | |
| 1266 | − p->flags |= FTRACE_FL_CONVERTED; | |
| 1267 | − ftrace_update_cnt++; | |
| 1268 | − } else | |
| 1273 | + /* | |
| 1274 | + * Do the initial record convertion from mcount jump | |
| 1275 | + * to the NOP instructions. | |
| 1276 | + */ | |
| 1277 | + if (!ftrace_code_disable(mod, p)) { | |
| 1269 | 1278 | ftrace_free_rec(p); |
| 1279 | + continue; | |
| 1280 | + } | |
| 1281 | + | |
| 1282 | + p->flags |= FTRACE_FL_CONVERTED; | |
| 1283 | + ftrace_update_cnt++; | |
| 1284 | + | |
| 1285 | + /* | |
| 1286 | + * If the tracing is enabled, go ahead and enable the record. | |
| 1287 | + * | |
| 1288 | + * The reason not to enable the record immediatelly is the | |
| 1289 | + * inherent check of ftrace_make_nop/ftrace_make_call for | |
| 1290 | + * correct previous instructions. Making first the NOP | |
| 1291 | + * conversion puts the module to the correct state, thus | |
| 1292 | + * passing the ftrace_make_call check. | |
| 1293 | + */ | |
| 1294 | + if (ftrace_start_up) { | |
| 1295 | + int failed = __ftrace_replace_code(p, 1); | |
| 1296 | + if (failed) { | |
| 1297 | + ftrace_bug(failed, p->ip); | |
| 1298 | + ftrace_free_rec(p); | |
| 1299 | + } | |
| 1300 | + } | |
| 1270 | 1301 | } |
| 1271 | 1302 | |
| 1272 | 1303 | stop = ftrace_now(raw_smp_processor_id()); |
| @@ -1656,60 +1687,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) · 383 unmodified lines | ||
| 1656 | 1687 | return ret; |
| 1657 | 1688 | } |
| 1658 | 1689 | |
| 1659 | −enum { | |
| 1660 | − MATCH_FULL, | |
| 1661 | − MATCH_FRONT_ONLY, | |
| 1662 | − MATCH_MIDDLE_ONLY, | |
| 1663 | − MATCH_END_ONLY, | |
| 1664 | −}; | |
| 1665 | − | |
| 1666 | −/* | |
| 1667 | − * (static function - no need for kernel doc) | |
| 1668 | − * | |
| 1669 | − * Pass in a buffer containing a glob and this function will | |
| 1670 | − * set search to point to the search part of the buffer and | |
| 1671 | − * return the type of search it is (see enum above). | |
| 1672 | − * This does modify buff. | |
| 1673 | − * | |
| 1674 | − * Returns enum type. | |
| 1675 | − * search returns the pointer to use for comparison. | |
| 1676 | − * not returns 1 if buff started with a '!' | |
| 1677 | − * 0 otherwise. | |
| 1678 | − */ | |
| 1679 | −static int | |
| 1680 | −ftrace_setup_glob(char *buff, int len, char **search, int *not) | |
| 1681 | −{ | |
| 1682 | − int type = MATCH_FULL; | |
| 1683 | − int i; | |
| 1684 | − | |
| 1685 | − if (buff[0] == '!') { | |
| 1686 | − *not = 1; | |
| 1687 | − buff++; | |
| 1688 | − len--; | |
| 1689 | − } else | |
| 1690 | − *not = 0; | |
| 1691 | − | |
| 1692 | − *search = buff; | |
| 1693 | − | |
| 1694 | − for (i = 0; i < len; i++) { | |
| 1695 | − if (buff[i] == '*') { | |
| 1696 | − if (!i) { | |
| 1697 | − *search = buff + 1; | |
| 1698 | − type = MATCH_END_ONLY; | |
| 1699 | − } else { | |
| 1700 | − if (type == MATCH_END_ONLY) | |
| 1701 | − type = MATCH_MIDDLE_ONLY; | |
| 1702 | − else | |
| 1703 | − type = MATCH_FRONT_ONLY; | |
| 1704 | − buff[i] = 0; | |
| 1705 | − break; | |
| 1706 | − } | |
| 1707 | − } | |
| 1708 | − } | |
| 1709 | − | |
| 1710 | − return type; | |
| 1711 | −} | |
| 1712 | − | |
| 1713 | 1690 | static int ftrace_match(char *str, char *regex, int len, int type) |
| 1714 | 1691 | { |
| 1715 | 1692 | int matched = 0; |
| @@ -1758,7 +1735,7 @@ static void ftrace_match_records(char *buff, int len, int enable) · 42 unmodified lines | ||
| 1758 | 1735 | int not; |
| 1759 | 1736 | |
| 1760 | 1737 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
| 1761 | − type = ftrace_setup_glob(buff, len, &search, ¬); | |
| 1738 | + type = filter_parse_regex(buff, len, &search, ¬); | |
| 1762 | 1739 | |
| 1763 | 1740 | search_len = strlen(search); |
| 1764 | 1741 | |
| @@ -1826,7 +1803,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) · 61 unmodified lines | ||
| 1826 | 1803 | } |
| 1827 | 1804 | |
| 1828 | 1805 | if (strlen(buff)) { |
| 1829 | − type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | |
| 1806 | + type = filter_parse_regex(buff, strlen(buff), &search, ¬); | |
| 1830 | 1807 | search_len = strlen(search); |
| 1831 | 1808 | } |
| 1832 | 1809 | |
| @@ -1991,7 +1968,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, · 158 unmodified lines | ||
| 1991 | 1968 | int count = 0; |
| 1992 | 1969 | char *search; |
| 1993 | 1970 | |
| 1994 | − type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | |
| 1971 | + type = filter_parse_regex(glob, strlen(glob), &search, ¬); | |
| 1995 | 1972 | len = strlen(search); |
| 1996 | 1973 | |
| 1997 | 1974 | /* we do not support '!' for function probes */ |
| @@ -2068,7 +2045,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, · 70 unmodified lines | ||
| 2068 | 2045 | else if (glob) { |
| 2069 | 2046 | int not; |
| 2070 | 2047 | |
| 2071 | − type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | |
| 2048 | + type = filter_parse_regex(glob, strlen(glob), &search, ¬); | |
| 2072 | 2049 | len = strlen(search); |
| 2073 | 2050 | |
| 2074 | 2051 | /* we do not support '!' for function probes */ |
| @@ -2312,6 +2289,32 @@ static int __init set_ftrace_filter(char *str) · 237 unmodified lines | ||
| 2312 | 2289 | } |
| 2313 | 2290 | __setup("ftrace_filter=", set_ftrace_filter); |
| 2314 | 2291 | |
| 2292 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| 2293 | +static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | |
| 2294 | +static int __init set_graph_function(char *str) | |
| 2295 | +{ | |
| 2296 | + strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); | |
| 2297 | + return 1; | |
| 2298 | +} | |
| 2299 | +__setup("ftrace_graph_filter=", set_graph_function); | |
| 2300 | + | |
| 2301 | +static void __init set_ftrace_early_graph(char *buf) | |
| 2302 | +{ | |
| 2303 | + int ret; | |
| 2304 | + char *func; | |
| 2305 | + | |
| 2306 | + while (buf) { | |
| 2307 | + func = strsep(&buf, ","); | |
| 2308 | + /* we allow only one expression at a time */ | |
| 2309 | + ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | |
| 2310 | + func); | |
| 2311 | + if (ret) | |
| 2312 | + printk(KERN_DEBUG "ftrace: function %s not " | |
| 2313 | + "traceable\n", func); | |
| 2314 | + } | |
| 2315 | +} | |
| 2316 | +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | |
| 2317 | + | |
| 2315 | 2318 | static void __init set_ftrace_early_filter(char *buf, int enable) |
| 2316 | 2319 | { |
| 2317 | 2320 | char *func; |
| @@ -2328,6 +2331,10 @@ static void __init set_ftrace_early_filters(void) · 10 unmodified lines | ||
| 2328 | 2331 | set_ftrace_early_filter(ftrace_filter_buf, 1); |
| 2329 | 2332 | if (ftrace_notrace_buf[0]) |
| 2330 | 2333 | set_ftrace_early_filter(ftrace_notrace_buf, 0); |
| 2334 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| 2335 | + if (ftrace_graph_buf[0]) | |
| 2336 | + set_ftrace_early_graph(ftrace_graph_buf); | |
| 2337 | +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | |
| 2331 | 2338 | } |
| 2332 | 2339 | |
| 2333 | 2340 | static int |
| @@ -2513,7 +2520,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) · 179 unmodified lines | ||
| 2513 | 2520 | return -ENODEV; |
| 2514 | 2521 | |
| 2515 | 2522 | /* decode regex */ |
| 2516 | − type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); | |
| 2523 | + type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); | |
| 2517 | 2524 | if (not) |
| 2518 | 2525 | return -EINVAL; |
| 2519 | 2526 | |
| @@ -2624,7 +2631,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) · 104 unmodified lines | ||
| 2624 | 2631 | return 0; |
| 2625 | 2632 | } |
| 2626 | 2633 | |
| 2627 | −static int ftrace_convert_nops(struct module *mod, | |
| 2634 | +static int ftrace_process_locs(struct module *mod, | |
| 2628 | 2635 | unsigned long *start, |
| 2629 | 2636 | unsigned long *end) |
| 2630 | 2637 | { |
| @@ -2684,7 +2691,7 @@ static void ftrace_init_module(struct module *mod, · 53 unmodified lines | ||
| 2684 | 2691 | { |
| 2685 | 2692 | if (ftrace_disabled || start == end) |
| 2686 | 2693 | return; |
| 2687 | − ftrace_convert_nops(mod, start, end); | |
| 2694 | + ftrace_process_locs(mod, start, end); | |
| 2688 | 2695 | } |
| 2689 | 2696 | |
| 2690 | 2697 | static int ftrace_module_notify(struct notifier_block *self, |
| @@ -2745,7 +2752,7 @@ void __init ftrace_init(void) · 54 unmodified lines | ||
| 2745 | 2752 | |
| 2746 | 2753 | last_ftrace_enabled = ftrace_enabled = 1; |
| 2747 | 2754 | |
| 2748 | − ret = ftrace_convert_nops(NULL, | |
| 2755 | + ret = ftrace_process_locs(NULL, | |
| 2749 | 2756 | __start_mcount_loc, |
| 2750 | 2757 | __stop_mcount_loc); |
| 2751 | 2758 | |
| @@ -2778,23 +2785,6 @@ static inline void ftrace_startup_enable(int command) { } · 26 unmodified lines | ||
| 2778 | 2785 | # define ftrace_shutdown_sysctl() do { } while (0) |
| 2779 | 2786 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
| 2780 | 2787 | |
| 2781 | −static ssize_t | |
| 2782 | −ftrace_pid_read(struct file *file, char __user *ubuf, | |
| 2783 | − size_t cnt, loff_t *ppos) | |
| 2784 | −{ | |
| 2785 | − char buf[64]; | |
| 2786 | − int r; | |
| 2787 | − | |
| 2788 | − if (ftrace_pid_trace == ftrace_swapper_pid) | |
| 2789 | − r = sprintf(buf, "swapper tasks\n"); | |
| 2790 | − else if (ftrace_pid_trace) | |
| 2791 | − r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace)); | |
| 2792 | − else | |
| 2793 | − r = sprintf(buf, "no pid\n"); | |
| 2794 | − | |
| 2795 | − return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | |
| 2796 | −} | |
| 2797 | − | |
| 2798 | 2788 | static void clear_ftrace_swapper(void) |
| 2799 | 2789 | { |
| 2800 | 2790 | struct task_struct *p; |
| @@ -2845,14 +2835,12 @@ static void set_ftrace_pid(struct pid *pid) · 44 unmodified lines | ||
| 2845 | 2835 | rcu_read_unlock(); |
| 2846 | 2836 | } |
| 2847 | 2837 | |
| 2848 | −static void clear_ftrace_pid_task(struct pid **pid) | |
| 2838 | +static void clear_ftrace_pid_task(struct pid *pid) | |
| 2849 | 2839 | { |
| 2850 | − if (*pid == ftrace_swapper_pid) | |
| 2840 | + if (pid == ftrace_swapper_pid) | |
| 2851 | 2841 | clear_ftrace_swapper(); |
| 2852 | 2842 | else |
| 2853 | − clear_ftrace_pid(*pid); | |
| 2854 | − | |
| 2855 | − *pid = NULL; | |
| 2843 | + clear_ftrace_pid(pid); | |
| 2856 | 2844 | } |
| 2857 | 2845 | |
| 2858 | 2846 | static void set_ftrace_pid_task(struct pid *pid) |
| @@ -2863,74 +2851,184 @@ static void set_ftrace_pid_task(struct pid *pid) · 4 unmodified lines | ||
| 2863 | 2851 | set_ftrace_pid(pid); |
| 2864 | 2852 | } |
| 2865 | 2853 | |
| 2866 | −static ssize_t | |
| 2867 | −ftrace_pid_write(struct file *filp, const char __user *ubuf, | |
| 2868 | − size_t cnt, loff_t *ppos) | |
| 2854 | +static int ftrace_pid_add(int p) | |
| 2869 | 2855 | { |
| 2870 | 2856 | struct pid *pid; |
| 2871 | − char buf[64]; | |
| 2872 | − long val; | |
| 2873 | − int ret; | |
| 2857 | + struct ftrace_pid *fpid; | |
| 2858 | + int ret = -EINVAL; | |
| 2874 | 2859 | |
| 2875 | − if (cnt >= sizeof(buf)) | |
| 2876 | − return -EINVAL; | |
| 2860 | + mutex_lock(&ftrace_lock); | |
| 2877 | 2861 | |
| 2878 | − if (copy_from_user(&buf, ubuf, cnt)) | |
| 2879 | − return -EFAULT; | |
| 2862 | + if (!p) | |
| 2863 | + pid = ftrace_swapper_pid; | |
| 2864 | + else | |
| 2865 | + pid = find_get_pid(p); | |
| 2880 | 2866 | |
| 2881 | − buf[cnt] = 0; | |
| 2867 | + if (!pid) | |
| 2868 | + goto out; | |
| 2882 | 2869 | |
| 2883 | − ret = strict_strtol(buf, 10, &val); | |
| 2884 | − if (ret < 0) | |
| 2885 | − return ret; | |
| 2870 | + ret = 0; | |
| 2886 | 2871 | |
| 2887 | − mutex_lock(&ftrace_lock); | |
| 2888 | − if (val < 0) { | |
| 2889 | − /* disable pid tracing */ | |
| 2890 | − if (!ftrace_pid_trace) | |
| 2891 | − goto out; | |
| 2872 | + list_for_each_entry(fpid, &ftrace_pids, list) | |
| 2873 | + if (fpid->pid == pid) | |
| 2874 | + goto out_put; | |
| 2892 | 2875 | |
| 2893 | − clear_ftrace_pid_task(&ftrace_pid_trace); | |
| 2876 | + ret = -ENOMEM; | |
| 2894 | 2877 | |
| 2895 | − } else { | |
| 2896 | − /* swapper task is special */ | |
| 2897 | − if (!val) { | |
| 2898 | − pid = ftrace_swapper_pid; | |
| 2899 | − if (pid == ftrace_pid_trace) | |
| 2900 | − goto out; | |
| 2901 | − } else { | |
| 2902 | − pid = find_get_pid(val); | |
| 2878 | + fpid = kmalloc(sizeof(*fpid), GFP_KERNEL); | |
| 2879 | + if (!fpid) | |
| 2880 | + goto out_put; | |
| 2903 | 2881 | |
| 2904 | − if (pid == ftrace_pid_trace) { | |
| 2905 | − put_pid(pid); | |
| 2906 | − goto out; | |
| 2907 | − } | |
| 2908 | − } | |
| 2882 | + list_add(&fpid->list, &ftrace_pids); | |
| 2883 | + fpid->pid = pid; | |
| 2909 | 2884 | |
| 2910 | − if (ftrace_pid_trace) | |
| 2911 | − clear_ftrace_pid_task(&ftrace_pid_trace); | |
| 2885 | + set_ftrace_pid_task(pid); | |
| 2912 | 2886 | |
| 2913 | − if (!pid) | |
| 2914 | − goto out; | |
| 2887 | + ftrace_update_pid_func(); | |
| 2888 | + ftrace_startup_enable(0); | |
| 2889 | + | |
| 2890 | + mutex_unlock(&ftrace_lock); | |
| 2891 | + return 0; | |
| 2892 | + | |
| 2893 | +out_put: | |
| 2894 | + if (pid != ftrace_swapper_pid) | |
| 2895 | + put_pid(pid); | |
| 2915 | 2896 | |
| 2916 | − ftrace_pid_trace = pid; | |
| 2897 | +out: | |
| 2898 | + mutex_unlock(&ftrace_lock); | |
| 2899 | + return ret; | |
| 2900 | +} | |
| 2901 | + | |
| 2902 | +static void ftrace_pid_reset(void) | |
| 2903 | +{ | |
| 2904 | + struct ftrace_pid *fpid, *safe; | |
| 2917 | 2905 | |
| 2918 | − set_ftrace_pid_task(ftrace_pid_trace); | |
| 2906 | + mutex_lock(&ftrace_lock); | |
| 2907 | + list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) { | |
| 2908 | + struct pid *pid = fpid->pid; | |
| 2909 | + | |
| 2910 | + clear_ftrace_pid_task(pid); | |
| 2911 | + | |
| 2912 | + list_del(&fpid->list); | |
| 2913 | + kfree(fpid); | |
| 2919 | 2914 | } |
| 2920 | 2915 | |
| 2921 | − /* update the function call */ | |
| 2922 | 2916 | ftrace_update_pid_func(); |
| 2923 | 2917 | ftrace_startup_enable(0); |
| 2924 | 2918 | |
| 2925 | − out: | |
| 2926 | 2919 | mutex_unlock(&ftrace_lock); |
| 2920 | +} | |
| 2927 | 2921 | |
| 2928 | − return cnt; | |
| 2922 | +static void *fpid_start(struct seq_file *m, loff_t *pos) | |
| 2923 | +{ | |
| 2924 | + mutex_lock(&ftrace_lock); | |
| 2925 | + | |
| 2926 | + if (list_empty(&ftrace_pids) && (!*pos)) | |
| 2927 | + return (void *) 1; | |
| 2928 | + | |
| 2929 | + return seq_list_start(&ftrace_pids, *pos); | |
| 2930 | +} | |
| 2931 | + | |
| 2932 | +static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) | |
| 2933 | +{ | |
| 2934 | + if (v == (void *)1) | |
| 2935 | + return NULL; | |
| 2936 | + | |
| 2937 | + return seq_list_next(v, &ftrace_pids, pos); | |
| 2938 | +} | |
| 2939 | + | |
| 2940 | +static void fpid_stop(struct seq_file *m, void *p) | |
| 2941 | +{ | |
| 2942 | + mutex_unlock(&ftrace_lock); | |
| 2943 | +} | |
| 2944 | + | |
| 2945 | +static int fpid_show(struct seq_file *m, void *v) | |
| 2946 | +{ | |
| 2947 | + const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list); | |
| 2948 | + | |
| 2949 | + if (v == (void *)1) { | |
| 2950 | + seq_printf(m, "no pid\n"); | |
| 2951 | + return 0; | |
| 2952 | + } | |
| 2953 | + | |
| 2954 | + if (fpid->pid == ftrace_swapper_pid) | |
| 2955 | + seq_printf(m, "swapper tasks\n"); | |
| 2956 | + else | |
| 2957 | + seq_printf(m, "%u\n", pid_vnr(fpid->pid)); | |
| 2958 | + | |
| 2959 | + return 0; | |
| 2960 | +} | |
| 2961 | + | |
| 2962 | +static const struct seq_operations ftrace_pid_sops = { | |
| 2963 | + .start = fpid_start, | |
| 2964 | + .next = fpid_next, | |
| 2965 | + .stop = fpid_stop, | |
| 2966 | + .show = fpid_show, | |
| 2967 | +}; | |
| 2968 | + | |
| 2969 | +static int | |
| 2970 | +ftrace_pid_open(struct inode *inode, struct file *file) | |
| 2971 | +{ | |
| 2972 | + int ret = 0; | |
| 2973 | + | |
| 2974 | + if ((file->f_mode & FMODE_WRITE) && | |
| 2975 | + (file->f_flags & O_TRUNC)) | |
| 2976 | + ftrace_pid_reset(); | |
| 2977 | + | |
| 2978 | + if (file->f_mode & FMODE_READ) | |
| 2979 | + ret = seq_open(file, &ftrace_pid_sops); | |
| 2980 | + | |
| 2981 | + return ret; | |
| 2982 | +} | |
| 2983 | + | |
| 2984 | +static ssize_t | |
| 2985 | +ftrace_pid_write(struct file *filp, const char __user *ubuf, | |
| 2986 | + size_t cnt, loff_t *ppos) | |
| 2987 | +{ | |
| 2988 | + char buf[64], *tmp; | |
| 2989 | + long val; | |
| 2990 | + int ret; | |
| 2991 | + | |
| 2992 | + if (cnt >= sizeof(buf)) | |
| 2993 | + return -EINVAL; | |
| 2994 | + | |
| 2995 | + if (copy_from_user(&buf, ubuf, cnt)) | |
| 2996 | + return -EFAULT; | |
| 2997 | + | |
| 2998 | + buf[cnt] = 0; | |
| 2999 | + | |
| 3000 | + /* | |
| 3001 | + * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" | |
| 3002 | + * to clean the filter quietly. | |
| 3003 | + */ | |
| 3004 | + tmp = strstrip(buf); | |
| 3005 | + if (strlen(tmp) == 0) | |
| 3006 | + return 1; | |
| 3007 | + | |
| 3008 | + ret = strict_strtol(tmp, 10, &val); | |
| 3009 | + if (ret < 0) | |
| 3010 | + return ret; | |
| 3011 | + | |
| 3012 | + ret = ftrace_pid_add(val); | |
| 3013 | + | |
| 3014 | + return ret ? ret : cnt; | |
| 3015 | +} | |
| 3016 | + | |
| 3017 | +static int | |
| 3018 | +ftrace_pid_release(struct inode *inode, struct file *file) | |
| 3019 | +{ | |
| 3020 | + if (file->f_mode & FMODE_READ) | |
| 3021 | + seq_release(inode, file); | |
| 3022 | + | |
| 3023 | + return 0; | |
| 2929 | 3024 | } |
| 2930 | 3025 | |
| 2931 | 3026 | static const struct file_operations ftrace_pid_fops = { |
| 2932 | − .read = ftrace_pid_read, | |
| 2933 | − .write = ftrace_pid_write, | |
| 3027 | + .open = ftrace_pid_open, | |
| 3028 | + .write = ftrace_pid_write, | |
| 3029 | + .read = seq_read, | |
| 3030 | + .llseek = seq_lseek, | |
| 3031 | + .release = ftrace_pid_release, | |
| 2934 | 3032 | }; |
| 2935 | 3033 | |
| 2936 | 3034 | static __init int ftrace_init_debugfs(void) |
| @@ -3293,4 +3391,3 @@ void ftrace_graph_stop(void) · 356 unmodified lines | ||
| 3293 | 3391 | ftrace_stop(); |
| 3294 | 3392 | } |
| 3295 | 3393 | #endif |
| 3296 | − | |
| @@ -1787,9 +1787,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, · 1786 unmodified lines | ||
| 1787 | 1787 | static struct ring_buffer_event * |
| 1788 | 1788 | rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, |
| 1789 | 1789 | unsigned long length, unsigned long tail, |
| 1790 | − struct buffer_page *commit_page, | |
| 1791 | 1790 | struct buffer_page *tail_page, u64 *ts) |
| 1792 | 1791 | { |
| 1792 | + struct buffer_page *commit_page = cpu_buffer->commit_page; | |
| 1793 | 1793 | struct ring_buffer *buffer = cpu_buffer->buffer; |
| 1794 | 1794 | struct buffer_page *next_page; |
| 1795 | 1795 | int ret; |
| @@ -1892,13 +1892,10 @@ static struct ring_buffer_event * · 96 unmodified lines | ||
| 1892 | 1892 | __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, |
| 1893 | 1893 | unsigned type, unsigned long length, u64 *ts) |
| 1894 | 1894 | { |
| 1895 | − struct buffer_page *tail_page, *commit_page; | |
| 1895 | + struct buffer_page *tail_page; | |
| 1896 | 1896 | struct ring_buffer_event *event; |
| 1897 | 1897 | unsigned long tail, write; |
| 1898 | 1898 | |
| 1899 | − commit_page = cpu_buffer->commit_page; | |
| 1900 | − /* we just need to protect against interrupts */ | |
| 1901 | − barrier(); | |
| 1902 | 1899 | tail_page = cpu_buffer->tail_page; |
| 1903 | 1900 | write = local_add_return(length, &tail_page->write); |
| 1904 | 1901 | |
| @@ -1909,7 +1906,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, · 4 unmodified lines | ||
| 1909 | 1906 | /* See if we shot pass the end of this buffer page */ |
| 1910 | 1907 | if (write > BUF_PAGE_SIZE) |
| 1911 | 1908 | return rb_move_tail(cpu_buffer, length, tail, |
| 1912 | − commit_page, tail_page, ts); | |
| 1909 | + tail_page, ts); | |
| 1913 | 1910 | |
| 1914 | 1911 | /* We reserved something on the buffer */ |
| 1915 | 1912 | |
| @@ -35,6 +35,28 @@ static int disable_reader; · 34 unmodified lines | ||
| 35 | 35 | module_param(disable_reader, uint, 0644); |
| 36 | 36 | MODULE_PARM_DESC(disable_reader, "only run producer"); |
| 37 | 37 | |
| 38 | +static int write_iteration = 50; | |
| 39 | +module_param(write_iteration, uint, 0644); | |
| 40 | +MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings"); | |
| 41 | + | |
| 42 | +static int producer_nice = 19; | |
| 43 | +static int consumer_nice = 19; | |
| 44 | + | |
| 45 | +static int producer_fifo = -1; | |
| 46 | +static int consumer_fifo = -1; | |
| 47 | + | |
| 48 | +module_param(producer_nice, uint, 0644); | |
| 49 | +MODULE_PARM_DESC(producer_nice, "nice prio for producer"); | |
| 50 | + | |
| 51 | +module_param(consumer_nice, uint, 0644); | |
| 52 | +MODULE_PARM_DESC(consumer_nice, "nice prio for consumer"); | |
| 53 | + | |
| 54 | +module_param(producer_fifo, uint, 0644); | |
| 55 | +MODULE_PARM_DESC(producer_fifo, "fifo prio for producer"); | |
| 56 | + | |
| 57 | +module_param(consumer_fifo, uint, 0644); | |
| 58 | +MODULE_PARM_DESC(consumer_fifo, "fifo prio for consumer"); | |
| 59 | + | |
| 38 | 60 | static int read_events; |
| 39 | 61 | |
| 40 | 62 | static int kill_test; |
| @@ -208,15 +230,18 @@ static void ring_buffer_producer(void) · 167 unmodified lines | ||
| 208 | 230 | do { |
| 209 | 231 | struct ring_buffer_event *event; |
| 210 | 232 | int *entry; |
| 211 | − | |
| 212 | − event = ring_buffer_lock_reserve(buffer, 10); | |
| 213 | − if (!event) { | |
| 214 | − missed++; | |
| 215 | − } else { | |
| 216 | − hit++; | |
| 217 | − entry = ring_buffer_event_data(event); | |
| 218 | − *entry = smp_processor_id(); | |
| 219 | − ring_buffer_unlock_commit(buffer, event); | |
| 233 | + int i; | |
| 234 | + | |
| 235 | + for (i = 0; i < write_iteration; i++) { | |
| 236 | + event = ring_buffer_lock_reserve(buffer, 10); | |
| 237 | + if (!event) { | |
| 238 | + missed++; | |
| 239 | + } else { | |
| 240 | + hit++; | |
| 241 | + entry = ring_buffer_event_data(event); | |
| 242 | + *entry = smp_processor_id(); | |
| 243 | + ring_buffer_unlock_commit(buffer, event); | |
| 244 | + } | |
| 220 | 245 | } |
| 221 | 246 | do_gettimeofday(&end_tv); |
| 222 | 247 | |
| @@ -263,6 +288,27 @@ static void ring_buffer_producer(void) · 40 unmodified lines | ||
| 263 | 288 | |
| 264 | 289 | if (kill_test) |
| 265 | 290 | trace_printk("ERROR!\n"); |
| 291 | + | |
| 292 | + if (!disable_reader) { | |
| 293 | + if (consumer_fifo < 0) | |
| 294 | + trace_printk("Running Consumer at nice: %d\n", | |
| 295 | + consumer_nice); | |
| 296 | + else | |
| 297 | + trace_printk("Running Consumer at SCHED_FIFO %d\n", | |
| 298 | + consumer_fifo); | |
| 299 | + } | |
| 300 | + if (producer_fifo < 0) | |
| 301 | + trace_printk("Running Producer at nice: %d\n", | |
| 302 | + producer_nice); | |
| 303 | + else | |
| 304 | + trace_printk("Running Producer at SCHED_FIFO %d\n", | |
| 305 | + producer_fifo); | |
| 306 | + | |
| 307 | + /* Let the user know that the test is running at low priority */ | |
| 308 | + if (producer_fifo < 0 && consumer_fifo < 0 && | |
| 309 | + producer_nice == 19 && consumer_nice == 19) | |
| 310 | + trace_printk("WARNING!!! This test is running at lowest priority.\n"); | |
| 311 | + | |
| 266 | 312 | trace_printk("Time: %lld (usecs)\n", time); |
| 267 | 313 | trace_printk("Overruns: %lld\n", overruns); |
| 268 | 314 | if (disable_reader) |
| @@ -392,6 +438,27 @@ static int __init ring_buffer_benchmark_init(void) · 123 unmodified lines | ||
| 392 | 438 | if (IS_ERR(producer)) |
| 393 | 439 | goto out_kill; |
| 394 | 440 | |
| 441 | + /* | |
| 442 | + * Run them as low-prio background tasks by default: | |
| 443 | + */ | |
| 444 | + if (!disable_reader) { | |
| 445 | + if (consumer_fifo >= 0) { | |
| 446 | + struct sched_param param = { | |
| 447 | + .sched_priority = consumer_fifo | |
| 448 | + }; | |
| 449 | + sched_setscheduler(consumer, SCHED_FIFO, ¶m); | |
| 450 | + } else | |
| 451 | + set_user_nice(consumer, consumer_nice); | |
| 452 | + } | |
| 453 | + | |
| 454 | + if (producer_fifo >= 0) { | |
| 455 | + struct sched_param param = { | |
| 456 | + .sched_priority = consumer_fifo | |
| 457 | + }; | |
| 458 | + sched_setscheduler(producer, SCHED_FIFO, ¶m); | |
| 459 | + } else | |
| 460 | + set_user_nice(producer, producer_nice); | |
| 461 | + | |
| 395 | 462 | return 0; |
| 396 | 463 | |
| 397 | 464 | out_kill: |
| @@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf); · 128 unmodified lines | ||
| 129 | 129 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; |
| 130 | 130 | static char *default_bootup_tracer; |
| 131 | 131 | |
| 132 | −static int __init set_ftrace(char *str) | |
| 132 | +static int __init set_cmdline_ftrace(char *str) | |
| 133 | 133 | { |
| 134 | 134 | strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); |
| 135 | 135 | default_bootup_tracer = bootup_tracer_buf; |
| @@ -137,7 +137,7 @@ static int __init set_ftrace(char *str) · 1 unmodified line | ||
| 137 | 137 | ring_buffer_expanded = 1; |
| 138 | 138 | return 1; |
| 139 | 139 | } |
| 140 | −__setup("ftrace=", set_ftrace); | |
| 140 | +__setup("ftrace=", set_cmdline_ftrace); | |
| 141 | 141 | |
| 142 | 142 | static int __init set_ftrace_dump_on_oops(char *str) |
| 143 | 143 | { |
| @@ -483,10 +483,6 @@ static inline int ftrace_graph_addr(unsigned long addr) · 482 unmodified lines | ||
| 483 | 483 | return 0; |
| 484 | 484 | } |
| 485 | 485 | #else |
| 486 | −static inline int ftrace_trace_addr(unsigned long addr) | |
| 487 | −{ | |
| 488 | − return 1; | |
| 489 | −} | |
| 490 | 486 | static inline int ftrace_graph_addr(unsigned long addr) |
| 491 | 487 | { |
| 492 | 488 | return 1; |
| @@ -500,12 +496,12 @@ print_graph_function(struct trace_iterator *iter) · 7 unmodified lines | ||
| 500 | 496 | } |
| 501 | 497 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
| 502 | 498 | |
| 503 | −extern struct pid *ftrace_pid_trace; | |
| 499 | +extern struct list_head ftrace_pids; | |
| 504 | 500 | |
| 505 | 501 | #ifdef CONFIG_FUNCTION_TRACER |
| 506 | 502 | static inline int ftrace_trace_task(struct task_struct *task) |
| 507 | 503 | { |
| 508 | − if (!ftrace_pid_trace) | |
| 504 | + if (list_empty(&ftrace_pids)) | |
| 509 | 505 | return 1; |
| 510 | 506 | |
| 511 | 507 | return test_tsk_trace_trace(task); |
| @@ -699,22 +695,40 @@ struct event_subsystem { · 187 unmodified lines | ||
| 699 | 695 | }; |
| 700 | 696 | |
| 701 | 697 | struct filter_pred; |
| 698 | +struct regex; | |
| 702 | 699 | |
| 703 | 700 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, |
| 704 | 701 | int val1, int val2); |
| 705 | 702 | |
| 703 | +typedef int (*regex_match_func)(char *str, struct regex *r, int len); | |
| 704 | + | |
| 705 | +enum regex_type { | |
| 706 | + MATCH_FULL, | |
| 707 | + MATCH_FRONT_ONLY, | |
| 708 | + MATCH_MIDDLE_ONLY, | |
| 709 | + MATCH_END_ONLY, | |
| 710 | +}; | |
| 711 | + | |
| 712 | +struct regex { | |
| 713 | + char pattern[MAX_FILTER_STR_VAL]; | |
| 714 | + int len; | |
| 715 | + int field_len; | |
| 716 | + regex_match_func match; | |
| 717 | +}; | |
| 718 | + | |
| 706 | 719 | struct filter_pred { |
| 707 | − filter_pred_fn_t fn; | |
| 708 | − u64 val; | |
| 709 | − char str_val[MAX_FILTER_STR_VAL]; | |
| 710 | − int str_len; | |
| 711 | − char *field_name; | |
| 712 | − int offset; | |
| 713 | − int not; | |
| 714 | − int op; | |
| 715 | − int pop_n; | |
| 720 | + filter_pred_fn_t fn; | |
| 721 | + u64 val; | |
| 722 | + struct regex regex; | |
| 723 | + char *field_name; | |
| 724 | + int offset; | |
| 725 | + int not; | |
| 726 | + int op; | |
| 727 | + int pop_n; | |
| 716 | 728 | }; |
| 717 | 729 | |
| 730 | +extern enum regex_type | |
| 731 | +filter_parse_regex(char *buff, int len, char **search, int *not); | |
| 718 | 732 | extern void print_event_filter(struct ftrace_event_call *call, |
| 719 | 733 | struct trace_seq *s); |
| 720 | 734 | extern int apply_event_filter(struct ftrace_event_call *call, |
| @@ -20,6 +20,8 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/ktime.h> |
| 21 | 21 | #include <linux/trace_clock.h> |
| 22 | 22 | |
| 23 | +#include "trace.h" | |
| 24 | + | |
| 23 | 25 | /* |
| 24 | 26 | * trace_clock_local(): the simplest and least coherent tracing clock. |
| 25 | 27 | * |
| @@ -28,17 +30,17 @@ · 2 unmodified lines | ||
| 28 | 30 | */ |
| 29 | 31 | u64 notrace trace_clock_local(void) |
| 30 | 32 | { |
| 31 | − unsigned long flags; | |
| 32 | 33 | u64 clock; |
| 34 | + int resched; | |
| 33 | 35 | |
| 34 | 36 | /* |
| 35 | 37 | * sched_clock() is an architecture implemented, fast, scalable, |
| 36 | 38 | * lockless clock. It is not guaranteed to be coherent across |
| 37 | 39 | * CPUs, nor across CPU idle events. |
| 38 | 40 | */ |
| 39 | − raw_local_irq_save(flags); | |
| 41 | + resched = ftrace_preempt_disable(); | |
| 40 | 42 | clock = sched_clock(); |
| 41 | − raw_local_irq_restore(flags); | |
| 43 | + ftrace_preempt_enable(resched); | |
| 42 | 44 | |
| 43 | 45 | return clock; |
| 44 | 46 | } |
| @@ -878,9 +878,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) · 877 unmodified lines | ||
| 878 | 878 | "'%s/filter' entry\n", name); |
| 879 | 879 | } |
| 880 | 880 | |
| 881 | − entry = trace_create_file("enable", 0644, system->entry, | |
| 882 | − (void *)system->name, | |
| 883 | − &ftrace_system_enable_fops); | |
| 881 | + trace_create_file("enable", 0644, system->entry, | |
| 882 | + (void *)system->name, | |
| 883 | + &ftrace_system_enable_fops); | |
| 884 | 884 | |
| 885 | 885 | return system->entry; |
| 886 | 886 | } |
| @@ -892,7 +892,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, · 5 unmodified lines | ||
| 892 | 892 | const struct file_operations *filter, |
| 893 | 893 | const struct file_operations *format) |
| 894 | 894 | { |
| 895 | − struct dentry *entry; | |
| 896 | 895 | int ret; |
| 897 | 896 | |
| 898 | 897 | /* |
| @@ -910,12 +909,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, · 11 unmodified lines | ||
| 910 | 909 | } |
| 911 | 910 | |
| 912 | 911 | if (call->regfunc) |
| 913 | − entry = trace_create_file("enable", 0644, call->dir, call, | |
| 914 | − enable); | |
| 912 | + trace_create_file("enable", 0644, call->dir, call, | |
| 913 | + enable); | |
| 915 | 914 | |
| 916 | 915 | if (call->id && call->profile_enable) |
| 917 | − entry = trace_create_file("id", 0444, call->dir, call, | |
| 918 | − id); | |
| 916 | + trace_create_file("id", 0444, call->dir, call, | |
| 917 | + id); | |
| 919 | 918 | |
| 920 | 919 | if (call->define_fields) { |
| 921 | 920 | ret = call->define_fields(call); |
| @@ -924,16 +923,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, · 2 unmodified lines | ||
| 924 | 923 | " events/%s\n", call->name); |
| 925 | 924 | return ret; |
| 926 | 925 | } |
| 927 | − entry = trace_create_file("filter", 0644, call->dir, call, | |
| 928 | − filter); | |
| 926 | + trace_create_file("filter", 0644, call->dir, call, | |
| 927 | + filter); | |
| 929 | 928 | } |
| 930 | 929 | |
| 931 | 930 | /* A trace may not want to export its format */ |
| 932 | 931 | if (!call->show_format) |
| 933 | 932 | return 0; |
| 934 | 933 | |
| 935 | − entry = trace_create_file("format", 0444, call->dir, call, | |
| 936 | − format); | |
| 934 | + trace_create_file("format", 0444, call->dir, call, | |
| 935 | + format); | |
| 937 | 936 | |
| 938 | 937 | return 0; |
| 939 | 938 | } |
| @@ -18,8 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> |
| 19 | 19 | */ |
| 20 | 20 | |
| 21 | −#include <linux/debugfs.h> | |
| 22 | −#include <linux/uaccess.h> | |
| 23 | 21 | #include <linux/module.h> |
| 24 | 22 | #include <linux/ctype.h> |
| 25 | 23 | #include <linux/mutex.h> |
| @@ -197,9 +195,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event, · 171 unmodified lines | ||
| 197 | 195 | char *addr = (char *)(event + pred->offset); |
| 198 | 196 | int cmp, match; |
| 199 | 197 | |
| 200 | − cmp = strncmp(addr, pred->str_val, pred->str_len); | |
| 198 | + cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len); | |
| 201 | 199 | |
| 202 | − match = (!cmp) ^ pred->not; | |
| 200 | + match = cmp ^ pred->not; | |
| 203 | 201 | |
| 204 | 202 | return match; |
| 205 | 203 | } |
| @@ -211,9 +209,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event, · 5 unmodified lines | ||
| 211 | 209 | char **addr = (char **)(event + pred->offset); |
| 212 | 210 | int cmp, match; |
| 213 | 211 | |
| 214 | − cmp = strncmp(*addr, pred->str_val, pred->str_len); | |
| 212 | + cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len); | |
| 215 | 213 | |
| 216 | − match = (!cmp) ^ pred->not; | |
| 214 | + match = cmp ^ pred->not; | |
| 217 | 215 | |
| 218 | 216 | return match; |
| 219 | 217 | } |
| @@ -237,9 +235,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event, · 17 unmodified lines | ||
| 237 | 235 | char *addr = (char *)(event + str_loc); |
| 238 | 236 | int cmp, match; |
| 239 | 237 | |
| 240 | − cmp = strncmp(addr, pred->str_val, str_len); | |
| 238 | + cmp = pred->regex.match(addr, &pred->regex, str_len); | |
| 241 | 239 | |
| 242 | − match = (!cmp) ^ pred->not; | |
| 240 | + match = cmp ^ pred->not; | |
| 243 | 241 | |
| 244 | 242 | return match; |
| 245 | 243 | } |
| @@ -250,6 +248,124 @@ static int filter_pred_none(struct filter_pred *pred, void *event, · 4 unmodified lines | ||
| 250 | 248 | return 0; |
| 251 | 249 | } |
| 252 | 250 | |
| 251 | +/* Basic regex callbacks */ | |
| 252 | +static int regex_match_full(char *str, struct regex *r, int len) | |
| 253 | +{ | |
| 254 | + if (strncmp(str, r->pattern, len) == 0) | |
| 255 | + return 1; | |
| 256 | + return 0; | |
| 257 | +} | |
| 258 | + | |
| 259 | +static int regex_match_front(char *str, struct regex *r, int len) | |
| 260 | +{ | |
| 261 | + if (strncmp(str, r->pattern, len) == 0) | |
| 262 | + return 1; | |
| 263 | + return 0; | |
| 264 | +} | |
| 265 | + | |
| 266 | +static int regex_match_middle(char *str, struct regex *r, int len) | |
| 267 | +{ | |
| 268 | + if (strstr(str, r->pattern)) | |
| 269 | + return 1; | |
| 270 | + return 0; | |
| 271 | +} | |
| 272 | + | |
| 273 | +static int regex_match_end(char *str, struct regex *r, int len) | |
| 274 | +{ | |
| 275 | + char *ptr = strstr(str, r->pattern); | |
| 276 | + | |
| 277 | + if (ptr && (ptr[r->len] == 0)) | |
| 278 | + return 1; | |
| 279 | + return 0; | |
| 280 | +} | |
| 281 | + | |
| 282 | +/** | |
| 283 | + * filter_parse_regex - parse a basic regex | |
| 284 | + * @buff: the raw regex | |
| 285 | + * @len: length of the regex | |
| 286 | + * @search: will point to the beginning of the string to compare | |
| 287 | + * @not: tell whether the match will have to be inverted | |
| 288 | + * | |
| 289 | + * This passes in a buffer containing a regex and this function will | |
| 290 | + * set search to point to the search part of the buffer and | |
| 291 | + * return the type of search it is (see enum above). | |
| 292 | + * This does modify buff. | |
| 293 | + * | |
| 294 | + * Returns enum type. | |
| 295 | + * search returns the pointer to use for comparison. | |
| 296 | + * not returns 1 if buff started with a '!' | |
| 297 | + * 0 otherwise. | |
| 298 | + */ | |
| 299 | +enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not) | |
| 300 | +{ | |
| 301 | + int type = MATCH_FULL; | |
| 302 | + int i; | |
| 303 | + | |
| 304 | + if (buff[0] == '!') { | |
| 305 | + *not = 1; | |
| 306 | + buff++; | |
| 307 | + len--; | |
| 308 | + } else | |
| 309 | + *not = 0; | |
| 310 | + | |
| 311 | + *search = buff; | |
| 312 | + | |
| 313 | + for (i = 0; i < len; i++) { | |
| 314 | + if (buff[i] == '*') { | |
| 315 | + if (!i) { | |
| 316 | + *search = buff + 1; | |
| 317 | + type = MATCH_END_ONLY; | |
| 318 | + } else { | |
| 319 | + if (type == MATCH_END_ONLY) | |
| 320 | + type = MATCH_MIDDLE_ONLY; | |
| 321 | + else | |
| 322 | + type = MATCH_FRONT_ONLY; | |
| 323 | + buff[i] = 0; | |
| 324 | + break; | |
| 325 | + } | |
| 326 | + } | |
| 327 | + } | |
| 328 | + | |
| 329 | + return type; | |
| 330 | +} | |
| 331 | + | |
| 332 | +static int filter_build_regex(struct filter_pred *pred) | |
| 333 | +{ | |
| 334 | + struct regex *r = &pred->regex; | |
| 335 | + char *search, *dup; | |
| 336 | + enum regex_type type; | |
| 337 | + int not; | |
| 338 | + | |
| 339 | + type = filter_parse_regex(r->pattern, r->len, &search, ¬); | |
| 340 | + dup = kstrdup(search, GFP_KERNEL); | |
| 341 | + if (!dup) | |
| 342 | + return -ENOMEM; | |
| 343 | + | |
| 344 | + strcpy(r->pattern, dup); | |
| 345 | + kfree(dup); | |
| 346 | + | |
| 347 | + r->len = strlen(r->pattern); | |
| 348 | + | |
| 349 | + switch (type) { | |
| 350 | + case MATCH_FULL: | |
| 351 | + r->match = regex_match_full; | |
| 352 | + break; | |
| 353 | + case MATCH_FRONT_ONLY: | |
| 354 | + r->match = regex_match_front; | |
| 355 | + break; | |
| 356 | + case MATCH_MIDDLE_ONLY: | |
| 357 | + r->match = regex_match_middle; | |
| 358 | + break; | |
| 359 | + case MATCH_END_ONLY: | |
| 360 | + r->match = regex_match_end; | |
| 361 | + break; | |
| 362 | + } | |
| 363 | + | |
| 364 | + pred->not ^= not; | |
| 365 | + | |
| 366 | + return 0; | |
| 367 | +} | |
| 368 | + | |
| 253 | 369 | /* return 1 if event matches, 0 otherwise (discard) */ |
| 254 | 370 | int filter_match_preds(struct ftrace_event_call *call, void *rec) |
| 255 | 371 | { |
| @@ -396,7 +512,7 @@ static void filter_clear_pred(struct filter_pred *pred) · 140 unmodified lines | ||
| 396 | 512 | { |
| 397 | 513 | kfree(pred->field_name); |
| 398 | 514 | pred->field_name = NULL; |
| 399 | − pred->str_len = 0; | |
| 515 | + pred->regex.len = 0; | |
| 400 | 516 | } |
| 401 | 517 | |
| 402 | 518 | static int filter_set_pred(struct filter_pred *dest, |
| @@ -660,21 +776,24 @@ static int filter_add_pred(struct filter_parse_state *ps, · 257 unmodified lines | ||
| 660 | 776 | } |
| 661 | 777 | |
| 662 | 778 | if (is_string_field(field)) { |
| 663 | − pred->str_len = field->size; | |
| 779 | + ret = filter_build_regex(pred); | |
| 780 | + if (ret) | |
| 781 | + return ret; | |
| 664 | 782 | |
| 665 | − if (field->filter_type == FILTER_STATIC_STRING) | |
| 783 | + if (field->filter_type == FILTER_STATIC_STRING) { | |
| 666 | 784 | fn = filter_pred_string; |
| 667 | − else if (field->filter_type == FILTER_DYN_STRING) | |
| 668 | − fn = filter_pred_strloc; | |
| 785 | + pred->regex.field_len = field->size; | |
| 786 | + } else if (field->filter_type == FILTER_DYN_STRING) | |
| 787 | + fn = filter_pred_strloc; | |
| 669 | 788 | else { |
| 670 | 789 | fn = filter_pred_pchar; |
| 671 | − pred->str_len = strlen(pred->str_val); | |
| 790 | + pred->regex.field_len = strlen(pred->regex.pattern); | |
| 672 | 791 | } |
| 673 | 792 | } else { |
| 674 | 793 | if (field->is_signed) |
| 675 | − ret = strict_strtoll(pred->str_val, 0, &val); | |
| 794 | + ret = strict_strtoll(pred->regex.pattern, 0, &val); | |
| 676 | 795 | else |
| 677 | − ret = strict_strtoull(pred->str_val, 0, &val); | |
| 796 | + ret = strict_strtoull(pred->regex.pattern, 0, &val); | |
| 678 | 797 | if (ret) { |
| 679 | 798 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); |
| 680 | 799 | return -EINVAL; |
| @@ -1045,8 +1164,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2) · 364 unmodified lines | ||
| 1045 | 1164 | return NULL; |
| 1046 | 1165 | } |
| 1047 | 1166 | |
| 1048 | − strcpy(pred->str_val, operand2); | |
| 1049 | − pred->str_len = strlen(operand2); | |
| 1167 | + strcpy(pred->regex.pattern, operand2); | |
| 1168 | + pred->regex.len = strlen(pred->regex.pattern); | |
| 1050 | 1169 | |
| 1051 | 1170 | pred->op = op; |
| 1052 | 1171 | |
| @@ -48,11 +48,11 @@ · 47 unmodified lines | ||
| 48 | 48 | struct ____ftrace_##name { \ |
| 49 | 49 | tstruct \ |
| 50 | 50 | }; \ |
| 51 | −static void __used ____ftrace_check_##name(void) \ | |
| 51 | +static void __always_unused ____ftrace_check_##name(void) \ | |
| 52 | 52 | { \ |
| 53 | 53 | struct ____ftrace_##name *__entry = NULL; \ |
| 54 | 54 | \ |
| 55 | − /* force cmpile-time check on F_printk() */ \ | |
| 55 | + /* force compile-time check on F_printk() */ \ | |
| 56 | 56 | printk(print); \ |
| 57 | 57 | } |
| 58 | 58 | |
| @@ -14,6 +14,69 @@ static int sys_refcount_exit; · 13 unmodified lines | ||
| 14 | 14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); |
| 15 | 15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
| 16 | 16 | |
| 17 | +extern unsigned long __start_syscalls_metadata[]; | |
| 18 | +extern unsigned long __stop_syscalls_metadata[]; | |
| 19 | + | |
| 20 | +static struct syscall_metadata **syscalls_metadata; | |
| 21 | + | |
| 22 | +static struct syscall_metadata *find_syscall_meta(unsigned long syscall) | |
| 23 | +{ | |
| 24 | + struct syscall_metadata *start; | |
| 25 | + struct syscall_metadata *stop; | |
| 26 | + char str[KSYM_SYMBOL_LEN]; | |
| 27 | + | |
| 28 | + | |
| 29 | + start = (struct syscall_metadata *)__start_syscalls_metadata; | |
| 30 | + stop = (struct syscall_metadata *)__stop_syscalls_metadata; | |
| 31 | + kallsyms_lookup(syscall, NULL, NULL, NULL, str); | |
| 32 | + | |
| 33 | + for ( ; start < stop; start++) { | |
| 34 | + /* | |
| 35 | + * Only compare after the "sys" prefix. Archs that use | |
| 36 | + * syscall wrappers may have syscalls symbols aliases prefixed | |
| 37 | + * with "SyS" instead of "sys", leading to an unwanted | |
| 38 | + * mismatch. | |
| 39 | + */ | |
| 40 | + if (start->name && !strcmp(start->name + 3, str + 3)) | |
| 41 | + return start; | |
| 42 | + } | |
| 43 | + return NULL; | |
| 44 | +} | |
| 45 | + | |
| 46 | +static struct syscall_metadata *syscall_nr_to_meta(int nr) | |
| 47 | +{ | |
| 48 | + if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | |
| 49 | + return NULL; | |
| 50 | + | |
| 51 | + return syscalls_metadata[nr]; | |
| 52 | +} | |
| 53 | + | |
| 54 | +int syscall_name_to_nr(char *name) | |
| 55 | +{ | |
| 56 | + int i; | |
| 57 | + | |
| 58 | + if (!syscalls_metadata) | |
| 59 | + return -1; | |
| 60 | + | |
| 61 | + for (i = 0; i < NR_syscalls; i++) { | |
| 62 | + if (syscalls_metadata[i]) { | |
| 63 | + if (!strcmp(syscalls_metadata[i]->name, name)) | |
| 64 | + return i; | |
| 65 | + } | |
| 66 | + } | |
| 67 | + return -1; | |
| 68 | +} | |
| 69 | + | |
| 70 | +void set_syscall_enter_id(int num, int id) | |
| 71 | +{ | |
| 72 | + syscalls_metadata[num]->enter_id = id; | |
| 73 | +} | |
| 74 | + | |
| 75 | +void set_syscall_exit_id(int num, int id) | |
| 76 | +{ | |
| 77 | + syscalls_metadata[num]->exit_id = id; | |
| 78 | +} | |
| 79 | + | |
| 17 | 80 | enum print_line_t |
| 18 | 81 | print_syscall_enter(struct trace_iterator *iter, int flags) |
| 19 | 82 | { |
| @@ -375,6 +438,29 @@ struct trace_event event_syscall_exit = { · 355 unmodified lines | ||
| 375 | 438 | .trace = print_syscall_exit, |
| 376 | 439 | }; |
| 377 | 440 | |
| 441 | +int __init init_ftrace_syscalls(void) | |
| 442 | +{ | |
| 443 | + struct syscall_metadata *meta; | |
| 444 | + unsigned long addr; | |
| 445 | + int i; | |
| 446 | + | |
| 447 | + syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | |
| 448 | + NR_syscalls, GFP_KERNEL); | |
| 449 | + if (!syscalls_metadata) { | |
| 450 | + WARN_ON(1); | |
| 451 | + return -ENOMEM; | |
| 452 | + } | |
| 453 | + | |
| 454 | + for (i = 0; i < NR_syscalls; i++) { | |
| 455 | + addr = arch_syscall_addr(i); | |
| 456 | + meta = find_syscall_meta(addr); | |
| 457 | + syscalls_metadata[i] = meta; | |
| 458 | + } | |
| 459 | + | |
| 460 | + return 0; | |
| 461 | +} | |
| 462 | +core_initcall(init_ftrace_syscalls); | |
| 463 | + | |
| 378 | 464 | #ifdef CONFIG_EVENT_PROFILE |
| 379 | 465 | |
| 380 | 466 | static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); |
| @@ -5,10 +5,13 @@ · 4 unmodified lines | ||
| 5 | 5 | * relegated to obsolescence, but used by various less |
| 6 | 6 | * important (or lazy) subsystems. |
| 7 | 7 | */ |
| 8 | −#include <linux/smp_lock.h> | |
| 9 | 8 | #include <linux/module.h> |
| 10 | 9 | #include <linux/kallsyms.h> |
| 11 | 10 | #include <linux/semaphore.h> |
| 11 | +#include <linux/smp_lock.h> | |
| 12 | + | |
| 13 | +#define CREATE_TRACE_POINTS | |
| 14 | +#include <trace/events/bkl.h> | |
| 12 | 15 | |
| 13 | 16 | /* |
| 14 | 17 | * The 'big kernel lock' |
| @@ -113,21 +116,26 @@ static inline void __unlock_kernel(void) · 98 unmodified lines | ||
| 113 | 116 | * This cannot happen asynchronously, so we only need to |
| 114 | 117 | * worry about other CPU's. |
| 115 | 118 | */ |
| 116 | −void __lockfunc lock_kernel(void) | |
| 119 | +void __lockfunc _lock_kernel(const char *func, const char *file, int line) | |
| 117 | 120 | { |
| 118 | − int depth = current->lock_depth+1; | |
| 121 | + int depth = current->lock_depth + 1; | |
| 122 | + | |
| 123 | + trace_lock_kernel(func, file, line); | |
| 124 | + | |
| 119 | 125 | if (likely(!depth)) |
| 120 | 126 | __lock_kernel(); |
| 121 | 127 | current->lock_depth = depth; |
| 122 | 128 | } |
| 123 | 129 | |
| 124 | −void __lockfunc unlock_kernel(void) | |
| 130 | +void __lockfunc _unlock_kernel(const char *func, const char *file, int line) | |
| 125 | 131 | { |
| 126 | 132 | BUG_ON(current->lock_depth < 0); |
| 127 | 133 | if (likely(--current->lock_depth < 0)) |
| 128 | 134 | __unlock_kernel(); |
| 135 | + | |
| 136 | + trace_unlock_kernel(func, file, line); | |
| 129 | 137 | } |
| 130 | 138 | |
| 131 | −EXPORT_SYMBOL(lock_kernel); | |
| 132 | −EXPORT_SYMBOL(unlock_kernel); | |
| 139 | +EXPORT_SYMBOL(_lock_kernel); | |
| 140 | +EXPORT_SYMBOL(_unlock_kernel); | |
| 133 | 141 | |
| @@ -6,77 +6,93 @@ · 5 unmodified lines | ||
| 6 | 6 | # all the offsets to the calls to mcount. |
| 7 | 7 | # |
| 8 | 8 | # |
| 9 | −# What we want to end up with is a section in vmlinux called | |
| 10 | −# __mcount_loc that contains a list of pointers to all the | |
| 11 | −# call sites in the kernel that call mcount. Later on boot up, the kernel | |
| 12 | −# will read this list, save the locations and turn them into nops. | |
| 13 | −# When tracing or profiling is later enabled, these locations will then | |
| 14 | −# be converted back to pointers to some function. | |
| 9 | +# What we want to end up with this is that each object file will have a | |
| 10 | +# section called __mcount_loc that will hold the list of pointers to mcount | |
| 11 | +# callers. After final linking, the vmlinux will have within .init.data the | |
| 12 | +# list of all callers to mcount between __start_mcount_loc and __stop_mcount_loc. | |
| 13 | +# Later on boot up, the kernel will read this list, save the locations and turn | |
| 14 | +# them into nops. When tracing or profiling is later enabled, these locations | |
| 15 | +# will then be converted back to pointers to some function. | |
| 15 | 16 | # |
| 16 | 17 | # This is no easy feat. This script is called just after the original |
| 17 | 18 | # object is compiled and before it is linked. |
| 18 | 19 | # |
| 19 | −# The references to the call sites are offsets from the section of text | |
| 20 | −# that the call site is in. Hence, all functions in a section that | |
| 21 | −# has a call site to mcount, will have the offset from the beginning of | |
| 22 | −# the section and not the beginning of the function. | |
| 20 | +# When parse this object file using 'objdump', the references to the call | |
| 21 | +# sites are offsets from the section that the call site is in. Hence, all | |
| 22 | +# functions in a section that has a call site to mcount, will have the | |
| 23 | +# offset from the beginning of the section and not the beginning of the | |
| 24 | +# function. | |
| 25 | +# | |
| 26 | +# But where this section will reside finally in vmlinx is undetermined at | |
| 27 | +# this point. So we can't use this kind of offsets to record the final | |
| 28 | +# address of this call site. | |
| 29 | +# | |
| 30 | +# The trick is to change the call offset referring the start of a section to | |
| 31 | +# referring a function symbol in this section. During the link step, 'ld' will | |
| 32 | +# compute the final address according to the information we record. | |
| 23 | 33 | # |
| 24 | −# The trick is to find a way to record the beginning of the section. | |
| 25 | −# The way we do this is to look at the first function in the section | |
| 26 | −# which will also be the location of that section after final link. | |
| 27 | 34 | # e.g. |
| 28 | 35 | # |
| 29 | 36 | # .section ".sched.text", "ax" |
| 30 | −# .globl my_func | |
| 31 | −# my_func: | |
| 32 | 37 | # [...] |
| 33 | −# call mcount (offset: 0x5) | |
| 38 | +# func1: | |
| 39 | +# [...] | |
| 40 | +# call mcount (offset: 0x10) | |
| 34 | 41 | # [...] |
| 35 | 42 | # ret |
| 36 | −# other_func: | |
| 43 | +# .globl fun2 | |
| 44 | +# func2: (offset: 0x20) | |
| 37 | 45 | # [...] |
| 38 | −# call mcount (offset: 0x1b) | |
| 46 | +# [...] | |
| 47 | +# ret | |
| 48 | +# func3: | |
| 49 | +# [...] | |
| 50 | +# call mcount (offset: 0x30) | |
| 39 | 51 | # [...] |
| 40 | 52 | # |
| 41 | 53 | # Both relocation offsets for the mcounts in the above example will be |
| 42 | −# offset from .sched.text. If we make another file called tmp.s with: | |
| 54 | +# offset from .sched.text. If we choose global symbol func2 as a reference and | |
| 55 | +# make another file called tmp.s with the new offsets: | |
| 43 | 56 | # |
| 44 | 57 | # .section __mcount_loc |
| 45 | −# .quad my_func + 0x5 | |
| 46 | −# .quad my_func + 0x1b | |
| 58 | +# .quad func2 - 0x10 | |
| 59 | +# .quad func2 + 0x10 | |
| 47 | 60 | # |
| 48 | −# We can then compile this tmp.s into tmp.o, and link it to the original | |
| 61 | +# We can then compile this tmp.s into tmp.o, and link it back to the original | |
| 49 | 62 | # object. |
| 50 | 63 | # |
| 51 | −# But this gets hard if my_func is not globl (a static function). | |
| 52 | −# In such a case we have: | |
| 64 | +# In our algorithm, we will choose the first global function we meet in this | |
| 65 | +# section as the reference. But this gets hard if there is no global functions | |
| 66 | +# in this section. In such a case we have to select a local one. E.g. func1: | |
| 53 | 67 | # |
| 54 | 68 | # .section ".sched.text", "ax" |
| 55 | −# my_func: | |
| 69 | +# func1: | |
| 56 | 70 | # [...] |
| 57 | −# call mcount (offset: 0x5) | |
| 71 | +# call mcount (offset: 0x10) | |
| 58 | 72 | # [...] |
| 59 | 73 | # ret |
| 60 | −# other_func: | |
| 74 | +# func2: | |
| 61 | 75 | # [...] |
| 62 | −# call mcount (offset: 0x1b) | |
| 76 | +# call mcount (offset: 0x20) | |
| 63 | 77 | # [...] |
| 78 | +# .section "other.section" | |
| 64 | 79 | # |
| 65 | 80 | # If we make the tmp.s the same as above, when we link together with |
| 66 | −# the original object, we will end up with two symbols for my_func: | |
| 81 | +# the original object, we will end up with two symbols for func1: | |
| 67 | 82 | # one local, one global. After final compile, we will end up with |
| 68 | −# an undefined reference to my_func. | |
| 83 | +# an undefined reference to func1 or a wrong reference to another global | |
| 84 | +# func1 in other files. | |
| 69 | 85 | # |
| 70 | 86 | # Since local objects can reference local variables, we need to find |
| 71 | 87 | # a way to make tmp.o reference the local objects of the original object |
| 72 | −# file after it is linked together. To do this, we convert the my_func | |
| 88 | +# file after it is linked together. To do this, we convert func1 | |
| 73 | 89 | # into a global symbol before linking tmp.o. Then after we link tmp.o |
| 74 | −# we will only have a single symbol for my_func that is global. | |
| 75 | −# We can convert my_func back into a local symbol and we are done. | |
| 90 | +# we will only have a single symbol for func1 that is global. | |
| 91 | +# We can convert func1 back into a local symbol and we are done. | |
| 76 | 92 | # |
| 77 | 93 | # Here are the steps we take: |
| 78 | 94 | # |
| 79 | −# 1) Record all the local symbols by using 'nm' | |
| 95 | +# 1) Record all the local and weak symbols by using 'nm' | |
| 80 | 96 | # 2) Use objdump to find all the call site offsets and sections for |
| 81 | 97 | # mcount. |
| 82 | 98 | # 3) Compile the list into its own object. |
| @@ -86,10 +102,8 @@ · 3 unmodified lines | ||
| 86 | 102 | # 6) Link together this new object with the list object. |
| 87 | 103 | # 7) Convert the local functions back to local symbols and rename |
| 88 | 104 | # the result as the original object. |
| 89 | −# End. | |
| 90 | 105 | # 8) Link the object with the list object. |
| 91 | 106 | # 9) Move the result back to the original object. |
| 92 | −# End. | |
| 93 | 107 | # |
| 94 | 108 | |
| 95 | 109 | use strict; |
| @@ -99,7 +113,7 @@ $P =~ s@.*/@@g; · 3 unmodified lines | ||
| 99 | 113 | |
| 100 | 114 | my $V = '0.1'; |
| 101 | 115 | |
| 102 | −if ($#ARGV < 7) { | |
| 116 | +if ($#ARGV != 10) { | |
| 103 | 117 | print "usage: $P arch bits objdump objcopy cc ld nm rm mv is_module inputfile\n"; |
| 104 | 118 | print "version: $V\n"; |
| 105 | 119 | exit(1); |
| @@ -109,7 +123,7 @@ my ($arch, $bits, $objdump, $objcopy, $cc, · 3 unmodified lines | ||
| 109 | 123 | $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV; |
| 110 | 124 | |
| 111 | 125 | # This file refers to mcount and shouldn't be ftraced, so lets' ignore it |
| 112 | −if ($inputfile eq "kernel/trace/ftrace.o") { | |
| 126 | +if ($inputfile =~ m,kernel/trace/ftrace\.o$,) { | |
| 113 | 127 | exit(0); |
| 114 | 128 | } |
| 115 | 129 | |
| @@ -119,6 +133,7 @@ my %text_sections = ( · 3 unmodified lines | ||
| 119 | 133 | ".sched.text" => 1, |
| 120 | 134 | ".spinlock.text" => 1, |
| 121 | 135 | ".irqentry.text" => 1, |
| 136 | + ".text.unlikely" => 1, | |
| 122 | 137 | ); |
| 123 | 138 | |
| 124 | 139 | $objdump = "objdump" if ((length $objdump) == 0); |
| @@ -137,13 +152,47 @@ my %weak; # List of weak functions · 12 unmodified lines | ||
| 137 | 152 | my %convert; # List of local functions used that needs conversion |
| 138 | 153 | |
| 139 | 154 | my $type; |
| 140 | −my $nm_regex; # Find the local functions (return function) | |
| 155 | +my $local_regex; # Match a local function (return function) | |
| 156 | +my $weak_regex; # Match a weak function (return function) | |
| 141 | 157 | my $section_regex; # Find the start of a section |
| 142 | 158 | my $function_regex; # Find the name of a function |
| 143 | 159 | # (return offset and func name) |
| 144 | 160 | my $mcount_regex; # Find the call site to mcount (return offset) |
| 145 | 161 | my $alignment; # The .align value to use for $mcount_section |
| 146 | 162 | my $section_type; # Section header plus possible alignment command |
| 163 | +my $can_use_local = 0; # If we can use local function references | |
| 164 | + | |
| 165 | +# Shut up recordmcount if user has older objcopy | |
| 166 | +my $quiet_recordmcount = ".tmp_quiet_recordmcount"; | |
| 167 | +my $print_warning = 1; | |
| 168 | +$print_warning = 0 if ( -f $quiet_recordmcount); | |
| 169 | + | |
| 170 | +## | |
| 171 | +# check_objcopy - whether objcopy supports --globalize-symbols | |
| 172 | +# | |
| 173 | +# --globalize-symbols came out in 2.17, we must test the version | |
| 174 | +# of objcopy, and if it is less than 2.17, then we can not | |
| 175 | +# record local functions. | |
| 176 | +sub check_objcopy | |
| 177 | +{ | |
| 178 | + open (IN, "$objcopy --version |") or die "error running $objcopy"; | |
| 179 | + while (<IN>) { | |
| 180 | + if (/objcopy.*\s(\d+)\.(\d+)/) { | |
| 181 | + $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17)); | |
| 182 | + last; | |
| 183 | + } | |
| 184 | + } | |
| 185 | + close (IN); | |
| 186 | + | |
| 187 | + if (!$can_use_local && $print_warning) { | |
| 188 | + print STDERR "WARNING: could not find objcopy version or version " . | |
| 189 | + "is less than 2.17.\n" . | |
| 190 | + "\tLocal function references are disabled.\n"; | |
| 191 | + open (QUIET, ">$quiet_recordmcount"); | |
| 192 | + printf QUIET "Disables the warning from recordmcount.pl\n"; | |
| 193 | + close QUIET; | |
| 194 | + } | |
| 195 | +} | |
| 147 | 196 | |
| 148 | 197 | if ($arch eq "x86") { |
| 149 | 198 | if ($bits == 64) { |
| @@ -157,7 +206,8 @@ if ($arch eq "x86") { · 7 unmodified lines | ||
| 157 | 206 | # We base the defaults off of i386, the other archs may |
| 158 | 207 | # feel free to change them in the below if statements. |
| 159 | 208 | # |
| 160 | −$nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; | |
| 209 | +$local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; | |
| 210 | +$weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)"; | |
| 161 | 211 | $section_regex = "Disassembly of section\\s+(\\S+):"; |
| 162 | 212 | $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; |
| 163 | 213 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; |
| @@ -206,7 +256,7 @@ if ($arch eq "x86_64") { · 42 unmodified lines | ||
| 206 | 256 | $cc .= " -m32"; |
| 207 | 257 | |
| 208 | 258 | } elsif ($arch eq "powerpc") { |
| 209 | − $nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; | |
| 259 | + $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; | |
| 210 | 260 | $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:"; |
| 211 | 261 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; |
| 212 | 262 | |
| @@ -278,44 +328,17 @@ if ($filename =~ m,^(.*)(\.\S),) { · 65 unmodified lines | ||
| 278 | 328 | my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; |
| 279 | 329 | my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; |
| 280 | 330 | |
| 281 | −# | |
| 282 | −# --globalize-symbols came out in 2.17, we must test the version | |
| 283 | −# of objcopy, and if it is less than 2.17, then we can not | |
| 284 | −# record local functions. | |
| 285 | −my $use_locals = 01; | |
| 286 | −my $local_warn_once = 0; | |
| 287 | −my $found_version = 0; | |
| 288 | − | |
| 289 | −open (IN, "$objcopy --version |") || die "error running $objcopy"; | |
| 290 | −while (<IN>) { | |
| 291 | − if (/objcopy.*\s(\d+)\.(\d+)/) { | |
| 292 | − my $major = $1; | |
| 293 | − my $minor = $2; | |
| 294 | − | |
| 295 | − $found_version = 1; | |
| 296 | − if ($major < 2 || | |
| 297 | − ($major == 2 && $minor < 17)) { | |
| 298 | − $use_locals = 0; | |
| 299 | − } | |
| 300 | − last; | |
| 301 | − } | |
| 302 | −} | |
| 303 | −close (IN); | |
| 304 | − | |
| 305 | −if (!$found_version) { | |
| 306 | − print STDERR "WARNING: could not find objcopy version.\n" . | |
| 307 | − "\tDisabling local function references.\n"; | |
| 308 | −} | |
| 331 | +check_objcopy(); | |
| 309 | 332 | |
| 310 | 333 | # |
| 311 | 334 | # Step 1: find all the local (static functions) and weak symbols. |
| 312 | −# 't' is local, 'w/W' is weak (we never use a weak function) | |
| 335 | +# 't' is local, 'w/W' is weak | |
| 313 | 336 | # |
| 314 | 337 | open (IN, "$nm $inputfile|") || die "error running $nm"; |
| 315 | 338 | while (<IN>) { |
| 316 | − if (/$nm_regex/) { | |
| 339 | + if (/$local_regex/) { | |
| 317 | 340 | $locals{$1} = 1; |
| 318 | − } elsif (/^[0-9a-fA-F]+\s+([wW])\s+(\S+)/) { | |
| 341 | + } elsif (/$weak_regex/) { | |
| 319 | 342 | $weak{$2} = $1; |
| 320 | 343 | } |
| 321 | 344 | } |
| @@ -333,26 +356,20 @@ my $offset = 0; # offset of ref_func to section beginning · 11 unmodified lines | ||
| 333 | 356 | # |
| 334 | 357 | sub update_funcs |
| 335 | 358 | { |
| 336 | − return if ($#offsets < 0); | |
| 337 | − | |
| 338 | − defined($ref_func) || die "No function to reference"; | |
| 359 | + return unless ($ref_func and @offsets); | |
| 339 | 360 | |
| 340 | − # A section only had a weak function, to represent it. | |
| 341 | − # Unfortunately, a weak function may be overwritten by another | |
| 342 | − # function of the same name, making all these offsets incorrect. | |
| 343 | − # To be safe, we simply print a warning and bail. | |
| 361 | + # Sanity check on weak function. A weak function may be overwritten by | |
| 362 | + # another function of the same name, making all these offsets incorrect. | |
| 344 | 363 | if (defined $weak{$ref_func}) { |
| 345 | − print STDERR | |
| 346 | − "$inputfile: WARNING: referencing weak function" . | |
| 364 | + die "$inputfile: ERROR: referencing weak function" . | |
| 347 | 365 | " $ref_func for mcount\n"; |
| 348 | − return; | |
| 349 | 366 | } |
| 350 | 367 | |
| 351 | 368 | # is this function static? If so, note this fact. |
| 352 | 369 | if (defined $locals{$ref_func}) { |
| 353 | 370 | |
| 354 | 371 | # only use locals if objcopy supports globalize-symbols |
| 355 | − if (!$use_locals) { | |
| 372 | + if (!$can_use_local) { | |
| 356 | 373 | return; |
| 357 | 374 | } |
| 358 | 375 | $convert{$ref_func} = 1; |
| @@ -378,9 +395,27 @@ open(IN, "$objdump -hdr $inputfile|") || die "error running $objdump"; · 19 unmodified lines | ||
| 378 | 395 | |
| 379 | 396 | my $text; |
| 380 | 397 | |
| 398 | + | |
| 399 | +# read headers first | |
| 381 | 400 | my $read_headers = 1; |
| 382 | 401 | |
| 383 | 402 | while (<IN>) { |
| 403 | + | |
| 404 | + if ($read_headers && /$mcount_section/) { | |
| 405 | + # | |
| 406 | + # Somehow the make process can execute this script on an | |
| 407 | + # object twice. If it does, we would duplicate the mcount | |
| 408 | + # section and it will cause the function tracer self test | |
| 409 | + # to fail. Check if the mcount section exists, and if it does, | |
| 410 | + # warn and exit. | |
| 411 | + # | |
| 412 | + print STDERR "ERROR: $mcount_section already in $inputfile\n" . | |
| 413 | + "\tThis may be an indication that your build is corrupted.\n" . | |
| 414 | + "\tDelete $inputfile and try again. If the same object file\n" . | |
| 415 | + "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; | |
| 416 | + exit(-1); | |
| 417 | + } | |
| 418 | + | |
| 384 | 419 | # is it a section? |
| 385 | 420 | if (/$section_regex/) { |
| 386 | 421 | $read_headers = 0; |
| @@ -392,7 +427,7 @@ while (<IN>) { · 5 unmodified lines | ||
| 392 | 427 | $read_function = 0; |
| 393 | 428 | } |
| 394 | 429 | # print out any recorded offsets |
| 395 | − update_funcs() if (defined($ref_func)); | |
| 430 | + update_funcs(); | |
| 396 | 431 | |
| 397 | 432 | # reset all markers and arrays |
| 398 | 433 | $text_found = 0; |
| @@ -421,21 +456,7 @@ while (<IN>) { · 22 unmodified lines | ||
| 421 | 456 | $offset = hex $1; |
| 422 | 457 | } |
| 423 | 458 | } |
| 424 | − } elsif ($read_headers && /$mcount_section/) { | |
| 425 | − # | |
| 426 | − # Somehow the make process can execute this script on an | |
| 427 | − # object twice. If it does, we would duplicate the mcount | |
| 428 | − # section and it will cause the function tracer self test | |
| 429 | − # to fail. Check if the mcount section exists, and if it does, | |
| 430 | − # warn and exit. | |
| 431 | − # | |
| 432 | − print STDERR "ERROR: $mcount_section already in $inputfile\n" . | |
| 433 | − "\tThis may be an indication that your build is corrupted.\n" . | |
| 434 | − "\tDelete $inputfile and try again. If the same object file\n" . | |
| 435 | − "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; | |
| 436 | − exit(-1); | |
| 437 | 459 | } |
| 438 | − | |
| 439 | 460 | # is this a call site to mcount? If so, record it to print later |
| 440 | 461 | if ($text_found && /$mcount_regex/) { |
| 441 | 462 | $offsets[$#offsets + 1] = hex $1; |
| @@ -443,7 +464,7 @@ while (<IN>) { · 1 unmodified line | ||
| 443 | 464 | } |
| 444 | 465 | |
| 445 | 466 | # dump out anymore offsets that may have been found |
| 446 | −update_funcs() if (defined($ref_func)); | |
| 467 | +update_funcs(); | |
| 447 | 468 | |
| 448 | 469 | # If we did not find any mcount callers, we are done (do nothing). |
| 449 | 470 | if (!$opened) { |