diff options
| -rw-r--r-- | include/linux/trace_events.h | 4 | ||||
| -rw-r--r-- | kernel/events/core.c | 48 | ||||
| -rw-r--r-- | kernel/trace/trace_event_perf.c | 53 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.h | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 86 |
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); | |||
| 537 | extern int perf_kprobe_init(struct perf_event *event, bool is_retprobe); | 537 | extern int perf_kprobe_init(struct perf_event *event, bool is_retprobe); |
| 538 | extern void perf_kprobe_destroy(struct perf_event *event); | 538 | extern void perf_kprobe_destroy(struct perf_event *event); |
| 539 | #endif | 539 | #endif |
| 540 | #ifdef CONFIG_UPROBE_EVENTS | ||
| 541 | extern int perf_uprobe_init(struct perf_event *event, bool is_retprobe); | ||
| 542 | extern void perf_uprobe_destroy(struct perf_event *event); | ||
| 543 | #endif | ||
| 540 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, | 544 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, |
| 541 | char *filter_str); | 545 | char *filter_str); |
| 542 | extern void ftrace_profile_free_filter(struct perf_event *event); | 546 | extern 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 | ||
| 8024 | static int perf_kprobe_event_init(struct perf_event *event); | 8026 | static int perf_kprobe_event_init(struct perf_event *event); |
| 8025 | static struct pmu perf_kprobe = { | 8027 | static 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 | ||
| 8063 | static int perf_uprobe_event_init(struct perf_event *event); | ||
| 8064 | static 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 | |||
| 8075 | static 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 | |||
| 8060 | static inline void perf_tp_register(void) | 8099 | static 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 | ||
| 8068 | static void perf_event_free_filter(struct perf_event *event) | 8110 | static 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 | ||
| 290 | int 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); | ||
| 327 | out: | ||
| 328 | kfree(path); | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 332 | void 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 | |||
| 289 | int perf_trace_add(struct perf_event *p_event, int flags) | 342 | int 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 * | |||
| 410 | create_local_trace_kprobe(char *func, void *addr, unsigned long offs, | 410 | create_local_trace_kprobe(char *func, void *addr, unsigned long offs, |
| 411 | bool is_return); | 411 | bool is_return); |
| 412 | extern void destroy_local_trace_kprobe(struct trace_event_call *event_call); | 412 | extern void destroy_local_trace_kprobe(struct trace_event_call *event_call); |
| 413 | |||
| 414 | extern struct trace_event_call * | ||
| 415 | create_local_trace_uprobe(char *name, unsigned long offs, bool is_return); | ||
| 416 | extern 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 | ||
| 1295 | static int register_uprobe_event(struct trace_uprobe *tu) | 1295 | static 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 | |||
| 1307 | static 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 | ||
| 1349 | struct trace_event_call * | ||
| 1350 | create_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; | ||
| 1394 | error: | ||
| 1395 | free_trace_uprobe(tu); | ||
| 1396 | return ERR_PTR(ret); | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | void 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 */ |
| 1343 | static __init int init_uprobe_trace(void) | 1413 | static __init int init_uprobe_trace(void) |
| 1344 | { | 1414 | { |
