|
@@ -780,6 +780,84 @@ static __init int register_trigger_snapshot_cmd(void)
|
|
|
static __init int register_trigger_snapshot_cmd(void) { return 0; }
|
|
|
#endif /* CONFIG_TRACER_SNAPSHOT */
|
|
|
|
|
|
+#ifdef CONFIG_STACKTRACE
|
|
|
+/*
|
|
|
+ * Skip 3:
|
|
|
+ * stacktrace_trigger()
|
|
|
+ * event_triggers_post_call()
|
|
|
+ * ftrace_raw_event_xxx()
|
|
|
+ */
|
|
|
+#define STACK_SKIP 3
|
|
|
+
|
|
|
+static void
|
|
|
+stacktrace_trigger(struct event_trigger_data *data)
|
|
|
+{
|
|
|
+ trace_dump_stack(STACK_SKIP);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+stacktrace_count_trigger(struct event_trigger_data *data)
|
|
|
+{
|
|
|
+ if (!data->count)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (data->count != -1)
|
|
|
+ (data->count)--;
|
|
|
+
|
|
|
+ stacktrace_trigger(data);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+stacktrace_trigger_print(struct seq_file *m, struct event_trigger_ops *ops,
|
|
|
+ struct event_trigger_data *data)
|
|
|
+{
|
|
|
+ return event_trigger_print("stacktrace", m, (void *)data->count,
|
|
|
+ data->filter_str);
|
|
|
+}
|
|
|
+
|
|
|
+static struct event_trigger_ops stacktrace_trigger_ops = {
|
|
|
+ .func = stacktrace_trigger,
|
|
|
+ .print = stacktrace_trigger_print,
|
|
|
+ .init = event_trigger_init,
|
|
|
+ .free = event_trigger_free,
|
|
|
+};
|
|
|
+
|
|
|
+static struct event_trigger_ops stacktrace_count_trigger_ops = {
|
|
|
+ .func = stacktrace_count_trigger,
|
|
|
+ .print = stacktrace_trigger_print,
|
|
|
+ .init = event_trigger_init,
|
|
|
+ .free = event_trigger_free,
|
|
|
+};
|
|
|
+
|
|
|
+static struct event_trigger_ops *
|
|
|
+stacktrace_get_trigger_ops(char *cmd, char *param)
|
|
|
+{
|
|
|
+ return param ? &stacktrace_count_trigger_ops : &stacktrace_trigger_ops;
|
|
|
+}
|
|
|
+
|
|
|
+static struct event_command trigger_stacktrace_cmd = {
|
|
|
+ .name = "stacktrace",
|
|
|
+ .trigger_type = ETT_STACKTRACE,
|
|
|
+ .post_trigger = true,
|
|
|
+ .func = event_trigger_callback,
|
|
|
+ .reg = register_trigger,
|
|
|
+ .unreg = unregister_trigger,
|
|
|
+ .get_trigger_ops = stacktrace_get_trigger_ops,
|
|
|
+};
|
|
|
+
|
|
|
+static __init int register_trigger_stacktrace_cmd(void)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = register_event_command(&trigger_stacktrace_cmd);
|
|
|
+ WARN_ON(ret < 0);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#else
|
|
|
+static __init int register_trigger_stacktrace_cmd(void) { return 0; }
|
|
|
+#endif /* CONFIG_STACKTRACE */
|
|
|
+
|
|
|
static __init void unregister_trigger_traceon_traceoff_cmds(void)
|
|
|
{
|
|
|
unregister_event_command(&trigger_traceon_cmd);
|
|
@@ -804,6 +882,7 @@ __init int register_trigger_cmds(void)
|
|
|
{
|
|
|
register_trigger_traceon_traceoff_cmds();
|
|
|
register_trigger_snapshot_cmd();
|
|
|
+ register_trigger_stacktrace_cmd();
|
|
|
|
|
|
return 0;
|
|
|
}
|