diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_functions.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index 36bf9568ccd9..5c95708b9dc3 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * Copyright (C) 2004-2006 Ingo Molnar | 9 | * Copyright (C) 2004-2006 Ingo Molnar |
10 | * Copyright (C) 2004 William Lee Irwin III | 10 | * Copyright (C) 2004 William Lee Irwin III |
11 | */ | 11 | */ |
12 | #include <linux/ring_buffer.h> | ||
12 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
13 | #include <linux/uaccess.h> | 14 | #include <linux/uaccess.h> |
14 | #include <linux/ftrace.h> | 15 | #include <linux/ftrace.h> |
@@ -231,9 +232,143 @@ static struct tracer function_trace __read_mostly = | |||
231 | #endif | 232 | #endif |
232 | }; | 233 | }; |
233 | 234 | ||
235 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
236 | static void | ||
237 | ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data) | ||
238 | { | ||
239 | long *count = (long *)data; | ||
240 | |||
241 | if (tracing_is_on()) | ||
242 | return; | ||
243 | |||
244 | if (!*count) | ||
245 | return; | ||
246 | |||
247 | if (*count != -1) | ||
248 | (*count)--; | ||
249 | |||
250 | tracing_on(); | ||
251 | } | ||
252 | |||
253 | static void | ||
254 | ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data) | ||
255 | { | ||
256 | long *count = (long *)data; | ||
257 | |||
258 | if (!tracing_is_on()) | ||
259 | return; | ||
260 | |||
261 | if (!*count) | ||
262 | return; | ||
263 | |||
264 | if (*count != -1) | ||
265 | (*count)--; | ||
266 | |||
267 | tracing_off(); | ||
268 | } | ||
269 | |||
270 | static struct ftrace_hook_ops traceon_hook_ops = { | ||
271 | .func = ftrace_traceon, | ||
272 | }; | ||
273 | |||
274 | static struct ftrace_hook_ops traceoff_hook_ops = { | ||
275 | .func = ftrace_traceoff, | ||
276 | }; | ||
277 | |||
278 | static int | ||
279 | ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param) | ||
280 | { | ||
281 | struct ftrace_hook_ops *ops; | ||
282 | |||
283 | /* we register both traceon and traceoff to this callback */ | ||
284 | if (strcmp(cmd, "traceon") == 0) | ||
285 | ops = &traceon_hook_ops; | ||
286 | else | ||
287 | ops = &traceoff_hook_ops; | ||
288 | |||
289 | unregister_ftrace_function_hook_func(glob, ops); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int | ||
295 | ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable) | ||
296 | { | ||
297 | struct ftrace_hook_ops *ops; | ||
298 | void *count = (void *)-1; | ||
299 | char *number; | ||
300 | int ret; | ||
301 | |||
302 | /* hash funcs only work with set_ftrace_filter */ | ||
303 | if (!enable) | ||
304 | return -EINVAL; | ||
305 | |||
306 | if (glob[0] == '!') | ||
307 | return ftrace_trace_onoff_unreg(glob+1, cmd, param); | ||
308 | |||
309 | /* we register both traceon and traceoff to this callback */ | ||
310 | if (strcmp(cmd, "traceon") == 0) | ||
311 | ops = &traceon_hook_ops; | ||
312 | else | ||
313 | ops = &traceoff_hook_ops; | ||
314 | |||
315 | if (!param) | ||
316 | goto out_reg; | ||
317 | |||
318 | number = strsep(¶m, ":"); | ||
319 | |||
320 | if (!strlen(number)) | ||
321 | goto out_reg; | ||
322 | |||
323 | /* | ||
324 | * We use the callback data field (which is a pointer) | ||
325 | * as our counter. | ||
326 | */ | ||
327 | ret = strict_strtoul(number, 0, (unsigned long *)&count); | ||
328 | if (ret) | ||
329 | return ret; | ||
330 | |||
331 | out_reg: | ||
332 | ret = register_ftrace_function_hook(glob, ops, count); | ||
333 | |||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | static struct ftrace_func_command ftrace_traceon_cmd = { | ||
338 | .name = "traceon", | ||
339 | .func = ftrace_trace_onoff_callback, | ||
340 | }; | ||
341 | |||
342 | static struct ftrace_func_command ftrace_traceoff_cmd = { | ||
343 | .name = "traceoff", | ||
344 | .func = ftrace_trace_onoff_callback, | ||
345 | }; | ||
346 | |||
347 | static int __init init_func_cmd_traceon(void) | ||
348 | { | ||
349 | int ret; | ||
350 | |||
351 | ret = register_ftrace_command(&ftrace_traceoff_cmd); | ||
352 | if (ret) | ||
353 | return ret; | ||
354 | |||
355 | ret = register_ftrace_command(&ftrace_traceon_cmd); | ||
356 | if (ret) | ||
357 | unregister_ftrace_command(&ftrace_traceoff_cmd); | ||
358 | return ret; | ||
359 | } | ||
360 | #else | ||
361 | static inline int init_func_cmd_traceon(void) | ||
362 | { | ||
363 | return 0; | ||
364 | } | ||
365 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
366 | |||
234 | static __init int init_function_trace(void) | 367 | static __init int init_function_trace(void) |
235 | { | 368 | { |
369 | init_func_cmd_traceon(); | ||
236 | return register_tracer(&function_trace); | 370 | return register_tracer(&function_trace); |
237 | } | 371 | } |
238 | 372 | ||
239 | device_initcall(init_function_trace); | 373 | device_initcall(init_function_trace); |
374 | |||