xref: /openbmc/linux/arch/s390/kernel/ftrace.c (revision c1d45424)
1 /*
2  * Dynamic function tracer architecture backend.
3  *
4  * Copyright IBM Corp. 2009
5  *
6  *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
7  *		Martin Schwidefsky <schwidefsky@de.ibm.com>
8  */
9 
10 #include <linux/hardirq.h>
11 #include <linux/uaccess.h>
12 #include <linux/ftrace.h>
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/kprobes.h>
16 #include <trace/syscall.h>
17 #include <asm/asm-offsets.h>
18 
19 #ifdef CONFIG_DYNAMIC_FTRACE
20 
21 void ftrace_disable_code(void);
22 void ftrace_enable_insn(void);
23 
24 #ifdef CONFIG_64BIT
25 /*
26  * The 64-bit mcount code looks like this:
27  *	stg	%r14,8(%r15)		# offset 0
28  * >	larl	%r1,<&counter>		# offset 6
29  * >	brasl	%r14,_mcount		# offset 12
30  *	lg	%r14,8(%r15)		# offset 18
31  * Total length is 24 bytes. The middle two instructions of the mcount
32  * block get overwritten by ftrace_make_nop / ftrace_make_call.
33  * The 64-bit enabled ftrace code block looks like this:
34  *	stg	%r14,8(%r15)		# offset 0
35  * >	lg	%r1,__LC_FTRACE_FUNC	# offset 6
36  * >	lgr	%r0,%r0			# offset 12
37  * >	basr	%r14,%r1		# offset 16
38  *	lg	%r14,8(%15)		# offset 18
39  * The return points of the mcount/ftrace function have the same offset 18.
40  * The 64-bit disable ftrace code block looks like this:
41  *	stg	%r14,8(%r15)		# offset 0
42  * >	jg	.+18			# offset 6
43  * >	lgr	%r0,%r0			# offset 12
44  * >	basr	%r14,%r1		# offset 16
45  *	lg	%r14,8(%15)		# offset 18
46  * The jg instruction branches to offset 24 to skip as many instructions
47  * as possible.
48  */
49 asm(
50 	"	.align	4\n"
51 	"ftrace_disable_code:\n"
52 	"	jg	0f\n"
53 	"	lgr	%r0,%r0\n"
54 	"	basr	%r14,%r1\n"
55 	"0:\n"
56 	"	.align	4\n"
57 	"ftrace_enable_insn:\n"
58 	"	lg	%r1,"__stringify(__LC_FTRACE_FUNC)"\n");
59 
60 #define FTRACE_INSN_SIZE	6
61 
62 #else /* CONFIG_64BIT */
63 /*
64  * The 31-bit mcount code looks like this:
65  *	st	%r14,4(%r15)		# offset 0
66  * >	bras	%r1,0f			# offset 4
67  * >	.long	_mcount			# offset 8
68  * >	.long	<&counter>		# offset 12
69  * > 0:	l	%r14,0(%r1)		# offset 16
70  * >	l	%r1,4(%r1)		# offset 20
71  *	basr	%r14,%r14		# offset 24
72  *	l	%r14,4(%r15)		# offset 26
73  * Total length is 30 bytes. The twenty bytes starting from offset 4
74  * to offset 24 get overwritten by ftrace_make_nop / ftrace_make_call.
75  * The 31-bit enabled ftrace code block looks like this:
76  *	st	%r14,4(%r15)		# offset 0
77  * >	l	%r14,__LC_FTRACE_FUNC	# offset 4
78  * >	j	0f			# offset 8
79  * >	.fill	12,1,0x07		# offset 12
80  *   0:	basr	%r14,%r14		# offset 24
81  *	l	%r14,4(%r14)		# offset 26
82  * The return points of the mcount/ftrace function have the same offset 26.
83  * The 31-bit disabled ftrace code block looks like this:
84  *	st	%r14,4(%r15)		# offset 0
85  * >	j	.+26			# offset 4
86  * >	j	0f			# offset 8
87  * >	.fill	12,1,0x07		# offset 12
88  *   0:	basr	%r14,%r14		# offset 24
89  *	l	%r14,4(%r14)		# offset 26
90  * The j instruction branches to offset 30 to skip as many instructions
91  * as possible.
92  */
93 asm(
94 	"	.align	4\n"
95 	"ftrace_disable_code:\n"
96 	"	j	1f\n"
97 	"	j	0f\n"
98 	"	.fill	12,1,0x07\n"
99 	"0:	basr	%r14,%r14\n"
100 	"1:\n"
101 	"	.align	4\n"
102 	"ftrace_enable_insn:\n"
103 	"	l	%r14,"__stringify(__LC_FTRACE_FUNC)"\n");
104 
105 #define FTRACE_INSN_SIZE	4
106 
107 #endif /* CONFIG_64BIT */
108 
109 
110 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
111 		    unsigned long addr)
112 {
113 	if (probe_kernel_write((void *) rec->ip, ftrace_disable_code,
114 			       MCOUNT_INSN_SIZE))
115 		return -EPERM;
116 	return 0;
117 }
118 
119 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
120 {
121 	if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn,
122 			       FTRACE_INSN_SIZE))
123 		return -EPERM;
124 	return 0;
125 }
126 
127 int ftrace_update_ftrace_func(ftrace_func_t func)
128 {
129 	return 0;
130 }
131 
132 int __init ftrace_dyn_arch_init(void *data)
133 {
134 	*(unsigned long *) data = 0;
135 	return 0;
136 }
137 
138 #endif /* CONFIG_DYNAMIC_FTRACE */
139 
140 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
141 /*
142  * Hook the return address and push it in the stack of return addresses
143  * in current thread info.
144  */
145 unsigned long __kprobes prepare_ftrace_return(unsigned long parent,
146 					      unsigned long ip)
147 {
148 	struct ftrace_graph_ent trace;
149 
150 	if (unlikely(atomic_read(&current->tracing_graph_pause)))
151 		goto out;
152 	ip = (ip & PSW_ADDR_INSN) - MCOUNT_INSN_SIZE;
153 	if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY)
154 		goto out;
155 	trace.func = ip;
156 	/* Only trace if the calling function expects to. */
157 	if (!ftrace_graph_entry(&trace)) {
158 		current->curr_ret_stack--;
159 		goto out;
160 	}
161 	parent = (unsigned long) return_to_handler;
162 out:
163 	return parent;
164 }
165 
166 #ifdef CONFIG_DYNAMIC_FTRACE
167 /*
168  * Patch the kernel code at ftrace_graph_caller location. The instruction
169  * there is branch relative and save to prepare_ftrace_return. To disable
170  * the call to prepare_ftrace_return we patch the bras offset to point
171  * directly after the instructions. To enable the call we calculate
172  * the original offset to prepare_ftrace_return and put it back.
173  */
174 int ftrace_enable_ftrace_graph_caller(void)
175 {
176 	unsigned short offset;
177 
178 	offset = ((void *) prepare_ftrace_return -
179 		  (void *) ftrace_graph_caller) / 2;
180 	return probe_kernel_write(ftrace_graph_caller + 2,
181 				  &offset, sizeof(offset));
182 }
183 
184 int ftrace_disable_ftrace_graph_caller(void)
185 {
186 	static unsigned short offset = 0x0002;
187 
188 	return probe_kernel_write(ftrace_graph_caller + 2,
189 				  &offset, sizeof(offset));
190 }
191 
192 #endif /* CONFIG_DYNAMIC_FTRACE */
193 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
194