aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-08-26 06:57:45 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-08-26 09:41:12 -0400
commitda15bd9df4afd2f9f78cf29f85f013e3a38402b5 (patch)
tree131d0d4606401fbb722b3c6fe88ef349769cee32 /tools
parent6c6e024f0a62a6a08c06002fd3caa2307cc54fd0 (diff)
perf probe: Support probing at absolute address
It should be useful to allow 'perf probe' probe at absolute offset of a target. For example, when (u)probing at a instruction of a shared object in a embedded system where debuginfo is not avaliable but we know the offset of that instruction by manually digging. This patch enables following perf probe command syntax: # perf probe 0xffffffff811e6615 And # perf probe /lib/x86_64-linux-gnu/libc-2.19.so 0xeb860 In the above example, we don't need a anchor symbol, so it is possible to compute absolute addresses using other methods and then use 'perf probe' to create the probing points. v1 -> v2: Drop the leading '+' in cmdline; Allow uprobing at offset 0x0; Improve 'perf probe -l' result when uprobe at area without debuginfo. v2 -> v3: Split bugfix to a separated patch. Test result: # perf probe 0xffffffff8119d175 %ax # perf probe sys_write %ax # perf probe /lib64/libc-2.18.so 0x0 %ax # perf probe /lib64/libc-2.18.so 0x5 %ax # perf probe /lib64/libc-2.18.so 0xd8e40 %ax # perf probe /lib64/libc-2.18.so __write %ax # perf probe /lib64/libc-2.18.so 0xd8e49 %ax # cat /sys/kernel/debug/tracing/uprobe_events p:probe_libc/abs_0 /lib64/libc-2.18.so:0x (null) arg1=%ax p:probe_libc/abs_5 /lib64/libc-2.18.so:0x0000000000000005 arg1=%ax p:probe_libc/abs_d8e40 /lib64/libc-2.18.so:0x00000000000d8e40 arg1=%ax p:probe_libc/__write /lib64/libc-2.18.so:0x00000000000d8e40 arg1=%ax p:probe_libc/abs_d8e49 /lib64/libc-2.18.so:0x00000000000d8e49 arg1=%ax # cat /sys/kernel/debug/tracing/kprobe_events p:probe/abs_ffffffff8119d175 0xffffffff8119d175 arg1=%ax p:probe/sys_write _text+1692016 arg1=%ax # perf probe -l Failed to find debug information for address 5 probe:abs_ffffffff8119d175 (on sys_write+5 with arg1) probe:sys_write (on sys_write with arg1) probe_libc:__write (on @unix/syscall-template.S:81 in /lib64/libc-2.18.so with arg1) probe_libc:abs_0 (on 0x0 in /lib64/libc-2.18.so with arg1) probe_libc:abs_5 (on 0x5 in /lib64/libc-2.18.so with arg1) probe_libc:abs_d8e40 (on @unix/syscall-template.S:81 in /lib64/libc-2.18.so with arg1) probe_libc:abs_d8e49 (on __GI___libc_write+9 in /lib64/libc-2.18.so with arg1) Signed-off-by: Wang Nan <wangnan0@huawei.com> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1440586666-235233-7-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/probe-event.c162
-rw-r--r--tools/perf/util/probe-event.h4
-rw-r--r--tools/perf/util/probe-finder.c21
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
1876static int convert_to_perf_probe_point(struct probe_trace_point *tp, 1909static 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
2636static 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
2720errout:
2721 if (*tevs) {
2722 clear_probe_trace_events(*tevs, 1);
2723 *tevs = NULL;
2724 }
2725 return err;
2726}
2727
2601bool __weak arch__prefers_symtab(void) { return false; } 2728bool __weak arch__prefers_symtab(void) { return false; }
2602 2729
2603static int convert_to_probe_trace_events(struct perf_probe_event *pev, 2730static 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
2918int 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
160int 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);