Commit fe60b0ce authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Steven Rostedt (VMware)

tracing/probe: Reject exactly same probe event

Reject exactly same probe events as existing probes.

Multiprobe allows user to define multiple probes on same
event. If user appends a probe which exactly same definition
(same probe address and same arguments) on existing event,
the event will record same probe information twice.
That can be confusing users, so reject it.

Link: http://lkml.kernel.org/r/156879694602.31056.5533024778165036763.stgit@devnote2Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent 44d00dc7
...@@ -528,10 +528,53 @@ static int unregister_trace_kprobe(struct trace_kprobe *tk) ...@@ -528,10 +528,53 @@ static int unregister_trace_kprobe(struct trace_kprobe *tk)
return 0; return 0;
} }
static bool trace_kprobe_has_same_kprobe(struct trace_kprobe *orig,
struct trace_kprobe *comp)
{
struct trace_probe_event *tpe = orig->tp.event;
struct trace_probe *pos;
int i;
list_for_each_entry(pos, &tpe->probes, list) {
orig = container_of(pos, struct trace_kprobe, tp);
if (strcmp(trace_kprobe_symbol(orig),
trace_kprobe_symbol(comp)) ||
trace_kprobe_offset(orig) != trace_kprobe_offset(comp))
continue;
/*
* trace_probe_compare_arg_type() ensured that nr_args and
* each argument name and type are same. Let's compare comm.
*/
for (i = 0; i < orig->tp.nr_args; i++) {
if (strcmp(orig->tp.args[i].comm,
comp->tp.args[i].comm))
continue;
}
return true;
}
return false;
}
static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprobe *to) static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprobe *to)
{ {
int ret; int ret;
ret = trace_probe_compare_arg_type(&tk->tp, &to->tp);
if (ret) {
/* Note that argument starts index = 2 */
trace_probe_log_set_index(ret + 1);
trace_probe_log_err(0, DIFF_ARG_TYPE);
return -EEXIST;
}
if (trace_kprobe_has_same_kprobe(to, tk)) {
trace_probe_log_set_index(0);
trace_probe_log_err(0, SAME_PROBE);
return -EEXIST;
}
/* Append to existing event */ /* Append to existing event */
ret = trace_probe_append(&tk->tp, &to->tp); ret = trace_probe_append(&tk->tp, &to->tp);
if (ret) if (ret)
...@@ -568,14 +611,7 @@ static int register_trace_kprobe(struct trace_kprobe *tk) ...@@ -568,14 +611,7 @@ static int register_trace_kprobe(struct trace_kprobe *tk)
trace_probe_log_err(0, DIFF_PROBE_TYPE); trace_probe_log_err(0, DIFF_PROBE_TYPE);
ret = -EEXIST; ret = -EEXIST;
} else { } else {
ret = trace_probe_compare_arg_type(&tk->tp, &old_tk->tp); ret = append_trace_kprobe(tk, old_tk);
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; goto end;
} }
......
...@@ -436,7 +436,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, ...@@ -436,7 +436,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
C(BAD_INSN_BNDRY, "Probe point is not an instruction boundary"),\ 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_PROBE_TYPE, "Probe type is different from existing probe"),\
C(DIFF_ARG_TYPE, "Argument type or name is different from existing probe"), C(DIFF_ARG_TYPE, "Argument type or name is different from existing probe"),\
C(SAME_PROBE, "There is already the exact same probe event"),
#undef C #undef C
#define C(a, b) TP_ERR_##a #define C(a, b) TP_ERR_##a
......
...@@ -410,10 +410,53 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu) ...@@ -410,10 +410,53 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu)
return 0; return 0;
} }
static bool trace_uprobe_has_same_uprobe(struct trace_uprobe *orig,
struct trace_uprobe *comp)
{
struct trace_probe_event *tpe = orig->tp.event;
struct trace_probe *pos;
struct inode *comp_inode = d_real_inode(comp->path.dentry);
int i;
list_for_each_entry(pos, &tpe->probes, list) {
orig = container_of(pos, struct trace_uprobe, tp);
if (comp_inode != d_real_inode(orig->path.dentry) ||
comp->offset != orig->offset)
continue;
/*
* trace_probe_compare_arg_type() ensured that nr_args and
* each argument name and type are same. Let's compare comm.
*/
for (i = 0; i < orig->tp.nr_args; i++) {
if (strcmp(orig->tp.args[i].comm,
comp->tp.args[i].comm))
continue;
}
return true;
}
return false;
}
static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to) static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
{ {
int ret; int ret;
ret = trace_probe_compare_arg_type(&tu->tp, &to->tp);
if (ret) {
/* Note that argument starts index = 2 */
trace_probe_log_set_index(ret + 1);
trace_probe_log_err(0, DIFF_ARG_TYPE);
return -EEXIST;
}
if (trace_uprobe_has_same_uprobe(to, tu)) {
trace_probe_log_set_index(0);
trace_probe_log_err(0, SAME_PROBE);
return -EEXIST;
}
/* Append to existing event */ /* Append to existing event */
ret = trace_probe_append(&tu->tp, &to->tp); ret = trace_probe_append(&tu->tp, &to->tp);
if (!ret) if (!ret)
...@@ -469,14 +512,7 @@ static int register_trace_uprobe(struct trace_uprobe *tu) ...@@ -469,14 +512,7 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
trace_probe_log_err(0, DIFF_PROBE_TYPE); trace_probe_log_err(0, DIFF_PROBE_TYPE);
ret = -EEXIST; ret = -EEXIST;
} else { } else {
ret = trace_probe_compare_arg_type(&tu->tp, &old_tu->tp); ret = append_trace_uprobe(tu, old_tu);
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; goto end;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment