@@ -94,104 +94,123 @@ static unsigned long find_ftrace_tramp(unsigned long ip)
94
94
return 0 ;
95
95
}
96
96
97
- #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
98
- int ftrace_modify_call (struct dyn_ftrace * rec , unsigned long old_addr , unsigned long addr )
97
+ static int ftrace_get_call_inst (struct dyn_ftrace * rec , unsigned long addr , ppc_inst_t * call_inst )
99
98
{
100
- unsigned long tramp , tramp_old , ip = rec -> ip ;
101
- ppc_inst_t old , new ;
102
- struct module * mod ;
99
+ unsigned long ip = rec -> ip ;
100
+ unsigned long stub ;
103
101
104
- if (is_offset_in_branch_range (old_addr - ip ) && is_offset_in_branch_range ( addr - ip )) {
102
+ if (is_offset_in_branch_range (addr - ip )) {
105
103
/* Within range */
106
- old = ftrace_create_branch_inst (ip , old_addr , 1 );
107
- new = ftrace_create_branch_inst (ip , addr , 1 );
108
- return ftrace_modify_code (ip , old , new );
109
- } else if (core_kernel_text (ip )) {
110
- /*
111
- * We always patch out of range locations to go to the regs
112
- * variant, so there is nothing to do here
113
- */
114
- return 0 ;
115
- } else if (IS_ENABLED (CONFIG_MODULES )) {
104
+ stub = addr ;
105
+ #ifdef CONFIG_MODULES
106
+ } else if (rec -> arch .mod ) {
116
107
/* Module code would be going to one of the module stubs */
117
- mod = rec -> arch .mod ;
118
- if (addr == (unsigned long )ftrace_caller ) {
119
- tramp_old = mod -> arch .tramp_regs ;
120
- tramp = mod -> arch .tramp ;
121
- } else {
122
- tramp_old = mod -> arch .tramp ;
123
- tramp = mod -> arch .tramp_regs ;
108
+ stub = (addr == (unsigned long )ftrace_caller ? rec -> arch .mod -> arch .tramp :
109
+ rec -> arch .mod -> arch .tramp_regs );
110
+ #endif
111
+ } else if (core_kernel_text (ip )) {
112
+ /* We would be branching to one of our ftrace stubs */
113
+ stub = find_ftrace_tramp (ip );
114
+ if (!stub ) {
115
+ pr_err ("0x%lx: No ftrace stubs reachable\n" , ip );
116
+ return - EINVAL ;
124
117
}
125
- old = ftrace_create_branch_inst (ip , tramp_old , 1 );
126
- new = ftrace_create_branch_inst (ip , tramp , 1 );
127
- return ftrace_modify_code (ip , old , new );
118
+ } else {
119
+ return - EINVAL ;
128
120
}
129
121
122
+ * call_inst = ftrace_create_branch_inst (ip , stub , 1 );
123
+ return 0 ;
124
+ }
125
+
126
+ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
127
+ int ftrace_modify_call (struct dyn_ftrace * rec , unsigned long old_addr , unsigned long addr )
128
+ {
129
+ /* This should never be called since we override ftrace_replace_code() */
130
+ WARN_ON (1 );
130
131
return - EINVAL ;
131
132
}
132
133
#endif
133
134
134
135
int ftrace_make_call (struct dyn_ftrace * rec , unsigned long addr )
135
136
{
136
- unsigned long tramp , ip = rec -> ip ;
137
137
ppc_inst_t old , new ;
138
- struct module * mod ;
138
+ int ret ;
139
+
140
+ /* This can only ever be called during module load */
141
+ if (WARN_ON (!IS_ENABLED (CONFIG_MODULES ) || core_kernel_text (rec -> ip )))
142
+ return - EINVAL ;
139
143
140
144
old = ppc_inst (PPC_RAW_NOP ());
141
- if (is_offset_in_branch_range (addr - ip )) {
142
- /* Within range */
143
- new = ftrace_create_branch_inst (ip , addr , 1 );
144
- return ftrace_modify_code (ip , old , new );
145
- } else if (core_kernel_text (ip )) {
146
- /* We would be branching to one of our ftrace tramps */
147
- tramp = find_ftrace_tramp (ip );
148
- if (!tramp ) {
149
- pr_err ("0x%lx: No ftrace trampolines reachable\n" , ip );
150
- return - EINVAL ;
151
- }
152
- new = ftrace_create_branch_inst (ip , tramp , 1 );
153
- return ftrace_modify_code (ip , old , new );
154
- } else if (IS_ENABLED (CONFIG_MODULES )) {
155
- /* Module code would be going to one of the module stubs */
156
- mod = rec -> arch .mod ;
157
- tramp = (addr == (unsigned long )ftrace_caller ? mod -> arch .tramp : mod -> arch .tramp_regs );
158
- new = ftrace_create_branch_inst (ip , tramp , 1 );
159
- return ftrace_modify_code (ip , old , new );
160
- }
145
+ ret = ftrace_get_call_inst (rec , addr , & new );
146
+ if (ret )
147
+ return ret ;
161
148
162
- return - EINVAL ;
149
+ return ftrace_modify_code ( rec -> ip , old , new ) ;
163
150
}
164
151
165
152
int ftrace_make_nop (struct module * mod , struct dyn_ftrace * rec , unsigned long addr )
166
153
{
167
- unsigned long tramp , ip = rec -> ip ;
168
- ppc_inst_t old , new ;
154
+ /*
155
+ * This should never be called since we override ftrace_replace_code(),
156
+ * as well as ftrace_init_nop()
157
+ */
158
+ WARN_ON (1 );
159
+ return - EINVAL ;
160
+ }
169
161
170
- /* Nop-out the ftrace location */
171
- new = ppc_inst (PPC_RAW_NOP ());
172
- if (is_offset_in_branch_range (addr - ip )) {
173
- /* Within range */
174
- old = ftrace_create_branch_inst (ip , addr , 1 );
175
- return ftrace_modify_code (ip , old , new );
176
- } else if (core_kernel_text (ip )) {
177
- /* We would be branching to one of our ftrace tramps */
178
- tramp = find_ftrace_tramp (ip );
179
- if (!tramp ) {
180
- pr_err ("0x%lx: No ftrace trampolines reachable\n" , ip );
181
- return - EINVAL ;
162
+ void ftrace_replace_code (int enable )
163
+ {
164
+ ppc_inst_t old , new , call_inst , new_call_inst ;
165
+ ppc_inst_t nop_inst = ppc_inst (PPC_RAW_NOP ());
166
+ unsigned long ip , new_addr , addr ;
167
+ struct ftrace_rec_iter * iter ;
168
+ struct dyn_ftrace * rec ;
169
+ int ret = 0 , update ;
170
+
171
+ for_ftrace_rec_iter (iter ) {
172
+ rec = ftrace_rec_iter_record (iter );
173
+ ip = rec -> ip ;
174
+
175
+ if (rec -> flags & FTRACE_FL_DISABLED && !(rec -> flags & FTRACE_FL_ENABLED ))
176
+ continue ;
177
+
178
+ addr = ftrace_get_addr_curr (rec );
179
+ new_addr = ftrace_get_addr_new (rec );
180
+ update = ftrace_update_record (rec , enable );
181
+
182
+ switch (update ) {
183
+ case FTRACE_UPDATE_IGNORE :
184
+ default :
185
+ continue ;
186
+ case FTRACE_UPDATE_MODIFY_CALL :
187
+ ret = ftrace_get_call_inst (rec , new_addr , & new_call_inst );
188
+ ret |= ftrace_get_call_inst (rec , addr , & call_inst );
189
+ old = call_inst ;
190
+ new = new_call_inst ;
191
+ break ;
192
+ case FTRACE_UPDATE_MAKE_NOP :
193
+ ret = ftrace_get_call_inst (rec , addr , & call_inst );
194
+ old = call_inst ;
195
+ new = nop_inst ;
196
+ break ;
197
+ case FTRACE_UPDATE_MAKE_CALL :
198
+ ret = ftrace_get_call_inst (rec , new_addr , & call_inst );
199
+ old = nop_inst ;
200
+ new = call_inst ;
201
+ break ;
182
202
}
183
- old = ftrace_create_branch_inst (ip , tramp , 1 );
184
- return ftrace_modify_code (ip , old , new );
185
- } else if (IS_ENABLED (CONFIG_MODULES )) {
186
- /* Module code would be going to one of the module stubs */
187
- if (!mod )
188
- mod = rec -> arch .mod ;
189
- tramp = (addr == (unsigned long )ftrace_caller ? mod -> arch .tramp : mod -> arch .tramp_regs );
190
- old = ftrace_create_branch_inst (ip , tramp , 1 );
191
- return ftrace_modify_code (ip , old , new );
203
+
204
+ if (!ret )
205
+ ret = ftrace_modify_code (ip , old , new );
206
+ if (ret )
207
+ goto out ;
192
208
}
193
209
194
- return - EINVAL ;
210
+ out :
211
+ if (ret )
212
+ ftrace_bug (ret , rec );
213
+ return ;
195
214
}
196
215
197
216
int ftrace_init_nop (struct module * mod , struct dyn_ftrace * rec )
0 commit comments