|
@@ -715,6 +715,38 @@ static inline void sanitize_event_name(char *name)
|
|
|
*name = '_';
|
|
|
}
|
|
|
|
|
|
+struct count_symbols_struct {
|
|
|
+ const char *func_name;
|
|
|
+ unsigned int count;
|
|
|
+};
|
|
|
+
|
|
|
+static int count_symbols(void *data, const char *name, struct module *unused0,
|
|
|
+ unsigned long unused1)
|
|
|
+{
|
|
|
+ struct count_symbols_struct *args = data;
|
|
|
+
|
|
|
+ if (strcmp(args->func_name, name))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ args->count++;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int number_of_same_symbols(char *func_name)
|
|
|
+{
|
|
|
+ struct count_symbols_struct args = {
|
|
|
+ .func_name = func_name,
|
|
|
+ .count = 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ kallsyms_on_each_symbol(count_symbols, &args);
|
|
|
+
|
|
|
+ module_kallsyms_on_each_symbol(count_symbols, &args);
|
|
|
+
|
|
|
+ return args.count;
|
|
|
+}
|
|
|
+
|
|
|
static int trace_kprobe_create(int argc, const char *argv[])
|
|
|
{
|
|
|
/*
|
|
@@ -842,6 +874,31 @@ static int trace_kprobe_create(int argc, const char *argv[])
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (symbol && !strchr(symbol, ':')) {
|
|
|
+ unsigned int count;
|
|
|
+
|
|
|
+ count = number_of_same_symbols(symbol);
|
|
|
+ if (count > 1) {
|
|
|
+ /*
|
|
|
+ * Users should use ADDR to remove the ambiguity of
|
|
|
+ * using KSYM only.
|
|
|
+ */
|
|
|
+ trace_probe_log_err(0, NON_UNIQ_SYMBOL);
|
|
|
+ ret = -EADDRNOTAVAIL;
|
|
|
+
|
|
|
+ goto error;
|
|
|
+ } else if (count == 0) {
|
|
|
+ /*
|
|
|
+ * We can return ENOENT earlier than when register the
|
|
|
+ * kprobe.
|
|
|
+ */
|
|
|
+ trace_probe_log_err(0, BAD_PROBE_ADDR);
|
|
|
+ ret = -ENOENT;
|
|
|
+
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
trace_probe_log_set_index(0);
|
|
|
if (event) {
|
|
|
ret = traceprobe_parse_event_name(&event, &group, buf,
|
|
@@ -1805,6 +1862,7 @@ static int unregister_kprobe_event(struct trace_kprobe *tk)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PERF_EVENTS
|
|
|
+
|
|
|
/* create a trace_kprobe, but don't add it to global lists */
|
|
|
struct trace_event_call *
|
|
|
create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
|
|
@@ -1814,6 +1872,24 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
|
|
|
int ret;
|
|
|
char *event;
|
|
|
|
|
|
+ if (func) {
|
|
|
+ unsigned int count;
|
|
|
+
|
|
|
+ count = number_of_same_symbols(func);
|
|
|
+ if (count > 1)
|
|
|
+ /*
|
|
|
+ * Users should use addr to remove the ambiguity of
|
|
|
+ * using func only.
|
|
|
+ */
|
|
|
+ return ERR_PTR(-EADDRNOTAVAIL);
|
|
|
+ else if (count == 0)
|
|
|
+ /*
|
|
|
+ * We can return ENOENT earlier than when register the
|
|
|
+ * kprobe.
|
|
|
+ */
|
|
|
+ return ERR_PTR(-ENOENT);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* local trace_kprobes are not added to dyn_event, so they are never
|
|
|
* searched in find_trace_kprobe(). Therefore, there is no concern of
|