diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-28 13:17:55 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-28 13:17:55 -0500 |
commit | e0d272429a34ff143bfa04ee8e29dd4eed2964c7 (patch) | |
tree | 5a719135b245811b5d61ed084d7b8c1bc2e87031 | |
parent | d25e8dbdab203ed8b4fd0a174bb5259e35ecd87c (diff) | |
parent | 480917427b0b6ff39de55ffc81391055472e6c26 (diff) |
Merge branch 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (28 commits)
ftrace: Add function names to dangling } in function graph tracer
tracing: Simplify memory recycle of trace_define_field
tracing: Remove unnecessary variable in print_graph_return
tracing: Fix typo of info text in trace_kprobe.c
tracing: Fix typo in prof_sysexit_enable()
tracing: Remove CONFIG_TRACE_POWER from kernel config
tracing: Fix ftrace_event_call alignment for use with gcc 4.5
ftrace: Remove memory barriers from NMI code when not needed
tracing/kprobes: Add short documentation for HAVE_REGS_AND_STACK_ACCESS_API
s390: Add pt_regs register and stack access API
tracing/kprobes: Make Kconfig dependencies generic
tracing: Unify arch_syscall_addr() implementations
tracing: Add notrace to TRACE_EVENT implementation functions
ftrace: Allow to remove a single function from function graph filter
tracing: Add correct/incorrect to sort keys for branch annotation output
tracing: Simplify test for function_graph tracing start point
tracing: Drop the tr check from the graph tracing path
tracing: Add stack dump to trace_printk if stacktrace option is set
tracing: Use appropriate perl constructs in recordmcount.pl
tracing: optimize recordmcount.pl for offsets-handling
...
30 files changed, 580 insertions, 547 deletions
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 6a5a579126b0..f1f81afee8a0 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt | |||
@@ -238,11 +238,10 @@ HAVE_SYSCALL_TRACEPOINTS | |||
238 | 238 | ||
239 | You need very few things to get the syscalls tracing in an arch. | 239 | You need very few things to get the syscalls tracing in an arch. |
240 | 240 | ||
241 | - Support HAVE_ARCH_TRACEHOOK (see arch/Kconfig). | ||
241 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number | 242 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number |
242 | of syscalls supported by the arch. | 243 | of syscalls supported by the arch. |
243 | - Implement arch_syscall_addr() that resolves a syscall address from a | 244 | - Support the TIF_SYSCALL_TRACEPOINT thread flags. |
244 | syscall number. | ||
245 | - Support the TIF_SYSCALL_TRACEPOINT thread flags | ||
246 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace | 245 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace |
247 | in the ptrace syscalls tracing path. | 246 | in the ptrace syscalls tracing path. |
248 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. | 247 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. |
diff --git a/arch/Kconfig b/arch/Kconfig index 06a13729c8df..215e46073c45 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -105,6 +105,14 @@ config HAVE_DMA_ATTRS | |||
105 | config USE_GENERIC_SMP_HELPERS | 105 | config USE_GENERIC_SMP_HELPERS |
106 | bool | 106 | bool |
107 | 107 | ||
108 | config HAVE_REGS_AND_STACK_ACCESS_API | ||
109 | bool | ||
110 | help | ||
111 | This symbol should be selected by an architecure if it supports | ||
112 | the API needed to access registers and stack entries from pt_regs, | ||
113 | declared in asm/ptrace.h | ||
114 | For example the kprobes-based event tracer needs this API. | ||
115 | |||
108 | config HAVE_CLK | 116 | config HAVE_CLK |
109 | bool | 117 | bool |
110 | help | 118 | help |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 19deda8d8875..0d8cd9bbe101 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -90,6 +90,7 @@ config S390 | |||
90 | select HAVE_SYSCALL_TRACEPOINTS | 90 | select HAVE_SYSCALL_TRACEPOINTS |
91 | select HAVE_DYNAMIC_FTRACE | 91 | select HAVE_DYNAMIC_FTRACE |
92 | select HAVE_FUNCTION_GRAPH_TRACER | 92 | select HAVE_FUNCTION_GRAPH_TRACER |
93 | select HAVE_REGS_AND_STACK_ACCESS_API | ||
93 | select HAVE_DEFAULT_NO_SPIN_MUTEXES | 94 | select HAVE_DEFAULT_NO_SPIN_MUTEXES |
94 | select HAVE_OPROFILE | 95 | select HAVE_OPROFILE |
95 | select HAVE_KPROBES | 96 | select HAVE_KPROBES |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 95dcf183a28d..dd2d913afcae 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -492,13 +492,24 @@ struct user_regs_struct | |||
492 | struct task_struct; | 492 | struct task_struct; |
493 | extern void user_enable_single_step(struct task_struct *); | 493 | extern void user_enable_single_step(struct task_struct *); |
494 | extern void user_disable_single_step(struct task_struct *); | 494 | extern void user_disable_single_step(struct task_struct *); |
495 | extern void show_regs(struct pt_regs * regs); | ||
495 | 496 | ||
496 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) | 497 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) |
497 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) | 498 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) |
498 | #define user_stack_pointer(regs)((regs)->gprs[15]) | 499 | #define user_stack_pointer(regs)((regs)->gprs[15]) |
499 | #define regs_return_value(regs)((regs)->gprs[2]) | 500 | #define regs_return_value(regs)((regs)->gprs[2]) |
500 | #define profile_pc(regs) instruction_pointer(regs) | 501 | #define profile_pc(regs) instruction_pointer(regs) |
501 | extern void show_regs(struct pt_regs * regs); | 502 | |
503 | int regs_query_register_offset(const char *name); | ||
504 | const char *regs_query_register_name(unsigned int offset); | ||
505 | unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset); | ||
506 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n); | ||
507 | |||
508 | static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) | ||
509 | { | ||
510 | return regs->gprs[15] & PSW_ADDR_INSN; | ||
511 | } | ||
512 | |||
502 | #endif /* __KERNEL__ */ | 513 | #endif /* __KERNEL__ */ |
503 | #endif /* __ASSEMBLY__ */ | 514 | #endif /* __ASSEMBLY__ */ |
504 | 515 | ||
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index e0a73d3eb837..8429686951f9 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
@@ -15,6 +15,13 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
17 | 17 | ||
18 | /* | ||
19 | * The syscall table always contains 32 bit pointers since we know that the | ||
20 | * address of the function to be called is (way) below 4GB. So the "int" | ||
21 | * type here is what we want [need] for both 32 bit and 64 bit systems. | ||
22 | */ | ||
23 | extern const unsigned int sys_call_table[]; | ||
24 | |||
18 | static inline long syscall_get_nr(struct task_struct *task, | 25 | static inline long syscall_get_nr(struct task_struct *task, |
19 | struct pt_regs *regs) | 26 | struct pt_regs *regs) |
20 | { | 27 | { |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 314d8f09cf31..6a83d0581317 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
@@ -200,13 +200,3 @@ out: | |||
200 | return parent; | 200 | return parent; |
201 | } | 201 | } |
202 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 202 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
203 | |||
204 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
205 | |||
206 | extern unsigned int sys_call_table[]; | ||
207 | |||
208 | unsigned long __init arch_syscall_addr(int nr) | ||
209 | { | ||
210 | return (unsigned long)sys_call_table[nr]; | ||
211 | } | ||
212 | #endif | ||
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 7cf464234419..33fdc5a79764 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -992,3 +992,61 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
992 | #endif | 992 | #endif |
993 | return &user_s390_view; | 993 | return &user_s390_view; |
994 | } | 994 | } |
995 | |||
996 | static const char *gpr_names[NUM_GPRS] = { | ||
997 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | ||
998 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | ||
999 | }; | ||
1000 | |||
1001 | unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset) | ||
1002 | { | ||
1003 | if (offset >= NUM_GPRS) | ||
1004 | return 0; | ||
1005 | return regs->gprs[offset]; | ||
1006 | } | ||
1007 | |||
1008 | int regs_query_register_offset(const char *name) | ||
1009 | { | ||
1010 | unsigned long offset; | ||
1011 | |||
1012 | if (!name || *name != 'r') | ||
1013 | return -EINVAL; | ||
1014 | if (strict_strtoul(name + 1, 10, &offset)) | ||
1015 | return -EINVAL; | ||
1016 | if (offset >= NUM_GPRS) | ||
1017 | return -EINVAL; | ||
1018 | return offset; | ||
1019 | } | ||
1020 | |||
1021 | const char *regs_query_register_name(unsigned int offset) | ||
1022 | { | ||
1023 | if (offset >= NUM_GPRS) | ||
1024 | return NULL; | ||
1025 | return gpr_names[offset]; | ||
1026 | } | ||
1027 | |||
1028 | static int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) | ||
1029 | { | ||
1030 | unsigned long ksp = kernel_stack_pointer(regs); | ||
1031 | |||
1032 | return (addr & ~(THREAD_SIZE - 1)) == (ksp & ~(THREAD_SIZE - 1)); | ||
1033 | } | ||
1034 | |||
1035 | /** | ||
1036 | * regs_get_kernel_stack_nth() - get Nth entry of the stack | ||
1037 | * @regs:pt_regs which contains kernel stack pointer. | ||
1038 | * @n:stack entry number. | ||
1039 | * | ||
1040 | * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | ||
1041 | * is specifined by @regs. If the @n th entry is NOT in the kernel stack, | ||
1042 | * this returns 0. | ||
1043 | */ | ||
1044 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) | ||
1045 | { | ||
1046 | unsigned long addr; | ||
1047 | |||
1048 | addr = kernel_stack_pointer(regs) + n * sizeof(long); | ||
1049 | if (!regs_within_kernel_stack(regs, addr)) | ||
1050 | return 0; | ||
1051 | return *(unsigned long *)addr; | ||
1052 | } | ||
diff --git a/arch/sh/include/asm/syscall.h b/arch/sh/include/asm/syscall.h index 6a381429ee9d..aa7777bdc370 100644 --- a/arch/sh/include/asm/syscall.h +++ b/arch/sh/include/asm/syscall.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __ASM_SH_SYSCALL_H | 1 | #ifndef __ASM_SH_SYSCALL_H |
2 | #define __ASM_SH_SYSCALL_H | 2 | #define __ASM_SH_SYSCALL_H |
3 | 3 | ||
4 | extern const unsigned long sys_call_table[]; | ||
5 | |||
4 | #ifdef CONFIG_SUPERH32 | 6 | #ifdef CONFIG_SUPERH32 |
5 | # include "syscall_32.h" | 7 | # include "syscall_32.h" |
6 | #else | 8 | #else |
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index a48cdedc73b5..30e13196d35b 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c | |||
@@ -399,12 +399,3 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | |||
399 | } | 399 | } |
400 | } | 400 | } |
401 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 401 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
402 | |||
403 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
404 | extern unsigned long *sys_call_table; | ||
405 | |||
406 | unsigned long __init arch_syscall_addr(int nr) | ||
407 | { | ||
408 | return (unsigned long)sys_call_table[nr]; | ||
409 | } | ||
410 | #endif /* CONFIG_FTRACE_SYSCALLS */ | ||
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h index 7486c605e23c..025a02ad2e31 100644 --- a/arch/sparc/include/asm/syscall.h +++ b/arch/sparc/include/asm/syscall.h | |||
@@ -5,6 +5,13 @@ | |||
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | #include <asm/ptrace.h> | 6 | #include <asm/ptrace.h> |
7 | 7 | ||
8 | /* | ||
9 | * The syscall table always contains 32 bit pointers since we know that the | ||
10 | * address of the function to be called is (way) below 4GB. So the "int" | ||
11 | * type here is what we want [need] for both 32 bit and 64 bit systems. | ||
12 | */ | ||
13 | extern const unsigned int sys_call_table[]; | ||
14 | |||
8 | /* The system call number is given by the user in %g1 */ | 15 | /* The system call number is given by the user in %g1 */ |
9 | static inline long syscall_get_nr(struct task_struct *task, | 16 | static inline long syscall_get_nr(struct task_struct *task, |
10 | struct pt_regs *regs) | 17 | struct pt_regs *regs) |
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index 29973daa9930..9103a56b39e8 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c | |||
@@ -91,14 +91,3 @@ int __init ftrace_dyn_arch_init(void *data) | |||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | #endif | 93 | #endif |
94 | |||
95 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
96 | |||
97 | extern unsigned int sys_call_table[]; | ||
98 | |||
99 | unsigned long __init arch_syscall_addr(int nr) | ||
100 | { | ||
101 | return (unsigned long)sys_call_table[nr]; | ||
102 | } | ||
103 | |||
104 | #endif | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index eb4092568f9e..0896008f7509 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -45,6 +45,7 @@ config X86 | |||
45 | select HAVE_GENERIC_DMA_COHERENT if X86_32 | 45 | select HAVE_GENERIC_DMA_COHERENT if X86_32 |
46 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | 46 | select HAVE_EFFICIENT_UNALIGNED_ACCESS |
47 | select USER_STACKTRACE_SUPPORT | 47 | select USER_STACKTRACE_SUPPORT |
48 | select HAVE_REGS_AND_STACK_ACCESS_API | ||
48 | select HAVE_DMA_API_DEBUG | 49 | select HAVE_DMA_API_DEBUG |
49 | select HAVE_KERNEL_GZIP | 50 | select HAVE_KERNEL_GZIP |
50 | select HAVE_KERNEL_BZIP2 | 51 | select HAVE_KERNEL_BZIP2 |
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index 8d33bc5462d1..c4a348f7bd43 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | 18 | ||
19 | extern const unsigned long sys_call_table[]; | ||
20 | |||
19 | /* | 21 | /* |
20 | * Only the low 32 bits of orig_ax are meaningful, so we return int. | 22 | * Only the low 32 bits of orig_ax are meaningful, so we return int. |
21 | * This importantly ignores the high bits on 64-bit, so comparisons | 23 | * This importantly ignores the high bits on 64-bit, so comparisons |
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 309689245431..cd37469b54ee 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
@@ -30,14 +30,32 @@ | |||
30 | 30 | ||
31 | #ifdef CONFIG_DYNAMIC_FTRACE | 31 | #ifdef CONFIG_DYNAMIC_FTRACE |
32 | 32 | ||
33 | /* | ||
34 | * modifying_code is set to notify NMIs that they need to use | ||
35 | * memory barriers when entering or exiting. But we don't want | ||
36 | * to burden NMIs with unnecessary memory barriers when code | ||
37 | * modification is not being done (which is most of the time). | ||
38 | * | ||
39 | * A mutex is already held when ftrace_arch_code_modify_prepare | ||
40 | * and post_process are called. No locks need to be taken here. | ||
41 | * | ||
42 | * Stop machine will make sure currently running NMIs are done | ||
43 | * and new NMIs will see the updated variable before we need | ||
44 | * to worry about NMIs doing memory barriers. | ||
45 | */ | ||
46 | static int modifying_code __read_mostly; | ||
47 | static DEFINE_PER_CPU(int, save_modifying_code); | ||
48 | |||
33 | int ftrace_arch_code_modify_prepare(void) | 49 | int ftrace_arch_code_modify_prepare(void) |
34 | { | 50 | { |
35 | set_kernel_text_rw(); | 51 | set_kernel_text_rw(); |
52 | modifying_code = 1; | ||
36 | return 0; | 53 | return 0; |
37 | } | 54 | } |
38 | 55 | ||
39 | int ftrace_arch_code_modify_post_process(void) | 56 | int ftrace_arch_code_modify_post_process(void) |
40 | { | 57 | { |
58 | modifying_code = 0; | ||
41 | set_kernel_text_ro(); | 59 | set_kernel_text_ro(); |
42 | return 0; | 60 | return 0; |
43 | } | 61 | } |
@@ -149,6 +167,11 @@ static void ftrace_mod_code(void) | |||
149 | 167 | ||
150 | void ftrace_nmi_enter(void) | 168 | void ftrace_nmi_enter(void) |
151 | { | 169 | { |
170 | __get_cpu_var(save_modifying_code) = modifying_code; | ||
171 | |||
172 | if (!__get_cpu_var(save_modifying_code)) | ||
173 | return; | ||
174 | |||
152 | if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) { | 175 | if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) { |
153 | smp_rmb(); | 176 | smp_rmb(); |
154 | ftrace_mod_code(); | 177 | ftrace_mod_code(); |
@@ -160,6 +183,9 @@ void ftrace_nmi_enter(void) | |||
160 | 183 | ||
161 | void ftrace_nmi_exit(void) | 184 | void ftrace_nmi_exit(void) |
162 | { | 185 | { |
186 | if (!__get_cpu_var(save_modifying_code)) | ||
187 | return; | ||
188 | |||
163 | /* Finish all executions before clearing nmi_running */ | 189 | /* Finish all executions before clearing nmi_running */ |
164 | smp_mb(); | 190 | smp_mb(); |
165 | atomic_dec(&nmi_running); | 191 | atomic_dec(&nmi_running); |
@@ -484,13 +510,3 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
484 | } | 510 | } |
485 | } | 511 | } |
486 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 512 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
487 | |||
488 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
489 | |||
490 | extern unsigned long *sys_call_table; | ||
491 | |||
492 | unsigned long __init arch_syscall_addr(int nr) | ||
493 | { | ||
494 | return (unsigned long)(&sys_call_table)[nr]; | ||
495 | } | ||
496 | #endif | ||
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 0b4f97d24d7f..1cbb36f2759c 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -511,4 +511,10 @@ static inline void trace_hw_branch_oops(void) {} | |||
511 | 511 | ||
512 | #endif /* CONFIG_HW_BRANCH_TRACER */ | 512 | #endif /* CONFIG_HW_BRANCH_TRACER */ |
513 | 513 | ||
514 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
515 | |||
516 | unsigned long arch_syscall_addr(int nr); | ||
517 | |||
518 | #endif /* CONFIG_FTRACE_SYSCALLS */ | ||
519 | |||
514 | #endif /* _LINUX_FTRACE_H */ | 520 | #endif /* _LINUX_FTRACE_H */ |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 2233c98d80df..84a5629adfd8 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -121,9 +121,8 @@ struct ftrace_event_call { | |||
121 | int (*regfunc)(struct ftrace_event_call *); | 121 | int (*regfunc)(struct ftrace_event_call *); |
122 | void (*unregfunc)(struct ftrace_event_call *); | 122 | void (*unregfunc)(struct ftrace_event_call *); |
123 | int id; | 123 | int id; |
124 | const char *print_fmt; | ||
124 | int (*raw_init)(struct ftrace_event_call *); | 125 | int (*raw_init)(struct ftrace_event_call *); |
125 | int (*show_format)(struct ftrace_event_call *, | ||
126 | struct trace_seq *); | ||
127 | int (*define_fields)(struct ftrace_event_call *); | 126 | int (*define_fields)(struct ftrace_event_call *); |
128 | struct list_head fields; | 127 | struct list_head fields; |
129 | int filter_active; | 128 | int filter_active; |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 207466a49f3d..91bd7d78a07d 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -132,7 +132,8 @@ struct perf_event_attr; | |||
132 | 132 | ||
133 | #define SYSCALL_TRACE_ENTER_EVENT(sname) \ | 133 | #define SYSCALL_TRACE_ENTER_EVENT(sname) \ |
134 | static const struct syscall_metadata __syscall_meta_##sname; \ | 134 | static const struct syscall_metadata __syscall_meta_##sname; \ |
135 | static struct ftrace_event_call event_enter_##sname; \ | 135 | static struct ftrace_event_call \ |
136 | __attribute__((__aligned__(4))) event_enter_##sname; \ | ||
136 | static struct trace_event enter_syscall_print_##sname = { \ | 137 | static struct trace_event enter_syscall_print_##sname = { \ |
137 | .trace = print_syscall_enter, \ | 138 | .trace = print_syscall_enter, \ |
138 | }; \ | 139 | }; \ |
@@ -143,8 +144,7 @@ struct perf_event_attr; | |||
143 | .name = "sys_enter"#sname, \ | 144 | .name = "sys_enter"#sname, \ |
144 | .system = "syscalls", \ | 145 | .system = "syscalls", \ |
145 | .event = &enter_syscall_print_##sname, \ | 146 | .event = &enter_syscall_print_##sname, \ |
146 | .raw_init = trace_event_raw_init, \ | 147 | .raw_init = init_syscall_trace, \ |
147 | .show_format = syscall_enter_format, \ | ||
148 | .define_fields = syscall_enter_define_fields, \ | 148 | .define_fields = syscall_enter_define_fields, \ |
149 | .regfunc = reg_event_syscall_enter, \ | 149 | .regfunc = reg_event_syscall_enter, \ |
150 | .unregfunc = unreg_event_syscall_enter, \ | 150 | .unregfunc = unreg_event_syscall_enter, \ |
@@ -154,7 +154,8 @@ struct perf_event_attr; | |||
154 | 154 | ||
155 | #define SYSCALL_TRACE_EXIT_EVENT(sname) \ | 155 | #define SYSCALL_TRACE_EXIT_EVENT(sname) \ |
156 | static const struct syscall_metadata __syscall_meta_##sname; \ | 156 | static const struct syscall_metadata __syscall_meta_##sname; \ |
157 | static struct ftrace_event_call event_exit_##sname; \ | 157 | static struct ftrace_event_call \ |
158 | __attribute__((__aligned__(4))) event_exit_##sname; \ | ||
158 | static struct trace_event exit_syscall_print_##sname = { \ | 159 | static struct trace_event exit_syscall_print_##sname = { \ |
159 | .trace = print_syscall_exit, \ | 160 | .trace = print_syscall_exit, \ |
160 | }; \ | 161 | }; \ |
@@ -165,8 +166,7 @@ struct perf_event_attr; | |||
165 | .name = "sys_exit"#sname, \ | 166 | .name = "sys_exit"#sname, \ |
166 | .system = "syscalls", \ | 167 | .system = "syscalls", \ |
167 | .event = &exit_syscall_print_##sname, \ | 168 | .event = &exit_syscall_print_##sname, \ |
168 | .raw_init = trace_event_raw_init, \ | 169 | .raw_init = init_syscall_trace, \ |
169 | .show_format = syscall_exit_format, \ | ||
170 | .define_fields = syscall_exit_define_fields, \ | 170 | .define_fields = syscall_exit_define_fields, \ |
171 | .regfunc = reg_event_syscall_exit, \ | 171 | .regfunc = reg_event_syscall_exit, \ |
172 | .unregfunc = unreg_event_syscall_exit, \ | 172 | .unregfunc = unreg_event_syscall_exit, \ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index c6fe03e902ca..f23a0ca6910a 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -65,7 +65,8 @@ | |||
65 | }; | 65 | }; |
66 | #undef DEFINE_EVENT | 66 | #undef DEFINE_EVENT |
67 | #define DEFINE_EVENT(template, name, proto, args) \ | 67 | #define DEFINE_EVENT(template, name, proto, args) \ |
68 | static struct ftrace_event_call event_##name | 68 | static struct ftrace_event_call \ |
69 | __attribute__((__aligned__(4))) event_##name | ||
69 | 70 | ||
70 | #undef DEFINE_EVENT_PRINT | 71 | #undef DEFINE_EVENT_PRINT |
71 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ | 72 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ |
@@ -131,130 +132,6 @@ | |||
131 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 132 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
132 | 133 | ||
133 | /* | 134 | /* |
134 | * Setup the showing format of trace point. | ||
135 | * | ||
136 | * int | ||
137 | * ftrace_format_##call(struct trace_seq *s) | ||
138 | * { | ||
139 | * struct ftrace_raw_##call field; | ||
140 | * int ret; | ||
141 | * | ||
142 | * ret = trace_seq_printf(s, #type " " #item ";" | ||
143 | * " offset:%u; size:%u;\n", | ||
144 | * offsetof(struct ftrace_raw_##call, item), | ||
145 | * sizeof(field.type)); | ||
146 | * | ||
147 | * } | ||
148 | */ | ||
149 | |||
150 | #undef TP_STRUCT__entry | ||
151 | #define TP_STRUCT__entry(args...) args | ||
152 | |||
153 | #undef __field | ||
154 | #define __field(type, item) \ | ||
155 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
156 | "offset:%u;\tsize:%u;\tsigned:%u;\n", \ | ||
157 | (unsigned int)offsetof(typeof(field), item), \ | ||
158 | (unsigned int)sizeof(field.item), \ | ||
159 | (unsigned int)is_signed_type(type)); \ | ||
160 | if (!ret) \ | ||
161 | return 0; | ||
162 | |||
163 | #undef __field_ext | ||
164 | #define __field_ext(type, item, filter_type) __field(type, item) | ||
165 | |||
166 | #undef __array | ||
167 | #define __array(type, item, len) \ | ||
168 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ | ||
169 | "offset:%u;\tsize:%u;\tsigned:%u;\n", \ | ||
170 | (unsigned int)offsetof(typeof(field), item), \ | ||
171 | (unsigned int)sizeof(field.item), \ | ||
172 | (unsigned int)is_signed_type(type)); \ | ||
173 | if (!ret) \ | ||
174 | return 0; | ||
175 | |||
176 | #undef __dynamic_array | ||
177 | #define __dynamic_array(type, item, len) \ | ||
178 | ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\ | ||
179 | "offset:%u;\tsize:%u;\tsigned:%u;\n", \ | ||
180 | (unsigned int)offsetof(typeof(field), \ | ||
181 | __data_loc_##item), \ | ||
182 | (unsigned int)sizeof(field.__data_loc_##item), \ | ||
183 | (unsigned int)is_signed_type(type)); \ | ||
184 | if (!ret) \ | ||
185 | return 0; | ||
186 | |||
187 | #undef __string | ||
188 | #define __string(item, src) __dynamic_array(char, item, -1) | ||
189 | |||
190 | #undef __entry | ||
191 | #define __entry REC | ||
192 | |||
193 | #undef __print_symbolic | ||
194 | #undef __get_dynamic_array | ||
195 | #undef __get_str | ||
196 | |||
197 | #undef TP_printk | ||
198 | #define TP_printk(fmt, args...) "\"%s\", %s\n", fmt, __stringify(args) | ||
199 | |||
200 | #undef TP_fast_assign | ||
201 | #define TP_fast_assign(args...) args | ||
202 | |||
203 | #undef TP_perf_assign | ||
204 | #define TP_perf_assign(args...) | ||
205 | |||
206 | #undef DECLARE_EVENT_CLASS | ||
207 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \ | ||
208 | static int \ | ||
209 | ftrace_format_setup_##call(struct ftrace_event_call *unused, \ | ||
210 | struct trace_seq *s) \ | ||
211 | { \ | ||
212 | struct ftrace_raw_##call field __attribute__((unused)); \ | ||
213 | int ret = 0; \ | ||
214 | \ | ||
215 | tstruct; \ | ||
216 | \ | ||
217 | return ret; \ | ||
218 | } \ | ||
219 | \ | ||
220 | static int \ | ||
221 | ftrace_format_##call(struct ftrace_event_call *unused, \ | ||
222 | struct trace_seq *s) \ | ||
223 | { \ | ||
224 | int ret = 0; \ | ||
225 | \ | ||
226 | ret = ftrace_format_setup_##call(unused, s); \ | ||
227 | if (!ret) \ | ||
228 | return ret; \ | ||
229 | \ | ||
230 | ret = trace_seq_printf(s, "\nprint fmt: " print); \ | ||
231 | \ | ||
232 | return ret; \ | ||
233 | } | ||
234 | |||
235 | #undef DEFINE_EVENT | ||
236 | #define DEFINE_EVENT(template, name, proto, args) | ||
237 | |||
238 | #undef DEFINE_EVENT_PRINT | ||
239 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ | ||
240 | static int \ | ||
241 | ftrace_format_##name(struct ftrace_event_call *unused, \ | ||
242 | struct trace_seq *s) \ | ||
243 | { \ | ||
244 | int ret = 0; \ | ||
245 | \ | ||
246 | ret = ftrace_format_setup_##template(unused, s); \ | ||
247 | if (!ret) \ | ||
248 | return ret; \ | ||
249 | \ | ||
250 | trace_seq_printf(s, "\nprint fmt: " print); \ | ||
251 | \ | ||
252 | return ret; \ | ||
253 | } | ||
254 | |||
255 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | ||
256 | |||
257 | /* | ||
258 | * Stage 3 of the trace events. | 135 | * Stage 3 of the trace events. |
259 | * | 136 | * |
260 | * Override the macros in <trace/trace_events.h> to include the following: | 137 | * Override the macros in <trace/trace_events.h> to include the following: |
@@ -323,7 +200,7 @@ ftrace_format_##name(struct ftrace_event_call *unused, \ | |||
323 | 200 | ||
324 | #undef DECLARE_EVENT_CLASS | 201 | #undef DECLARE_EVENT_CLASS |
325 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ | 202 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
326 | static enum print_line_t \ | 203 | static notrace enum print_line_t \ |
327 | ftrace_raw_output_id_##call(int event_id, const char *name, \ | 204 | ftrace_raw_output_id_##call(int event_id, const char *name, \ |
328 | struct trace_iterator *iter, int flags) \ | 205 | struct trace_iterator *iter, int flags) \ |
329 | { \ | 206 | { \ |
@@ -356,7 +233,7 @@ ftrace_raw_output_id_##call(int event_id, const char *name, \ | |||
356 | 233 | ||
357 | #undef DEFINE_EVENT | 234 | #undef DEFINE_EVENT |
358 | #define DEFINE_EVENT(template, name, proto, args) \ | 235 | #define DEFINE_EVENT(template, name, proto, args) \ |
359 | static enum print_line_t \ | 236 | static notrace enum print_line_t \ |
360 | ftrace_raw_output_##name(struct trace_iterator *iter, int flags) \ | 237 | ftrace_raw_output_##name(struct trace_iterator *iter, int flags) \ |
361 | { \ | 238 | { \ |
362 | return ftrace_raw_output_id_##template(event_##name.id, \ | 239 | return ftrace_raw_output_id_##template(event_##name.id, \ |
@@ -365,7 +242,7 @@ ftrace_raw_output_##name(struct trace_iterator *iter, int flags) \ | |||
365 | 242 | ||
366 | #undef DEFINE_EVENT_PRINT | 243 | #undef DEFINE_EVENT_PRINT |
367 | #define DEFINE_EVENT_PRINT(template, call, proto, args, print) \ | 244 | #define DEFINE_EVENT_PRINT(template, call, proto, args, print) \ |
368 | static enum print_line_t \ | 245 | static notrace enum print_line_t \ |
369 | ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ | 246 | ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ |
370 | { \ | 247 | { \ |
371 | struct trace_seq *s = &iter->seq; \ | 248 | struct trace_seq *s = &iter->seq; \ |
@@ -431,7 +308,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ | |||
431 | 308 | ||
432 | #undef DECLARE_EVENT_CLASS | 309 | #undef DECLARE_EVENT_CLASS |
433 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \ | 310 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \ |
434 | static int \ | 311 | static int notrace \ |
435 | ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ | 312 | ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ |
436 | { \ | 313 | { \ |
437 | struct ftrace_raw_##call field; \ | 314 | struct ftrace_raw_##call field; \ |
@@ -479,7 +356,7 @@ ftrace_define_fields_##call(struct ftrace_event_call *event_call) \ | |||
479 | 356 | ||
480 | #undef DECLARE_EVENT_CLASS | 357 | #undef DECLARE_EVENT_CLASS |
481 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ | 358 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
482 | static inline int ftrace_get_offsets_##call( \ | 359 | static inline notrace int ftrace_get_offsets_##call( \ |
483 | struct ftrace_data_offsets_##call *__data_offsets, proto) \ | 360 | struct ftrace_data_offsets_##call *__data_offsets, proto) \ |
484 | { \ | 361 | { \ |
485 | int __data_size = 0; \ | 362 | int __data_size = 0; \ |
@@ -526,12 +403,14 @@ static inline int ftrace_get_offsets_##call( \ | |||
526 | \ | 403 | \ |
527 | static void ftrace_profile_##name(proto); \ | 404 | static void ftrace_profile_##name(proto); \ |
528 | \ | 405 | \ |
529 | static int ftrace_profile_enable_##name(struct ftrace_event_call *unused)\ | 406 | static notrace int \ |
407 | ftrace_profile_enable_##name(struct ftrace_event_call *unused) \ | ||
530 | { \ | 408 | { \ |
531 | return register_trace_##name(ftrace_profile_##name); \ | 409 | return register_trace_##name(ftrace_profile_##name); \ |
532 | } \ | 410 | } \ |
533 | \ | 411 | \ |
534 | static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ | 412 | static notrace void \ |
413 | ftrace_profile_disable_##name(struct ftrace_event_call *unused) \ | ||
535 | { \ | 414 | { \ |
536 | unregister_trace_##name(ftrace_profile_##name); \ | 415 | unregister_trace_##name(ftrace_profile_##name); \ |
537 | } | 416 | } |
@@ -622,7 +501,6 @@ static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ | |||
622 | * .raw_init = trace_event_raw_init, | 501 | * .raw_init = trace_event_raw_init, |
623 | * .regfunc = ftrace_reg_event_<call>, | 502 | * .regfunc = ftrace_reg_event_<call>, |
624 | * .unregfunc = ftrace_unreg_event_<call>, | 503 | * .unregfunc = ftrace_unreg_event_<call>, |
625 | * .show_format = ftrace_format_<call>, | ||
626 | * } | 504 | * } |
627 | * | 505 | * |
628 | */ | 506 | */ |
@@ -657,10 +535,17 @@ static void ftrace_profile_disable_##name(struct ftrace_event_call *unused)\ | |||
657 | #define __assign_str(dst, src) \ | 535 | #define __assign_str(dst, src) \ |
658 | strcpy(__get_str(dst), src); | 536 | strcpy(__get_str(dst), src); |
659 | 537 | ||
538 | #undef TP_fast_assign | ||
539 | #define TP_fast_assign(args...) args | ||
540 | |||
541 | #undef TP_perf_assign | ||
542 | #define TP_perf_assign(args...) | ||
543 | |||
660 | #undef DECLARE_EVENT_CLASS | 544 | #undef DECLARE_EVENT_CLASS |
661 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ | 545 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
662 | \ | 546 | \ |
663 | static void ftrace_raw_event_id_##call(struct ftrace_event_call *event_call, \ | 547 | static notrace void \ |
548 | ftrace_raw_event_id_##call(struct ftrace_event_call *event_call, \ | ||
664 | proto) \ | 549 | proto) \ |
665 | { \ | 550 | { \ |
666 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ | 551 | struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ |
@@ -697,17 +582,19 @@ static void ftrace_raw_event_id_##call(struct ftrace_event_call *event_call, \ | |||
697 | #undef DEFINE_EVENT | 582 | #undef DEFINE_EVENT |
698 | #define DEFINE_EVENT(template, call, proto, args) \ | 583 | #define DEFINE_EVENT(template, call, proto, args) \ |
699 | \ | 584 | \ |
700 | static void ftrace_raw_event_##call(proto) \ | 585 | static notrace void ftrace_raw_event_##call(proto) \ |
701 | { \ | 586 | { \ |
702 | ftrace_raw_event_id_##template(&event_##call, args); \ | 587 | ftrace_raw_event_id_##template(&event_##call, args); \ |
703 | } \ | 588 | } \ |
704 | \ | 589 | \ |
705 | static int ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)\ | 590 | static notrace int \ |
591 | ftrace_raw_reg_event_##call(struct ftrace_event_call *unused) \ | ||
706 | { \ | 592 | { \ |
707 | return register_trace_##call(ftrace_raw_event_##call); \ | 593 | return register_trace_##call(ftrace_raw_event_##call); \ |
708 | } \ | 594 | } \ |
709 | \ | 595 | \ |
710 | static void ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)\ | 596 | static notrace void \ |
597 | ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused) \ | ||
711 | { \ | 598 | { \ |
712 | unregister_trace_##call(ftrace_raw_event_##call); \ | 599 | unregister_trace_##call(ftrace_raw_event_##call); \ |
713 | } \ | 600 | } \ |
@@ -722,8 +609,20 @@ static struct trace_event ftrace_event_type_##call = { \ | |||
722 | 609 | ||
723 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 610 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
724 | 611 | ||
612 | #undef __entry | ||
613 | #define __entry REC | ||
614 | |||
615 | #undef __print_flags | ||
616 | #undef __print_symbolic | ||
617 | #undef __get_dynamic_array | ||
618 | #undef __get_str | ||
619 | |||
620 | #undef TP_printk | ||
621 | #define TP_printk(fmt, args...) "\"" fmt "\", " __stringify(args) | ||
622 | |||
725 | #undef DECLARE_EVENT_CLASS | 623 | #undef DECLARE_EVENT_CLASS |
726 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) | 624 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
625 | static const char print_fmt_##call[] = print; | ||
727 | 626 | ||
728 | #undef DEFINE_EVENT | 627 | #undef DEFINE_EVENT |
729 | #define DEFINE_EVENT(template, call, proto, args) \ | 628 | #define DEFINE_EVENT(template, call, proto, args) \ |
@@ -737,7 +636,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
737 | .raw_init = trace_event_raw_init, \ | 636 | .raw_init = trace_event_raw_init, \ |
738 | .regfunc = ftrace_raw_reg_event_##call, \ | 637 | .regfunc = ftrace_raw_reg_event_##call, \ |
739 | .unregfunc = ftrace_raw_unreg_event_##call, \ | 638 | .unregfunc = ftrace_raw_unreg_event_##call, \ |
740 | .show_format = ftrace_format_##template, \ | 639 | .print_fmt = print_fmt_##template, \ |
741 | .define_fields = ftrace_define_fields_##template, \ | 640 | .define_fields = ftrace_define_fields_##template, \ |
742 | _TRACE_PROFILE_INIT(call) \ | 641 | _TRACE_PROFILE_INIT(call) \ |
743 | } | 642 | } |
@@ -745,6 +644,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
745 | #undef DEFINE_EVENT_PRINT | 644 | #undef DEFINE_EVENT_PRINT |
746 | #define DEFINE_EVENT_PRINT(template, call, proto, args, print) \ | 645 | #define DEFINE_EVENT_PRINT(template, call, proto, args, print) \ |
747 | \ | 646 | \ |
647 | static const char print_fmt_##call[] = print; \ | ||
648 | \ | ||
748 | static struct ftrace_event_call __used \ | 649 | static struct ftrace_event_call __used \ |
749 | __attribute__((__aligned__(4))) \ | 650 | __attribute__((__aligned__(4))) \ |
750 | __attribute__((section("_ftrace_events"))) event_##call = { \ | 651 | __attribute__((section("_ftrace_events"))) event_##call = { \ |
@@ -754,7 +655,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
754 | .raw_init = trace_event_raw_init, \ | 655 | .raw_init = trace_event_raw_init, \ |
755 | .regfunc = ftrace_raw_reg_event_##call, \ | 656 | .regfunc = ftrace_raw_reg_event_##call, \ |
756 | .unregfunc = ftrace_raw_unreg_event_##call, \ | 657 | .unregfunc = ftrace_raw_unreg_event_##call, \ |
757 | .show_format = ftrace_format_##call, \ | 658 | .print_fmt = print_fmt_##call, \ |
758 | .define_fields = ftrace_define_fields_##template, \ | 659 | .define_fields = ftrace_define_fields_##template, \ |
759 | _TRACE_PROFILE_INIT(call) \ | 660 | _TRACE_PROFILE_INIT(call) \ |
760 | } | 661 | } |
@@ -837,6 +738,16 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
837 | 738 | ||
838 | #ifdef CONFIG_EVENT_PROFILE | 739 | #ifdef CONFIG_EVENT_PROFILE |
839 | 740 | ||
741 | #undef __entry | ||
742 | #define __entry entry | ||
743 | |||
744 | #undef __get_dynamic_array | ||
745 | #define __get_dynamic_array(field) \ | ||
746 | ((void *)__entry + (__entry->__data_loc_##field & 0xffff)) | ||
747 | |||
748 | #undef __get_str | ||
749 | #define __get_str(field) (char *)__get_dynamic_array(field) | ||
750 | |||
840 | #undef __perf_addr | 751 | #undef __perf_addr |
841 | #define __perf_addr(a) __addr = (a) | 752 | #define __perf_addr(a) __addr = (a) |
842 | 753 | ||
@@ -845,7 +756,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
845 | 756 | ||
846 | #undef DECLARE_EVENT_CLASS | 757 | #undef DECLARE_EVENT_CLASS |
847 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ | 758 | #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
848 | static void \ | 759 | static notrace void \ |
849 | ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ | 760 | ftrace_profile_templ_##call(struct ftrace_event_call *event_call, \ |
850 | proto) \ | 761 | proto) \ |
851 | { \ | 762 | { \ |
@@ -915,7 +826,7 @@ end_recursion: \ | |||
915 | 826 | ||
916 | #undef DEFINE_EVENT | 827 | #undef DEFINE_EVENT |
917 | #define DEFINE_EVENT(template, call, proto, args) \ | 828 | #define DEFINE_EVENT(template, call, proto, args) \ |
918 | static void ftrace_profile_##call(proto) \ | 829 | static notrace void ftrace_profile_##call(proto) \ |
919 | { \ | 830 | { \ |
920 | struct ftrace_event_call *event_call = &event_##call; \ | 831 | struct ftrace_event_call *event_call = &event_##call; \ |
921 | \ | 832 | \ |
diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 961fda3556bb..8cd410254456 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h | |||
@@ -34,10 +34,6 @@ struct syscall_metadata { | |||
34 | extern unsigned long arch_syscall_addr(int nr); | 34 | extern unsigned long arch_syscall_addr(int nr); |
35 | extern int init_syscall_trace(struct ftrace_event_call *call); | 35 | extern int init_syscall_trace(struct ftrace_event_call *call); |
36 | 36 | ||
37 | extern int syscall_enter_format(struct ftrace_event_call *call, | ||
38 | struct trace_seq *s); | ||
39 | extern int syscall_exit_format(struct ftrace_event_call *call, | ||
40 | struct trace_seq *s); | ||
41 | extern int syscall_enter_define_fields(struct ftrace_event_call *call); | 37 | extern int syscall_enter_define_fields(struct ftrace_event_call *call); |
42 | extern int syscall_exit_define_fields(struct ftrace_event_call *call); | 38 | extern int syscall_exit_define_fields(struct ftrace_event_call *call); |
43 | extern int reg_event_syscall_enter(struct ftrace_event_call *call); | 39 | extern int reg_event_syscall_enter(struct ftrace_event_call *call); |
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 60e2ce0181ee..13e13d428cd3 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -328,15 +328,6 @@ config BRANCH_TRACER | |||
328 | 328 | ||
329 | Say N if unsure. | 329 | Say N if unsure. |
330 | 330 | ||
331 | config POWER_TRACER | ||
332 | bool "Trace power consumption behavior" | ||
333 | depends on X86 | ||
334 | select GENERIC_TRACER | ||
335 | help | ||
336 | This tracer helps developers to analyze and optimize the kernel's | ||
337 | power management decisions, specifically the C-state and P-state | ||
338 | behavior. | ||
339 | |||
340 | config KSYM_TRACER | 331 | config KSYM_TRACER |
341 | bool "Trace read and write access on kernel memory locations" | 332 | bool "Trace read and write access on kernel memory locations" |
342 | depends on HAVE_HW_BREAKPOINT | 333 | depends on HAVE_HW_BREAKPOINT |
@@ -449,7 +440,7 @@ config BLK_DEV_IO_TRACE | |||
449 | 440 | ||
450 | config KPROBE_EVENT | 441 | config KPROBE_EVENT |
451 | depends on KPROBES | 442 | depends on KPROBES |
452 | depends on X86 | 443 | depends on HAVE_REGS_AND_STACK_ACCESS_API |
453 | bool "Enable kprobes-based dynamic events" | 444 | bool "Enable kprobes-based dynamic events" |
454 | select TRACING | 445 | select TRACING |
455 | default y | 446 | default y |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1e6640f80454..d996353473fd 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -2426,6 +2426,7 @@ static const struct file_operations ftrace_notrace_fops = { | |||
2426 | static DEFINE_MUTEX(graph_lock); | 2426 | static DEFINE_MUTEX(graph_lock); |
2427 | 2427 | ||
2428 | int ftrace_graph_count; | 2428 | int ftrace_graph_count; |
2429 | int ftrace_graph_filter_enabled; | ||
2429 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | 2430 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; |
2430 | 2431 | ||
2431 | static void * | 2432 | static void * |
@@ -2448,7 +2449,7 @@ static void *g_start(struct seq_file *m, loff_t *pos) | |||
2448 | mutex_lock(&graph_lock); | 2449 | mutex_lock(&graph_lock); |
2449 | 2450 | ||
2450 | /* Nothing, tell g_show to print all functions are enabled */ | 2451 | /* Nothing, tell g_show to print all functions are enabled */ |
2451 | if (!ftrace_graph_count && !*pos) | 2452 | if (!ftrace_graph_filter_enabled && !*pos) |
2452 | return (void *)1; | 2453 | return (void *)1; |
2453 | 2454 | ||
2454 | return __g_next(m, pos); | 2455 | return __g_next(m, pos); |
@@ -2494,6 +2495,7 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2494 | mutex_lock(&graph_lock); | 2495 | mutex_lock(&graph_lock); |
2495 | if ((file->f_mode & FMODE_WRITE) && | 2496 | if ((file->f_mode & FMODE_WRITE) && |
2496 | (file->f_flags & O_TRUNC)) { | 2497 | (file->f_flags & O_TRUNC)) { |
2498 | ftrace_graph_filter_enabled = 0; | ||
2497 | ftrace_graph_count = 0; | 2499 | ftrace_graph_count = 0; |
2498 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2500 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2499 | } | 2501 | } |
@@ -2519,7 +2521,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2519 | struct dyn_ftrace *rec; | 2521 | struct dyn_ftrace *rec; |
2520 | struct ftrace_page *pg; | 2522 | struct ftrace_page *pg; |
2521 | int search_len; | 2523 | int search_len; |
2522 | int found = 0; | 2524 | int fail = 1; |
2523 | int type, not; | 2525 | int type, not; |
2524 | char *search; | 2526 | char *search; |
2525 | bool exists; | 2527 | bool exists; |
@@ -2530,37 +2532,51 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2530 | 2532 | ||
2531 | /* decode regex */ | 2533 | /* decode regex */ |
2532 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); | 2534 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
2533 | if (not) | 2535 | if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS) |
2534 | return -EINVAL; | 2536 | return -EBUSY; |
2535 | 2537 | ||
2536 | search_len = strlen(search); | 2538 | search_len = strlen(search); |
2537 | 2539 | ||
2538 | mutex_lock(&ftrace_lock); | 2540 | mutex_lock(&ftrace_lock); |
2539 | do_for_each_ftrace_rec(pg, rec) { | 2541 | do_for_each_ftrace_rec(pg, rec) { |
2540 | 2542 | ||
2541 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2542 | break; | ||
2543 | |||
2544 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) | 2543 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) |
2545 | continue; | 2544 | continue; |
2546 | 2545 | ||
2547 | if (ftrace_match_record(rec, search, search_len, type)) { | 2546 | if (ftrace_match_record(rec, search, search_len, type)) { |
2548 | /* ensure it is not already in the array */ | 2547 | /* if it is in the array */ |
2549 | exists = false; | 2548 | exists = false; |
2550 | for (i = 0; i < *idx; i++) | 2549 | for (i = 0; i < *idx; i++) { |
2551 | if (array[i] == rec->ip) { | 2550 | if (array[i] == rec->ip) { |
2552 | exists = true; | 2551 | exists = true; |
2553 | break; | 2552 | break; |
2554 | } | 2553 | } |
2555 | if (!exists) | 2554 | } |
2556 | array[(*idx)++] = rec->ip; | 2555 | |
2557 | found = 1; | 2556 | if (!not) { |
2557 | fail = 0; | ||
2558 | if (!exists) { | ||
2559 | array[(*idx)++] = rec->ip; | ||
2560 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2561 | goto out; | ||
2562 | } | ||
2563 | } else { | ||
2564 | if (exists) { | ||
2565 | array[i] = array[--(*idx)]; | ||
2566 | array[*idx] = 0; | ||
2567 | fail = 0; | ||
2568 | } | ||
2569 | } | ||
2558 | } | 2570 | } |
2559 | } while_for_each_ftrace_rec(); | 2571 | } while_for_each_ftrace_rec(); |
2560 | 2572 | out: | |
2561 | mutex_unlock(&ftrace_lock); | 2573 | mutex_unlock(&ftrace_lock); |
2562 | 2574 | ||
2563 | return found ? 0 : -EINVAL; | 2575 | if (fail) |
2576 | return -EINVAL; | ||
2577 | |||
2578 | ftrace_graph_filter_enabled = 1; | ||
2579 | return 0; | ||
2564 | } | 2580 | } |
2565 | 2581 | ||
2566 | static ssize_t | 2582 | static ssize_t |
@@ -2570,16 +2586,11 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2570 | struct trace_parser parser; | 2586 | struct trace_parser parser; |
2571 | ssize_t read, ret; | 2587 | ssize_t read, ret; |
2572 | 2588 | ||
2573 | if (!cnt || cnt < 0) | 2589 | if (!cnt) |
2574 | return 0; | 2590 | return 0; |
2575 | 2591 | ||
2576 | mutex_lock(&graph_lock); | 2592 | mutex_lock(&graph_lock); |
2577 | 2593 | ||
2578 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { | ||
2579 | ret = -EBUSY; | ||
2580 | goto out_unlock; | ||
2581 | } | ||
2582 | |||
2583 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { | 2594 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
2584 | ret = -ENOMEM; | 2595 | ret = -ENOMEM; |
2585 | goto out_unlock; | 2596 | goto out_unlock; |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index eac6875cb990..032c57ca6502 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/splice.h> | 32 | #include <linux/splice.h> |
33 | #include <linux/kdebug.h> | 33 | #include <linux/kdebug.h> |
34 | #include <linux/string.h> | 34 | #include <linux/string.h> |
35 | #include <linux/rwsem.h> | ||
35 | #include <linux/ctype.h> | 36 | #include <linux/ctype.h> |
36 | #include <linux/init.h> | 37 | #include <linux/init.h> |
37 | #include <linux/poll.h> | 38 | #include <linux/poll.h> |
@@ -102,9 +103,6 @@ static inline void ftrace_enable_cpu(void) | |||
102 | 103 | ||
103 | static cpumask_var_t __read_mostly tracing_buffer_mask; | 104 | static cpumask_var_t __read_mostly tracing_buffer_mask; |
104 | 105 | ||
105 | /* Define which cpu buffers are currently read in trace_pipe */ | ||
106 | static cpumask_var_t tracing_reader_cpumask; | ||
107 | |||
108 | #define for_each_tracing_cpu(cpu) \ | 106 | #define for_each_tracing_cpu(cpu) \ |
109 | for_each_cpu(cpu, tracing_buffer_mask) | 107 | for_each_cpu(cpu, tracing_buffer_mask) |
110 | 108 | ||
@@ -243,12 +241,91 @@ static struct tracer *current_trace __read_mostly; | |||
243 | 241 | ||
244 | /* | 242 | /* |
245 | * trace_types_lock is used to protect the trace_types list. | 243 | * trace_types_lock is used to protect the trace_types list. |
246 | * This lock is also used to keep user access serialized. | ||
247 | * Accesses from userspace will grab this lock while userspace | ||
248 | * activities happen inside the kernel. | ||
249 | */ | 244 | */ |
250 | static DEFINE_MUTEX(trace_types_lock); | 245 | static DEFINE_MUTEX(trace_types_lock); |
251 | 246 | ||
247 | /* | ||
248 | * serialize the access of the ring buffer | ||
249 | * | ||
250 | * ring buffer serializes readers, but it is low level protection. | ||
251 | * The validity of the events (which returns by ring_buffer_peek() ..etc) | ||
252 | * are not protected by ring buffer. | ||
253 | * | ||
254 | * The content of events may become garbage if we allow other process consumes | ||
255 | * these events concurrently: | ||
256 | * A) the page of the consumed events may become a normal page | ||
257 | * (not reader page) in ring buffer, and this page will be rewrited | ||
258 | * by events producer. | ||
259 | * B) The page of the consumed events may become a page for splice_read, | ||
260 | * and this page will be returned to system. | ||
261 | * | ||
262 | * These primitives allow multi process access to different cpu ring buffer | ||
263 | * concurrently. | ||
264 | * | ||
265 | * These primitives don't distinguish read-only and read-consume access. | ||
266 | * Multi read-only access are also serialized. | ||
267 | */ | ||
268 | |||
269 | #ifdef CONFIG_SMP | ||
270 | static DECLARE_RWSEM(all_cpu_access_lock); | ||
271 | static DEFINE_PER_CPU(struct mutex, cpu_access_lock); | ||
272 | |||
273 | static inline void trace_access_lock(int cpu) | ||
274 | { | ||
275 | if (cpu == TRACE_PIPE_ALL_CPU) { | ||
276 | /* gain it for accessing the whole ring buffer. */ | ||
277 | down_write(&all_cpu_access_lock); | ||
278 | } else { | ||
279 | /* gain it for accessing a cpu ring buffer. */ | ||
280 | |||
281 | /* Firstly block other trace_access_lock(TRACE_PIPE_ALL_CPU). */ | ||
282 | down_read(&all_cpu_access_lock); | ||
283 | |||
284 | /* Secondly block other access to this @cpu ring buffer. */ | ||
285 | mutex_lock(&per_cpu(cpu_access_lock, cpu)); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | static inline void trace_access_unlock(int cpu) | ||
290 | { | ||
291 | if (cpu == TRACE_PIPE_ALL_CPU) { | ||
292 | up_write(&all_cpu_access_lock); | ||
293 | } else { | ||
294 | mutex_unlock(&per_cpu(cpu_access_lock, cpu)); | ||
295 | up_read(&all_cpu_access_lock); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static inline void trace_access_lock_init(void) | ||
300 | { | ||
301 | int cpu; | ||
302 | |||
303 | for_each_possible_cpu(cpu) | ||
304 | mutex_init(&per_cpu(cpu_access_lock, cpu)); | ||
305 | } | ||
306 | |||
307 | #else | ||
308 | |||
309 | static DEFINE_MUTEX(access_lock); | ||
310 | |||
311 | static inline void trace_access_lock(int cpu) | ||
312 | { | ||
313 | (void)cpu; | ||
314 | mutex_lock(&access_lock); | ||
315 | } | ||
316 | |||
317 | static inline void trace_access_unlock(int cpu) | ||
318 | { | ||
319 | (void)cpu; | ||
320 | mutex_unlock(&access_lock); | ||
321 | } | ||
322 | |||
323 | static inline void trace_access_lock_init(void) | ||
324 | { | ||
325 | } | ||
326 | |||
327 | #endif | ||
328 | |||
252 | /* trace_wait is a waitqueue for tasks blocked on trace_poll */ | 329 | /* trace_wait is a waitqueue for tasks blocked on trace_poll */ |
253 | static DECLARE_WAIT_QUEUE_HEAD(trace_wait); | 330 | static DECLARE_WAIT_QUEUE_HEAD(trace_wait); |
254 | 331 | ||
@@ -1320,8 +1397,10 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) | |||
1320 | entry->fmt = fmt; | 1397 | entry->fmt = fmt; |
1321 | 1398 | ||
1322 | memcpy(entry->buf, trace_buf, sizeof(u32) * len); | 1399 | memcpy(entry->buf, trace_buf, sizeof(u32) * len); |
1323 | if (!filter_check_discard(call, entry, buffer, event)) | 1400 | if (!filter_check_discard(call, entry, buffer, event)) { |
1324 | ring_buffer_unlock_commit(buffer, event); | 1401 | ring_buffer_unlock_commit(buffer, event); |
1402 | ftrace_trace_stack(buffer, flags, 6, pc); | ||
1403 | } | ||
1325 | 1404 | ||
1326 | out_unlock: | 1405 | out_unlock: |
1327 | arch_spin_unlock(&trace_buf_lock); | 1406 | arch_spin_unlock(&trace_buf_lock); |
@@ -1394,8 +1473,10 @@ int trace_array_vprintk(struct trace_array *tr, | |||
1394 | 1473 | ||
1395 | memcpy(&entry->buf, trace_buf, len); | 1474 | memcpy(&entry->buf, trace_buf, len); |
1396 | entry->buf[len] = '\0'; | 1475 | entry->buf[len] = '\0'; |
1397 | if (!filter_check_discard(call, entry, buffer, event)) | 1476 | if (!filter_check_discard(call, entry, buffer, event)) { |
1398 | ring_buffer_unlock_commit(buffer, event); | 1477 | ring_buffer_unlock_commit(buffer, event); |
1478 | ftrace_trace_stack(buffer, irq_flags, 6, pc); | ||
1479 | } | ||
1399 | 1480 | ||
1400 | out_unlock: | 1481 | out_unlock: |
1401 | arch_spin_unlock(&trace_buf_lock); | 1482 | arch_spin_unlock(&trace_buf_lock); |
@@ -1585,12 +1666,6 @@ static void tracing_iter_reset(struct trace_iterator *iter, int cpu) | |||
1585 | } | 1666 | } |
1586 | 1667 | ||
1587 | /* | 1668 | /* |
1588 | * No necessary locking here. The worst thing which can | ||
1589 | * happen is loosing events consumed at the same time | ||
1590 | * by a trace_pipe reader. | ||
1591 | * Other than that, we don't risk to crash the ring buffer | ||
1592 | * because it serializes the readers. | ||
1593 | * | ||
1594 | * The current tracer is copied to avoid a global locking | 1669 | * The current tracer is copied to avoid a global locking |
1595 | * all around. | 1670 | * all around. |
1596 | */ | 1671 | */ |
@@ -1645,12 +1720,16 @@ static void *s_start(struct seq_file *m, loff_t *pos) | |||
1645 | } | 1720 | } |
1646 | 1721 | ||
1647 | trace_event_read_lock(); | 1722 | trace_event_read_lock(); |
1723 | trace_access_lock(cpu_file); | ||
1648 | return p; | 1724 | return p; |
1649 | } | 1725 | } |
1650 | 1726 | ||
1651 | static void s_stop(struct seq_file *m, void *p) | 1727 | static void s_stop(struct seq_file *m, void *p) |
1652 | { | 1728 | { |
1729 | struct trace_iterator *iter = m->private; | ||
1730 | |||
1653 | atomic_dec(&trace_record_cmdline_disabled); | 1731 | atomic_dec(&trace_record_cmdline_disabled); |
1732 | trace_access_unlock(iter->cpu_file); | ||
1654 | trace_event_read_unlock(); | 1733 | trace_event_read_unlock(); |
1655 | } | 1734 | } |
1656 | 1735 | ||
@@ -2841,22 +2920,6 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) | |||
2841 | 2920 | ||
2842 | mutex_lock(&trace_types_lock); | 2921 | mutex_lock(&trace_types_lock); |
2843 | 2922 | ||
2844 | /* We only allow one reader per cpu */ | ||
2845 | if (cpu_file == TRACE_PIPE_ALL_CPU) { | ||
2846 | if (!cpumask_empty(tracing_reader_cpumask)) { | ||
2847 | ret = -EBUSY; | ||
2848 | goto out; | ||
2849 | } | ||
2850 | cpumask_setall(tracing_reader_cpumask); | ||
2851 | } else { | ||
2852 | if (!cpumask_test_cpu(cpu_file, tracing_reader_cpumask)) | ||
2853 | cpumask_set_cpu(cpu_file, tracing_reader_cpumask); | ||
2854 | else { | ||
2855 | ret = -EBUSY; | ||
2856 | goto out; | ||
2857 | } | ||
2858 | } | ||
2859 | |||
2860 | /* create a buffer to store the information to pass to userspace */ | 2923 | /* create a buffer to store the information to pass to userspace */ |
2861 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | 2924 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); |
2862 | if (!iter) { | 2925 | if (!iter) { |
@@ -2912,12 +2975,6 @@ static int tracing_release_pipe(struct inode *inode, struct file *file) | |||
2912 | 2975 | ||
2913 | mutex_lock(&trace_types_lock); | 2976 | mutex_lock(&trace_types_lock); |
2914 | 2977 | ||
2915 | if (iter->cpu_file == TRACE_PIPE_ALL_CPU) | ||
2916 | cpumask_clear(tracing_reader_cpumask); | ||
2917 | else | ||
2918 | cpumask_clear_cpu(iter->cpu_file, tracing_reader_cpumask); | ||
2919 | |||
2920 | |||
2921 | if (iter->trace->pipe_close) | 2978 | if (iter->trace->pipe_close) |
2922 | iter->trace->pipe_close(iter); | 2979 | iter->trace->pipe_close(iter); |
2923 | 2980 | ||
@@ -3079,6 +3136,7 @@ waitagain: | |||
3079 | iter->pos = -1; | 3136 | iter->pos = -1; |
3080 | 3137 | ||
3081 | trace_event_read_lock(); | 3138 | trace_event_read_lock(); |
3139 | trace_access_lock(iter->cpu_file); | ||
3082 | while (find_next_entry_inc(iter) != NULL) { | 3140 | while (find_next_entry_inc(iter) != NULL) { |
3083 | enum print_line_t ret; | 3141 | enum print_line_t ret; |
3084 | int len = iter->seq.len; | 3142 | int len = iter->seq.len; |
@@ -3095,6 +3153,7 @@ waitagain: | |||
3095 | if (iter->seq.len >= cnt) | 3153 | if (iter->seq.len >= cnt) |
3096 | break; | 3154 | break; |
3097 | } | 3155 | } |
3156 | trace_access_unlock(iter->cpu_file); | ||
3098 | trace_event_read_unlock(); | 3157 | trace_event_read_unlock(); |
3099 | 3158 | ||
3100 | /* Now copy what we have to the user */ | 3159 | /* Now copy what we have to the user */ |
@@ -3220,6 +3279,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | |||
3220 | } | 3279 | } |
3221 | 3280 | ||
3222 | trace_event_read_lock(); | 3281 | trace_event_read_lock(); |
3282 | trace_access_lock(iter->cpu_file); | ||
3223 | 3283 | ||
3224 | /* Fill as many pages as possible. */ | 3284 | /* Fill as many pages as possible. */ |
3225 | for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) { | 3285 | for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) { |
@@ -3243,6 +3303,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | |||
3243 | trace_seq_init(&iter->seq); | 3303 | trace_seq_init(&iter->seq); |
3244 | } | 3304 | } |
3245 | 3305 | ||
3306 | trace_access_unlock(iter->cpu_file); | ||
3246 | trace_event_read_unlock(); | 3307 | trace_event_read_unlock(); |
3247 | mutex_unlock(&iter->mutex); | 3308 | mutex_unlock(&iter->mutex); |
3248 | 3309 | ||
@@ -3544,10 +3605,12 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, | |||
3544 | 3605 | ||
3545 | info->read = 0; | 3606 | info->read = 0; |
3546 | 3607 | ||
3608 | trace_access_lock(info->cpu); | ||
3547 | ret = ring_buffer_read_page(info->tr->buffer, | 3609 | ret = ring_buffer_read_page(info->tr->buffer, |
3548 | &info->spare, | 3610 | &info->spare, |
3549 | count, | 3611 | count, |
3550 | info->cpu, 0); | 3612 | info->cpu, 0); |
3613 | trace_access_unlock(info->cpu); | ||
3551 | if (ret < 0) | 3614 | if (ret < 0) |
3552 | return 0; | 3615 | return 0; |
3553 | 3616 | ||
@@ -3675,6 +3738,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
3675 | len &= PAGE_MASK; | 3738 | len &= PAGE_MASK; |
3676 | } | 3739 | } |
3677 | 3740 | ||
3741 | trace_access_lock(info->cpu); | ||
3678 | entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu); | 3742 | entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu); |
3679 | 3743 | ||
3680 | for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) { | 3744 | for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) { |
@@ -3722,6 +3786,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
3722 | entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu); | 3786 | entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu); |
3723 | } | 3787 | } |
3724 | 3788 | ||
3789 | trace_access_unlock(info->cpu); | ||
3725 | spd.nr_pages = i; | 3790 | spd.nr_pages = i; |
3726 | 3791 | ||
3727 | /* did we read anything? */ | 3792 | /* did we read anything? */ |
@@ -4158,6 +4223,8 @@ static __init int tracer_init_debugfs(void) | |||
4158 | struct dentry *d_tracer; | 4223 | struct dentry *d_tracer; |
4159 | int cpu; | 4224 | int cpu; |
4160 | 4225 | ||
4226 | trace_access_lock_init(); | ||
4227 | |||
4161 | d_tracer = tracing_init_dentry(); | 4228 | d_tracer = tracing_init_dentry(); |
4162 | 4229 | ||
4163 | trace_create_file("tracing_enabled", 0644, d_tracer, | 4230 | trace_create_file("tracing_enabled", 0644, d_tracer, |
@@ -4392,9 +4459,6 @@ __init static int tracer_alloc_buffers(void) | |||
4392 | if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL)) | 4459 | if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL)) |
4393 | goto out_free_buffer_mask; | 4460 | goto out_free_buffer_mask; |
4394 | 4461 | ||
4395 | if (!zalloc_cpumask_var(&tracing_reader_cpumask, GFP_KERNEL)) | ||
4396 | goto out_free_tracing_cpumask; | ||
4397 | |||
4398 | /* To save memory, keep the ring buffer size to its minimum */ | 4462 | /* To save memory, keep the ring buffer size to its minimum */ |
4399 | if (ring_buffer_expanded) | 4463 | if (ring_buffer_expanded) |
4400 | ring_buf_size = trace_buf_size; | 4464 | ring_buf_size = trace_buf_size; |
@@ -4452,8 +4516,6 @@ __init static int tracer_alloc_buffers(void) | |||
4452 | return 0; | 4516 | return 0; |
4453 | 4517 | ||
4454 | out_free_cpumask: | 4518 | out_free_cpumask: |
4455 | free_cpumask_var(tracing_reader_cpumask); | ||
4456 | out_free_tracing_cpumask: | ||
4457 | free_cpumask_var(tracing_cpumask); | 4519 | free_cpumask_var(tracing_cpumask); |
4458 | out_free_buffer_mask: | 4520 | out_free_buffer_mask: |
4459 | free_cpumask_var(tracing_buffer_mask); | 4521 | free_cpumask_var(tracing_buffer_mask); |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 4df6a77eb196..fd05bcaf91b0 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -497,6 +497,7 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s); | |||
497 | #ifdef CONFIG_DYNAMIC_FTRACE | 497 | #ifdef CONFIG_DYNAMIC_FTRACE |
498 | /* TODO: make this variable */ | 498 | /* TODO: make this variable */ |
499 | #define FTRACE_GRAPH_MAX_FUNCS 32 | 499 | #define FTRACE_GRAPH_MAX_FUNCS 32 |
500 | extern int ftrace_graph_filter_enabled; | ||
500 | extern int ftrace_graph_count; | 501 | extern int ftrace_graph_count; |
501 | extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS]; | 502 | extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS]; |
502 | 503 | ||
@@ -504,7 +505,7 @@ static inline int ftrace_graph_addr(unsigned long addr) | |||
504 | { | 505 | { |
505 | int i; | 506 | int i; |
506 | 507 | ||
507 | if (!ftrace_graph_count || test_tsk_trace_graph(current)) | 508 | if (!ftrace_graph_filter_enabled) |
508 | return 1; | 509 | return 1; |
509 | 510 | ||
510 | for (i = 0; i < ftrace_graph_count; i++) { | 511 | for (i = 0; i < ftrace_graph_count; i++) { |
@@ -791,7 +792,8 @@ extern const char *__stop___trace_bprintk_fmt[]; | |||
791 | 792 | ||
792 | #undef FTRACE_ENTRY | 793 | #undef FTRACE_ENTRY |
793 | #define FTRACE_ENTRY(call, struct_name, id, tstruct, print) \ | 794 | #define FTRACE_ENTRY(call, struct_name, id, tstruct, print) \ |
794 | extern struct ftrace_event_call event_##call; | 795 | extern struct ftrace_event_call \ |
796 | __attribute__((__aligned__(4))) event_##call; | ||
795 | #undef FTRACE_ENTRY_DUP | 797 | #undef FTRACE_ENTRY_DUP |
796 | #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print) \ | 798 | #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print) \ |
797 | FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) | 799 | FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) |
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c index 4a194f08f88c..b9bc4d470177 100644 --- a/kernel/trace/trace_branch.c +++ b/kernel/trace/trace_branch.c | |||
@@ -307,8 +307,23 @@ static int annotated_branch_stat_cmp(void *p1, void *p2) | |||
307 | return -1; | 307 | return -1; |
308 | if (percent_a > percent_b) | 308 | if (percent_a > percent_b) |
309 | return 1; | 309 | return 1; |
310 | else | 310 | |
311 | return 0; | 311 | if (a->incorrect < b->incorrect) |
312 | return -1; | ||
313 | if (a->incorrect > b->incorrect) | ||
314 | return 1; | ||
315 | |||
316 | /* | ||
317 | * Since the above shows worse (incorrect) cases | ||
318 | * first, we continue that by showing best (correct) | ||
319 | * cases last. | ||
320 | */ | ||
321 | if (a->correct > b->correct) | ||
322 | return -1; | ||
323 | if (a->correct < b->correct) | ||
324 | return 1; | ||
325 | |||
326 | return 0; | ||
312 | } | 327 | } |
313 | 328 | ||
314 | static struct tracer_stat annotated_branch_stats = { | 329 | static struct tracer_stat annotated_branch_stats = { |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 189b09baf4fb..3f972ad98d04 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -60,10 +60,8 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, | |||
60 | return 0; | 60 | return 0; |
61 | 61 | ||
62 | err: | 62 | err: |
63 | if (field) { | 63 | if (field) |
64 | kfree(field->name); | 64 | kfree(field->name); |
65 | kfree(field->type); | ||
66 | } | ||
67 | kfree(field); | 65 | kfree(field); |
68 | 66 | ||
69 | return -ENOMEM; | 67 | return -ENOMEM; |
@@ -520,41 +518,16 @@ out: | |||
520 | return ret; | 518 | return ret; |
521 | } | 519 | } |
522 | 520 | ||
523 | extern char *__bad_type_size(void); | ||
524 | |||
525 | #undef FIELD | ||
526 | #define FIELD(type, name) \ | ||
527 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ | ||
528 | #type, "common_" #name, offsetof(typeof(field), name), \ | ||
529 | sizeof(field.name), is_signed_type(type) | ||
530 | |||
531 | static int trace_write_header(struct trace_seq *s) | ||
532 | { | ||
533 | struct trace_entry field; | ||
534 | |||
535 | /* struct trace_entry */ | ||
536 | return trace_seq_printf(s, | ||
537 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" | ||
538 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" | ||
539 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" | ||
540 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" | ||
541 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" | ||
542 | "\n", | ||
543 | FIELD(unsigned short, type), | ||
544 | FIELD(unsigned char, flags), | ||
545 | FIELD(unsigned char, preempt_count), | ||
546 | FIELD(int, pid), | ||
547 | FIELD(int, lock_depth)); | ||
548 | } | ||
549 | |||
550 | static ssize_t | 521 | static ssize_t |
551 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | 522 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, |
552 | loff_t *ppos) | 523 | loff_t *ppos) |
553 | { | 524 | { |
554 | struct ftrace_event_call *call = filp->private_data; | 525 | struct ftrace_event_call *call = filp->private_data; |
526 | struct ftrace_event_field *field; | ||
555 | struct trace_seq *s; | 527 | struct trace_seq *s; |
528 | int common_field_count = 5; | ||
556 | char *buf; | 529 | char *buf; |
557 | int r; | 530 | int r = 0; |
558 | 531 | ||
559 | if (*ppos) | 532 | if (*ppos) |
560 | return 0; | 533 | return 0; |
@@ -565,14 +538,48 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
565 | 538 | ||
566 | trace_seq_init(s); | 539 | trace_seq_init(s); |
567 | 540 | ||
568 | /* If any of the first writes fail, so will the show_format. */ | ||
569 | |||
570 | trace_seq_printf(s, "name: %s\n", call->name); | 541 | trace_seq_printf(s, "name: %s\n", call->name); |
571 | trace_seq_printf(s, "ID: %d\n", call->id); | 542 | trace_seq_printf(s, "ID: %d\n", call->id); |
572 | trace_seq_printf(s, "format:\n"); | 543 | trace_seq_printf(s, "format:\n"); |
573 | trace_write_header(s); | ||
574 | 544 | ||
575 | r = call->show_format(call, s); | 545 | list_for_each_entry_reverse(field, &call->fields, link) { |
546 | /* | ||
547 | * Smartly shows the array type(except dynamic array). | ||
548 | * Normal: | ||
549 | * field:TYPE VAR | ||
550 | * If TYPE := TYPE[LEN], it is shown: | ||
551 | * field:TYPE VAR[LEN] | ||
552 | */ | ||
553 | const char *array_descriptor = strchr(field->type, '['); | ||
554 | |||
555 | if (!strncmp(field->type, "__data_loc", 10)) | ||
556 | array_descriptor = NULL; | ||
557 | |||
558 | if (!array_descriptor) { | ||
559 | r = trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" | ||
560 | "\tsize:%u;\tsigned:%d;\n", | ||
561 | field->type, field->name, field->offset, | ||
562 | field->size, !!field->is_signed); | ||
563 | } else { | ||
564 | r = trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" | ||
565 | "\tsize:%u;\tsigned:%d;\n", | ||
566 | (int)(array_descriptor - field->type), | ||
567 | field->type, field->name, | ||
568 | array_descriptor, field->offset, | ||
569 | field->size, !!field->is_signed); | ||
570 | } | ||
571 | |||
572 | if (--common_field_count == 0) | ||
573 | r = trace_seq_printf(s, "\n"); | ||
574 | |||
575 | if (!r) | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | if (r) | ||
580 | r = trace_seq_printf(s, "\nprint fmt: %s\n", | ||
581 | call->print_fmt); | ||
582 | |||
576 | if (!r) { | 583 | if (!r) { |
577 | /* | 584 | /* |
578 | * ug! The format output is bigger than a PAGE!! | 585 | * ug! The format output is bigger than a PAGE!! |
@@ -948,10 +955,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
948 | filter); | 955 | filter); |
949 | } | 956 | } |
950 | 957 | ||
951 | /* A trace may not want to export its format */ | ||
952 | if (!call->show_format) | ||
953 | return 0; | ||
954 | |||
955 | trace_create_file("format", 0444, call->dir, call, | 958 | trace_create_file("format", 0444, call->dir, call, |
956 | format); | 959 | format); |
957 | 960 | ||
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index d4fa5dc1ee4e..e091f64ba6ce 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c | |||
@@ -62,78 +62,6 @@ static void __always_unused ____ftrace_check_##name(void) \ | |||
62 | 62 | ||
63 | #include "trace_entries.h" | 63 | #include "trace_entries.h" |
64 | 64 | ||
65 | |||
66 | #undef __field | ||
67 | #define __field(type, item) \ | ||
68 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
69 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ | ||
70 | offsetof(typeof(field), item), \ | ||
71 | sizeof(field.item), is_signed_type(type)); \ | ||
72 | if (!ret) \ | ||
73 | return 0; | ||
74 | |||
75 | #undef __field_desc | ||
76 | #define __field_desc(type, container, item) \ | ||
77 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
78 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ | ||
79 | offsetof(typeof(field), container.item), \ | ||
80 | sizeof(field.container.item), \ | ||
81 | is_signed_type(type)); \ | ||
82 | if (!ret) \ | ||
83 | return 0; | ||
84 | |||
85 | #undef __array | ||
86 | #define __array(type, item, len) \ | ||
87 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ | ||
88 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ | ||
89 | offsetof(typeof(field), item), \ | ||
90 | sizeof(field.item), is_signed_type(type)); \ | ||
91 | if (!ret) \ | ||
92 | return 0; | ||
93 | |||
94 | #undef __array_desc | ||
95 | #define __array_desc(type, container, item, len) \ | ||
96 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ | ||
97 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ | ||
98 | offsetof(typeof(field), container.item), \ | ||
99 | sizeof(field.container.item), \ | ||
100 | is_signed_type(type)); \ | ||
101 | if (!ret) \ | ||
102 | return 0; | ||
103 | |||
104 | #undef __dynamic_array | ||
105 | #define __dynamic_array(type, item) \ | ||
106 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
107 | "offset:%zu;\tsize:0;\tsigned:%u;\n", \ | ||
108 | offsetof(typeof(field), item), \ | ||
109 | is_signed_type(type)); \ | ||
110 | if (!ret) \ | ||
111 | return 0; | ||
112 | |||
113 | #undef F_printk | ||
114 | #define F_printk(fmt, args...) "%s, %s\n", #fmt, __stringify(args) | ||
115 | |||
116 | #undef __entry | ||
117 | #define __entry REC | ||
118 | |||
119 | #undef FTRACE_ENTRY | ||
120 | #define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \ | ||
121 | static int \ | ||
122 | ftrace_format_##name(struct ftrace_event_call *unused, \ | ||
123 | struct trace_seq *s) \ | ||
124 | { \ | ||
125 | struct struct_name field __attribute__((unused)); \ | ||
126 | int ret = 0; \ | ||
127 | \ | ||
128 | tstruct; \ | ||
129 | \ | ||
130 | trace_seq_printf(s, "\nprint fmt: " print); \ | ||
131 | \ | ||
132 | return ret; \ | ||
133 | } | ||
134 | |||
135 | #include "trace_entries.h" | ||
136 | |||
137 | #undef __field | 65 | #undef __field |
138 | #define __field(type, item) \ | 66 | #define __field(type, item) \ |
139 | ret = trace_define_field(event_call, #type, #item, \ | 67 | ret = trace_define_field(event_call, #type, #item, \ |
@@ -175,7 +103,12 @@ ftrace_format_##name(struct ftrace_event_call *unused, \ | |||
175 | return ret; | 103 | return ret; |
176 | 104 | ||
177 | #undef __dynamic_array | 105 | #undef __dynamic_array |
178 | #define __dynamic_array(type, item) | 106 | #define __dynamic_array(type, item) \ |
107 | ret = trace_define_field(event_call, #type, #item, \ | ||
108 | offsetof(typeof(field), item), \ | ||
109 | 0, is_signed_type(type), FILTER_OTHER);\ | ||
110 | if (ret) \ | ||
111 | return ret; | ||
179 | 112 | ||
180 | #undef FTRACE_ENTRY | 113 | #undef FTRACE_ENTRY |
181 | #define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \ | 114 | #define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \ |
@@ -198,6 +131,9 @@ static int ftrace_raw_init_event(struct ftrace_event_call *call) | |||
198 | return 0; | 131 | return 0; |
199 | } | 132 | } |
200 | 133 | ||
134 | #undef __entry | ||
135 | #define __entry REC | ||
136 | |||
201 | #undef __field | 137 | #undef __field |
202 | #define __field(type, item) | 138 | #define __field(type, item) |
203 | 139 | ||
@@ -213,6 +149,9 @@ static int ftrace_raw_init_event(struct ftrace_event_call *call) | |||
213 | #undef __dynamic_array | 149 | #undef __dynamic_array |
214 | #define __dynamic_array(type, item) | 150 | #define __dynamic_array(type, item) |
215 | 151 | ||
152 | #undef F_printk | ||
153 | #define F_printk(fmt, args...) #fmt ", " __stringify(args) | ||
154 | |||
216 | #undef FTRACE_ENTRY | 155 | #undef FTRACE_ENTRY |
217 | #define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \ | 156 | #define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \ |
218 | \ | 157 | \ |
@@ -223,7 +162,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
223 | .id = type, \ | 162 | .id = type, \ |
224 | .system = __stringify(TRACE_SYSTEM), \ | 163 | .system = __stringify(TRACE_SYSTEM), \ |
225 | .raw_init = ftrace_raw_init_event, \ | 164 | .raw_init = ftrace_raw_init_event, \ |
226 | .show_format = ftrace_format_##call, \ | 165 | .print_fmt = print, \ |
227 | .define_fields = ftrace_define_fields_##call, \ | 166 | .define_fields = ftrace_define_fields_##call, \ |
228 | }; \ | 167 | }; \ |
229 | 168 | ||
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index b1342c5d37cf..e998a824e9db 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -18,6 +18,7 @@ struct fgraph_cpu_data { | |||
18 | pid_t last_pid; | 18 | pid_t last_pid; |
19 | int depth; | 19 | int depth; |
20 | int ignore; | 20 | int ignore; |
21 | unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; | ||
21 | }; | 22 | }; |
22 | 23 | ||
23 | struct fgraph_data { | 24 | struct fgraph_data { |
@@ -212,13 +213,11 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
212 | int cpu; | 213 | int cpu; |
213 | int pc; | 214 | int pc; |
214 | 215 | ||
215 | if (unlikely(!tr)) | ||
216 | return 0; | ||
217 | |||
218 | if (!ftrace_trace_task(current)) | 216 | if (!ftrace_trace_task(current)) |
219 | return 0; | 217 | return 0; |
220 | 218 | ||
221 | if (!ftrace_graph_addr(trace->func)) | 219 | /* trace it when it is-nested-in or is a function enabled. */ |
220 | if (!(trace->depth || ftrace_graph_addr(trace->func))) | ||
222 | return 0; | 221 | return 0; |
223 | 222 | ||
224 | local_irq_save(flags); | 223 | local_irq_save(flags); |
@@ -231,9 +230,6 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
231 | } else { | 230 | } else { |
232 | ret = 0; | 231 | ret = 0; |
233 | } | 232 | } |
234 | /* Only do the atomic if it is not already set */ | ||
235 | if (!test_tsk_trace_graph(current)) | ||
236 | set_tsk_trace_graph(current); | ||
237 | 233 | ||
238 | atomic_dec(&data->disabled); | 234 | atomic_dec(&data->disabled); |
239 | local_irq_restore(flags); | 235 | local_irq_restore(flags); |
@@ -281,17 +277,24 @@ void trace_graph_return(struct ftrace_graph_ret *trace) | |||
281 | pc = preempt_count(); | 277 | pc = preempt_count(); |
282 | __trace_graph_return(tr, trace, flags, pc); | 278 | __trace_graph_return(tr, trace, flags, pc); |
283 | } | 279 | } |
284 | if (!trace->depth) | ||
285 | clear_tsk_trace_graph(current); | ||
286 | atomic_dec(&data->disabled); | 280 | atomic_dec(&data->disabled); |
287 | local_irq_restore(flags); | 281 | local_irq_restore(flags); |
288 | } | 282 | } |
289 | 283 | ||
284 | void set_graph_array(struct trace_array *tr) | ||
285 | { | ||
286 | graph_array = tr; | ||
287 | |||
288 | /* Make graph_array visible before we start tracing */ | ||
289 | |||
290 | smp_mb(); | ||
291 | } | ||
292 | |||
290 | static int graph_trace_init(struct trace_array *tr) | 293 | static int graph_trace_init(struct trace_array *tr) |
291 | { | 294 | { |
292 | int ret; | 295 | int ret; |
293 | 296 | ||
294 | graph_array = tr; | 297 | set_graph_array(tr); |
295 | ret = register_ftrace_graph(&trace_graph_return, | 298 | ret = register_ftrace_graph(&trace_graph_return, |
296 | &trace_graph_entry); | 299 | &trace_graph_entry); |
297 | if (ret) | 300 | if (ret) |
@@ -301,11 +304,6 @@ static int graph_trace_init(struct trace_array *tr) | |||
301 | return 0; | 304 | return 0; |
302 | } | 305 | } |
303 | 306 | ||
304 | void set_graph_array(struct trace_array *tr) | ||
305 | { | ||
306 | graph_array = tr; | ||
307 | } | ||
308 | |||
309 | static void graph_trace_reset(struct trace_array *tr) | 307 | static void graph_trace_reset(struct trace_array *tr) |
310 | { | 308 | { |
311 | tracing_stop_cmdline_record(); | 309 | tracing_stop_cmdline_record(); |
@@ -673,15 +671,21 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
673 | duration = graph_ret->rettime - graph_ret->calltime; | 671 | duration = graph_ret->rettime - graph_ret->calltime; |
674 | 672 | ||
675 | if (data) { | 673 | if (data) { |
674 | struct fgraph_cpu_data *cpu_data; | ||
676 | int cpu = iter->cpu; | 675 | int cpu = iter->cpu; |
677 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | 676 | |
677 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | ||
678 | 678 | ||
679 | /* | 679 | /* |
680 | * Comments display at + 1 to depth. Since | 680 | * Comments display at + 1 to depth. Since |
681 | * this is a leaf function, keep the comments | 681 | * this is a leaf function, keep the comments |
682 | * equal to this depth. | 682 | * equal to this depth. |
683 | */ | 683 | */ |
684 | *depth = call->depth - 1; | 684 | cpu_data->depth = call->depth - 1; |
685 | |||
686 | /* No need to keep this function around for this depth */ | ||
687 | if (call->depth < FTRACE_RETFUNC_DEPTH) | ||
688 | cpu_data->enter_funcs[call->depth] = 0; | ||
685 | } | 689 | } |
686 | 690 | ||
687 | /* Overhead */ | 691 | /* Overhead */ |
@@ -721,10 +725,15 @@ print_graph_entry_nested(struct trace_iterator *iter, | |||
721 | int i; | 725 | int i; |
722 | 726 | ||
723 | if (data) { | 727 | if (data) { |
728 | struct fgraph_cpu_data *cpu_data; | ||
724 | int cpu = iter->cpu; | 729 | int cpu = iter->cpu; |
725 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | ||
726 | 730 | ||
727 | *depth = call->depth; | 731 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); |
732 | cpu_data->depth = call->depth; | ||
733 | |||
734 | /* Save this function pointer to see if the exit matches */ | ||
735 | if (call->depth < FTRACE_RETFUNC_DEPTH) | ||
736 | cpu_data->enter_funcs[call->depth] = call->func; | ||
728 | } | 737 | } |
729 | 738 | ||
730 | /* No overhead */ | 739 | /* No overhead */ |
@@ -854,19 +863,28 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
854 | struct fgraph_data *data = iter->private; | 863 | struct fgraph_data *data = iter->private; |
855 | pid_t pid = ent->pid; | 864 | pid_t pid = ent->pid; |
856 | int cpu = iter->cpu; | 865 | int cpu = iter->cpu; |
866 | int func_match = 1; | ||
857 | int ret; | 867 | int ret; |
858 | int i; | 868 | int i; |
859 | 869 | ||
860 | if (data) { | 870 | if (data) { |
871 | struct fgraph_cpu_data *cpu_data; | ||
861 | int cpu = iter->cpu; | 872 | int cpu = iter->cpu; |
862 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | 873 | |
874 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | ||
863 | 875 | ||
864 | /* | 876 | /* |
865 | * Comments display at + 1 to depth. This is the | 877 | * Comments display at + 1 to depth. This is the |
866 | * return from a function, we now want the comments | 878 | * return from a function, we now want the comments |
867 | * to display at the same level of the bracket. | 879 | * to display at the same level of the bracket. |
868 | */ | 880 | */ |
869 | *depth = trace->depth - 1; | 881 | cpu_data->depth = trace->depth - 1; |
882 | |||
883 | if (trace->depth < FTRACE_RETFUNC_DEPTH) { | ||
884 | if (cpu_data->enter_funcs[trace->depth] != trace->func) | ||
885 | func_match = 0; | ||
886 | cpu_data->enter_funcs[trace->depth] = 0; | ||
887 | } | ||
870 | } | 888 | } |
871 | 889 | ||
872 | if (print_graph_prologue(iter, s, 0, 0)) | 890 | if (print_graph_prologue(iter, s, 0, 0)) |
@@ -891,9 +909,21 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
891 | return TRACE_TYPE_PARTIAL_LINE; | 909 | return TRACE_TYPE_PARTIAL_LINE; |
892 | } | 910 | } |
893 | 911 | ||
894 | ret = trace_seq_printf(s, "}\n"); | 912 | /* |
895 | if (!ret) | 913 | * If the return function does not have a matching entry, |
896 | return TRACE_TYPE_PARTIAL_LINE; | 914 | * then the entry was lost. Instead of just printing |
915 | * the '}' and letting the user guess what function this | ||
916 | * belongs to, write out the function name. | ||
917 | */ | ||
918 | if (func_match) { | ||
919 | ret = trace_seq_printf(s, "}\n"); | ||
920 | if (!ret) | ||
921 | return TRACE_TYPE_PARTIAL_LINE; | ||
922 | } else { | ||
923 | ret = trace_seq_printf(s, "} (%ps)\n", (void *)trace->func); | ||
924 | if (!ret) | ||
925 | return TRACE_TYPE_PARTIAL_LINE; | ||
926 | } | ||
897 | 927 | ||
898 | /* Overrun */ | 928 | /* Overrun */ |
899 | if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { | 929 | if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 50b1b8239806..465b36bef4ca 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -651,12 +651,12 @@ static int create_trace_probe(int argc, char **argv) | |||
651 | event = strchr(group, '/') + 1; | 651 | event = strchr(group, '/') + 1; |
652 | event[-1] = '\0'; | 652 | event[-1] = '\0'; |
653 | if (strlen(group) == 0) { | 653 | if (strlen(group) == 0) { |
654 | pr_info("Group name is not specifiled\n"); | 654 | pr_info("Group name is not specified\n"); |
655 | return -EINVAL; | 655 | return -EINVAL; |
656 | } | 656 | } |
657 | } | 657 | } |
658 | if (strlen(event) == 0) { | 658 | if (strlen(event) == 0) { |
659 | pr_info("Event name is not specifiled\n"); | 659 | pr_info("Event name is not specified\n"); |
660 | return -EINVAL; | 660 | return -EINVAL; |
661 | } | 661 | } |
662 | } | 662 | } |
@@ -1174,80 +1174,60 @@ static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
1174 | return 0; | 1174 | return 0; |
1175 | } | 1175 | } |
1176 | 1176 | ||
1177 | static int __probe_event_show_format(struct trace_seq *s, | 1177 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len) |
1178 | struct trace_probe *tp, const char *fmt, | ||
1179 | const char *arg) | ||
1180 | { | 1178 | { |
1181 | int i; | 1179 | int i; |
1180 | int pos = 0; | ||
1182 | 1181 | ||
1183 | /* Show format */ | 1182 | const char *fmt, *arg; |
1184 | if (!trace_seq_printf(s, "\nprint fmt: \"%s", fmt)) | ||
1185 | return 0; | ||
1186 | 1183 | ||
1187 | for (i = 0; i < tp->nr_args; i++) | 1184 | if (!probe_is_return(tp)) { |
1188 | if (!trace_seq_printf(s, " %s=%%lx", tp->args[i].name)) | 1185 | fmt = "(%lx)"; |
1189 | return 0; | 1186 | arg = "REC->" FIELD_STRING_IP; |
1187 | } else { | ||
1188 | fmt = "(%lx <- %lx)"; | ||
1189 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | ||
1190 | } | ||
1190 | 1191 | ||
1191 | if (!trace_seq_printf(s, "\", %s", arg)) | 1192 | /* When len=0, we just calculate the needed length */ |
1192 | return 0; | 1193 | #define LEN_OR_ZERO (len ? len - pos : 0) |
1193 | 1194 | ||
1194 | for (i = 0; i < tp->nr_args; i++) | 1195 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
1195 | if (!trace_seq_printf(s, ", REC->%s", tp->args[i].name)) | ||
1196 | return 0; | ||
1197 | 1196 | ||
1198 | return trace_seq_puts(s, "\n"); | 1197 | for (i = 0; i < tp->nr_args; i++) { |
1199 | } | 1198 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%%lx", |
1199 | tp->args[i].name); | ||
1200 | } | ||
1200 | 1201 | ||
1201 | #undef SHOW_FIELD | 1202 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); |
1202 | #define SHOW_FIELD(type, item, name) \ | ||
1203 | do { \ | ||
1204 | ret = trace_seq_printf(s, "\tfield:" #type " %s;\t" \ | ||
1205 | "offset:%u;\tsize:%u;\tsigned:%d;\n", name,\ | ||
1206 | (unsigned int)offsetof(typeof(field), item),\ | ||
1207 | (unsigned int)sizeof(type), \ | ||
1208 | is_signed_type(type)); \ | ||
1209 | if (!ret) \ | ||
1210 | return 0; \ | ||
1211 | } while (0) | ||
1212 | 1203 | ||
1213 | static int kprobe_event_show_format(struct ftrace_event_call *call, | 1204 | for (i = 0; i < tp->nr_args; i++) { |
1214 | struct trace_seq *s) | 1205 | pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", |
1215 | { | 1206 | tp->args[i].name); |
1216 | struct kprobe_trace_entry field __attribute__((unused)); | 1207 | } |
1217 | int ret, i; | ||
1218 | struct trace_probe *tp = (struct trace_probe *)call->data; | ||
1219 | |||
1220 | SHOW_FIELD(unsigned long, ip, FIELD_STRING_IP); | ||
1221 | SHOW_FIELD(int, nargs, FIELD_STRING_NARGS); | ||
1222 | 1208 | ||
1223 | /* Show fields */ | 1209 | #undef LEN_OR_ZERO |
1224 | for (i = 0; i < tp->nr_args; i++) | ||
1225 | SHOW_FIELD(unsigned long, args[i], tp->args[i].name); | ||
1226 | trace_seq_puts(s, "\n"); | ||
1227 | 1210 | ||
1228 | return __probe_event_show_format(s, tp, "(%lx)", | 1211 | /* return the length of print_fmt */ |
1229 | "REC->" FIELD_STRING_IP); | 1212 | return pos; |
1230 | } | 1213 | } |
1231 | 1214 | ||
1232 | static int kretprobe_event_show_format(struct ftrace_event_call *call, | 1215 | static int set_print_fmt(struct trace_probe *tp) |
1233 | struct trace_seq *s) | ||
1234 | { | 1216 | { |
1235 | struct kretprobe_trace_entry field __attribute__((unused)); | 1217 | int len; |
1236 | int ret, i; | 1218 | char *print_fmt; |
1237 | struct trace_probe *tp = (struct trace_probe *)call->data; | ||
1238 | 1219 | ||
1239 | SHOW_FIELD(unsigned long, func, FIELD_STRING_FUNC); | 1220 | /* First: called with 0 length to calculate the needed length */ |
1240 | SHOW_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP); | 1221 | len = __set_print_fmt(tp, NULL, 0); |
1241 | SHOW_FIELD(int, nargs, FIELD_STRING_NARGS); | 1222 | print_fmt = kmalloc(len + 1, GFP_KERNEL); |
1223 | if (!print_fmt) | ||
1224 | return -ENOMEM; | ||
1242 | 1225 | ||
1243 | /* Show fields */ | 1226 | /* Second: actually write the @print_fmt */ |
1244 | for (i = 0; i < tp->nr_args; i++) | 1227 | __set_print_fmt(tp, print_fmt, len + 1); |
1245 | SHOW_FIELD(unsigned long, args[i], tp->args[i].name); | 1228 | tp->call.print_fmt = print_fmt; |
1246 | trace_seq_puts(s, "\n"); | ||
1247 | 1229 | ||
1248 | return __probe_event_show_format(s, tp, "(%lx <- %lx)", | 1230 | return 0; |
1249 | "REC->" FIELD_STRING_FUNC | ||
1250 | ", REC->" FIELD_STRING_RETIP); | ||
1251 | } | 1231 | } |
1252 | 1232 | ||
1253 | #ifdef CONFIG_EVENT_PROFILE | 1233 | #ifdef CONFIG_EVENT_PROFILE |
@@ -1448,18 +1428,20 @@ static int register_probe_event(struct trace_probe *tp) | |||
1448 | if (probe_is_return(tp)) { | 1428 | if (probe_is_return(tp)) { |
1449 | tp->event.trace = print_kretprobe_event; | 1429 | tp->event.trace = print_kretprobe_event; |
1450 | call->raw_init = probe_event_raw_init; | 1430 | call->raw_init = probe_event_raw_init; |
1451 | call->show_format = kretprobe_event_show_format; | ||
1452 | call->define_fields = kretprobe_event_define_fields; | 1431 | call->define_fields = kretprobe_event_define_fields; |
1453 | } else { | 1432 | } else { |
1454 | tp->event.trace = print_kprobe_event; | 1433 | tp->event.trace = print_kprobe_event; |
1455 | call->raw_init = probe_event_raw_init; | 1434 | call->raw_init = probe_event_raw_init; |
1456 | call->show_format = kprobe_event_show_format; | ||
1457 | call->define_fields = kprobe_event_define_fields; | 1435 | call->define_fields = kprobe_event_define_fields; |
1458 | } | 1436 | } |
1437 | if (set_print_fmt(tp) < 0) | ||
1438 | return -ENOMEM; | ||
1459 | call->event = &tp->event; | 1439 | call->event = &tp->event; |
1460 | call->id = register_ftrace_event(&tp->event); | 1440 | call->id = register_ftrace_event(&tp->event); |
1461 | if (!call->id) | 1441 | if (!call->id) { |
1442 | kfree(call->print_fmt); | ||
1462 | return -ENODEV; | 1443 | return -ENODEV; |
1444 | } | ||
1463 | call->enabled = 0; | 1445 | call->enabled = 0; |
1464 | call->regfunc = probe_event_enable; | 1446 | call->regfunc = probe_event_enable; |
1465 | call->unregfunc = probe_event_disable; | 1447 | call->unregfunc = probe_event_disable; |
@@ -1472,6 +1454,7 @@ static int register_probe_event(struct trace_probe *tp) | |||
1472 | ret = trace_add_event_call(call); | 1454 | ret = trace_add_event_call(call); |
1473 | if (ret) { | 1455 | if (ret) { |
1474 | pr_info("Failed to register kprobe event: %s\n", call->name); | 1456 | pr_info("Failed to register kprobe event: %s\n", call->name); |
1457 | kfree(call->print_fmt); | ||
1475 | unregister_ftrace_event(&tp->event); | 1458 | unregister_ftrace_event(&tp->event); |
1476 | } | 1459 | } |
1477 | return ret; | 1460 | return ret; |
@@ -1481,6 +1464,7 @@ static void unregister_probe_event(struct trace_probe *tp) | |||
1481 | { | 1464 | { |
1482 | /* tp->event is unregistered in trace_remove_event_call() */ | 1465 | /* tp->event is unregistered in trace_remove_event_call() */ |
1483 | trace_remove_event_call(&tp->call); | 1466 | trace_remove_event_call(&tp->call); |
1467 | kfree(tp->call.print_fmt); | ||
1484 | } | 1468 | } |
1485 | 1469 | ||
1486 | /* Make a debugfs interface for controling probe points */ | 1470 | /* Make a debugfs interface for controling probe points */ |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 75289f372dd2..a1834dda85f4 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -143,70 +143,65 @@ extern char *__bad_type_size(void); | |||
143 | #type, #name, offsetof(typeof(trace), name), \ | 143 | #type, #name, offsetof(typeof(trace), name), \ |
144 | sizeof(trace.name), is_signed_type(type) | 144 | sizeof(trace.name), is_signed_type(type) |
145 | 145 | ||
146 | int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | 146 | static |
147 | int __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len) | ||
147 | { | 148 | { |
148 | int i; | 149 | int i; |
149 | int ret; | 150 | int pos = 0; |
150 | struct syscall_metadata *entry = call->data; | ||
151 | struct syscall_trace_enter trace; | ||
152 | int offset = offsetof(struct syscall_trace_enter, args); | ||
153 | 151 | ||
154 | ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | 152 | /* When len=0, we just calculate the needed length */ |
155 | "\tsigned:%u;\n", | 153 | #define LEN_OR_ZERO (len ? len - pos : 0) |
156 | SYSCALL_FIELD(int, nr)); | ||
157 | if (!ret) | ||
158 | return 0; | ||
159 | 154 | ||
155 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); | ||
160 | for (i = 0; i < entry->nb_args; i++) { | 156 | for (i = 0; i < entry->nb_args; i++) { |
161 | ret = trace_seq_printf(s, "\tfield:%s %s;", entry->types[i], | 157 | pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s", |
162 | entry->args[i]); | 158 | entry->args[i], sizeof(unsigned long), |
163 | if (!ret) | 159 | i == entry->nb_args - 1 ? "" : ", "); |
164 | return 0; | ||
165 | ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;" | ||
166 | "\tsigned:%u;\n", offset, | ||
167 | sizeof(unsigned long), | ||
168 | is_signed_type(unsigned long)); | ||
169 | if (!ret) | ||
170 | return 0; | ||
171 | offset += sizeof(unsigned long); | ||
172 | } | 160 | } |
161 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); | ||
173 | 162 | ||
174 | trace_seq_puts(s, "\nprint fmt: \""); | ||
175 | for (i = 0; i < entry->nb_args; i++) { | 163 | for (i = 0; i < entry->nb_args; i++) { |
176 | ret = trace_seq_printf(s, "%s: 0x%%0%zulx%s", entry->args[i], | 164 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
177 | sizeof(unsigned long), | 165 | ", ((unsigned long)(REC->%s))", entry->args[i]); |
178 | i == entry->nb_args - 1 ? "" : ", "); | ||
179 | if (!ret) | ||
180 | return 0; | ||
181 | } | 166 | } |
182 | trace_seq_putc(s, '"'); | ||
183 | 167 | ||
184 | for (i = 0; i < entry->nb_args; i++) { | 168 | #undef LEN_OR_ZERO |
185 | ret = trace_seq_printf(s, ", ((unsigned long)(REC->%s))", | ||
186 | entry->args[i]); | ||
187 | if (!ret) | ||
188 | return 0; | ||
189 | } | ||
190 | 169 | ||
191 | return trace_seq_putc(s, '\n'); | 170 | /* return the length of print_fmt */ |
171 | return pos; | ||
192 | } | 172 | } |
193 | 173 | ||
194 | int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) | 174 | static int set_syscall_print_fmt(struct ftrace_event_call *call) |
195 | { | 175 | { |
196 | int ret; | 176 | char *print_fmt; |
197 | struct syscall_trace_exit trace; | 177 | int len; |
178 | struct syscall_metadata *entry = call->data; | ||
198 | 179 | ||
199 | ret = trace_seq_printf(s, | 180 | if (entry->enter_event != call) { |
200 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | 181 | call->print_fmt = "\"0x%lx\", REC->ret"; |
201 | "\tsigned:%u;\n" | ||
202 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | ||
203 | "\tsigned:%u;\n", | ||
204 | SYSCALL_FIELD(int, nr), | ||
205 | SYSCALL_FIELD(long, ret)); | ||
206 | if (!ret) | ||
207 | return 0; | 182 | return 0; |
183 | } | ||
208 | 184 | ||
209 | return trace_seq_printf(s, "\nprint fmt: \"0x%%lx\", REC->ret\n"); | 185 | /* First: called with 0 length to calculate the needed length */ |
186 | len = __set_enter_print_fmt(entry, NULL, 0); | ||
187 | |||
188 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | ||
189 | if (!print_fmt) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | /* Second: actually write the @print_fmt */ | ||
193 | __set_enter_print_fmt(entry, print_fmt, len + 1); | ||
194 | call->print_fmt = print_fmt; | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static void free_syscall_print_fmt(struct ftrace_event_call *call) | ||
200 | { | ||
201 | struct syscall_metadata *entry = call->data; | ||
202 | |||
203 | if (entry->enter_event == call) | ||
204 | kfree(call->print_fmt); | ||
210 | } | 205 | } |
211 | 206 | ||
212 | int syscall_enter_define_fields(struct ftrace_event_call *call) | 207 | int syscall_enter_define_fields(struct ftrace_event_call *call) |
@@ -386,12 +381,22 @@ int init_syscall_trace(struct ftrace_event_call *call) | |||
386 | { | 381 | { |
387 | int id; | 382 | int id; |
388 | 383 | ||
389 | id = register_ftrace_event(call->event); | 384 | if (set_syscall_print_fmt(call) < 0) |
390 | if (!id) | 385 | return -ENOMEM; |
391 | return -ENODEV; | 386 | |
392 | call->id = id; | 387 | id = trace_event_raw_init(call); |
393 | INIT_LIST_HEAD(&call->fields); | 388 | |
394 | return 0; | 389 | if (id < 0) { |
390 | free_syscall_print_fmt(call); | ||
391 | return id; | ||
392 | } | ||
393 | |||
394 | return id; | ||
395 | } | ||
396 | |||
397 | unsigned long __init arch_syscall_addr(int nr) | ||
398 | { | ||
399 | return (unsigned long)sys_call_table[nr]; | ||
395 | } | 400 | } |
396 | 401 | ||
397 | int __init init_ftrace_syscalls(void) | 402 | int __init init_ftrace_syscalls(void) |
@@ -603,7 +608,7 @@ int prof_sysexit_enable(struct ftrace_event_call *call) | |||
603 | ret = register_trace_sys_exit(prof_syscall_exit); | 608 | ret = register_trace_sys_exit(prof_syscall_exit); |
604 | if (ret) { | 609 | if (ret) { |
605 | pr_info("event trace: Could not activate" | 610 | pr_info("event trace: Could not activate" |
606 | "syscall entry trace point"); | 611 | "syscall exit trace point"); |
607 | } else { | 612 | } else { |
608 | set_bit(num, enabled_prof_exit_syscalls); | 613 | set_bit(num, enabled_prof_exit_syscalls); |
609 | sys_prof_refcount_exit++; | 614 | sys_prof_refcount_exit++; |
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index ea6f6e3adaea..f3c9c0a90b98 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
@@ -136,13 +136,14 @@ my %text_sections = ( | |||
136 | ".text.unlikely" => 1, | 136 | ".text.unlikely" => 1, |
137 | ); | 137 | ); |
138 | 138 | ||
139 | $objdump = "objdump" if ((length $objdump) == 0); | 139 | # Note: we are nice to C-programmers here, thus we skip the '||='-idiom. |
140 | $objcopy = "objcopy" if ((length $objcopy) == 0); | 140 | $objdump = 'objdump' if (!$objdump); |
141 | $cc = "gcc" if ((length $cc) == 0); | 141 | $objcopy = 'objcopy' if (!$objcopy); |
142 | $ld = "ld" if ((length $ld) == 0); | 142 | $cc = 'gcc' if (!$cc); |
143 | $nm = "nm" if ((length $nm) == 0); | 143 | $ld = 'ld' if (!$ld); |
144 | $rm = "rm" if ((length $rm) == 0); | 144 | $nm = 'nm' if (!$nm); |
145 | $mv = "mv" if ((length $mv) == 0); | 145 | $rm = 'rm' if (!$rm); |
146 | $mv = 'mv' if (!$mv); | ||
146 | 147 | ||
147 | #print STDERR "running: $P '$arch' '$objdump' '$objcopy' '$cc' '$ld' " . | 148 | #print STDERR "running: $P '$arch' '$objdump' '$objcopy' '$cc' '$ld' " . |
148 | # "'$nm' '$rm' '$mv' '$inputfile'\n"; | 149 | # "'$nm' '$rm' '$mv' '$inputfile'\n"; |
@@ -432,14 +433,14 @@ sub update_funcs | |||
432 | 433 | ||
433 | # Loop through all the mcount caller offsets and print a reference | 434 | # Loop through all the mcount caller offsets and print a reference |
434 | # to the caller based from the ref_func. | 435 | # to the caller based from the ref_func. |
435 | for (my $i=0; $i <= $#offsets; $i++) { | 436 | if (!$opened) { |
436 | if (!$opened) { | 437 | open(FILE, ">$mcount_s") || die "can't create $mcount_s\n"; |
437 | open(FILE, ">$mcount_s") || die "can't create $mcount_s\n"; | 438 | $opened = 1; |
438 | $opened = 1; | 439 | print FILE "\t.section $mcount_section,\"a\",$section_type\n"; |
439 | print FILE "\t.section $mcount_section,\"a\",$section_type\n"; | 440 | print FILE "\t.align $alignment\n" if (defined($alignment)); |
440 | print FILE "\t.align $alignment\n" if (defined($alignment)); | 441 | } |
441 | } | 442 | foreach my $cur_offset (@offsets) { |
442 | printf FILE "\t%s %s + %d\n", $type, $ref_func, $offsets[$i] - $offset; | 443 | printf FILE "\t%s %s + %d\n", $type, $ref_func, $cur_offset - $offset; |
443 | } | 444 | } |
444 | } | 445 | } |
445 | 446 | ||
@@ -476,11 +477,7 @@ while (<IN>) { | |||
476 | $read_headers = 0; | 477 | $read_headers = 0; |
477 | 478 | ||
478 | # Only record text sections that we know are safe | 479 | # Only record text sections that we know are safe |
479 | if (defined($text_sections{$1})) { | 480 | $read_function = defined($text_sections{$1}); |
480 | $read_function = 1; | ||
481 | } else { | ||
482 | $read_function = 0; | ||
483 | } | ||
484 | # print out any recorded offsets | 481 | # print out any recorded offsets |
485 | update_funcs(); | 482 | update_funcs(); |
486 | 483 | ||
@@ -514,7 +511,7 @@ while (<IN>) { | |||
514 | } | 511 | } |
515 | # is this a call site to mcount? If so, record it to print later | 512 | # is this a call site to mcount? If so, record it to print later |
516 | if ($text_found && /$mcount_regex/) { | 513 | if ($text_found && /$mcount_regex/) { |
517 | $offsets[$#offsets + 1] = hex $1; | 514 | push(@offsets, hex $1); |
518 | } | 515 | } |
519 | } | 516 | } |
520 | 517 | ||