All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
@ 2019-06-19 15:07 Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 01/12] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Hello,

This is the 2nd version of multi-probes per event support on ftrace
and perf-tools.

Previous version is here;
https://lkml.org/lkml/2019/5/31/573

>From this version, I omitted first 9 patches which has been picked
to Steve's tree.
In this version, I've fixed some bugs and hardened some unexpected
error cases according to Steve's comment.
Here are changes in this version:

 - [1/12] This have below changes. 
    - Warn if the primary trace_probe does not exist.
    - Fix enable_trace_kprobe() to not return error if the any probes
      are "gone" state. If all probes have gone or any other error
      reason, the event can not be enabled and return error.
    - Fix trace_probe_enable() to roll back all enabled uprobe if
      any one of uprobe is failed to enable.
 - [7/12] Swap the checking order of filename for avoiding unexpected
     memory access.


====
For trace-event, we can insert same trace-event on several places
on the code, and those can record similar information as a same event
with same format.

This series implements similar feature on probe-event. Since the probe
event is based on the compiled binary, sometimes we find that the target
source line is complied into several different addresses, e.g. inlined
function, unrolled loop, etc. In those cases, it is useful to put a
same probe-event on different addresses.

With this series, we can append multi probes on one event as below

  # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
  # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
  # kprobe_events
  p:kprobes/testevent _do_fork r1=%ax r2=%dx
  p:kprobes/testevent fork_idle r1=%ax r2=%cx

This means testevent is hit on both of _do_fork and fork_idle.
As you can see, the appended event must have same number of arguments
and those must have same 'type' and 'name' as original one. This is like
a function signature, it checks whether the appending event has the same
type and name of event arguments and same probe type, but doesn't care
about the assignment.

So, below appending commands will be rejected.

  # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
  # echo p:testevent fork_idle r1=%ax >> kprobe_events
  (No 2nd argument)
  # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
  (The type of 2nd argument is different)

If one inlined code has an argument on a register, but another
inlined code has fixed value (as a result of optimization),
you can also specify the fixed immediate value, e.g.

  # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
  # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events


Thank you,

---

Masami Hiramatsu (12):
      tracing/probe: Split trace_event related data from trace_probe
      tracing/dynevent: Delete all matched events
      tracing/dynevent: Pass extra arguments to match operation
      tracing/kprobe: Add multi-probe per event support
      tracing/uprobe: Add multi-probe per uprobe event support
      tracing/kprobe: Add per-probe delete from event
      tracing/uprobe: Add per-probe delete from event
      tracing/probe: Add immediate parameter support
      tracing/probe: Add immediate string parameter support
      selftests/ftrace: Add a testcase for kprobe multiprobe event
      selftests/ftrace: Add syntax error test for immediates
      selftests/ftrace: Add syntax error test for multiprobe


 Documentation/trace/kprobetrace.rst                |    1 
 Documentation/trace/uprobetracer.rst               |    1 
 kernel/trace/trace.c                               |    8 -
 kernel/trace/trace_dynevent.c                      |   10 +
 kernel/trace/trace_dynevent.h                      |    7 -
 kernel/trace/trace_events_hist.c                   |    4 
 kernel/trace/trace_kprobe.c                        |  241 ++++++++++++++----
 kernel/trace/trace_probe.c                         |  176 +++++++++++--
 kernel/trace/trace_probe.h                         |   67 ++++-
 kernel/trace/trace_uprobe.c                        |  263 +++++++++++++++-----
 tools/testing/selftests/ftrace/test.d/functions    |    2 
 .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 +++
 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   15 +
 13 files changed, 665 insertions(+), 165 deletions(-)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc

--
Masami Hiramatsu (Linaro) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 01/12] tracing/probe: Split trace_event related data from trace_probe
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
@ 2019-06-19 15:07 ` Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 02/12] tracing/dynevent: Delete all matched events Masami Hiramatsu
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Split the trace_event related data from trace_probe data structure
and introduce trace_probe_event data structure for its folder.
This trace_probe_event data structure can have multiple trace_probe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
  Changes in v2:
   - Warn if the primary trace_probe does not exist according to Steve's
     comment. This must not happen but is easy to be handled.
   - Fix enable_trace_kprobe() to not return error if the any probes are
     "gone" state. If all probes have gone or any other error reason,
     the event can not be enabled and return error.
   - Fix trace_probe_enable() to roll back all enabled uprobe if any one
     of uprobe is failed to enable.
---
 kernel/trace/trace_kprobe.c |  157 ++++++++++++++++++++++++++++++-----------
 kernel/trace/trace_probe.c  |   53 +++++++++-----
 kernel/trace/trace_probe.h  |   48 ++++++++++---
 kernel/trace/trace_uprobe.c |  165 ++++++++++++++++++++++++++++++++-----------
 4 files changed, 311 insertions(+), 112 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 9d483ad9bb6c..eac6344a2e7c 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -180,20 +180,33 @@ unsigned long trace_kprobe_address(struct trace_kprobe *tk)
 	return addr;
 }
 
+static nokprobe_inline struct trace_kprobe *
+trace_kprobe_primary_from_call(struct trace_event_call *call)
+{
+	struct trace_probe *tp;
+
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return NULL;
+
+	return container_of(tp, struct trace_kprobe, tp);
+}
+
 bool trace_kprobe_on_func_entry(struct trace_event_call *call)
 {
-	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
+	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
 
-	return kprobe_on_func_entry(tk->rp.kp.addr,
+	return tk ? kprobe_on_func_entry(tk->rp.kp.addr,
 			tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name,
-			tk->rp.kp.addr ? 0 : tk->rp.kp.offset);
+			tk->rp.kp.addr ? 0 : tk->rp.kp.offset) : false;
 }
 
 bool trace_kprobe_error_injectable(struct trace_event_call *call)
 {
-	struct trace_kprobe *tk = (struct trace_kprobe *)call->data;
+	struct trace_kprobe *tk = trace_kprobe_primary_from_call(call);
 
-	return within_error_injection_list(trace_kprobe_address(tk));
+	return tk ? within_error_injection_list(trace_kprobe_address(tk)) :
+	       false;
 }
 
 static int register_kprobe_event(struct trace_kprobe *tk);
@@ -291,32 +304,75 @@ static inline int __enable_trace_kprobe(struct trace_kprobe *tk)
 	return ret;
 }
 
+static void __disable_trace_kprobe(struct trace_probe *tp)
+{
+	struct trace_probe *pos;
+	struct trace_kprobe *tk;
+
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tk = container_of(pos, struct trace_kprobe, tp);
+		if (!trace_kprobe_is_registered(tk))
+			continue;
+		if (trace_kprobe_is_return(tk))
+			disable_kretprobe(&tk->rp);
+		else
+			disable_kprobe(&tk->rp.kp);
+	}
+}
+
 /*
  * Enable trace_probe
  * if the file is NULL, enable "perf" handler, or enable "trace" handler.
  */
-static int
-enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
+static int enable_trace_kprobe(struct trace_event_call *call,
+				struct trace_event_file *file)
 {
-	bool enabled = trace_probe_is_enabled(&tk->tp);
+	struct trace_probe *pos, *tp;
+	struct trace_kprobe *tk;
+	bool enabled;
 	int ret = 0;
 
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return -ENODEV;
+	enabled = trace_probe_is_enabled(tp);
+
+	/* This also changes "enabled" state */
 	if (file) {
-		ret = trace_probe_add_file(&tk->tp, file);
+		ret = trace_probe_add_file(tp, file);
 		if (ret)
 			return ret;
 	} else
-		trace_probe_set_flag(&tk->tp, TP_FLAG_PROFILE);
+		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
 
 	if (enabled)
 		return 0;
 
-	ret = __enable_trace_kprobe(tk);
-	if (ret) {
+	enabled = false;
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tk = container_of(pos, struct trace_kprobe, tp);
+		if (trace_kprobe_has_gone(tk))
+			continue;
+		ret = __enable_trace_kprobe(tk);
+		if (ret) {
+			if (enabled) {
+				__disable_trace_kprobe(tp);
+				enabled = false;
+			}
+			break;
+		}
+		enabled = true;
+	}
+
+	if (!enabled) {
+		/* No probe is enabled. Roll back */
 		if (file)
-			trace_probe_remove_file(&tk->tp, file);
+			trace_probe_remove_file(tp, file);
 		else
-			trace_probe_clear_flag(&tk->tp, TP_FLAG_PROFILE);
+			trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
+		if (!ret)
+			/* Since all probes are gone, this is not available */
+			ret = -EADDRNOTAVAIL;
 	}
 
 	return ret;
@@ -326,11 +382,14 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
  * Disable trace_probe
  * if the file is NULL, disable "perf" handler, or disable "trace" handler.
  */
-static int
-disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
+static int disable_trace_kprobe(struct trace_event_call *call,
+				struct trace_event_file *file)
 {
-	struct trace_probe *tp = &tk->tp;
-	int ret = 0;
+	struct trace_probe *tp;
+
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return -ENODEV;
 
 	if (file) {
 		if (!trace_probe_get_file_link(tp, file))
@@ -341,12 +400,8 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 	} else
 		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
-	if (!trace_probe_is_enabled(tp) && trace_kprobe_is_registered(tk)) {
-		if (trace_kprobe_is_return(tk))
-			disable_kretprobe(&tk->rp);
-		else
-			disable_kprobe(&tk->rp.kp);
-	}
+	if (!trace_probe_is_enabled(tp))
+		__disable_trace_kprobe(tp);
 
  out:
 	if (file)
@@ -358,7 +413,7 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
 		 */
 		trace_probe_remove_file(tp, file);
 
-	return ret;
+	return 0;
 }
 
 #if defined(CONFIG_KPROBES_ON_FTRACE) && \
@@ -1089,7 +1144,10 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
 	struct trace_probe *tp;
 
 	field = (struct kprobe_trace_entry_head *)iter->ent;
-	tp = container_of(event, struct trace_probe, call.event);
+	tp = trace_probe_primary_from_call(
+		container_of(event, struct trace_event_call, event));
+	if (WARN_ON_ONCE(!tp))
+		goto out;
 
 	trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
@@ -1116,7 +1174,10 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
 	struct trace_probe *tp;
 
 	field = (struct kretprobe_trace_entry_head *)iter->ent;
-	tp = container_of(event, struct trace_probe, call.event);
+	tp = trace_probe_primary_from_call(
+		container_of(event, struct trace_event_call, event));
+	if (WARN_ON_ONCE(!tp))
+		goto out;
 
 	trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
@@ -1145,23 +1206,31 @@ static int kprobe_event_define_fields(struct trace_event_call *event_call)
 {
 	int ret;
 	struct kprobe_trace_entry_head field;
-	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
+	struct trace_probe *tp;
+
+	tp = trace_probe_primary_from_call(event_call);
+	if (WARN_ON_ONCE(!tp))
+		return -ENOENT;
 
 	DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
 
-	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
+	return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
 }
 
 static int kretprobe_event_define_fields(struct trace_event_call *event_call)
 {
 	int ret;
 	struct kretprobe_trace_entry_head field;
-	struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data;
+	struct trace_probe *tp;
+
+	tp = trace_probe_primary_from_call(event_call);
+	if (WARN_ON_ONCE(!tp))
+		return -ENOENT;
 
 	DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
 	DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
 
-	return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp);
+	return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1289,20 +1358,19 @@ int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type,
 static int kprobe_register(struct trace_event_call *event,
 			   enum trace_reg type, void *data)
 {
-	struct trace_kprobe *tk = (struct trace_kprobe *)event->data;
 	struct trace_event_file *file = data;
 
 	switch (type) {
 	case TRACE_REG_REGISTER:
-		return enable_trace_kprobe(tk, file);
+		return enable_trace_kprobe(event, file);
 	case TRACE_REG_UNREGISTER:
-		return disable_trace_kprobe(tk, file);
+		return disable_trace_kprobe(event, file);
 
 #ifdef CONFIG_PERF_EVENTS
 	case TRACE_REG_PERF_REGISTER:
-		return enable_trace_kprobe(tk, NULL);
+		return enable_trace_kprobe(event, NULL);
 	case TRACE_REG_PERF_UNREGISTER:
-		return disable_trace_kprobe(tk, NULL);
+		return disable_trace_kprobe(event, NULL);
 	case TRACE_REG_PERF_OPEN:
 	case TRACE_REG_PERF_CLOSE:
 	case TRACE_REG_PERF_ADD:
@@ -1369,7 +1437,6 @@ static inline void init_trace_event_call(struct trace_kprobe *tk)
 
 	call->flags = TRACE_EVENT_FL_KPROBE;
 	call->class->reg = kprobe_register;
-	call->data = tk;
 }
 
 static int register_kprobe_event(struct trace_kprobe *tk)
@@ -1432,7 +1499,9 @@ void destroy_local_trace_kprobe(struct trace_event_call *event_call)
 {
 	struct trace_kprobe *tk;
 
-	tk = container_of(event_call, struct trace_kprobe, tp.call);
+	tk = trace_kprobe_primary_from_call(event_call);
+	if (unlikely(!tk))
+		return;
 
 	if (trace_probe_is_enabled(&tk->tp)) {
 		WARN_ON(1);
@@ -1577,7 +1646,8 @@ static __init int kprobe_trace_self_tests_init(void)
 				pr_warn("error on getting probe file.\n");
 				warn++;
 			} else
-				enable_trace_kprobe(tk, file);
+				enable_trace_kprobe(
+					trace_probe_event_call(&tk->tp), file);
 		}
 	}
 
@@ -1598,7 +1668,8 @@ static __init int kprobe_trace_self_tests_init(void)
 				pr_warn("error on getting probe file.\n");
 				warn++;
 			} else
-				enable_trace_kprobe(tk, file);
+				enable_trace_kprobe(
+					trace_probe_event_call(&tk->tp), file);
 		}
 	}
 
@@ -1631,7 +1702,8 @@ static __init int kprobe_trace_self_tests_init(void)
 			pr_warn("error on getting probe file.\n");
 			warn++;
 		} else
-			disable_trace_kprobe(tk, file);
+			disable_trace_kprobe(
+				trace_probe_event_call(&tk->tp), file);
 	}
 
 	tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM);
@@ -1649,7 +1721,8 @@ static __init int kprobe_trace_self_tests_init(void)
 			pr_warn("error on getting probe file.\n");
 			warn++;
 		} else
-			disable_trace_kprobe(tk, file);
+			disable_trace_kprobe(
+				trace_probe_event_call(&tk->tp), file);
 	}
 
 	ret = trace_run_command("-:testprobe", create_or_delete_trace_kprobe);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index dbef0d135075..28733bd6b607 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -889,40 +889,59 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 
 void trace_probe_cleanup(struct trace_probe *tp)
 {
-	struct trace_event_call *call = trace_probe_event_call(tp);
 	int i;
 
 	for (i = 0; i < tp->nr_args; i++)
 		traceprobe_free_probe_arg(&tp->args[i]);
 
-	kfree(call->class->system);
-	kfree(call->name);
-	kfree(call->print_fmt);
+	if (tp->event) {
+		struct trace_event_call *call = trace_probe_event_call(tp);
+
+		kfree(tp->event->class.system);
+		kfree(call->name);
+		kfree(call->print_fmt);
+		kfree(tp->event);
+		tp->event = NULL;
+	}
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
 		     const char *group)
 {
-	struct trace_event_call *call = trace_probe_event_call(tp);
+	struct trace_event_call *call;
+	int ret = 0;
 
 	if (!event || !group)
 		return -EINVAL;
 
-	call->class = &tp->class;
-	call->name = kstrdup(event, GFP_KERNEL);
-	if (!call->name)
+	tp->event = kzalloc(sizeof(struct trace_probe_event), GFP_KERNEL);
+	if (!tp->event)
 		return -ENOMEM;
 
-	tp->class.system = kstrdup(group, GFP_KERNEL);
-	if (!tp->class.system) {
-		kfree(call->name);
-		call->name = NULL;
-		return -ENOMEM;
+	call = trace_probe_event_call(tp);
+	call->class = &tp->event->class;
+	call->name = kstrdup(event, GFP_KERNEL);
+	if (!call->name) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	tp->event->class.system = kstrdup(group, GFP_KERNEL);
+	if (!tp->event->class.system) {
+		ret = -ENOMEM;
+		goto error;
 	}
-	INIT_LIST_HEAD(&tp->files);
-	INIT_LIST_HEAD(&tp->class.fields);
+	INIT_LIST_HEAD(&tp->event->files);
+	INIT_LIST_HEAD(&tp->event->class.fields);
+	INIT_LIST_HEAD(&tp->event->probes);
+	INIT_LIST_HEAD(&tp->list);
+	list_add(&tp->event->probes, &tp->list);
 
 	return 0;
+
+error:
+	trace_probe_cleanup(tp);
+	return ret;
 }
 
 int trace_probe_register_event_call(struct trace_probe *tp)
@@ -951,7 +970,7 @@ int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file)
 
 	link->file = file;
 	INIT_LIST_HEAD(&link->list);
-	list_add_tail_rcu(&link->list, &tp->files);
+	list_add_tail_rcu(&link->list, &tp->event->files);
 	trace_probe_set_flag(tp, TP_FLAG_TRACE);
 	return 0;
 }
@@ -982,7 +1001,7 @@ int trace_probe_remove_file(struct trace_probe *tp,
 	synchronize_rcu();
 	kfree(link);
 
-	if (list_empty(&tp->files))
+	if (list_empty(&tp->event->files))
 		trace_probe_clear_flag(tp, TP_FLAG_TRACE);
 
 	return 0;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index d1714820efe1..0b84abb884c2 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -222,11 +222,18 @@ struct probe_arg {
 	const struct fetch_type	*type;	/* Type of this argument */
 };
 
-struct trace_probe {
+/* Event call and class holder */
+struct trace_probe_event {
 	unsigned int			flags;	/* For TP_FLAG_* */
 	struct trace_event_class	class;
 	struct trace_event_call		call;
 	struct list_head 		files;
+	struct list_head		probes;
+};
+
+struct trace_probe {
+	struct list_head		list;
+	struct trace_probe_event	*event;
 	ssize_t				size;	/* trace entry size */
 	unsigned int			nr_args;
 	struct probe_arg		args[];
@@ -240,19 +247,19 @@ struct event_file_link {
 static inline bool trace_probe_test_flag(struct trace_probe *tp,
 					 unsigned int flag)
 {
-	return !!(tp->flags & flag);
+	return !!(tp->event->flags & flag);
 }
 
 static inline void trace_probe_set_flag(struct trace_probe *tp,
 					unsigned int flag)
 {
-	tp->flags |= flag;
+	tp->event->flags |= flag;
 }
 
 static inline void trace_probe_clear_flag(struct trace_probe *tp,
 					  unsigned int flag)
 {
-	tp->flags &= ~flag;
+	tp->event->flags &= ~flag;
 }
 
 static inline bool trace_probe_is_enabled(struct trace_probe *tp)
@@ -262,29 +269,48 @@ static inline bool trace_probe_is_enabled(struct trace_probe *tp)
 
 static inline const char *trace_probe_name(struct trace_probe *tp)
 {
-	return trace_event_name(&tp->call);
+	return trace_event_name(&tp->event->call);
 }
 
 static inline const char *trace_probe_group_name(struct trace_probe *tp)
 {
-	return tp->call.class->system;
+	return tp->event->call.class->system;
 }
 
 static inline struct trace_event_call *
 	trace_probe_event_call(struct trace_probe *tp)
 {
-	return &tp->call;
+	return &tp->event->call;
+}
+
+static inline struct trace_probe_event *
+trace_probe_event_from_call(struct trace_event_call *event_call)
+{
+	return container_of(event_call, struct trace_probe_event, call);
+}
+
+static inline struct trace_probe *
+trace_probe_primary_from_call(struct trace_event_call *call)
+{
+	struct trace_probe_event *tpe = trace_probe_event_from_call(call);
+
+	return list_first_entry(&tpe->probes, struct trace_probe, list);
+}
+
+static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
+{
+	return &tp->event->probes;
 }
 
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
-	return trace_remove_event_call(&tp->call);
+	return trace_remove_event_call(&tp->event->call);
 }
 
 static inline bool trace_probe_has_single_file(struct trace_probe *tp)
 {
-	return !!list_is_singular(&tp->files);
+	return !!list_is_singular(&tp->event->files);
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
@@ -298,9 +324,9 @@ struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
 						struct trace_event_file *file);
 
 #define trace_probe_for_each_link(pos, tp)	\
-	list_for_each_entry(pos, &(tp)->files, list)
+	list_for_each_entry(pos, &(tp)->event->files, list)
 #define trace_probe_for_each_link_rcu(pos, tp)	\
-	list_for_each_entry_rcu(pos, &(tp)->files, list)
+	list_for_each_entry_rcu(pos, &(tp)->event->files, list)
 
 /* Check the name is good for event/group/fields */
 static inline bool is_good_name(const char *name)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 7fb9353b47d9..5b45f0a7ab38 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -293,6 +293,18 @@ static bool trace_uprobe_match(const char *system, const char *event,
 	    (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
 }
 
+static nokprobe_inline struct trace_uprobe *
+trace_uprobe_primary_from_call(struct trace_event_call *call)
+{
+	struct trace_probe *tp;
+
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return NULL;
+
+	return container_of(tp, struct trace_uprobe, tp);
+}
+
 /*
  * Allocate new trace_uprobe and initialize it (including uprobes).
  */
@@ -892,7 +904,10 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
 	u8 *data;
 
 	entry = (struct uprobe_trace_entry_head *)iter->ent;
-	tu = container_of(event, struct trace_uprobe, tp.call.event);
+	tu = trace_uprobe_primary_from_call(
+		container_of(event, struct trace_event_call, event));
+	if (unlikely(!tu))
+		goto out;
 
 	if (is_ret_probe(tu)) {
 		trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
@@ -919,27 +934,71 @@ typedef bool (*filter_func_t)(struct uprobe_consumer *self,
 				enum uprobe_filter_ctx ctx,
 				struct mm_struct *mm);
 
-static int
-probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
-		   filter_func_t filter)
+static int trace_uprobe_enable(struct trace_uprobe *tu, filter_func_t filter)
 {
-	bool enabled = trace_probe_is_enabled(&tu->tp);
 	int ret;
 
+	tu->consumer.filter = filter;
+	tu->inode = d_real_inode(tu->path.dentry);
+
+	if (tu->ref_ctr_offset)
+		ret = uprobe_register_refctr(tu->inode, tu->offset,
+				tu->ref_ctr_offset, &tu->consumer);
+	else
+		ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
+
+	if (ret)
+		tu->inode = NULL;
+
+	return ret;
+}
+
+static void __probe_event_disable(struct trace_probe *tp)
+{
+	struct trace_probe *pos;
+	struct trace_uprobe *tu;
+
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tu = container_of(pos, struct trace_uprobe, tp);
+		if (!tu->inode)
+			continue;
+
+		WARN_ON(!uprobe_filter_is_empty(&tu->filter));
+
+		uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
+		tu->inode = NULL;
+	}
+}
+
+static int probe_event_enable(struct trace_event_call *call,
+			struct trace_event_file *file, filter_func_t filter)
+{
+	struct trace_probe *pos, *tp;
+	struct trace_uprobe *tu;
+	bool enabled;
+	int ret;
+
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return -ENODEV;
+	enabled = trace_probe_is_enabled(tp);
+
+	/* This may also change "enabled" state */
 	if (file) {
-		if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
+		if (trace_probe_test_flag(tp, TP_FLAG_PROFILE))
 			return -EINTR;
 
-		ret = trace_probe_add_file(&tu->tp, file);
+		ret = trace_probe_add_file(tp, file);
 		if (ret < 0)
 			return ret;
 	} else {
-		if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
+		if (trace_probe_test_flag(tp, TP_FLAG_TRACE))
 			return -EINTR;
 
-		trace_probe_set_flag(&tu->tp, TP_FLAG_PROFILE);
+		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
 	}
 
+	tu = container_of(tp, struct trace_uprobe, tp);
 	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
 	if (enabled)
@@ -949,18 +1008,15 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 	if (ret)
 		goto err_flags;
 
-	tu->consumer.filter = filter;
-	tu->inode = d_real_inode(tu->path.dentry);
-	if (tu->ref_ctr_offset) {
-		ret = uprobe_register_refctr(tu->inode, tu->offset,
-				tu->ref_ctr_offset, &tu->consumer);
-	} else {
-		ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tu = container_of(pos, struct trace_uprobe, tp);
+		ret = trace_uprobe_enable(tu, filter);
+		if (ret) {
+			__probe_event_disable(tp);
+			goto err_buffer;
+		}
 	}
 
-	if (ret)
-		goto err_buffer;
-
 	return 0;
 
  err_buffer:
@@ -968,33 +1024,35 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
 
  err_flags:
 	if (file)
-		trace_probe_remove_file(&tu->tp, file);
+		trace_probe_remove_file(tp, file);
 	else
-		trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
+		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
 	return ret;
 }
 
-static void
-probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
+static void probe_event_disable(struct trace_event_call *call,
+				struct trace_event_file *file)
 {
-	if (!trace_probe_is_enabled(&tu->tp))
+	struct trace_probe *tp;
+
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return;
+
+	if (!trace_probe_is_enabled(tp))
 		return;
 
 	if (file) {
-		if (trace_probe_remove_file(&tu->tp, file) < 0)
+		if (trace_probe_remove_file(tp, file) < 0)
 			return;
 
-		if (trace_probe_is_enabled(&tu->tp))
+		if (trace_probe_is_enabled(tp))
 			return;
 	} else
-		trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
-
-	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
-
-	uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
-	tu->inode = NULL;
+		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
 
+	__probe_event_disable(tp);
 	uprobe_buffer_disable();
 }
 
@@ -1002,7 +1060,11 @@ static int uprobe_event_define_fields(struct trace_event_call *event_call)
 {
 	int ret, size;
 	struct uprobe_trace_entry_head field;
-	struct trace_uprobe *tu = event_call->data;
+	struct trace_uprobe *tu;
+
+	tu = trace_uprobe_primary_from_call(event_call);
+	if (unlikely(!tu))
+		return -ENODEV;
 
 	if (is_ret_probe(tu)) {
 		DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_FUNC, 0);
@@ -1095,6 +1157,27 @@ static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event)
 	return err;
 }
 
+static int uprobe_perf_multi_call(struct trace_event_call *call,
+				  struct perf_event *event,
+		int (*op)(struct trace_uprobe *tu, struct perf_event *event))
+{
+	struct trace_probe *pos, *tp;
+	struct trace_uprobe *tu;
+	int ret = 0;
+
+	tp = trace_probe_primary_from_call(call);
+	if (WARN_ON_ONCE(!tp))
+		return -ENODEV;
+
+	list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
+		tu = container_of(pos, struct trace_uprobe, tp);
+		ret = op(tu, event);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
 static bool uprobe_perf_filter(struct uprobe_consumer *uc,
 				enum uprobe_filter_ctx ctx, struct mm_struct *mm)
 {
@@ -1208,30 +1291,29 @@ static int
 trace_uprobe_register(struct trace_event_call *event, enum trace_reg type,
 		      void *data)
 {
-	struct trace_uprobe *tu = event->data;
 	struct trace_event_file *file = data;
 
 	switch (type) {
 	case TRACE_REG_REGISTER:
-		return probe_event_enable(tu, file, NULL);
+		return probe_event_enable(event, file, NULL);
 
 	case TRACE_REG_UNREGISTER:
-		probe_event_disable(tu, file);
+		probe_event_disable(event, file);
 		return 0;
 
 #ifdef CONFIG_PERF_EVENTS
 	case TRACE_REG_PERF_REGISTER:
-		return probe_event_enable(tu, NULL, uprobe_perf_filter);
+		return probe_event_enable(event, NULL, uprobe_perf_filter);
 
 	case TRACE_REG_PERF_UNREGISTER:
-		probe_event_disable(tu, NULL);
+		probe_event_disable(event, NULL);
 		return 0;
 
 	case TRACE_REG_PERF_OPEN:
-		return uprobe_perf_open(tu, data);
+		return uprobe_perf_multi_call(event, data, uprobe_perf_open);
 
 	case TRACE_REG_PERF_CLOSE:
-		return uprobe_perf_close(tu, data);
+		return uprobe_perf_multi_call(event, data, uprobe_perf_close);
 
 #endif
 	default:
@@ -1325,7 +1407,6 @@ static inline void init_trace_event_call(struct trace_uprobe *tu)
 
 	call->flags = TRACE_EVENT_FL_UPROBE;
 	call->class->reg = trace_uprobe_register;
-	call->data = tu;
 }
 
 static int register_uprobe_event(struct trace_uprobe *tu)
@@ -1394,7 +1475,7 @@ void destroy_local_trace_uprobe(struct trace_event_call *event_call)
 {
 	struct trace_uprobe *tu;
 
-	tu = container_of(event_call, struct trace_uprobe, tp.call);
+	tu = trace_uprobe_primary_from_call(event_call);
 
 	free_trace_uprobe(tu);
 }


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 02/12] tracing/dynevent: Delete all matched events
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 01/12] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
@ 2019-06-19 15:07 ` Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 03/12] tracing/dynevent: Pass extra arguments to match operation Masami Hiramatsu
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

When user gives an event name to delete, delete all
matched events instead of the first one.

This means if there are several events which have same
name but different group (subsystem) name, those are
removed if user passed only the event name, e.g.

  # cat kprobe_events
  p:group1/testevent _do_fork
  p:group2/testevent fork_idle
  # echo -:testevent >> kprobe_events
  # cat kprobe_events
  #

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_dynevent.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index fa100ed3b4de..1cc55c50c491 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -61,10 +61,12 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
 	for_each_dyn_event_safe(pos, n) {
 		if (type && type != pos->ops)
 			continue;
-		if (pos->ops->match(system, event, pos)) {
-			ret = pos->ops->free(pos);
+		if (!pos->ops->match(system, event, pos))
+			continue;
+
+		ret = pos->ops->free(pos);
+		if (ret)
 			break;
-		}
 	}
 	mutex_unlock(&event_mutex);
 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 03/12] tracing/dynevent: Pass extra arguments to match operation
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 01/12] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 02/12] tracing/dynevent: Delete all matched events Masami Hiramatsu
@ 2019-06-19 15:07 ` Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 04/12] tracing/kprobe: Add multi-probe per event support Masami Hiramatsu
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Pass extra arguments to match operation for checking
exact match. If the event doesn't support exact match,
it will be ignored.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_dynevent.c    |    4 +++-
 kernel/trace/trace_dynevent.h    |    7 ++++---
 kernel/trace/trace_events_hist.c |    4 ++--
 kernel/trace/trace_kprobe.c      |    4 ++--
 kernel/trace/trace_uprobe.c      |    4 ++--
 5 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index 1cc55c50c491..a41fed46c285 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -47,6 +47,7 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
 			return -EINVAL;
 		event++;
 	}
+	argc--; argv++;
 
 	p = strchr(event, '/');
 	if (p) {
@@ -61,7 +62,8 @@ int dyn_event_release(int argc, char **argv, struct dyn_event_operations *type)
 	for_each_dyn_event_safe(pos, n) {
 		if (type && type != pos->ops)
 			continue;
-		if (!pos->ops->match(system, event, pos))
+		if (!pos->ops->match(system, event,
+				argc, (const char **)argv, pos))
 			continue;
 
 		ret = pos->ops->free(pos);
diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
index 8c334064e4d6..46898138d2df 100644
--- a/kernel/trace/trace_dynevent.h
+++ b/kernel/trace/trace_dynevent.h
@@ -31,8 +31,9 @@ struct dyn_event;
  * @is_busy: Check whether given event is busy so that it can not be deleted.
  *  Return true if it is busy, otherwides false.
  * @free: Delete the given event. Return 0 if success, otherwides error.
- * @match: Check whether given event and system name match this event.
- *  Return true if it matches, otherwides false.
+ * @match: Check whether given event and system name match this event. The argc
+ *  and argv is used for exact match. Return true if it matches, otherwides
+ *  false.
  *
  * Except for @create, these methods are called under holding event_mutex.
  */
@@ -43,7 +44,7 @@ struct dyn_event_operations {
 	bool (*is_busy)(struct dyn_event *ev);
 	int (*free)(struct dyn_event *ev);
 	bool (*match)(const char *system, const char *event,
-			struct dyn_event *ev);
+		      int argc, const char **argv, struct dyn_event *ev);
 };
 
 /* Register new dyn_event type -- must be called at first */
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index ca6b0dff60c5..65e7d071ed28 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -374,7 +374,7 @@ static int synth_event_show(struct seq_file *m, struct dyn_event *ev);
 static int synth_event_release(struct dyn_event *ev);
 static bool synth_event_is_busy(struct dyn_event *ev);
 static bool synth_event_match(const char *system, const char *event,
-			      struct dyn_event *ev);
+			int argc, const char **argv, struct dyn_event *ev);
 
 static struct dyn_event_operations synth_event_ops = {
 	.create = synth_event_create,
@@ -422,7 +422,7 @@ static bool synth_event_is_busy(struct dyn_event *ev)
 }
 
 static bool synth_event_match(const char *system, const char *event,
-			      struct dyn_event *ev)
+			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct synth_event *sev = to_synth_event(ev);
 
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index eac6344a2e7c..e8f72431b866 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -39,7 +39,7 @@ static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev);
 static int trace_kprobe_release(struct dyn_event *ev);
 static bool trace_kprobe_is_busy(struct dyn_event *ev);
 static bool trace_kprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev);
+			int argc, const char **argv, struct dyn_event *ev);
 
 static struct dyn_event_operations trace_kprobe_ops = {
 	.create = trace_kprobe_create,
@@ -138,7 +138,7 @@ static bool trace_kprobe_is_busy(struct dyn_event *ev)
 }
 
 static bool trace_kprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev)
+			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_kprobe *tk = to_trace_kprobe(ev);
 
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 5b45f0a7ab38..437dddeca8bf 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -44,7 +44,7 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev);
 static int trace_uprobe_release(struct dyn_event *ev);
 static bool trace_uprobe_is_busy(struct dyn_event *ev);
 static bool trace_uprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev);
+			int argc, const char **argv, struct dyn_event *ev);
 
 static struct dyn_event_operations trace_uprobe_ops = {
 	.create = trace_uprobe_create,
@@ -285,7 +285,7 @@ static bool trace_uprobe_is_busy(struct dyn_event *ev)
 }
 
 static bool trace_uprobe_match(const char *system, const char *event,
-			       struct dyn_event *ev)
+			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_uprobe *tu = to_trace_uprobe(ev);
 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 04/12] tracing/kprobe: Add multi-probe per event support
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2019-06-19 15:07 ` [PATCH v2 03/12] tracing/dynevent: Pass extra arguments to match operation Masami Hiramatsu
@ 2019-06-19 15:07 ` Masami Hiramatsu
  2019-06-19 15:07 ` [PATCH v2 05/12] tracing/uprobe: Add multi-probe per uprobe " Masami Hiramatsu
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add multi-probe per one event support to kprobe events.
User can define several different probes on one trace event
if those events have same "event signature",
e.g.

  # echo p:testevent _do_fork > kprobe_events
  # echo p:testevent fork_idle >> kprobe_events
  # kprobe_events
  p:kprobes/testevent _do_fork
  p:kprobes/testevent fork_idle

The event signature is defined by kprobe type (retprobe or not),
the number of args, argument names, and argument types.

Note that this only support appending method. Delete event
operation will delete all probes on the event.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace.c        |    4 +--
 kernel/trace/trace_kprobe.c |   52 ++++++++++++++++++++++++++++++++++----
 kernel/trace/trace_probe.c  |   59 ++++++++++++++++++++++++++++++++++++-------
 kernel/trace/trace_probe.h  |   14 +++++++++-
 4 files changed, 111 insertions(+), 18 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 77b9c4ca5faa..8f5455046504 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4813,11 +4813,11 @@ static const char readme_msg[] =
 #endif
 #endif /* CONFIG_STACK_TRACER */
 #ifdef CONFIG_DYNAMIC_EVENTS
-	"  dynamic_events\t\t- Add/remove/show the generic dynamic events\n"
+	"  dynamic_events\t\t- Create/append/remove/show the generic dynamic events\n"
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #ifdef CONFIG_KPROBE_EVENTS
-	"  kprobe_events\t\t- Add/remove/show the kernel dynamic events\n"
+	"  kprobe_events\t\t- Create/append/remove/show the kernel dynamic events\n"
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index e8f72431b866..f43098bf62dd 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -492,6 +492,10 @@ static void __unregister_trace_kprobe(struct trace_kprobe *tk)
 /* Unregister a trace_probe and probe_event */
 static int unregister_trace_kprobe(struct trace_kprobe *tk)
 {
+	/* If other probes are on the event, just unregister kprobe */
+	if (trace_probe_has_sibling(&tk->tp))
+		goto unreg;
+
 	/* Enabled event can not be unregistered */
 	if (trace_probe_is_enabled(&tk->tp))
 		return -EBUSY;
@@ -500,12 +504,38 @@ static int unregister_trace_kprobe(struct trace_kprobe *tk)
 	if (unregister_kprobe_event(tk))
 		return -EBUSY;
 
+unreg:
 	__unregister_trace_kprobe(tk);
 	dyn_event_remove(&tk->devent);
+	trace_probe_unlink(&tk->tp);
 
 	return 0;
 }
 
+static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprobe *to)
+{
+	int ret;
+
+	/* Append to existing event */
+	ret = trace_probe_append(&tk->tp, &to->tp);
+	if (ret)
+		return ret;
+
+	/* Register k*probe */
+	ret = __register_trace_kprobe(tk);
+	if (ret == -ENOENT && !trace_kprobe_module_exist(tk)) {
+		pr_warn("This probe might be able to register after target module is loaded. Continue.\n");
+		ret = 0;
+	}
+
+	if (ret)
+		trace_probe_unlink(&tk->tp);
+	else
+		dyn_event_add(&tk->devent);
+
+	return ret;
+}
+
 /* Register a trace_probe and probe_event */
 static int register_trace_kprobe(struct trace_kprobe *tk)
 {
@@ -514,14 +544,24 @@ static int register_trace_kprobe(struct trace_kprobe *tk)
 
 	mutex_lock(&event_mutex);
 
-	/* Delete old (same name) event if exist */
 	old_tk = find_trace_kprobe(trace_probe_name(&tk->tp),
 				   trace_probe_group_name(&tk->tp));
 	if (old_tk) {
-		ret = unregister_trace_kprobe(old_tk);
-		if (ret < 0)
-			goto end;
-		free_trace_kprobe(old_tk);
+		if (trace_kprobe_is_return(tk) != trace_kprobe_is_return(old_tk)) {
+			trace_probe_log_set_index(0);
+			trace_probe_log_err(0, DIFF_PROBE_TYPE);
+			ret = -EEXIST;
+		} else {
+			ret = trace_probe_compare_arg_type(&tk->tp, &old_tk->tp);
+			if (ret) {
+				/* Note that argument starts index = 2 */
+				trace_probe_log_set_index(ret + 1);
+				trace_probe_log_err(0, DIFF_ARG_TYPE);
+				ret = -EEXIST;
+			} else
+				ret = append_trace_kprobe(tk, old_tk);
+		}
+		goto end;
 	}
 
 	/* Register new event */
@@ -755,7 +795,7 @@ static int trace_kprobe_create(int argc, const char *argv[])
 			trace_probe_log_err(0, BAD_INSN_BNDRY);
 		else if (ret == -ENOENT)
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
-		else if (ret != -ENOMEM)
+		else if (ret != -ENOMEM && ret != -EEXIST)
 			trace_probe_log_err(0, FAIL_REG_PROBE);
 		goto error;
 	}
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 28733bd6b607..651a1449acde 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -886,6 +886,35 @@ int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	return 0;
 }
 
+static void trace_probe_event_free(struct trace_probe_event *tpe)
+{
+	kfree(tpe->class.system);
+	kfree(tpe->call.name);
+	kfree(tpe->call.print_fmt);
+	kfree(tpe);
+}
+
+int trace_probe_append(struct trace_probe *tp, struct trace_probe *to)
+{
+	if (trace_probe_has_sibling(tp))
+		return -EBUSY;
+
+	list_del_init(&tp->list);
+	trace_probe_event_free(tp->event);
+
+	tp->event = to->event;
+	list_add_tail(&tp->list, trace_probe_probe_list(to));
+
+	return 0;
+}
+
+void trace_probe_unlink(struct trace_probe *tp)
+{
+	list_del_init(&tp->list);
+	if (list_empty(trace_probe_probe_list(tp)))
+		trace_probe_event_free(tp->event);
+	tp->event = NULL;
+}
 
 void trace_probe_cleanup(struct trace_probe *tp)
 {
@@ -894,15 +923,8 @@ void trace_probe_cleanup(struct trace_probe *tp)
 	for (i = 0; i < tp->nr_args; i++)
 		traceprobe_free_probe_arg(&tp->args[i]);
 
-	if (tp->event) {
-		struct trace_event_call *call = trace_probe_event_call(tp);
-
-		kfree(tp->event->class.system);
-		kfree(call->name);
-		kfree(call->print_fmt);
-		kfree(tp->event);
-		tp->event = NULL;
-	}
+	if (tp->event)
+		trace_probe_unlink(tp);
 }
 
 int trace_probe_init(struct trace_probe *tp, const char *event,
@@ -1006,3 +1028,22 @@ int trace_probe_remove_file(struct trace_probe *tp,
 
 	return 0;
 }
+
+/*
+ * Return the smallest index of different type argument (start from 1).
+ * If all argument types and name are same, return 0.
+ */
+int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)
+{
+	int i;
+
+	for (i = 0; i < a->nr_args; i++) {
+		if ((b->nr_args <= i) ||
+		    ((a->args[i].type != b->args[i].type) ||
+		     (a->args[i].count != b->args[i].count) ||
+		     strcmp(a->args[i].name, b->args[i].name)))
+			return i + 1;
+	}
+
+	return 0;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 0b84abb884c2..39926e8a344b 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -302,6 +302,13 @@ static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
 	return &tp->event->probes;
 }
 
+static inline bool trace_probe_has_sibling(struct trace_probe *tp)
+{
+	struct list_head *list = trace_probe_probe_list(tp);
+
+	return !list_empty(list) && !list_is_singular(list);
+}
+
 static inline int trace_probe_unregister_event_call(struct trace_probe *tp)
 {
 	/* tp->event is unregistered in trace_remove_event_call() */
@@ -316,12 +323,15 @@ static inline bool trace_probe_has_single_file(struct trace_probe *tp)
 int trace_probe_init(struct trace_probe *tp, const char *event,
 		     const char *group);
 void trace_probe_cleanup(struct trace_probe *tp);
+int trace_probe_append(struct trace_probe *tp, struct trace_probe *to);
+void trace_probe_unlink(struct trace_probe *tp);
 int trace_probe_register_event_call(struct trace_probe *tp);
 int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file);
 int trace_probe_remove_file(struct trace_probe *tp,
 			    struct trace_event_file *file);
 struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
 						struct trace_event_file *file);
+int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b);
 
 #define trace_probe_for_each_link(pos, tp)	\
 	list_for_each_entry(pos, &(tp)->event->files, list)
@@ -419,7 +429,9 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	C(ARG_TOO_LONG,		"Argument expression is too long"),	\
 	C(NO_ARG_BODY,		"No argument expression"),		\
 	C(BAD_INSN_BNDRY,	"Probe point is not an instruction boundary"),\
-	C(FAIL_REG_PROBE,	"Failed to register probe event"),
+	C(FAIL_REG_PROBE,	"Failed to register probe event"),\
+	C(DIFF_PROBE_TYPE,	"Probe type is different from existing probe"),\
+	C(DIFF_ARG_TYPE,	"Argument type or name is different from existing probe"),
 
 #undef C
 #define C(a, b)		TP_ERR_##a


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 05/12] tracing/uprobe: Add multi-probe per uprobe event support
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2019-06-19 15:07 ` [PATCH v2 04/12] tracing/kprobe: Add multi-probe per event support Masami Hiramatsu
@ 2019-06-19 15:07 ` Masami Hiramatsu
  2019-06-19 15:08 ` [PATCH v2 06/12] tracing/kprobe: Add per-probe delete from event Masami Hiramatsu
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Allow user to define several probes on one uprobe event.
Note that this only support appending method. So deleting
event will delete all probes on the event.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace.c        |    2 +
 kernel/trace/trace_uprobe.c |   60 ++++++++++++++++++++++++++++++-------------
 2 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8f5455046504..73fbe3b0dd08 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4821,7 +4821,7 @@ static const char readme_msg[] =
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
-	"  uprobe_events\t\t- Add/remove/show the userspace dynamic events\n"
+	"  uprobe_events\t\t- Create/append/remove/show the userspace dynamic events\n"
 	"\t\t\t  Write into this file to define/undefine new trace events.\n"
 #endif
 #if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 437dddeca8bf..c568f7b16f5c 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -364,15 +364,32 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
 {
 	int ret;
 
+	if (trace_probe_has_sibling(&tu->tp))
+		goto unreg;
+
 	ret = unregister_uprobe_event(tu);
 	if (ret)
 		return ret;
 
+unreg:
 	dyn_event_remove(&tu->devent);
+	trace_probe_unlink(&tu->tp);
 	free_trace_uprobe(tu);
 	return 0;
 }
 
+static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
+{
+	int ret;
+
+	/* Append to existing event */
+	ret = trace_probe_append(&tu->tp, &to->tp);
+	if (!ret)
+		dyn_event_add(&tu->devent);
+
+	return ret;
+}
+
 /*
  * Uprobe with multiple reference counter is not allowed. i.e.
  * If inode and offset matches, reference counter offset *must*
@@ -382,25 +399,21 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
  * as the new one does not conflict with any other existing
  * ones.
  */
-static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
+static int validate_ref_ctr_offset(struct trace_uprobe *new)
 {
 	struct dyn_event *pos;
-	struct trace_uprobe *tmp, *old = NULL;
+	struct trace_uprobe *tmp;
 	struct inode *new_inode = d_real_inode(new->path.dentry);
 
-	old = find_probe_event(trace_probe_name(&new->tp),
-				trace_probe_group_name(&new->tp));
-
 	for_each_trace_uprobe(tmp, pos) {
-		if ((old ? old != tmp : true) &&
-		    new_inode == d_real_inode(tmp->path.dentry) &&
+		if (new_inode == d_real_inode(tmp->path.dentry) &&
 		    new->offset == tmp->offset &&
 		    new->ref_ctr_offset != tmp->ref_ctr_offset) {
 			pr_warn("Reference counter offset mismatch.");
-			return ERR_PTR(-EINVAL);
+			return -EINVAL;
 		}
 	}
-	return old;
+	return 0;
 }
 
 /* Register a trace_uprobe and probe_event */
@@ -411,18 +424,29 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
 
 	mutex_lock(&event_mutex);
 
-	/* register as an event */
-	old_tu = find_old_trace_uprobe(tu);
-	if (IS_ERR(old_tu)) {
-		ret = PTR_ERR(old_tu);
+	ret = validate_ref_ctr_offset(tu);
+	if (ret)
 		goto end;
-	}
 
+	/* register as an event */
+	old_tu = find_probe_event(trace_probe_name(&tu->tp),
+				  trace_probe_group_name(&tu->tp));
 	if (old_tu) {
-		/* delete old event */
-		ret = unregister_trace_uprobe(old_tu);
-		if (ret)
-			goto end;
+		if (is_ret_probe(tu) != is_ret_probe(old_tu)) {
+			trace_probe_log_set_index(0);
+			trace_probe_log_err(0, DIFF_PROBE_TYPE);
+			ret = -EEXIST;
+		} else {
+			ret = trace_probe_compare_arg_type(&tu->tp, &old_tu->tp);
+			if (ret) {
+				/* Note that argument starts index = 2 */
+				trace_probe_log_set_index(ret + 1);
+				trace_probe_log_err(0, DIFF_ARG_TYPE);
+				ret = -EEXIST;
+			} else
+				ret = append_trace_uprobe(tu, old_tu);
+		}
+		goto end;
 	}
 
 	ret = register_uprobe_event(tu);


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 06/12] tracing/kprobe: Add per-probe delete from event
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2019-06-19 15:07 ` [PATCH v2 05/12] tracing/uprobe: Add multi-probe per uprobe " Masami Hiramatsu
@ 2019-06-19 15:08 ` Masami Hiramatsu
  2019-06-19 15:08 ` [PATCH v2 07/12] tracing/uprobe: " Masami Hiramatsu
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:08 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Allow user to delete a probe from event. This is done by head
match. For example, if we have 2 probes on an event

$ cat kprobe_events
p:kprobes/testprobe _do_fork r1=%ax r2=%dx
p:kprobes/testprobe idle_fork r1=%ax r2=%cx

Then you can remove one of them by passing the head of definition
which identify the probe.

$ echo "-:kprobes/testprobe idle_fork" >> kprobe_events

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   25 ++++++++++++++++++++++++-
 kernel/trace/trace_probe.c  |   18 ++++++++++++++++++
 kernel/trace/trace_probe.h  |    2 ++
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f43098bf62dd..18c4175b6585 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -137,13 +137,36 @@ static bool trace_kprobe_is_busy(struct dyn_event *ev)
 	return trace_probe_is_enabled(&tk->tp);
 }
 
+static bool trace_kprobe_match_command_head(struct trace_kprobe *tk,
+					    int argc, const char **argv)
+{
+	char buf[MAX_ARGSTR_LEN + 1];
+
+	if (!argc)
+		return true;
+
+	if (!tk->symbol)
+		snprintf(buf, sizeof(buf), "0x%p", tk->rp.kp.addr);
+	else if (tk->rp.kp.offset)
+		snprintf(buf, sizeof(buf), "%s+%u",
+			 trace_kprobe_symbol(tk), tk->rp.kp.offset);
+	else
+		snprintf(buf, sizeof(buf), "%s", trace_kprobe_symbol(tk));
+	if (strcmp(buf, argv[0]))
+		return false;
+	argc--; argv++;
+
+	return trace_probe_match_command_args(&tk->tp, argc, argv);
+}
+
 static bool trace_kprobe_match(const char *system, const char *event,
 			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_kprobe *tk = to_trace_kprobe(ev);
 
 	return strcmp(trace_probe_name(&tk->tp), event) == 0 &&
-	    (!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0);
+	    (!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0) &&
+	    trace_kprobe_match_command_head(tk, argc, argv);
 }
 
 static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk)
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 651a1449acde..f8c3c65c035d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -1047,3 +1047,21 @@ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)
 
 	return 0;
 }
+
+bool trace_probe_match_command_args(struct trace_probe *tp,
+				    int argc, const char **argv)
+{
+	char buf[MAX_ARGSTR_LEN + 1];
+	int i;
+
+	if (tp->nr_args < argc)
+		return false;
+
+	for (i = 0; i < argc; i++) {
+		snprintf(buf, sizeof(buf), "%s=%s",
+			 tp->args[i].name, tp->args[i].comm);
+		if (strcmp(buf, argv[i]))
+			return false;
+	}
+	return true;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 39926e8a344b..2dcc4e317787 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -332,6 +332,8 @@ int trace_probe_remove_file(struct trace_probe *tp,
 struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,
 						struct trace_event_file *file);
 int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b);
+bool trace_probe_match_command_args(struct trace_probe *tp,
+				    int argc, const char **argv);
 
 #define trace_probe_for_each_link(pos, tp)	\
 	list_for_each_entry(pos, &(tp)->event->files, list)


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 07/12] tracing/uprobe: Add per-probe delete from event
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2019-06-19 15:08 ` [PATCH v2 06/12] tracing/kprobe: Add per-probe delete from event Masami Hiramatsu
@ 2019-06-19 15:08 ` Masami Hiramatsu
  2019-06-19 15:08 ` [PATCH v2 08/12] tracing/probe: Add immediate parameter support Masami Hiramatsu
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:08 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add per-probe delete method from one event passing the head of
definition. In other words, the events which match the head
N parameters are deleted.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Changes in v2:
  - Swap the checking order of filename for avoiding unexpected memory
    access.
---
 kernel/trace/trace_uprobe.c |   31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index c568f7b16f5c..878219552177 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -284,13 +284,42 @@ static bool trace_uprobe_is_busy(struct dyn_event *ev)
 	return trace_probe_is_enabled(&tu->tp);
 }
 
+static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
+					    int argc, const char **argv)
+{
+	char buf[MAX_ARGSTR_LEN + 1];
+	int len;
+
+	if (!argc)
+		return true;
+
+	len = strlen(tu->filename);
+	if (strncmp(tu->filename, argv[0], len) || argv[0][len] != ':')
+		return false;
+
+	if (tu->ref_ctr_offset == 0)
+		snprintf(buf, sizeof(buf), "0x%0*lx",
+				(int)(sizeof(void *) * 2), tu->offset);
+	else
+		snprintf(buf, sizeof(buf), "0x%0*lx(0x%lx)",
+				(int)(sizeof(void *) * 2), tu->offset,
+				tu->ref_ctr_offset);
+	if (strcmp(buf, &argv[0][len + 1]))
+		return false;
+
+	argc--; argv++;
+
+	return trace_probe_match_command_args(&tu->tp, argc, argv);
+}
+
 static bool trace_uprobe_match(const char *system, const char *event,
 			int argc, const char **argv, struct dyn_event *ev)
 {
 	struct trace_uprobe *tu = to_trace_uprobe(ev);
 
 	return strcmp(trace_probe_name(&tu->tp), event) == 0 &&
-	    (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
+	   (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0) &&
+	   trace_uprobe_match_command_head(tu, argc, argv);
 }
 
 static nokprobe_inline struct trace_uprobe *


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 08/12] tracing/probe: Add immediate parameter support
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (6 preceding siblings ...)
  2019-06-19 15:08 ` [PATCH v2 07/12] tracing/uprobe: " Masami Hiramatsu
@ 2019-06-19 15:08 ` Masami Hiramatsu
  2019-06-19 15:08 ` [PATCH v2 09/12] tracing/probe: Add immediate string " Masami Hiramatsu
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:08 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add immediate value parameter (\1234) support to
probe events. This allows you to specify an immediate
(or dummy) parameter instead of fetching from memory
or register.

This feature looks odd, but imagine when you put a probe
on a code to trace some data. If the code is compiled into
2 instructions and 1 instruction has a value but other has
nothing since it is optimized out.
In that case, you can not fold those into one event, even
if ftrace supported multiple probes on one event.
With this feature, you can set a dummy value like
foo=\deadbeef instead of something like foo=%di.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 Documentation/trace/kprobetrace.rst  |    1 +
 Documentation/trace/uprobetracer.rst |    1 +
 kernel/trace/trace.c                 |    2 +-
 kernel/trace/trace_probe.c           |   18 ++++++++++++++++++
 kernel/trace/trace_probe.h           |    1 +
 5 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
index af776989caca..772467f65a36 100644
--- a/Documentation/trace/kprobetrace.rst
+++ b/Documentation/trace/kprobetrace.rst
@@ -52,6 +52,7 @@ Synopsis of kprobe_events
   $retval	: Fetch return value.(\*2)
   $comm		: Fetch current task comm.
   +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\*4)
+  \IMM		: Store an immediate value to the argument.
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
 		  (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
diff --git a/Documentation/trace/uprobetracer.rst b/Documentation/trace/uprobetracer.rst
index ab13319c66ac..2b4697c0bed7 100644
--- a/Documentation/trace/uprobetracer.rst
+++ b/Documentation/trace/uprobetracer.rst
@@ -45,6 +45,7 @@ Synopsis of uprobe_tracer
    $retval	: Fetch return value.(\*1)
    $comm	: Fetch current task comm.
    +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*2)(\*3)
+   \IMM		: Store an immediate value to the argument.
    NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
    FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
 		       (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 73fbe3b0dd08..3608535f1935 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4846,7 +4846,7 @@ static const char readme_msg[] =
 #else
 	"\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
-	"\t           +|-[u]<offset>(<fetcharg>)\n"
+	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value\n"
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
 	"\t           <type>\\[<array-size>\\]\n"
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index f8c3c65c035d..fb90baec3cd8 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -316,6 +316,17 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
 	return -EINVAL;
 }
 
+static int str_to_immediate(char *str, unsigned long *imm)
+{
+	if (isdigit(str[0]))
+		return kstrtoul(str, 0, imm);
+	else if (str[0] == '-')
+		return kstrtol(str, 0, (long *)imm);
+	else if (str[0] == '+')
+		return kstrtol(str + 1, 0, (long *)imm);
+	return -EINVAL;
+}
+
 /* Recursive argument parser */
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
@@ -444,6 +455,13 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			code->offset = offset;
 		}
 		break;
+	case '\\':	/* Immediate value */
+		ret = str_to_immediate(arg + 1, &code->immediate);
+		if (ret)
+			trace_probe_log_err(offs + 1, BAD_IMM);
+		else
+			code->op = FETCH_OP_IMM;
+		break;
 	}
 	if (!ret && code->op == FETCH_OP_NOP) {
 		/* Parsed, but do not find fetch method */
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 2dcc4e317787..cc113b82a4ce 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -408,6 +408,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	C(BAD_VAR,		"Invalid $-valiable specified"),	\
 	C(BAD_REG_NAME,		"Invalid register name"),		\
 	C(BAD_MEM_ADDR,		"Invalid memory address"),		\
+	C(BAD_IMM,		"Invalid immediate value"),		\
 	C(FILE_ON_KPROBE,	"File offset is not available with kprobe"), \
 	C(BAD_FILE_OFFS,	"Invalid file offset value"),		\
 	C(SYM_ON_UPROBE,	"Symbol is not available with uprobe"),	\


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 09/12] tracing/probe: Add immediate string parameter support
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (7 preceding siblings ...)
  2019-06-19 15:08 ` [PATCH v2 08/12] tracing/probe: Add immediate parameter support Masami Hiramatsu
@ 2019-06-19 15:08 ` Masami Hiramatsu
  2019-06-19 15:08 ` [PATCH v2 10/12] selftests/ftrace: Add a testcase for kprobe multiprobe event Masami Hiramatsu
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:08 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add immediate string parameter (\"string") support to
probe events. This allows you to specify an immediate
(or dummy) parameter instead of fetching a string from
memory.

This feature looks odd, but imagine that you put a probe
on a code to trace some string data. If the code is
compiled into 2 instructions and 1 instruction has a
string on memory but other has no string since it is
optimized out. In that case, you can not fold those into
one event, even if ftrace supported multiple probes on
one event. With this feature, you can set a dummy string
like foo=\"(optimized)":string instead of something
like foo=+0(+0(%bp)):string.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 kernel/trace/trace.c        |    2 +-
 kernel/trace/trace_kprobe.c |    3 ++
 kernel/trace/trace_probe.c  |   56 ++++++++++++++++++++++++++++++++-----------
 kernel/trace/trace_probe.h  |    2 ++
 kernel/trace/trace_uprobe.c |    3 ++
 5 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 3608535f1935..ff9c9e627a87 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4846,7 +4846,7 @@ static const char readme_msg[] =
 #else
 	"\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
-	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value\n"
+	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
 	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
 	"\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
 	"\t           <type>\\[<array-size>\\]\n"
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 18c4175b6585..7579c53bb053 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1083,6 +1083,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	case FETCH_OP_COMM:
 		val = (unsigned long)current->comm;
 		break;
+	case FETCH_OP_DATA:
+		val = (unsigned long)code->data;
+		break;
 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
 	case FETCH_OP_ARG:
 		val = regs_get_kernel_argument(regs, code->param);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index fb90baec3cd8..1e67fef06e53 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -327,6 +327,18 @@ static int str_to_immediate(char *str, unsigned long *imm)
 	return -EINVAL;
 }
 
+static int __parse_imm_string(char *str, char **pbuf, int offs)
+{
+	size_t len = strlen(str);
+
+	if (str[len - 1] != '"') {
+		trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE);
+		return -EINVAL;
+	}
+	*pbuf = kstrndup(str, len - 1, GFP_KERNEL);
+	return 0;
+}
+
 /* Recursive argument parser */
 static int
 parse_probe_arg(char *arg, const struct fetch_type *type,
@@ -441,7 +453,8 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 			ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
 			if (ret)
 				break;
-			if (code->op == FETCH_OP_COMM) {
+			if (code->op == FETCH_OP_COMM ||
+			    code->op == FETCH_OP_DATA) {
 				trace_probe_log_err(offs, COMM_CANT_DEREF);
 				return -EINVAL;
 			}
@@ -456,11 +469,19 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
 		}
 		break;
 	case '\\':	/* Immediate value */
-		ret = str_to_immediate(arg + 1, &code->immediate);
-		if (ret)
-			trace_probe_log_err(offs + 1, BAD_IMM);
-		else
-			code->op = FETCH_OP_IMM;
+		if (arg[1] == '"') {	/* Immediate string */
+			ret = __parse_imm_string(arg + 2, &tmp, offs + 2);
+			if (ret)
+				break;
+			code->op = FETCH_OP_DATA;
+			code->data = tmp;
+		} else {
+			ret = str_to_immediate(arg + 1, &code->immediate);
+			if (ret)
+				trace_probe_log_err(offs + 1, BAD_IMM);
+			else
+				code->op = FETCH_OP_IMM;
+		}
 		break;
 	}
 	if (!ret && code->op == FETCH_OP_NOP) {
@@ -560,8 +581,11 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 		}
 	}
 
-	/* Since $comm can not be dereferred, we can find $comm by strcmp */
-	if (strcmp(arg, "$comm") == 0) {
+	/*
+	 * Since $comm and immediate string can not be dereferred,
+	 * we can find those by strcmp.
+	 */
+	if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) {
 		/* The type of $comm must be "string", and not an array. */
 		if (parg->count || (t && strcmp(t, "string")))
 			return -EINVAL;
@@ -598,7 +622,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 	if (!strcmp(parg->type->name, "string") ||
 	    !strcmp(parg->type->name, "ustring")) {
 		if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
-		    code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM) {
+		    code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
+		    code->op != FETCH_OP_DATA) {
 			trace_probe_log_err(offset + (t ? (t - arg) : 0),
 					    BAD_STRING);
 			ret = -EINVAL;
@@ -607,9 +632,10 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 		if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) ||
 		     parg->count) {
 			/*
-			 * IMM and COMM is pointing actual address, those must
-			 * be kept, and if parg->count != 0, this is an array
-			 * of string pointers instead of string address itself.
+			 * IMM, DATA and COMM is pointing actual address, those
+			 * must be kept, and if parg->count != 0, this is an
+			 * array of string pointers instead of string address
+			 * itself.
 			 */
 			code++;
 			if (code->op != FETCH_OP_NOP) {
@@ -683,7 +709,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
 fail:
 	if (ret) {
 		for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)
-			if (code->op == FETCH_NOP_SYMBOL)
+			if (code->op == FETCH_NOP_SYMBOL ||
+			    code->op == FETCH_OP_DATA)
 				kfree(code->data);
 	}
 	kfree(tmp);
@@ -754,7 +781,8 @@ void traceprobe_free_probe_arg(struct probe_arg *arg)
 	struct fetch_insn *code = arg->code;
 
 	while (code && code->op != FETCH_OP_END) {
-		if (code->op == FETCH_NOP_SYMBOL)
+		if (code->op == FETCH_NOP_SYMBOL ||
+		    code->op == FETCH_OP_DATA)
 			kfree(code->data);
 		code++;
 	}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index cc113b82a4ce..f805cc4cbe7c 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -89,6 +89,7 @@ enum fetch_op {
 	FETCH_OP_COMM,		/* Current comm */
 	FETCH_OP_ARG,		/* Function argument : .param */
 	FETCH_OP_FOFFS,		/* File offset: .immediate */
+	FETCH_OP_DATA,		/* Allocated data: .data */
 	// Stage 2 (dereference) op
 	FETCH_OP_DEREF,		/* Dereference: .offset */
 	FETCH_OP_UDEREF,	/* User-space Dereference: .offset */
@@ -409,6 +410,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 	C(BAD_REG_NAME,		"Invalid register name"),		\
 	C(BAD_MEM_ADDR,		"Invalid memory address"),		\
 	C(BAD_IMM,		"Invalid immediate value"),		\
+	C(IMMSTR_NO_CLOSE,	"String is not closed with '\"'"),	\
 	C(FILE_ON_KPROBE,	"File offset is not available with kprobe"), \
 	C(BAD_FILE_OFFS,	"Invalid file offset value"),		\
 	C(SYM_ON_UPROBE,	"Symbol is not available with uprobe"),	\
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 878219552177..89ab3972fc77 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -248,6 +248,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
 	case FETCH_OP_COMM:
 		val = FETCH_TOKEN_COMM;
 		break;
+	case FETCH_OP_DATA:
+		val = (unsigned long)code->data;
+		break;
 	case FETCH_OP_FOFFS:
 		val = translate_user_vaddr(code->immediate);
 		break;


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 10/12] selftests/ftrace: Add a testcase for kprobe multiprobe event
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (8 preceding siblings ...)
  2019-06-19 15:08 ` [PATCH v2 09/12] tracing/probe: Add immediate string " Masami Hiramatsu
@ 2019-06-19 15:08 ` Masami Hiramatsu
  2019-06-19 15:08 ` [PATCH v2 11/12] selftests/ftrace: Add syntax error test for immediates Masami Hiramatsu
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:08 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add a testcase for kprobe event with multi-probe.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 ++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
new file mode 100644
index 000000000000..44494bac86d1
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
@@ -0,0 +1,35 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Create/delete multiprobe on kprobe event
+
+[ -f kprobe_events ] || exit_unsupported
+
+grep -q "Create/append/" README || exit_unsupported
+
+# Choose 2 symbols for target
+SYM1=_do_fork
+SYM2=do_exit
+EVENT_NAME=kprobes/testevent
+
+DEF1="p:$EVENT_NAME $SYM1"
+DEF2="p:$EVENT_NAME $SYM2"
+
+:;: "Define an event which has 2 probes" ;:
+echo $DEF1 >> kprobe_events
+echo $DEF2 >> kprobe_events
+cat kprobe_events | grep "$DEF1"
+cat kprobe_events | grep "$DEF2"
+
+:;: "Remove the event by name (should remove both)" ;:
+echo "-:$EVENT_NAME" >> kprobe_events
+test `cat kprobe_events | wc -l` -eq 0
+
+:;: "Remove just 1 event" ;:
+echo $DEF1 >> kprobe_events
+echo $DEF2 >> kprobe_events
+echo "-:$EVENT_NAME $SYM1" >> kprobe_events
+! cat kprobe_events | grep "$DEF1"
+cat kprobe_events | grep "$DEF2"
+
+:;: "Appending different type must fail" ;:
+! echo "$DEF1 \$stack" >> kprobe_events


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 11/12] selftests/ftrace: Add syntax error test for immediates
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (9 preceding siblings ...)
  2019-06-19 15:08 ` [PATCH v2 10/12] selftests/ftrace: Add a testcase for kprobe multiprobe event Masami Hiramatsu
@ 2019-06-19 15:08 ` Masami Hiramatsu
  2019-06-19 15:09 ` [PATCH v2 12/12] selftests/ftrace: Add syntax error test for multiprobe Masami Hiramatsu
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:08 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add syntax error test cases for immediate value and
immediate string.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
index 29faaec942c6..aa59944bcace 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
@@ -41,6 +41,11 @@ check_error 'p vfs_read ^%none_reg'	# BAD_REG_NAME
 check_error 'p vfs_read ^@12345678abcde'	# BAD_MEM_ADDR
 check_error 'p vfs_read ^@+10'		# FILE_ON_KPROBE
 
+grep -q "imm-value" README && \
+check_error 'p vfs_read arg1=\^x'	# BAD_IMM
+grep -q "imm-string" README && \
+check_error 'p vfs_read arg1=\"abcd^'	# IMMSTR_NO_CLOSE
+
 check_error 'p vfs_read ^+0@0)'		# DEREF_NEED_BRACE
 check_error 'p vfs_read ^+0ab1(@0)'	# BAD_DEREF_OFFS
 check_error 'p vfs_read +0(+0(@0^)'	# DEREF_OPEN_BRACE


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 12/12] selftests/ftrace: Add syntax error test for multiprobe
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (10 preceding siblings ...)
  2019-06-19 15:08 ` [PATCH v2 11/12] selftests/ftrace: Add syntax error test for immediates Masami Hiramatsu
@ 2019-06-19 15:09 ` Masami Hiramatsu
  2019-07-04  6:39 ` [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
  2019-07-31 15:25 ` Steven Rostedt
  13 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-06-19 15:09 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Ingo Molnar, linux-kernel, Tom Zanussi,
	Ravi Bangoria, Namhyung Kim, Arnaldo Carvalho de Melo

Add syntax error test cases for multiprobe appending
errors.

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
---
 tools/testing/selftests/ftrace/test.d/functions    |    2 +-
 .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index 779ec11f61bd..1cac8cc2cb35 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -115,7 +115,7 @@ ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
     command=$(echo "$2" | tr -d ^)
     echo "Test command: $command"
     echo > error_log
-    (! echo "$command" > "$3" ) 2> /dev/null
+    (! echo "$command" >> "$3" ) 2> /dev/null
     grep "$1: error:" -A 3 error_log
     N=$(tail -n 1 error_log | wc -c)
     # "  Command: " and "^\n" => 13
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
index aa59944bcace..39ef7ac1f51c 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc
@@ -87,4 +87,14 @@ case $(uname -m) in
     ;;
 esac
 
+# multiprobe errors
+if grep -q "Create/append/" README && grep -q "imm-value" README; then
+echo 'p:kprobes/testevent _do_fork' > kprobe_events
+check_error '^r:kprobes/testevent do_exit'	# DIFF_PROBE_TYPE
+echo 'p:kprobes/testevent _do_fork abcd=\1' > kprobe_events
+check_error 'p:kprobes/testevent _do_fork ^bcd=\1'	# DIFF_ARG_TYPE
+check_error 'p:kprobes/testevent _do_fork ^abcd=\1:u8'	# DIFF_ARG_TYPE
+check_error 'p:kprobes/testevent _do_fork ^abcd=\"foo"'	# DIFF_ARG_TYPE
+fi
+
 exit 0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (11 preceding siblings ...)
  2019-06-19 15:09 ` [PATCH v2 12/12] selftests/ftrace: Add syntax error test for multiprobe Masami Hiramatsu
@ 2019-07-04  6:39 ` Masami Hiramatsu
  2019-07-04 11:28   ` Steven Rostedt
  2019-07-31 15:25 ` Steven Rostedt
  13 siblings, 1 reply; 19+ messages in thread
From: Masami Hiramatsu @ 2019-07-04  6:39 UTC (permalink / raw)
  To: Steven Rostedt, Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

Hi Steve,

Would you have any comment on this?

Thank you,

On Thu, 20 Jun 2019 00:07:09 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hello,
> 
> This is the 2nd version of multi-probes per event support on ftrace
> and perf-tools.
> 
> Previous version is here;
> https://lkml.org/lkml/2019/5/31/573
> 
> >From this version, I omitted first 9 patches which has been picked
> to Steve's tree.
> In this version, I've fixed some bugs and hardened some unexpected
> error cases according to Steve's comment.
> Here are changes in this version:
> 
>  - [1/12] This have below changes. 
>     - Warn if the primary trace_probe does not exist.
>     - Fix enable_trace_kprobe() to not return error if the any probes
>       are "gone" state. If all probes have gone or any other error
>       reason, the event can not be enabled and return error.
>     - Fix trace_probe_enable() to roll back all enabled uprobe if
>       any one of uprobe is failed to enable.
>  - [7/12] Swap the checking order of filename for avoiding unexpected
>      memory access.
> 
> 
> ====
> For trace-event, we can insert same trace-event on several places
> on the code, and those can record similar information as a same event
> with same format.
> 
> This series implements similar feature on probe-event. Since the probe
> event is based on the compiled binary, sometimes we find that the target
> source line is complied into several different addresses, e.g. inlined
> function, unrolled loop, etc. In those cases, it is useful to put a
> same probe-event on different addresses.
> 
> With this series, we can append multi probes on one event as below
> 
>   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
>   # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
>   # kprobe_events
>   p:kprobes/testevent _do_fork r1=%ax r2=%dx
>   p:kprobes/testevent fork_idle r1=%ax r2=%cx
> 
> This means testevent is hit on both of _do_fork and fork_idle.
> As you can see, the appended event must have same number of arguments
> and those must have same 'type' and 'name' as original one. This is like
> a function signature, it checks whether the appending event has the same
> type and name of event arguments and same probe type, but doesn't care
> about the assignment.
> 
> So, below appending commands will be rejected.
> 
>   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
>   # echo p:testevent fork_idle r1=%ax >> kprobe_events
>   (No 2nd argument)
>   # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
>   (The type of 2nd argument is different)
> 
> If one inlined code has an argument on a register, but another
> inlined code has fixed value (as a result of optimization),
> you can also specify the fixed immediate value, e.g.
> 
>   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
>   # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events
> 
> 
> Thank you,
> 
> ---
> 
> Masami Hiramatsu (12):
>       tracing/probe: Split trace_event related data from trace_probe
>       tracing/dynevent: Delete all matched events
>       tracing/dynevent: Pass extra arguments to match operation
>       tracing/kprobe: Add multi-probe per event support
>       tracing/uprobe: Add multi-probe per uprobe event support
>       tracing/kprobe: Add per-probe delete from event
>       tracing/uprobe: Add per-probe delete from event
>       tracing/probe: Add immediate parameter support
>       tracing/probe: Add immediate string parameter support
>       selftests/ftrace: Add a testcase for kprobe multiprobe event
>       selftests/ftrace: Add syntax error test for immediates
>       selftests/ftrace: Add syntax error test for multiprobe
> 
> 
>  Documentation/trace/kprobetrace.rst                |    1 
>  Documentation/trace/uprobetracer.rst               |    1 
>  kernel/trace/trace.c                               |    8 -
>  kernel/trace/trace_dynevent.c                      |   10 +
>  kernel/trace/trace_dynevent.h                      |    7 -
>  kernel/trace/trace_events_hist.c                   |    4 
>  kernel/trace/trace_kprobe.c                        |  241 ++++++++++++++----
>  kernel/trace/trace_probe.c                         |  176 +++++++++++--
>  kernel/trace/trace_probe.h                         |   67 ++++-
>  kernel/trace/trace_uprobe.c                        |  263 +++++++++++++++-----
>  tools/testing/selftests/ftrace/test.d/functions    |    2 
>  .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 +++
>  .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   15 +
>  13 files changed, 665 insertions(+), 165 deletions(-)
>  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
> 
> --
> Masami Hiramatsu (Linaro) <mhiramat@kernel.org>


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
  2019-07-04  6:39 ` [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
@ 2019-07-04 11:28   ` Steven Rostedt
  2019-07-30  6:23     ` Masami Hiramatsu
  0 siblings, 1 reply; 19+ messages in thread
From: Steven Rostedt @ 2019-07-04 11:28 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Thu, 4 Jul 2019 15:39:58 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hi Steve,
> 
> Would you have any comment on this?
> 

Hi Masami,

It's on my todo list. As today is a US holiday, I'll look at this on
Monday.

Thanks for the reminder!

-- Steve


> Thank you,
> 
> On Thu, 20 Jun 2019 00:07:09 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > Hello,
> > 
> > This is the 2nd version of multi-probes per event support on ftrace
> > and perf-tools.
> > 
> > Previous version is here;
> > https://lkml.org/lkml/2019/5/31/573
> >   
> > >From this version, I omitted first 9 patches which has been picked  
> > to Steve's tree.
> > In this version, I've fixed some bugs and hardened some unexpected
> > error cases according to Steve's comment.
> > Here are changes in this version:
> > 
> >  - [1/12] This have below changes. 
> >     - Warn if the primary trace_probe does not exist.
> >     - Fix enable_trace_kprobe() to not return error if the any probes
> >       are "gone" state. If all probes have gone or any other error
> >       reason, the event can not be enabled and return error.
> >     - Fix trace_probe_enable() to roll back all enabled uprobe if
> >       any one of uprobe is failed to enable.
> >  - [7/12] Swap the checking order of filename for avoiding unexpected
> >      memory access.
> > 
> > 
> > ====
> > For trace-event, we can insert same trace-event on several places
> > on the code, and those can record similar information as a same event
> > with same format.
> > 
> > This series implements similar feature on probe-event. Since the probe
> > event is based on the compiled binary, sometimes we find that the target
> > source line is complied into several different addresses, e.g. inlined
> > function, unrolled loop, etc. In those cases, it is useful to put a
> > same probe-event on different addresses.
> > 
> > With this series, we can append multi probes on one event as below
> > 
> >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> >   # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
> >   # kprobe_events
> >   p:kprobes/testevent _do_fork r1=%ax r2=%dx
> >   p:kprobes/testevent fork_idle r1=%ax r2=%cx
> > 
> > This means testevent is hit on both of _do_fork and fork_idle.
> > As you can see, the appended event must have same number of arguments
> > and those must have same 'type' and 'name' as original one. This is like
> > a function signature, it checks whether the appending event has the same
> > type and name of event arguments and same probe type, but doesn't care
> > about the assignment.
> > 
> > So, below appending commands will be rejected.
> > 
> >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> >   # echo p:testevent fork_idle r1=%ax >> kprobe_events
> >   (No 2nd argument)
> >   # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
> >   (The type of 2nd argument is different)
> > 
> > If one inlined code has an argument on a register, but another
> > inlined code has fixed value (as a result of optimization),
> > you can also specify the fixed immediate value, e.g.
> > 
> >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> >   # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events
> > 
> > 
> > Thank you,
> > 
> > ---
> > 
> > Masami Hiramatsu (12):
> >       tracing/probe: Split trace_event related data from trace_probe
> >       tracing/dynevent: Delete all matched events
> >       tracing/dynevent: Pass extra arguments to match operation
> >       tracing/kprobe: Add multi-probe per event support
> >       tracing/uprobe: Add multi-probe per uprobe event support
> >       tracing/kprobe: Add per-probe delete from event
> >       tracing/uprobe: Add per-probe delete from event
> >       tracing/probe: Add immediate parameter support
> >       tracing/probe: Add immediate string parameter support
> >       selftests/ftrace: Add a testcase for kprobe multiprobe event
> >       selftests/ftrace: Add syntax error test for immediates
> >       selftests/ftrace: Add syntax error test for multiprobe
> > 
> > 
> >  Documentation/trace/kprobetrace.rst                |    1 
> >  Documentation/trace/uprobetracer.rst               |    1 
> >  kernel/trace/trace.c                               |    8 -
> >  kernel/trace/trace_dynevent.c                      |   10 +
> >  kernel/trace/trace_dynevent.h                      |    7 -
> >  kernel/trace/trace_events_hist.c                   |    4 
> >  kernel/trace/trace_kprobe.c                        |  241 ++++++++++++++----
> >  kernel/trace/trace_probe.c                         |  176 +++++++++++--
> >  kernel/trace/trace_probe.h                         |   67 ++++-
> >  kernel/trace/trace_uprobe.c                        |  263 +++++++++++++++-----
> >  tools/testing/selftests/ftrace/test.d/functions    |    2 
> >  .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 +++
> >  .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   15 +
> >  13 files changed, 665 insertions(+), 165 deletions(-)
> >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
> > 
> > --
> > Masami Hiramatsu (Linaro) <mhiramat@kernel.org>  
> 
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
  2019-07-04 11:28   ` Steven Rostedt
@ 2019-07-30  6:23     ` Masami Hiramatsu
  2019-07-30 15:03       ` Steven Rostedt
  0 siblings, 1 reply; 19+ messages in thread
From: Masami Hiramatsu @ 2019-07-30  6:23 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

Hi Steve,

Have you already picked this series?
If not yet, should I update and resend this series?

Thank you,

On Thu, 4 Jul 2019 07:28:33 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Thu, 4 Jul 2019 15:39:58 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > Hi Steve,
> > 
> > Would you have any comment on this?
> > 
> 
> Hi Masami,
> 
> It's on my todo list. As today is a US holiday, I'll look at this on
> Monday.
> 
> Thanks for the reminder!
> 
> -- Steve
> 
> 
> > Thank you,
> > 
> > On Thu, 20 Jun 2019 00:07:09 +0900
> > Masami Hiramatsu <mhiramat@kernel.org> wrote:
> > 
> > > Hello,
> > > 
> > > This is the 2nd version of multi-probes per event support on ftrace
> > > and perf-tools.
> > > 
> > > Previous version is here;
> > > https://lkml.org/lkml/2019/5/31/573
> > >   
> > > >From this version, I omitted first 9 patches which has been picked  
> > > to Steve's tree.
> > > In this version, I've fixed some bugs and hardened some unexpected
> > > error cases according to Steve's comment.
> > > Here are changes in this version:
> > > 
> > >  - [1/12] This have below changes. 
> > >     - Warn if the primary trace_probe does not exist.
> > >     - Fix enable_trace_kprobe() to not return error if the any probes
> > >       are "gone" state. If all probes have gone or any other error
> > >       reason, the event can not be enabled and return error.
> > >     - Fix trace_probe_enable() to roll back all enabled uprobe if
> > >       any one of uprobe is failed to enable.
> > >  - [7/12] Swap the checking order of filename for avoiding unexpected
> > >      memory access.
> > > 
> > > 
> > > ====
> > > For trace-event, we can insert same trace-event on several places
> > > on the code, and those can record similar information as a same event
> > > with same format.
> > > 
> > > This series implements similar feature on probe-event. Since the probe
> > > event is based on the compiled binary, sometimes we find that the target
> > > source line is complied into several different addresses, e.g. inlined
> > > function, unrolled loop, etc. In those cases, it is useful to put a
> > > same probe-event on different addresses.
> > > 
> > > With this series, we can append multi probes on one event as below
> > > 
> > >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> > >   # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
> > >   # kprobe_events
> > >   p:kprobes/testevent _do_fork r1=%ax r2=%dx
> > >   p:kprobes/testevent fork_idle r1=%ax r2=%cx
> > > 
> > > This means testevent is hit on both of _do_fork and fork_idle.
> > > As you can see, the appended event must have same number of arguments
> > > and those must have same 'type' and 'name' as original one. This is like
> > > a function signature, it checks whether the appending event has the same
> > > type and name of event arguments and same probe type, but doesn't care
> > > about the assignment.
> > > 
> > > So, below appending commands will be rejected.
> > > 
> > >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> > >   # echo p:testevent fork_idle r1=%ax >> kprobe_events
> > >   (No 2nd argument)
> > >   # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
> > >   (The type of 2nd argument is different)
> > > 
> > > If one inlined code has an argument on a register, but another
> > > inlined code has fixed value (as a result of optimization),
> > > you can also specify the fixed immediate value, e.g.
> > > 
> > >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> > >   # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events
> > > 
> > > 
> > > Thank you,
> > > 
> > > ---
> > > 
> > > Masami Hiramatsu (12):
> > >       tracing/probe: Split trace_event related data from trace_probe
> > >       tracing/dynevent: Delete all matched events
> > >       tracing/dynevent: Pass extra arguments to match operation
> > >       tracing/kprobe: Add multi-probe per event support
> > >       tracing/uprobe: Add multi-probe per uprobe event support
> > >       tracing/kprobe: Add per-probe delete from event
> > >       tracing/uprobe: Add per-probe delete from event
> > >       tracing/probe: Add immediate parameter support
> > >       tracing/probe: Add immediate string parameter support
> > >       selftests/ftrace: Add a testcase for kprobe multiprobe event
> > >       selftests/ftrace: Add syntax error test for immediates
> > >       selftests/ftrace: Add syntax error test for multiprobe
> > > 
> > > 
> > >  Documentation/trace/kprobetrace.rst                |    1 
> > >  Documentation/trace/uprobetracer.rst               |    1 
> > >  kernel/trace/trace.c                               |    8 -
> > >  kernel/trace/trace_dynevent.c                      |   10 +
> > >  kernel/trace/trace_dynevent.h                      |    7 -
> > >  kernel/trace/trace_events_hist.c                   |    4 
> > >  kernel/trace/trace_kprobe.c                        |  241 ++++++++++++++----
> > >  kernel/trace/trace_probe.c                         |  176 +++++++++++--
> > >  kernel/trace/trace_probe.h                         |   67 ++++-
> > >  kernel/trace/trace_uprobe.c                        |  263 +++++++++++++++-----
> > >  tools/testing/selftests/ftrace/test.d/functions    |    2 
> > >  .../ftrace/test.d/kprobe/kprobe_multiprobe.tc      |   35 +++
> > >  .../ftrace/test.d/kprobe/kprobe_syntax_errors.tc   |   15 +
> > >  13 files changed, 665 insertions(+), 165 deletions(-)
> > >  create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc
> > > 
> > > --
> > > Masami Hiramatsu (Linaro) <mhiramat@kernel.org>  
> > 
> > 
> 


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
  2019-07-30  6:23     ` Masami Hiramatsu
@ 2019-07-30 15:03       ` Steven Rostedt
  0 siblings, 0 replies; 19+ messages in thread
From: Steven Rostedt @ 2019-07-30 15:03 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Tue, 30 Jul 2019 15:23:31 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hi Steve,
> 
> Have you already picked this series?
> If not yet, should I update and resend this series?

I started to, but then got distracted :-/

I'll work with the current series, no need to resend.

Sorry for the delay.

-- Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
  2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
                   ` (12 preceding siblings ...)
  2019-07-04  6:39 ` [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
@ 2019-07-31 15:25 ` Steven Rostedt
  2019-08-01 14:01   ` Masami Hiramatsu
  13 siblings, 1 reply; 19+ messages in thread
From: Steven Rostedt @ 2019-07-31 15:25 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Thu, 20 Jun 2019 00:07:09 +0900
Masami Hiramatsu <mhiramat@kernel.org> wrote:

> Hello,
> 
> This is the 2nd version of multi-probes per event support on ftrace
> and perf-tools.
> 
> Previous version is here;
> https://lkml.org/lkml/2019/5/31/573
> 
> >From this version, I omitted first 9 patches which has been picked  
> to Steve's tree.
> In this version, I've fixed some bugs and hardened some unexpected
> error cases according to Steve's comment.
> Here are changes in this version:
> 
>  - [1/12] This have below changes. 
>     - Warn if the primary trace_probe does not exist.
>     - Fix enable_trace_kprobe() to not return error if the any probes
>       are "gone" state. If all probes have gone or any other error
>       reason, the event can not be enabled and return error.
>     - Fix trace_probe_enable() to roll back all enabled uprobe if
>       any one of uprobe is failed to enable.
>  - [7/12] Swap the checking order of filename for avoiding unexpected
>      memory access.
> 
> 
> ====
> For trace-event, we can insert same trace-event on several places
> on the code, and those can record similar information as a same event
> with same format.
> 
> This series implements similar feature on probe-event. Since the probe
> event is based on the compiled binary, sometimes we find that the target
> source line is complied into several different addresses, e.g. inlined
> function, unrolled loop, etc. In those cases, it is useful to put a
> same probe-event on different addresses.
> 
> With this series, we can append multi probes on one event as below
> 
>   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
>   # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
>   # kprobe_events
>   p:kprobes/testevent _do_fork r1=%ax r2=%dx
>   p:kprobes/testevent fork_idle r1=%ax r2=%cx
> 
> This means testevent is hit on both of _do_fork and fork_idle.
> As you can see, the appended event must have same number of arguments
> and those must have same 'type' and 'name' as original one. This is like
> a function signature, it checks whether the appending event has the same
> type and name of event arguments and same probe type, but doesn't care
> about the assignment.
> 
> So, below appending commands will be rejected.
> 
>   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
>   # echo p:testevent fork_idle r1=%ax >> kprobe_events
>   (No 2nd argument)
>   # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
>   (The type of 2nd argument is different)
> 
> If one inlined code has an argument on a register, but another
> inlined code has fixed value (as a result of optimization),
> you can also specify the fixed immediate value, e.g.
> 
>   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
>   # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events
> 
> 


Hi Masami,

I applied this patch set to my queue. Nice feature! I'll probably be
testing it a bit more. I wont be pushing it to my repo until v5.3-rc3
comes out, as I'll plan on rebasing my for-next branch on that.

Thanks!

-- Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/12] tracing/probe: Add multi-probes per event support
  2019-07-31 15:25 ` Steven Rostedt
@ 2019-08-01 14:01   ` Masami Hiramatsu
  0 siblings, 0 replies; 19+ messages in thread
From: Masami Hiramatsu @ 2019-08-01 14:01 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Tom Zanussi, Ravi Bangoria,
	Namhyung Kim, Arnaldo Carvalho de Melo

On Wed, 31 Jul 2019 11:25:39 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Thu, 20 Jun 2019 00:07:09 +0900
> Masami Hiramatsu <mhiramat@kernel.org> wrote:
> 
> > Hello,
> > 
> > This is the 2nd version of multi-probes per event support on ftrace
> > and perf-tools.
> > 
> > Previous version is here;
> > https://lkml.org/lkml/2019/5/31/573
> > 
> > >From this version, I omitted first 9 patches which has been picked  
> > to Steve's tree.
> > In this version, I've fixed some bugs and hardened some unexpected
> > error cases according to Steve's comment.
> > Here are changes in this version:
> > 
> >  - [1/12] This have below changes. 
> >     - Warn if the primary trace_probe does not exist.
> >     - Fix enable_trace_kprobe() to not return error if the any probes
> >       are "gone" state. If all probes have gone or any other error
> >       reason, the event can not be enabled and return error.
> >     - Fix trace_probe_enable() to roll back all enabled uprobe if
> >       any one of uprobe is failed to enable.
> >  - [7/12] Swap the checking order of filename for avoiding unexpected
> >      memory access.
> > 
> > 
> > ====
> > For trace-event, we can insert same trace-event on several places
> > on the code, and those can record similar information as a same event
> > with same format.
> > 
> > This series implements similar feature on probe-event. Since the probe
> > event is based on the compiled binary, sometimes we find that the target
> > source line is complied into several different addresses, e.g. inlined
> > function, unrolled loop, etc. In those cases, it is useful to put a
> > same probe-event on different addresses.
> > 
> > With this series, we can append multi probes on one event as below
> > 
> >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> >   # echo p:testevent fork_idle r1=%ax r2=%cx >> kprobe_events
> >   # kprobe_events
> >   p:kprobes/testevent _do_fork r1=%ax r2=%dx
> >   p:kprobes/testevent fork_idle r1=%ax r2=%cx
> > 
> > This means testevent is hit on both of _do_fork and fork_idle.
> > As you can see, the appended event must have same number of arguments
> > and those must have same 'type' and 'name' as original one. This is like
> > a function signature, it checks whether the appending event has the same
> > type and name of event arguments and same probe type, but doesn't care
> > about the assignment.
> > 
> > So, below appending commands will be rejected.
> > 
> >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> >   # echo p:testevent fork_idle r1=%ax >> kprobe_events
> >   (No 2nd argument)
> >   # echo p:testevent fork_idle r1=%ax r2=%ax:x8 >> kprobe_events
> >   (The type of 2nd argument is different)
> > 
> > If one inlined code has an argument on a register, but another
> > inlined code has fixed value (as a result of optimization),
> > you can also specify the fixed immediate value, e.g.
> > 
> >   # echo p:testevent _do_fork r1=%ax r2=%dx > kprobe_events
> >   # echo p:testevent fork_idle r1=%ax r2=\1 >> kprobe_events
> > 
> > 
> 
> 
> Hi Masami,
> 
> I applied this patch set to my queue. Nice feature! I'll probably be
> testing it a bit more. I wont be pushing it to my repo until v5.3-rc3
> comes out, as I'll plan on rebasing my for-next branch on that.

Thanks! if there is any issue, please let me know.
I also start working on perf probe part to support this.

Thank you,

> 
> Thanks!
> 
> -- Steve


-- 
Masami Hiramatsu <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2019-08-01 14:01 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-19 15:07 [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
2019-06-19 15:07 ` [PATCH v2 01/12] tracing/probe: Split trace_event related data from trace_probe Masami Hiramatsu
2019-06-19 15:07 ` [PATCH v2 02/12] tracing/dynevent: Delete all matched events Masami Hiramatsu
2019-06-19 15:07 ` [PATCH v2 03/12] tracing/dynevent: Pass extra arguments to match operation Masami Hiramatsu
2019-06-19 15:07 ` [PATCH v2 04/12] tracing/kprobe: Add multi-probe per event support Masami Hiramatsu
2019-06-19 15:07 ` [PATCH v2 05/12] tracing/uprobe: Add multi-probe per uprobe " Masami Hiramatsu
2019-06-19 15:08 ` [PATCH v2 06/12] tracing/kprobe: Add per-probe delete from event Masami Hiramatsu
2019-06-19 15:08 ` [PATCH v2 07/12] tracing/uprobe: " Masami Hiramatsu
2019-06-19 15:08 ` [PATCH v2 08/12] tracing/probe: Add immediate parameter support Masami Hiramatsu
2019-06-19 15:08 ` [PATCH v2 09/12] tracing/probe: Add immediate string " Masami Hiramatsu
2019-06-19 15:08 ` [PATCH v2 10/12] selftests/ftrace: Add a testcase for kprobe multiprobe event Masami Hiramatsu
2019-06-19 15:08 ` [PATCH v2 11/12] selftests/ftrace: Add syntax error test for immediates Masami Hiramatsu
2019-06-19 15:09 ` [PATCH v2 12/12] selftests/ftrace: Add syntax error test for multiprobe Masami Hiramatsu
2019-07-04  6:39 ` [PATCH v2 00/12] tracing/probe: Add multi-probes per event support Masami Hiramatsu
2019-07-04 11:28   ` Steven Rostedt
2019-07-30  6:23     ` Masami Hiramatsu
2019-07-30 15:03       ` Steven Rostedt
2019-07-31 15:25 ` Steven Rostedt
2019-08-01 14:01   ` Masami Hiramatsu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.