diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2009-06-12 04:26:46 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-12 04:27:39 -0400 |
commit | 88dbd2037229bd2ed7543ffd0d8f2d9dec9d31d2 (patch) | |
tree | 60dd9e5ec02fb95872809c7076a4e717fc82dea5 /arch/s390/kernel/ftrace.c | |
parent | 8b4488f85d619253c9e631ec723368f400106771 (diff) |
[S390] ftrace: add function graph tracer support
Function graph tracer support for s390.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/ftrace.c')
-rw-r--r-- | arch/s390/kernel/ftrace.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 0b81a784e039..c92a10953279 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
@@ -7,13 +7,17 @@ | |||
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/hardirq.h> | ||
10 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
11 | #include <linux/ftrace.h> | 12 | #include <linux/ftrace.h> |
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
14 | #include <asm/lowcore.h> | 15 | #include <asm/lowcore.h> |
15 | 16 | ||
17 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
18 | |||
16 | void ftrace_disable_code(void); | 19 | void ftrace_disable_code(void); |
20 | void ftrace_disable_return(void); | ||
17 | void ftrace_call_code(void); | 21 | void ftrace_call_code(void); |
18 | void ftrace_nop_code(void); | 22 | void ftrace_nop_code(void); |
19 | 23 | ||
@@ -28,6 +32,7 @@ asm( | |||
28 | " .word 0x0024\n" | 32 | " .word 0x0024\n" |
29 | " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n" | 33 | " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n" |
30 | " basr %r14,%r1\n" | 34 | " basr %r14,%r1\n" |
35 | "ftrace_disable_return:\n" | ||
31 | " lg %r14,8(15)\n" | 36 | " lg %r14,8(15)\n" |
32 | " lgr %r0,%r0\n" | 37 | " lgr %r0,%r0\n" |
33 | "0:\n"); | 38 | "0:\n"); |
@@ -50,6 +55,7 @@ asm( | |||
50 | " j 0f\n" | 55 | " j 0f\n" |
51 | " l %r1,"__stringify(__LC_FTRACE_FUNC)"\n" | 56 | " l %r1,"__stringify(__LC_FTRACE_FUNC)"\n" |
52 | " basr %r14,%r1\n" | 57 | " basr %r14,%r1\n" |
58 | "ftrace_disable_return:\n" | ||
53 | " l %r14,4(%r15)\n" | 59 | " l %r14,4(%r15)\n" |
54 | " j 0f\n" | 60 | " j 0f\n" |
55 | " bcr 0,%r7\n" | 61 | " bcr 0,%r7\n" |
@@ -130,3 +136,69 @@ int __init ftrace_dyn_arch_init(void *data) | |||
130 | *(unsigned long *)data = 0; | 136 | *(unsigned long *)data = 0; |
131 | return 0; | 137 | return 0; |
132 | } | 138 | } |
139 | |||
140 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
141 | |||
142 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
143 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
144 | /* | ||
145 | * Patch the kernel code at ftrace_graph_caller location: | ||
146 | * The instruction there is branch relative on condition. The condition mask | ||
147 | * is either all ones (always branch aka disable ftrace_graph_caller) or all | ||
148 | * zeroes (nop aka enable ftrace_graph_caller). | ||
149 | * Instruction format for brc is a7m4xxxx where m is the condition mask. | ||
150 | */ | ||
151 | int ftrace_enable_ftrace_graph_caller(void) | ||
152 | { | ||
153 | unsigned short opcode = 0xa704; | ||
154 | |||
155 | return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode)); | ||
156 | } | ||
157 | |||
158 | int ftrace_disable_ftrace_graph_caller(void) | ||
159 | { | ||
160 | unsigned short opcode = 0xa7f4; | ||
161 | |||
162 | return probe_kernel_write(ftrace_graph_caller, &opcode, sizeof(opcode)); | ||
163 | } | ||
164 | |||
165 | static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr) | ||
166 | { | ||
167 | return addr - (ftrace_disable_return - ftrace_disable_code); | ||
168 | } | ||
169 | |||
170 | #else /* CONFIG_DYNAMIC_FTRACE */ | ||
171 | |||
172 | static inline unsigned long ftrace_mcount_call_adjust(unsigned long addr) | ||
173 | { | ||
174 | return addr - MCOUNT_OFFSET_RET; | ||
175 | } | ||
176 | |||
177 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
178 | |||
179 | /* | ||
180 | * Hook the return address and push it in the stack of return addresses | ||
181 | * in current thread info. | ||
182 | */ | ||
183 | unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent) | ||
184 | { | ||
185 | struct ftrace_graph_ent trace; | ||
186 | |||
187 | /* Nmi's are currently unsupported. */ | ||
188 | if (unlikely(in_nmi())) | ||
189 | goto out; | ||
190 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
191 | goto out; | ||
192 | if (ftrace_push_return_trace(parent, ip, &trace.depth) == -EBUSY) | ||
193 | goto out; | ||
194 | trace.func = ftrace_mcount_call_adjust(ip) & PSW_ADDR_INSN; | ||
195 | /* Only trace if the calling function expects to. */ | ||
196 | if (!ftrace_graph_entry(&trace)) { | ||
197 | current->curr_ret_stack--; | ||
198 | goto out; | ||
199 | } | ||
200 | parent = (unsigned long)return_to_handler; | ||
201 | out: | ||
202 | return parent; | ||
203 | } | ||
204 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||