diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/util/probe-event.c | 162 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 21 |
3 files changed, 163 insertions, 24 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index eaacb58b9b36..eb5f18b75402 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -1204,9 +1204,27 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
| 1204 | 1204 | ||
| 1205 | if (file_spec) | 1205 | if (file_spec) |
| 1206 | pp->file = tmp; | 1206 | pp->file = tmp; |
| 1207 | else | 1207 | else { |
| 1208 | pp->function = tmp; | 1208 | pp->function = tmp; |
| 1209 | 1209 | ||
| 1210 | /* | ||
| 1211 | * Keep pp->function even if this is absolute address, | ||
| 1212 | * so it can mark whether abs_address is valid. | ||
| 1213 | * Which make 'perf probe lib.bin 0x0' possible. | ||
| 1214 | * | ||
| 1215 | * Note that checking length of tmp is not needed | ||
| 1216 | * because when we access tmp[1] we know tmp[0] is '0', | ||
| 1217 | * so tmp[1] should always valid (but could be '\0'). | ||
| 1218 | */ | ||
| 1219 | if (tmp && !strncmp(tmp, "0x", 2)) { | ||
| 1220 | pp->abs_address = strtoul(pp->function, &tmp, 0); | ||
| 1221 | if (*tmp != '\0') { | ||
| 1222 | semantic_error("Invalid absolute address.\n"); | ||
| 1223 | return -EINVAL; | ||
| 1224 | } | ||
| 1225 | } | ||
| 1226 | } | ||
| 1227 | |||
| 1210 | /* Parse other options */ | 1228 | /* Parse other options */ |
| 1211 | while (ptr) { | 1229 | while (ptr) { |
| 1212 | arg = ptr; | 1230 | arg = ptr; |
| @@ -1804,14 +1822,29 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) | |||
| 1804 | if (len <= 0) | 1822 | if (len <= 0) |
| 1805 | goto error; | 1823 | goto error; |
| 1806 | 1824 | ||
| 1807 | /* Uprobes must have tp->address and tp->module */ | 1825 | /* Uprobes must have tp->module */ |
| 1808 | if (tev->uprobes && (!tp->address || !tp->module)) | 1826 | if (tev->uprobes && !tp->module) |
| 1809 | goto error; | 1827 | goto error; |
| 1828 | /* | ||
| 1829 | * If tp->address == 0, then this point must be a | ||
| 1830 | * absolute address uprobe. | ||
| 1831 | * try_to_find_absolute_address() should have made | ||
| 1832 | * tp->symbol to "0x0". | ||
| 1833 | */ | ||
| 1834 | if (tev->uprobes && !tp->address) { | ||
| 1835 | if (!tp->symbol || strcmp(tp->symbol, "0x0")) | ||
| 1836 | goto error; | ||
| 1837 | } | ||
| 1810 | 1838 | ||
| 1811 | /* Use the tp->address for uprobes */ | 1839 | /* Use the tp->address for uprobes */ |
| 1812 | if (tev->uprobes) | 1840 | if (tev->uprobes) |
| 1813 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", | 1841 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", |
| 1814 | tp->module, tp->address); | 1842 | tp->module, tp->address); |
| 1843 | else if (!strncmp(tp->symbol, "0x", 2)) | ||
| 1844 | /* Absolute address. See try_to_find_absolute_address() */ | ||
| 1845 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s0x%lx", | ||
| 1846 | tp->module ?: "", tp->module ? ":" : "", | ||
| 1847 | tp->address); | ||
| 1815 | else | 1848 | else |
| 1816 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", | 1849 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", |
| 1817 | tp->module ?: "", tp->module ? ":" : "", | 1850 | tp->module ?: "", tp->module ? ":" : "", |
| @@ -1874,8 +1907,8 @@ out: | |||
| 1874 | } | 1907 | } |
| 1875 | 1908 | ||
| 1876 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | 1909 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, |
| 1877 | struct perf_probe_point *pp, | 1910 | struct perf_probe_point *pp, |
| 1878 | bool is_kprobe) | 1911 | bool is_kprobe) |
| 1879 | { | 1912 | { |
| 1880 | char buf[128]; | 1913 | char buf[128]; |
| 1881 | int ret; | 1914 | int ret; |
| @@ -2331,7 +2364,9 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
| 2331 | if (pev->event) | 2364 | if (pev->event) |
| 2332 | event = pev->event; | 2365 | event = pev->event; |
| 2333 | else | 2366 | else |
| 2334 | if (pev->point.function && !strisglob(pev->point.function)) | 2367 | if (pev->point.function && |
| 2368 | (strncmp(pev->point.function, "0x", 2) != 0) && | ||
| 2369 | !strisglob(pev->point.function)) | ||
| 2335 | event = pev->point.function; | 2370 | event = pev->point.function; |
| 2336 | else | 2371 | else |
| 2337 | event = tev->point.realname; | 2372 | event = tev->point.realname; |
| @@ -2598,6 +2633,98 @@ err_out: | |||
| 2598 | goto out; | 2633 | goto out; |
| 2599 | } | 2634 | } |
| 2600 | 2635 | ||
| 2636 | static int try_to_find_absolute_address(struct perf_probe_event *pev, | ||
| 2637 | struct probe_trace_event **tevs) | ||
| 2638 | { | ||
| 2639 | struct perf_probe_point *pp = &pev->point; | ||
| 2640 | struct probe_trace_event *tev; | ||
| 2641 | struct probe_trace_point *tp; | ||
| 2642 | int i, err; | ||
| 2643 | |||
| 2644 | if (!(pev->point.function && !strncmp(pev->point.function, "0x", 2))) | ||
| 2645 | return -EINVAL; | ||
| 2646 | if (perf_probe_event_need_dwarf(pev)) | ||
| 2647 | return -EINVAL; | ||
| 2648 | |||
| 2649 | /* | ||
| 2650 | * This is 'perf probe /lib/libc.so 0xabcd'. Try to probe at | ||
| 2651 | * absolute address. | ||
| 2652 | * | ||
| 2653 | * Only one tev can be generated by this. | ||
| 2654 | */ | ||
| 2655 | *tevs = zalloc(sizeof(*tev)); | ||
| 2656 | if (!*tevs) | ||
| 2657 | return -ENOMEM; | ||
| 2658 | |||
| 2659 | tev = *tevs; | ||
| 2660 | tp = &tev->point; | ||
| 2661 | |||
| 2662 | /* | ||
| 2663 | * Don't use tp->offset, use address directly, because | ||
| 2664 | * in synthesize_probe_trace_command() address cannot be | ||
| 2665 | * zero. | ||
| 2666 | */ | ||
| 2667 | tp->address = pev->point.abs_address; | ||
| 2668 | tp->retprobe = pp->retprobe; | ||
| 2669 | tev->uprobes = pev->uprobes; | ||
| 2670 | |||
| 2671 | err = -ENOMEM; | ||
| 2672 | /* | ||
| 2673 | * Give it a '0x' leading symbol name. | ||
| 2674 | * In __add_probe_trace_events, a NULL symbol is interpreted as | ||
| 2675 | * invalud. | ||
| 2676 | */ | ||
| 2677 | if (asprintf(&tp->symbol, "0x%lx", tp->address) < 0) | ||
| 2678 | goto errout; | ||
| 2679 | |||
| 2680 | /* For kprobe, check range */ | ||
| 2681 | if ((!tev->uprobes) && | ||
| 2682 | (kprobe_warn_out_range(tev->point.symbol, | ||
| 2683 | tev->point.address))) { | ||
| 2684 | err = -EACCES; | ||
| 2685 | goto errout; | ||
| 2686 | } | ||
| 2687 | |||
| 2688 | if (asprintf(&tp->realname, "abs_%lx", tp->address) < 0) | ||
| 2689 | goto errout; | ||
| 2690 | |||
| 2691 | if (pev->target) { | ||
| 2692 | tp->module = strdup(pev->target); | ||
| 2693 | if (!tp->module) | ||
| 2694 | goto errout; | ||
| 2695 | } | ||
| 2696 | |||
| 2697 | if (tev->group) { | ||
| 2698 | tev->group = strdup(pev->group); | ||
| 2699 | if (!tev->group) | ||
| 2700 | goto errout; | ||
| 2701 | } | ||
| 2702 | |||
| 2703 | if (pev->event) { | ||
| 2704 | tev->event = strdup(pev->event); | ||
| 2705 | if (!tev->event) | ||
| 2706 | goto errout; | ||
| 2707 | } | ||
| 2708 | |||
| 2709 | tev->nargs = pev->nargs; | ||
| 2710 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | ||
| 2711 | if (!tev->args) { | ||
| 2712 | err = -ENOMEM; | ||
| 2713 | goto errout; | ||
| 2714 | } | ||
| 2715 | for (i = 0; i < tev->nargs; i++) | ||
| 2716 | copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]); | ||
| 2717 | |||
| 2718 | return 1; | ||
| 2719 | |||
| 2720 | errout: | ||
| 2721 | if (*tevs) { | ||
| 2722 | clear_probe_trace_events(*tevs, 1); | ||
| 2723 | *tevs = NULL; | ||
| 2724 | } | ||
| 2725 | return err; | ||
| 2726 | } | ||
| 2727 | |||
| 2601 | bool __weak arch__prefers_symtab(void) { return false; } | 2728 | bool __weak arch__prefers_symtab(void) { return false; } |
| 2602 | 2729 | ||
| 2603 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, | 2730 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, |
| @@ -2614,6 +2741,10 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
| 2614 | } | 2741 | } |
| 2615 | } | 2742 | } |
| 2616 | 2743 | ||
| 2744 | ret = try_to_find_absolute_address(pev, tevs); | ||
| 2745 | if (ret > 0) | ||
| 2746 | return ret; | ||
| 2747 | |||
| 2617 | if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { | 2748 | if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { |
| 2618 | ret = find_probe_trace_events_from_map(pev, tevs); | 2749 | ret = find_probe_trace_events_from_map(pev, tevs); |
| 2619 | if (ret > 0) | 2750 | if (ret > 0) |
| @@ -2784,3 +2915,22 @@ end: | |||
| 2784 | return ret; | 2915 | return ret; |
| 2785 | } | 2916 | } |
| 2786 | 2917 | ||
| 2918 | int copy_to_probe_trace_arg(struct probe_trace_arg *tvar, | ||
| 2919 | struct perf_probe_arg *pvar) | ||
| 2920 | { | ||
| 2921 | tvar->value = strdup(pvar->var); | ||
| 2922 | if (tvar->value == NULL) | ||
| 2923 | return -ENOMEM; | ||
| 2924 | if (pvar->type) { | ||
| 2925 | tvar->type = strdup(pvar->type); | ||
| 2926 | if (tvar->type == NULL) | ||
| 2927 | return -ENOMEM; | ||
| 2928 | } | ||
| 2929 | if (pvar->name) { | ||
| 2930 | tvar->name = strdup(pvar->name); | ||
| 2931 | if (tvar->name == NULL) | ||
| 2932 | return -ENOMEM; | ||
| 2933 | } else | ||
| 2934 | tvar->name = NULL; | ||
| 2935 | return 0; | ||
| 2936 | } | ||
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 83ee95e9743b..6e7ec68a4aa8 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
| @@ -59,6 +59,7 @@ struct perf_probe_point { | |||
| 59 | bool retprobe; /* Return probe flag */ | 59 | bool retprobe; /* Return probe flag */ |
| 60 | char *lazy_line; /* Lazy matching pattern */ | 60 | char *lazy_line; /* Lazy matching pattern */ |
| 61 | unsigned long offset; /* Offset from function entry */ | 61 | unsigned long offset; /* Offset from function entry */ |
| 62 | unsigned long abs_address; /* Absolute address of the point */ | ||
| 62 | }; | 63 | }; |
| 63 | 64 | ||
| 64 | /* Perf probe probing argument field chain */ | 65 | /* Perf probe probing argument field chain */ |
| @@ -156,4 +157,7 @@ int e_snprintf(char *str, size_t size, const char *format, ...) | |||
| 156 | /* Maximum index number of event-name postfix */ | 157 | /* Maximum index number of event-name postfix */ |
| 157 | #define MAX_EVENT_INDEX 1024 | 158 | #define MAX_EVENT_INDEX 1024 |
| 158 | 159 | ||
| 160 | int copy_to_probe_trace_arg(struct probe_trace_arg *tvar, | ||
| 161 | struct perf_probe_arg *pvar); | ||
| 162 | |||
| 159 | #endif /*_PROBE_EVENT_H */ | 163 | #endif /*_PROBE_EVENT_H */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 7b80f8cb62b9..29c43c0680a8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -553,24 +553,9 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
| 553 | char buf[32], *ptr; | 553 | char buf[32], *ptr; |
| 554 | int ret = 0; | 554 | int ret = 0; |
| 555 | 555 | ||
| 556 | if (!is_c_varname(pf->pvar->var)) { | 556 | /* Copy raw parameters */ |
| 557 | /* Copy raw parameters */ | 557 | if (!is_c_varname(pf->pvar->var)) |
| 558 | pf->tvar->value = strdup(pf->pvar->var); | 558 | return copy_to_probe_trace_arg(pf->tvar, pf->pvar); |
| 559 | if (pf->tvar->value == NULL) | ||
| 560 | return -ENOMEM; | ||
| 561 | if (pf->pvar->type) { | ||
| 562 | pf->tvar->type = strdup(pf->pvar->type); | ||
| 563 | if (pf->tvar->type == NULL) | ||
| 564 | return -ENOMEM; | ||
| 565 | } | ||
| 566 | if (pf->pvar->name) { | ||
| 567 | pf->tvar->name = strdup(pf->pvar->name); | ||
| 568 | if (pf->tvar->name == NULL) | ||
| 569 | return -ENOMEM; | ||
| 570 | } else | ||
| 571 | pf->tvar->name = NULL; | ||
| 572 | return 0; | ||
| 573 | } | ||
| 574 | 559 | ||
| 575 | if (pf->pvar->name) | 560 | if (pf->pvar->name) |
| 576 | pf->tvar->name = strdup(pf->pvar->name); | 561 | pf->tvar->name = strdup(pf->pvar->name); |
