diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 85 |
1 files changed, 61 insertions, 24 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b7aaf9b2294d..e1dbc9821617 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -1325,27 +1325,30 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) | |||
1325 | { | 1325 | { |
1326 | char *ptr; | 1326 | char *ptr; |
1327 | 1327 | ||
1328 | ptr = strchr(*arg, ':'); | 1328 | ptr = strpbrk_esc(*arg, ":"); |
1329 | if (ptr) { | 1329 | if (ptr) { |
1330 | *ptr = '\0'; | 1330 | *ptr = '\0'; |
1331 | if (!pev->sdt && !is_c_func_name(*arg)) | 1331 | if (!pev->sdt && !is_c_func_name(*arg)) |
1332 | goto ng_name; | 1332 | goto ng_name; |
1333 | pev->group = strdup(*arg); | 1333 | pev->group = strdup_esc(*arg); |
1334 | if (!pev->group) | 1334 | if (!pev->group) |
1335 | return -ENOMEM; | 1335 | return -ENOMEM; |
1336 | *arg = ptr + 1; | 1336 | *arg = ptr + 1; |
1337 | } else | 1337 | } else |
1338 | pev->group = NULL; | 1338 | pev->group = NULL; |
1339 | if (!pev->sdt && !is_c_func_name(*arg)) { | 1339 | |
1340 | pev->event = strdup_esc(*arg); | ||
1341 | if (pev->event == NULL) | ||
1342 | return -ENOMEM; | ||
1343 | |||
1344 | if (!pev->sdt && !is_c_func_name(pev->event)) { | ||
1345 | zfree(&pev->event); | ||
1340 | ng_name: | 1346 | ng_name: |
1347 | zfree(&pev->group); | ||
1341 | semantic_error("%s is bad for event name -it must " | 1348 | semantic_error("%s is bad for event name -it must " |
1342 | "follow C symbol-naming rule.\n", *arg); | 1349 | "follow C symbol-naming rule.\n", *arg); |
1343 | return -EINVAL; | 1350 | return -EINVAL; |
1344 | } | 1351 | } |
1345 | pev->event = strdup(*arg); | ||
1346 | if (pev->event == NULL) | ||
1347 | return -ENOMEM; | ||
1348 | |||
1349 | return 0; | 1352 | return 0; |
1350 | } | 1353 | } |
1351 | 1354 | ||
@@ -1373,7 +1376,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1373 | arg++; | 1376 | arg++; |
1374 | } | 1377 | } |
1375 | 1378 | ||
1376 | ptr = strpbrk(arg, ";=@+%"); | 1379 | ptr = strpbrk_esc(arg, ";=@+%"); |
1377 | if (pev->sdt) { | 1380 | if (pev->sdt) { |
1378 | if (ptr) { | 1381 | if (ptr) { |
1379 | if (*ptr != '@') { | 1382 | if (*ptr != '@') { |
@@ -1387,7 +1390,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1387 | pev->target = build_id_cache__origname(tmp); | 1390 | pev->target = build_id_cache__origname(tmp); |
1388 | free(tmp); | 1391 | free(tmp); |
1389 | } else | 1392 | } else |
1390 | pev->target = strdup(ptr + 1); | 1393 | pev->target = strdup_esc(ptr + 1); |
1391 | if (!pev->target) | 1394 | if (!pev->target) |
1392 | return -ENOMEM; | 1395 | return -ENOMEM; |
1393 | *ptr = '\0'; | 1396 | *ptr = '\0'; |
@@ -1421,13 +1424,14 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1421 | * | 1424 | * |
1422 | * Otherwise, we consider arg to be a function specification. | 1425 | * Otherwise, we consider arg to be a function specification. |
1423 | */ | 1426 | */ |
1424 | if (!strpbrk(arg, "+@%") && (ptr = strpbrk(arg, ";:")) != NULL) { | 1427 | if (!strpbrk_esc(arg, "+@%")) { |
1428 | ptr = strpbrk_esc(arg, ";:"); | ||
1425 | /* This is a file spec if it includes a '.' before ; or : */ | 1429 | /* This is a file spec if it includes a '.' before ; or : */ |
1426 | if (memchr(arg, '.', ptr - arg)) | 1430 | if (ptr && memchr(arg, '.', ptr - arg)) |
1427 | file_spec = true; | 1431 | file_spec = true; |
1428 | } | 1432 | } |
1429 | 1433 | ||
1430 | ptr = strpbrk(arg, ";:+@%"); | 1434 | ptr = strpbrk_esc(arg, ";:+@%"); |
1431 | if (ptr) { | 1435 | if (ptr) { |
1432 | nc = *ptr; | 1436 | nc = *ptr; |
1433 | *ptr++ = '\0'; | 1437 | *ptr++ = '\0'; |
@@ -1436,7 +1440,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1436 | if (arg[0] == '\0') | 1440 | if (arg[0] == '\0') |
1437 | tmp = NULL; | 1441 | tmp = NULL; |
1438 | else { | 1442 | else { |
1439 | tmp = strdup(arg); | 1443 | tmp = strdup_esc(arg); |
1440 | if (tmp == NULL) | 1444 | if (tmp == NULL) |
1441 | return -ENOMEM; | 1445 | return -ENOMEM; |
1442 | } | 1446 | } |
@@ -1469,12 +1473,12 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1469 | arg = ptr; | 1473 | arg = ptr; |
1470 | c = nc; | 1474 | c = nc; |
1471 | if (c == ';') { /* Lazy pattern must be the last part */ | 1475 | if (c == ';') { /* Lazy pattern must be the last part */ |
1472 | pp->lazy_line = strdup(arg); | 1476 | pp->lazy_line = strdup(arg); /* let leave escapes */ |
1473 | if (pp->lazy_line == NULL) | 1477 | if (pp->lazy_line == NULL) |
1474 | return -ENOMEM; | 1478 | return -ENOMEM; |
1475 | break; | 1479 | break; |
1476 | } | 1480 | } |
1477 | ptr = strpbrk(arg, ";:+@%"); | 1481 | ptr = strpbrk_esc(arg, ";:+@%"); |
1478 | if (ptr) { | 1482 | if (ptr) { |
1479 | nc = *ptr; | 1483 | nc = *ptr; |
1480 | *ptr++ = '\0'; | 1484 | *ptr++ = '\0'; |
@@ -1501,7 +1505,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1501 | semantic_error("SRC@SRC is not allowed.\n"); | 1505 | semantic_error("SRC@SRC is not allowed.\n"); |
1502 | return -EINVAL; | 1506 | return -EINVAL; |
1503 | } | 1507 | } |
1504 | pp->file = strdup(arg); | 1508 | pp->file = strdup_esc(arg); |
1505 | if (pp->file == NULL) | 1509 | if (pp->file == NULL) |
1506 | return -ENOMEM; | 1510 | return -ENOMEM; |
1507 | break; | 1511 | break; |
@@ -2573,7 +2577,8 @@ int show_perf_probe_events(struct strfilter *filter) | |||
2573 | } | 2577 | } |
2574 | 2578 | ||
2575 | static int get_new_event_name(char *buf, size_t len, const char *base, | 2579 | static int get_new_event_name(char *buf, size_t len, const char *base, |
2576 | struct strlist *namelist, bool allow_suffix) | 2580 | struct strlist *namelist, bool ret_event, |
2581 | bool allow_suffix) | ||
2577 | { | 2582 | { |
2578 | int i, ret; | 2583 | int i, ret; |
2579 | char *p, *nbase; | 2584 | char *p, *nbase; |
@@ -2584,13 +2589,13 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2584 | if (!nbase) | 2589 | if (!nbase) |
2585 | return -ENOMEM; | 2590 | return -ENOMEM; |
2586 | 2591 | ||
2587 | /* Cut off the dot suffixes (e.g. .const, .isra)*/ | 2592 | /* Cut off the dot suffixes (e.g. .const, .isra) and version suffixes */ |
2588 | p = strchr(nbase, '.'); | 2593 | p = strpbrk(nbase, ".@"); |
2589 | if (p && p != nbase) | 2594 | if (p && p != nbase) |
2590 | *p = '\0'; | 2595 | *p = '\0'; |
2591 | 2596 | ||
2592 | /* Try no suffix number */ | 2597 | /* Try no suffix number */ |
2593 | ret = e_snprintf(buf, len, "%s", nbase); | 2598 | ret = e_snprintf(buf, len, "%s%s", nbase, ret_event ? "__return" : ""); |
2594 | if (ret < 0) { | 2599 | if (ret < 0) { |
2595 | pr_debug("snprintf() failed: %d\n", ret); | 2600 | pr_debug("snprintf() failed: %d\n", ret); |
2596 | goto out; | 2601 | goto out; |
@@ -2625,6 +2630,14 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2625 | 2630 | ||
2626 | out: | 2631 | out: |
2627 | free(nbase); | 2632 | free(nbase); |
2633 | |||
2634 | /* Final validation */ | ||
2635 | if (ret >= 0 && !is_c_func_name(buf)) { | ||
2636 | pr_warning("Internal error: \"%s\" is an invalid event name.\n", | ||
2637 | buf); | ||
2638 | ret = -EINVAL; | ||
2639 | } | ||
2640 | |||
2628 | return ret; | 2641 | return ret; |
2629 | } | 2642 | } |
2630 | 2643 | ||
@@ -2681,8 +2694,8 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2681 | group = PERFPROBE_GROUP; | 2694 | group = PERFPROBE_GROUP; |
2682 | 2695 | ||
2683 | /* Get an unused new event name */ | 2696 | /* Get an unused new event name */ |
2684 | ret = get_new_event_name(buf, 64, event, | 2697 | ret = get_new_event_name(buf, 64, event, namelist, |
2685 | namelist, allow_suffix); | 2698 | tev->point.retprobe, allow_suffix); |
2686 | if (ret < 0) | 2699 | if (ret < 0) |
2687 | return ret; | 2700 | return ret; |
2688 | 2701 | ||
@@ -2792,16 +2805,40 @@ static int find_probe_functions(struct map *map, char *name, | |||
2792 | int found = 0; | 2805 | int found = 0; |
2793 | struct symbol *sym; | 2806 | struct symbol *sym; |
2794 | struct rb_node *tmp; | 2807 | struct rb_node *tmp; |
2808 | const char *norm, *ver; | ||
2809 | char *buf = NULL; | ||
2810 | bool cut_version = true; | ||
2795 | 2811 | ||
2796 | if (map__load(map) < 0) | 2812 | if (map__load(map) < 0) |
2797 | return 0; | 2813 | return 0; |
2798 | 2814 | ||
2815 | /* If user gives a version, don't cut off the version from symbols */ | ||
2816 | if (strchr(name, '@')) | ||
2817 | cut_version = false; | ||
2818 | |||
2799 | map__for_each_symbol(map, sym, tmp) { | 2819 | map__for_each_symbol(map, sym, tmp) { |
2800 | if (strglobmatch(sym->name, name)) { | 2820 | norm = arch__normalize_symbol_name(sym->name); |
2821 | if (!norm) | ||
2822 | continue; | ||
2823 | |||
2824 | if (cut_version) { | ||
2825 | /* We don't care about default symbol or not */ | ||
2826 | ver = strchr(norm, '@'); | ||
2827 | if (ver) { | ||
2828 | buf = strndup(norm, ver - norm); | ||
2829 | if (!buf) | ||
2830 | return -ENOMEM; | ||
2831 | norm = buf; | ||
2832 | } | ||
2833 | } | ||
2834 | |||
2835 | if (strglobmatch(norm, name)) { | ||
2801 | found++; | 2836 | found++; |
2802 | if (syms && found < probe_conf.max_probes) | 2837 | if (syms && found < probe_conf.max_probes) |
2803 | syms[found - 1] = sym; | 2838 | syms[found - 1] = sym; |
2804 | } | 2839 | } |
2840 | if (buf) | ||
2841 | zfree(&buf); | ||
2805 | } | 2842 | } |
2806 | 2843 | ||
2807 | return found; | 2844 | return found; |
@@ -2847,7 +2884,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2847 | * same name but different addresses, this lists all the symbols. | 2884 | * same name but different addresses, this lists all the symbols. |
2848 | */ | 2885 | */ |
2849 | num_matched_functions = find_probe_functions(map, pp->function, syms); | 2886 | num_matched_functions = find_probe_functions(map, pp->function, syms); |
2850 | if (num_matched_functions == 0) { | 2887 | if (num_matched_functions <= 0) { |
2851 | pr_err("Failed to find symbol %s in %s\n", pp->function, | 2888 | pr_err("Failed to find symbol %s in %s\n", pp->function, |
2852 | pev->target ? : "kernel"); | 2889 | pev->target ? : "kernel"); |
2853 | ret = -ENOENT; | 2890 | ret = -ENOENT; |