|
@@ -9,6 +9,7 @@
|
|
* Copyright (C) 2004-2006 Ingo Molnar
|
|
* Copyright (C) 2004-2006 Ingo Molnar
|
|
* Copyright (C) 2004 William Lee Irwin III
|
|
* Copyright (C) 2004 William Lee Irwin III
|
|
*/
|
|
*/
|
|
|
|
+#include <linux/ring_buffer.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/ftrace.h>
|
|
#include <linux/ftrace.h>
|
|
@@ -231,9 +232,143 @@ static struct tracer function_trace __read_mostly =
|
|
#endif
|
|
#endif
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#ifdef CONFIG_DYNAMIC_FTRACE
|
|
|
|
+static void
|
|
|
|
+ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
|
|
|
|
+{
|
|
|
|
+ long *count = (long *)data;
|
|
|
|
+
|
|
|
|
+ if (tracing_is_on())
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (!*count)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (*count != -1)
|
|
|
|
+ (*count)--;
|
|
|
|
+
|
|
|
|
+ tracing_on();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
|
|
|
|
+{
|
|
|
|
+ long *count = (long *)data;
|
|
|
|
+
|
|
|
|
+ if (!tracing_is_on())
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (!*count)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (*count != -1)
|
|
|
|
+ (*count)--;
|
|
|
|
+
|
|
|
|
+ tracing_off();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct ftrace_hook_ops traceon_hook_ops = {
|
|
|
|
+ .func = ftrace_traceon,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct ftrace_hook_ops traceoff_hook_ops = {
|
|
|
|
+ .func = ftrace_traceoff,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
|
|
|
|
+{
|
|
|
|
+ struct ftrace_hook_ops *ops;
|
|
|
|
+
|
|
|
|
+ /* we register both traceon and traceoff to this callback */
|
|
|
|
+ if (strcmp(cmd, "traceon") == 0)
|
|
|
|
+ ops = &traceon_hook_ops;
|
|
|
|
+ else
|
|
|
|
+ ops = &traceoff_hook_ops;
|
|
|
|
+
|
|
|
|
+ unregister_ftrace_function_hook_func(glob, ops);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
|
|
|
|
+{
|
|
|
|
+ struct ftrace_hook_ops *ops;
|
|
|
|
+ void *count = (void *)-1;
|
|
|
|
+ char *number;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ /* hash funcs only work with set_ftrace_filter */
|
|
|
|
+ if (!enable)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (glob[0] == '!')
|
|
|
|
+ return ftrace_trace_onoff_unreg(glob+1, cmd, param);
|
|
|
|
+
|
|
|
|
+ /* we register both traceon and traceoff to this callback */
|
|
|
|
+ if (strcmp(cmd, "traceon") == 0)
|
|
|
|
+ ops = &traceon_hook_ops;
|
|
|
|
+ else
|
|
|
|
+ ops = &traceoff_hook_ops;
|
|
|
|
+
|
|
|
|
+ if (!param)
|
|
|
|
+ goto out_reg;
|
|
|
|
+
|
|
|
|
+ number = strsep(¶m, ":");
|
|
|
|
+
|
|
|
|
+ if (!strlen(number))
|
|
|
|
+ goto out_reg;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We use the callback data field (which is a pointer)
|
|
|
|
+ * as our counter.
|
|
|
|
+ */
|
|
|
|
+ ret = strict_strtoul(number, 0, (unsigned long *)&count);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ out_reg:
|
|
|
|
+ ret = register_ftrace_function_hook(glob, ops, count);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct ftrace_func_command ftrace_traceon_cmd = {
|
|
|
|
+ .name = "traceon",
|
|
|
|
+ .func = ftrace_trace_onoff_callback,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct ftrace_func_command ftrace_traceoff_cmd = {
|
|
|
|
+ .name = "traceoff",
|
|
|
|
+ .func = ftrace_trace_onoff_callback,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int __init init_func_cmd_traceon(void)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = register_ftrace_command(&ftrace_traceoff_cmd);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ ret = register_ftrace_command(&ftrace_traceon_cmd);
|
|
|
|
+ if (ret)
|
|
|
|
+ unregister_ftrace_command(&ftrace_traceoff_cmd);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+#else
|
|
|
|
+static inline int init_func_cmd_traceon(void)
|
|
|
|
+{
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_DYNAMIC_FTRACE */
|
|
|
|
+
|
|
static __init int init_function_trace(void)
|
|
static __init int init_function_trace(void)
|
|
{
|
|
{
|
|
|
|
+ init_func_cmd_traceon();
|
|
return register_tracer(&function_trace);
|
|
return register_tracer(&function_trace);
|
|
}
|
|
}
|
|
|
|
|
|
device_initcall(init_function_trace);
|
|
device_initcall(init_function_trace);
|
|
|
|
+
|