aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/trace_events.h4
-rw-r--r--kernel/events/core.c48
-rw-r--r--kernel/trace/trace_event_perf.c53
-rw-r--r--kernel/trace/trace_probe.h4
-rw-r--r--kernel/trace/trace_uprobe.c86
5 files changed, 186 insertions, 9 deletions
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 21c5d43a21af..0d9d6cb454b1 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -537,6 +537,10 @@ extern void perf_trace_del(struct perf_event *event, int flags);
537extern int perf_kprobe_init(struct perf_event *event, bool is_retprobe); 537extern int perf_kprobe_init(struct perf_event *event, bool is_retprobe);
538extern void perf_kprobe_destroy(struct perf_event *event); 538extern void perf_kprobe_destroy(struct perf_event *event);
539#endif 539#endif
540#ifdef CONFIG_UPROBE_EVENTS
541extern int perf_uprobe_init(struct perf_event *event, bool is_retprobe);
542extern void perf_uprobe_destroy(struct perf_event *event);
543#endif
540extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, 544extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
541 char *filter_str); 545 char *filter_str);
542extern void ftrace_profile_free_filter(struct perf_event *event); 546extern void ftrace_profile_free_filter(struct perf_event *event);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 333735531968..5a54630db86b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7992,7 +7992,7 @@ static struct pmu perf_tracepoint = {
7992 .read = perf_swevent_read, 7992 .read = perf_swevent_read,
7993}; 7993};
7994 7994
7995#ifdef CONFIG_KPROBE_EVENTS 7995#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS)
7996/* 7996/*
7997 * Flags in config, used by dynamic PMU kprobe and uprobe 7997 * Flags in config, used by dynamic PMU kprobe and uprobe
7998 * The flags should match following PMU_FORMAT_ATTR(). 7998 * The flags should match following PMU_FORMAT_ATTR().
@@ -8020,7 +8020,9 @@ static const struct attribute_group *probe_attr_groups[] = {
8020 &probe_format_group, 8020 &probe_format_group,
8021 NULL, 8021 NULL,
8022}; 8022};
8023#endif
8023 8024
8025#ifdef CONFIG_KPROBE_EVENTS
8024static int perf_kprobe_event_init(struct perf_event *event); 8026static int perf_kprobe_event_init(struct perf_event *event);
8025static struct pmu perf_kprobe = { 8027static struct pmu perf_kprobe = {
8026 .task_ctx_nr = perf_sw_context, 8028 .task_ctx_nr = perf_sw_context,
@@ -8057,12 +8059,52 @@ static int perf_kprobe_event_init(struct perf_event *event)
8057} 8059}
8058#endif /* CONFIG_KPROBE_EVENTS */ 8060#endif /* CONFIG_KPROBE_EVENTS */
8059 8061
8062#ifdef CONFIG_UPROBE_EVENTS
8063static int perf_uprobe_event_init(struct perf_event *event);
8064static struct pmu perf_uprobe = {
8065 .task_ctx_nr = perf_sw_context,
8066 .event_init = perf_uprobe_event_init,
8067 .add = perf_trace_add,
8068 .del = perf_trace_del,
8069 .start = perf_swevent_start,
8070 .stop = perf_swevent_stop,
8071 .read = perf_swevent_read,
8072 .attr_groups = probe_attr_groups,
8073};
8074
8075static int perf_uprobe_event_init(struct perf_event *event)
8076{
8077 int err;
8078 bool is_retprobe;
8079
8080 if (event->attr.type != perf_uprobe.type)
8081 return -ENOENT;
8082 /*
8083 * no branch sampling for probe events
8084 */
8085 if (has_branch_stack(event))
8086 return -EOPNOTSUPP;
8087
8088 is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
8089 err = perf_uprobe_init(event, is_retprobe);
8090 if (err)
8091 return err;
8092
8093 event->destroy = perf_uprobe_destroy;
8094
8095 return 0;
8096}
8097#endif /* CONFIG_UPROBE_EVENTS */
8098
8060static inline void perf_tp_register(void) 8099static inline void perf_tp_register(void)
8061{ 8100{
8062 perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); 8101 perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);
8063#ifdef CONFIG_KPROBE_EVENTS 8102#ifdef CONFIG_KPROBE_EVENTS
8064 perf_pmu_register(&perf_kprobe, "kprobe", -1); 8103 perf_pmu_register(&perf_kprobe, "kprobe", -1);
8065#endif 8104#endif
8105#ifdef CONFIG_UPROBE_EVENTS
8106 perf_pmu_register(&perf_uprobe, "uprobe", -1);
8107#endif
8066} 8108}
8067 8109
8068static void perf_event_free_filter(struct perf_event *event) 8110static void perf_event_free_filter(struct perf_event *event)
@@ -8151,6 +8193,10 @@ static inline bool perf_event_is_tracing(struct perf_event *event)
8151 if (event->pmu == &perf_kprobe) 8193 if (event->pmu == &perf_kprobe)
8152 return true; 8194 return true;
8153#endif 8195#endif
8196#ifdef CONFIG_UPROBE_EVENTS
8197 if (event->pmu == &perf_uprobe)
8198 return true;
8199#endif
8154 return false; 8200 return false;
8155} 8201}
8156 8202
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 779baade9114..2c416509b834 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -286,6 +286,59 @@ void perf_kprobe_destroy(struct perf_event *p_event)
286} 286}
287#endif /* CONFIG_KPROBE_EVENTS */ 287#endif /* CONFIG_KPROBE_EVENTS */
288 288
289#ifdef CONFIG_UPROBE_EVENTS
290int perf_uprobe_init(struct perf_event *p_event, bool is_retprobe)
291{
292 int ret;
293 char *path = NULL;
294 struct trace_event_call *tp_event;
295
296 if (!p_event->attr.uprobe_path)
297 return -EINVAL;
298 path = kzalloc(PATH_MAX, GFP_KERNEL);
299 if (!path)
300 return -ENOMEM;
301 ret = strncpy_from_user(
302 path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX);
303 if (ret < 0)
304 goto out;
305 if (path[0] == '\0') {
306 ret = -EINVAL;
307 goto out;
308 }
309
310 tp_event = create_local_trace_uprobe(
311 path, p_event->attr.probe_offset, is_retprobe);
312 if (IS_ERR(tp_event)) {
313 ret = PTR_ERR(tp_event);
314 goto out;
315 }
316
317 /*
318 * local trace_uprobe need to hold event_mutex to call
319 * uprobe_buffer_enable() and uprobe_buffer_disable().
320 * event_mutex is not required for local trace_kprobes.
321 */
322 mutex_lock(&event_mutex);
323 ret = perf_trace_event_init(tp_event, p_event);
324 if (ret)
325 destroy_local_trace_uprobe(tp_event);
326 mutex_unlock(&event_mutex);
327out:
328 kfree(path);
329 return ret;
330}
331
332void perf_uprobe_destroy(struct perf_event *p_event)
333{
334 mutex_lock(&event_mutex);
335 perf_trace_event_close(p_event);
336 perf_trace_event_unreg(p_event);
337 mutex_unlock(&event_mutex);
338 destroy_local_trace_uprobe(p_event->tp_event);
339}
340#endif /* CONFIG_UPROBE_EVENTS */
341
289int perf_trace_add(struct perf_event *p_event, int flags) 342int perf_trace_add(struct perf_event *p_event, int flags)
290{ 343{
291 struct trace_event_call *tp_event = p_event->tp_event; 344 struct trace_event_call *tp_event = p_event->tp_event;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index e3d940a49dcd..27de3174050a 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -410,4 +410,8 @@ extern struct trace_event_call *
410create_local_trace_kprobe(char *func, void *addr, unsigned long offs, 410create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
411 bool is_return); 411 bool is_return);
412extern void destroy_local_trace_kprobe(struct trace_event_call *event_call); 412extern void destroy_local_trace_kprobe(struct trace_event_call *event_call);
413
414extern struct trace_event_call *
415create_local_trace_uprobe(char *name, unsigned long offs, bool is_return);
416extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
413#endif 417#endif
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 40592e7b3568..e3cbae702a53 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -1292,16 +1292,25 @@ static struct trace_event_functions uprobe_funcs = {
1292 .trace = print_uprobe_event 1292 .trace = print_uprobe_event
1293}; 1293};
1294 1294
1295static int register_uprobe_event(struct trace_uprobe *tu) 1295static inline void init_trace_event_call(struct trace_uprobe *tu,
1296 struct trace_event_call *call)
1296{ 1297{
1297 struct trace_event_call *call = &tu->tp.call;
1298 int ret;
1299
1300 /* Initialize trace_event_call */
1301 INIT_LIST_HEAD(&call->class->fields); 1298 INIT_LIST_HEAD(&call->class->fields);
1302 call->event.funcs = &uprobe_funcs; 1299 call->event.funcs = &uprobe_funcs;
1303 call->class->define_fields = uprobe_event_define_fields; 1300 call->class->define_fields = uprobe_event_define_fields;
1304 1301
1302 call->flags = TRACE_EVENT_FL_UPROBE;
1303 call->class->reg = trace_uprobe_register;
1304 call->data = tu;
1305}
1306
1307static int register_uprobe_event(struct trace_uprobe *tu)
1308{
1309 struct trace_event_call *call = &tu->tp.call;
1310 int ret = 0;
1311
1312 init_trace_event_call(tu, call);
1313
1305 if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) 1314 if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
1306 return -ENOMEM; 1315 return -ENOMEM;
1307 1316
@@ -1311,9 +1320,6 @@ static int register_uprobe_event(struct trace_uprobe *tu)
1311 return -ENODEV; 1320 return -ENODEV;
1312 } 1321 }
1313 1322
1314 call->flags = TRACE_EVENT_FL_UPROBE;
1315 call->class->reg = trace_uprobe_register;
1316 call->data = tu;
1317 ret = trace_add_event_call(call); 1323 ret = trace_add_event_call(call);
1318 1324
1319 if (ret) { 1325 if (ret) {
@@ -1339,6 +1345,70 @@ static int unregister_uprobe_event(struct trace_uprobe *tu)
1339 return 0; 1345 return 0;
1340} 1346}
1341 1347
1348#ifdef CONFIG_PERF_EVENTS
1349struct trace_event_call *
1350create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
1351{
1352 struct trace_uprobe *tu;
1353 struct inode *inode;
1354 struct path path;
1355 int ret;
1356
1357 ret = kern_path(name, LOOKUP_FOLLOW, &path);
1358 if (ret)
1359 return ERR_PTR(ret);
1360
1361 inode = igrab(d_inode(path.dentry));
1362 path_put(&path);
1363
1364 if (!inode || !S_ISREG(inode->i_mode)) {
1365 iput(inode);
1366 return ERR_PTR(-EINVAL);
1367 }
1368
1369 /*
1370 * local trace_kprobes are not added to probe_list, so they are never
1371 * searched in find_trace_kprobe(). Therefore, there is no concern of
1372 * duplicated name "DUMMY_EVENT" here.
1373 */
1374 tu = alloc_trace_uprobe(UPROBE_EVENT_SYSTEM, "DUMMY_EVENT", 0,
1375 is_return);
1376
1377 if (IS_ERR(tu)) {
1378 pr_info("Failed to allocate trace_uprobe.(%d)\n",
1379 (int)PTR_ERR(tu));
1380 return ERR_CAST(tu);
1381 }
1382
1383 tu->offset = offs;
1384 tu->inode = inode;
1385 tu->filename = kstrdup(name, GFP_KERNEL);
1386 init_trace_event_call(tu, &tu->tp.call);
1387
1388 if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
1389 ret = -ENOMEM;
1390 goto error;
1391 }
1392
1393 return &tu->tp.call;
1394error:
1395 free_trace_uprobe(tu);
1396 return ERR_PTR(ret);
1397}
1398
1399void destroy_local_trace_uprobe(struct trace_event_call *event_call)
1400{
1401 struct trace_uprobe *tu;
1402
1403 tu = container_of(event_call, struct trace_uprobe, tp.call);
1404
1405 kfree(tu->tp.call.print_fmt);
1406 tu->tp.call.print_fmt = NULL;
1407
1408 free_trace_uprobe(tu);
1409}
1410#endif /* CONFIG_PERF_EVENTS */
1411
1342/* Make a trace interface for controling probe points */ 1412/* Make a trace interface for controling probe points */
1343static __init int init_uprobe_trace(void) 1413static __init int init_uprobe_trace(void)
1344{ 1414{