diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 422 |
1 files changed, 336 insertions, 86 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8a8ee64e72d..59dccc98b55 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include "trace-event.h" /* For __unused */ | 44 | #include "trace-event.h" /* For __unused */ |
45 | #include "probe-event.h" | 45 | #include "probe-event.h" |
46 | #include "probe-finder.h" | 46 | #include "probe-finder.h" |
47 | #include "session.h" | ||
47 | 48 | ||
48 | #define MAX_CMDLEN 256 | 49 | #define MAX_CMDLEN 256 |
49 | #define MAX_PROBE_ARGS 128 | 50 | #define MAX_PROBE_ARGS 128 |
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
70 | } | 71 | } |
71 | 72 | ||
72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 73 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
74 | static int convert_name_to_addr(struct perf_probe_event *pev, | ||
75 | const char *exec); | ||
73 | static struct machine machine; | 76 | static struct machine machine; |
74 | 77 | ||
75 | /* Initialize symbol maps and path of vmlinux/modules */ | 78 | /* Initialize symbol maps and path of vmlinux/modules */ |
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module) | |||
170 | return (dso) ? dso->long_name : NULL; | 173 | return (dso) ? dso->long_name : NULL; |
171 | } | 174 | } |
172 | 175 | ||
176 | static int init_user_exec(void) | ||
177 | { | ||
178 | int ret = 0; | ||
179 | |||
180 | symbol_conf.try_vmlinux_path = false; | ||
181 | symbol_conf.sort_by_name = true; | ||
182 | ret = symbol__init(); | ||
183 | |||
184 | if (ret < 0) | ||
185 | pr_debug("Failed to init symbol map.\n"); | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | ||
191 | struct perf_probe_point *pp) | ||
192 | { | ||
193 | pp->function = strdup(tp->symbol); | ||
194 | |||
195 | if (pp->function == NULL) | ||
196 | return -ENOMEM; | ||
197 | |||
198 | pp->offset = tp->offset; | ||
199 | pp->retprobe = tp->retprobe; | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
173 | #ifdef DWARF_SUPPORT | 204 | #ifdef DWARF_SUPPORT |
174 | /* Open new debuginfo of given module */ | 205 | /* Open new debuginfo of given module */ |
175 | static struct debuginfo *open_debuginfo(const char *module) | 206 | static struct debuginfo *open_debuginfo(const char *module) |
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
224 | if (ret <= 0) { | 255 | if (ret <= 0) { |
225 | pr_debug("Failed to find corresponding probes from " | 256 | pr_debug("Failed to find corresponding probes from " |
226 | "debuginfo. Use kprobe event information.\n"); | 257 | "debuginfo. Use kprobe event information.\n"); |
227 | pp->function = strdup(tp->symbol); | 258 | return convert_to_perf_probe_point(tp, pp); |
228 | if (pp->function == NULL) | ||
229 | return -ENOMEM; | ||
230 | pp->offset = tp->offset; | ||
231 | } | 259 | } |
232 | pp->retprobe = tp->retprobe; | 260 | pp->retprobe = tp->retprobe; |
233 | 261 | ||
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
275 | int max_tevs, const char *target) | 303 | int max_tevs, const char *target) |
276 | { | 304 | { |
277 | bool need_dwarf = perf_probe_event_need_dwarf(pev); | 305 | bool need_dwarf = perf_probe_event_need_dwarf(pev); |
278 | struct debuginfo *dinfo = open_debuginfo(target); | 306 | struct debuginfo *dinfo; |
279 | int ntevs, ret = 0; | 307 | int ntevs, ret = 0; |
280 | 308 | ||
309 | if (pev->uprobes) { | ||
310 | if (need_dwarf) { | ||
311 | pr_warning("Debuginfo-analysis is not yet supported" | ||
312 | " with -x/--exec option.\n"); | ||
313 | return -ENOSYS; | ||
314 | } | ||
315 | return convert_name_to_addr(pev, target); | ||
316 | } | ||
317 | |||
318 | dinfo = open_debuginfo(target); | ||
319 | |||
281 | if (!dinfo) { | 320 | if (!dinfo) { |
282 | if (need_dwarf) { | 321 | if (need_dwarf) { |
283 | pr_warning("Failed to open debuginfo file.\n"); | 322 | pr_warning("Failed to open debuginfo file.\n"); |
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
603 | pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); | 642 | pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); |
604 | return -ENOENT; | 643 | return -ENOENT; |
605 | } | 644 | } |
606 | pp->function = strdup(tp->symbol); | ||
607 | if (pp->function == NULL) | ||
608 | return -ENOMEM; | ||
609 | pp->offset = tp->offset; | ||
610 | pp->retprobe = tp->retprobe; | ||
611 | 645 | ||
612 | return 0; | 646 | return convert_to_perf_probe_point(tp, pp); |
613 | } | 647 | } |
614 | 648 | ||
615 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 649 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
616 | struct probe_trace_event **tevs __unused, | 650 | struct probe_trace_event **tevs __unused, |
617 | int max_tevs __unused, const char *mod __unused) | 651 | int max_tevs __unused, const char *target) |
618 | { | 652 | { |
619 | if (perf_probe_event_need_dwarf(pev)) { | 653 | if (perf_probe_event_need_dwarf(pev)) { |
620 | pr_warning("Debuginfo-analysis is not supported.\n"); | 654 | pr_warning("Debuginfo-analysis is not supported.\n"); |
621 | return -ENOSYS; | 655 | return -ENOSYS; |
622 | } | 656 | } |
657 | |||
658 | if (pev->uprobes) | ||
659 | return convert_name_to_addr(pev, target); | ||
660 | |||
623 | return 0; | 661 | return 0; |
624 | } | 662 | } |
625 | 663 | ||
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) | |||
1341 | if (buf == NULL) | 1379 | if (buf == NULL) |
1342 | return NULL; | 1380 | return NULL; |
1343 | 1381 | ||
1344 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", | 1382 | if (tev->uprobes) |
1345 | tp->retprobe ? 'r' : 'p', | 1383 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", |
1346 | tev->group, tev->event, | 1384 | tp->retprobe ? 'r' : 'p', |
1347 | tp->module ?: "", tp->module ? ":" : "", | 1385 | tev->group, tev->event, |
1348 | tp->symbol, tp->offset); | 1386 | tp->module, tp->symbol); |
1387 | else | ||
1388 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", | ||
1389 | tp->retprobe ? 'r' : 'p', | ||
1390 | tev->group, tev->event, | ||
1391 | tp->module ?: "", tp->module ? ":" : "", | ||
1392 | tp->symbol, tp->offset); | ||
1393 | |||
1349 | if (len <= 0) | 1394 | if (len <= 0) |
1350 | goto error; | 1395 | goto error; |
1351 | 1396 | ||
@@ -1364,7 +1409,7 @@ error: | |||
1364 | } | 1409 | } |
1365 | 1410 | ||
1366 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1411 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
1367 | struct perf_probe_event *pev) | 1412 | struct perf_probe_event *pev, bool is_kprobe) |
1368 | { | 1413 | { |
1369 | char buf[64] = ""; | 1414 | char buf[64] = ""; |
1370 | int i, ret; | 1415 | int i, ret; |
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, | |||
1376 | return -ENOMEM; | 1421 | return -ENOMEM; |
1377 | 1422 | ||
1378 | /* Convert trace_point to probe_point */ | 1423 | /* Convert trace_point to probe_point */ |
1379 | ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); | 1424 | if (is_kprobe) |
1425 | ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); | ||
1426 | else | ||
1427 | ret = convert_to_perf_probe_point(&tev->point, &pev->point); | ||
1428 | |||
1380 | if (ret < 0) | 1429 | if (ret < 0) |
1381 | return ret; | 1430 | return ret; |
1382 | 1431 | ||
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1472 | memset(tev, 0, sizeof(*tev)); | 1521 | memset(tev, 0, sizeof(*tev)); |
1473 | } | 1522 | } |
1474 | 1523 | ||
1475 | static int open_kprobe_events(bool readwrite) | 1524 | static void print_warn_msg(const char *file, bool is_kprobe) |
1525 | { | ||
1526 | |||
1527 | if (errno == ENOENT) { | ||
1528 | const char *config; | ||
1529 | |||
1530 | if (!is_kprobe) | ||
1531 | config = "CONFIG_UPROBE_EVENTS"; | ||
1532 | else | ||
1533 | config = "CONFIG_KPROBE_EVENTS"; | ||
1534 | |||
1535 | pr_warning("%s file does not exist - please rebuild kernel" | ||
1536 | " with %s.\n", file, config); | ||
1537 | } else | ||
1538 | pr_warning("Failed to open %s file: %s\n", file, | ||
1539 | strerror(errno)); | ||
1540 | } | ||
1541 | |||
1542 | static int open_probe_events(const char *trace_file, bool readwrite, | ||
1543 | bool is_kprobe) | ||
1476 | { | 1544 | { |
1477 | char buf[PATH_MAX]; | 1545 | char buf[PATH_MAX]; |
1478 | const char *__debugfs; | 1546 | const char *__debugfs; |
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite) | |||
1484 | return -ENOENT; | 1552 | return -ENOENT; |
1485 | } | 1553 | } |
1486 | 1554 | ||
1487 | ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); | 1555 | ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); |
1488 | if (ret >= 0) { | 1556 | if (ret >= 0) { |
1489 | pr_debug("Opening %s write=%d\n", buf, readwrite); | 1557 | pr_debug("Opening %s write=%d\n", buf, readwrite); |
1490 | if (readwrite && !probe_event_dry_run) | 1558 | if (readwrite && !probe_event_dry_run) |
1491 | ret = open(buf, O_RDWR, O_APPEND); | 1559 | ret = open(buf, O_RDWR, O_APPEND); |
1492 | else | 1560 | else |
1493 | ret = open(buf, O_RDONLY, 0); | 1561 | ret = open(buf, O_RDONLY, 0); |
1494 | } | ||
1495 | 1562 | ||
1496 | if (ret < 0) { | 1563 | if (ret < 0) |
1497 | if (errno == ENOENT) | 1564 | print_warn_msg(buf, is_kprobe); |
1498 | pr_warning("kprobe_events file does not exist - please" | ||
1499 | " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); | ||
1500 | else | ||
1501 | pr_warning("Failed to open kprobe_events file: %s\n", | ||
1502 | strerror(errno)); | ||
1503 | } | 1565 | } |
1504 | return ret; | 1566 | return ret; |
1505 | } | 1567 | } |
1506 | 1568 | ||
1507 | /* Get raw string list of current kprobe_events */ | 1569 | static int open_kprobe_events(bool readwrite) |
1570 | { | ||
1571 | return open_probe_events("tracing/kprobe_events", readwrite, true); | ||
1572 | } | ||
1573 | |||
1574 | static int open_uprobe_events(bool readwrite) | ||
1575 | { | ||
1576 | return open_probe_events("tracing/uprobe_events", readwrite, false); | ||
1577 | } | ||
1578 | |||
1579 | /* Get raw string list of current kprobe_events or uprobe_events */ | ||
1508 | static struct strlist *get_probe_trace_command_rawlist(int fd) | 1580 | static struct strlist *get_probe_trace_command_rawlist(int fd) |
1509 | { | 1581 | { |
1510 | int ret, idx; | 1582 | int ret, idx; |
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev) | |||
1569 | return ret; | 1641 | return ret; |
1570 | } | 1642 | } |
1571 | 1643 | ||
1572 | /* List up current perf-probe events */ | 1644 | static int __show_perf_probe_events(int fd, bool is_kprobe) |
1573 | int show_perf_probe_events(void) | ||
1574 | { | 1645 | { |
1575 | int fd, ret; | 1646 | int ret = 0; |
1576 | struct probe_trace_event tev; | 1647 | struct probe_trace_event tev; |
1577 | struct perf_probe_event pev; | 1648 | struct perf_probe_event pev; |
1578 | struct strlist *rawlist; | 1649 | struct strlist *rawlist; |
1579 | struct str_node *ent; | 1650 | struct str_node *ent; |
1580 | 1651 | ||
1581 | setup_pager(); | ||
1582 | ret = init_vmlinux(); | ||
1583 | if (ret < 0) | ||
1584 | return ret; | ||
1585 | |||
1586 | memset(&tev, 0, sizeof(tev)); | 1652 | memset(&tev, 0, sizeof(tev)); |
1587 | memset(&pev, 0, sizeof(pev)); | 1653 | memset(&pev, 0, sizeof(pev)); |
1588 | 1654 | ||
1589 | fd = open_kprobe_events(false); | ||
1590 | if (fd < 0) | ||
1591 | return fd; | ||
1592 | |||
1593 | rawlist = get_probe_trace_command_rawlist(fd); | 1655 | rawlist = get_probe_trace_command_rawlist(fd); |
1594 | close(fd); | ||
1595 | if (!rawlist) | 1656 | if (!rawlist) |
1596 | return -ENOENT; | 1657 | return -ENOENT; |
1597 | 1658 | ||
1598 | strlist__for_each(ent, rawlist) { | 1659 | strlist__for_each(ent, rawlist) { |
1599 | ret = parse_probe_trace_command(ent->s, &tev); | 1660 | ret = parse_probe_trace_command(ent->s, &tev); |
1600 | if (ret >= 0) { | 1661 | if (ret >= 0) { |
1601 | ret = convert_to_perf_probe_event(&tev, &pev); | 1662 | ret = convert_to_perf_probe_event(&tev, &pev, |
1663 | is_kprobe); | ||
1602 | if (ret >= 0) | 1664 | if (ret >= 0) |
1603 | ret = show_perf_probe_event(&pev); | 1665 | ret = show_perf_probe_event(&pev); |
1604 | } | 1666 | } |
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void) | |||
1612 | return ret; | 1674 | return ret; |
1613 | } | 1675 | } |
1614 | 1676 | ||
1677 | /* List up current perf-probe events */ | ||
1678 | int show_perf_probe_events(void) | ||
1679 | { | ||
1680 | int fd, ret; | ||
1681 | |||
1682 | setup_pager(); | ||
1683 | fd = open_kprobe_events(false); | ||
1684 | |||
1685 | if (fd < 0) | ||
1686 | return fd; | ||
1687 | |||
1688 | ret = init_vmlinux(); | ||
1689 | if (ret < 0) | ||
1690 | return ret; | ||
1691 | |||
1692 | ret = __show_perf_probe_events(fd, true); | ||
1693 | close(fd); | ||
1694 | |||
1695 | fd = open_uprobe_events(false); | ||
1696 | if (fd >= 0) { | ||
1697 | ret = __show_perf_probe_events(fd, false); | ||
1698 | close(fd); | ||
1699 | } | ||
1700 | |||
1701 | return ret; | ||
1702 | } | ||
1703 | |||
1615 | /* Get current perf-probe event names */ | 1704 | /* Get current perf-probe event names */ |
1616 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) | 1705 | static struct strlist *get_probe_trace_event_names(int fd, bool include_group) |
1617 | { | 1706 | { |
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
1717 | const char *event, *group; | 1806 | const char *event, *group; |
1718 | struct strlist *namelist; | 1807 | struct strlist *namelist; |
1719 | 1808 | ||
1720 | fd = open_kprobe_events(true); | 1809 | if (pev->uprobes) |
1810 | fd = open_uprobe_events(true); | ||
1811 | else | ||
1812 | fd = open_kprobe_events(true); | ||
1813 | |||
1721 | if (fd < 0) | 1814 | if (fd < 0) |
1722 | return fd; | 1815 | return fd; |
1723 | /* Get current event names */ | 1816 | /* Get current event names */ |
@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1829 | tev->point.offset = pev->point.offset; | 1922 | tev->point.offset = pev->point.offset; |
1830 | tev->point.retprobe = pev->point.retprobe; | 1923 | tev->point.retprobe = pev->point.retprobe; |
1831 | tev->nargs = pev->nargs; | 1924 | tev->nargs = pev->nargs; |
1925 | tev->uprobes = pev->uprobes; | ||
1926 | |||
1832 | if (tev->nargs) { | 1927 | if (tev->nargs) { |
1833 | tev->args = zalloc(sizeof(struct probe_trace_arg) | 1928 | tev->args = zalloc(sizeof(struct probe_trace_arg) |
1834 | * tev->nargs); | 1929 | * tev->nargs); |
@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1859 | } | 1954 | } |
1860 | } | 1955 | } |
1861 | 1956 | ||
1957 | if (pev->uprobes) | ||
1958 | return 1; | ||
1959 | |||
1862 | /* Currently just checking function name from symbol map */ | 1960 | /* Currently just checking function name from symbol map */ |
1863 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); | 1961 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); |
1864 | if (!sym) { | 1962 | if (!sym) { |
@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | |||
1894 | int i, j, ret; | 1992 | int i, j, ret; |
1895 | struct __event_package *pkgs; | 1993 | struct __event_package *pkgs; |
1896 | 1994 | ||
1995 | ret = 0; | ||
1897 | pkgs = zalloc(sizeof(struct __event_package) * npevs); | 1996 | pkgs = zalloc(sizeof(struct __event_package) * npevs); |
1997 | |||
1898 | if (pkgs == NULL) | 1998 | if (pkgs == NULL) |
1899 | return -ENOMEM; | 1999 | return -ENOMEM; |
1900 | 2000 | ||
1901 | /* Init vmlinux path */ | 2001 | if (!pevs->uprobes) |
1902 | ret = init_vmlinux(); | 2002 | /* Init vmlinux path */ |
2003 | ret = init_vmlinux(); | ||
2004 | else | ||
2005 | ret = init_user_exec(); | ||
2006 | |||
1903 | if (ret < 0) { | 2007 | if (ret < 0) { |
1904 | free(pkgs); | 2008 | free(pkgs); |
1905 | return ret; | 2009 | return ret; |
@@ -1971,23 +2075,15 @@ error: | |||
1971 | return ret; | 2075 | return ret; |
1972 | } | 2076 | } |
1973 | 2077 | ||
1974 | static int del_trace_probe_event(int fd, const char *group, | 2078 | static int del_trace_probe_event(int fd, const char *buf, |
1975 | const char *event, struct strlist *namelist) | 2079 | struct strlist *namelist) |
1976 | { | 2080 | { |
1977 | char buf[128]; | ||
1978 | struct str_node *ent, *n; | 2081 | struct str_node *ent, *n; |
1979 | int found = 0, ret = 0; | 2082 | int ret = -1; |
1980 | |||
1981 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | ||
1982 | if (ret < 0) { | ||
1983 | pr_err("Failed to copy event.\n"); | ||
1984 | return ret; | ||
1985 | } | ||
1986 | 2083 | ||
1987 | if (strpbrk(buf, "*?")) { /* Glob-exp */ | 2084 | if (strpbrk(buf, "*?")) { /* Glob-exp */ |
1988 | strlist__for_each_safe(ent, n, namelist) | 2085 | strlist__for_each_safe(ent, n, namelist) |
1989 | if (strglobmatch(ent->s, buf)) { | 2086 | if (strglobmatch(ent->s, buf)) { |
1990 | found++; | ||
1991 | ret = __del_trace_probe_event(fd, ent); | 2087 | ret = __del_trace_probe_event(fd, ent); |
1992 | if (ret < 0) | 2088 | if (ret < 0) |
1993 | break; | 2089 | break; |
@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group, | |||
1996 | } else { | 2092 | } else { |
1997 | ent = strlist__find(namelist, buf); | 2093 | ent = strlist__find(namelist, buf); |
1998 | if (ent) { | 2094 | if (ent) { |
1999 | found++; | ||
2000 | ret = __del_trace_probe_event(fd, ent); | 2095 | ret = __del_trace_probe_event(fd, ent); |
2001 | if (ret >= 0) | 2096 | if (ret >= 0) |
2002 | strlist__remove(namelist, ent); | 2097 | strlist__remove(namelist, ent); |
2003 | } | 2098 | } |
2004 | } | 2099 | } |
2005 | if (found == 0 && ret >= 0) | ||
2006 | pr_info("Info: Event \"%s\" does not exist.\n", buf); | ||
2007 | 2100 | ||
2008 | return ret; | 2101 | return ret; |
2009 | } | 2102 | } |
2010 | 2103 | ||
2011 | int del_perf_probe_events(struct strlist *dellist) | 2104 | int del_perf_probe_events(struct strlist *dellist) |
2012 | { | 2105 | { |
2013 | int fd, ret = 0; | 2106 | int ret = -1, ufd = -1, kfd = -1; |
2107 | char buf[128]; | ||
2014 | const char *group, *event; | 2108 | const char *group, *event; |
2015 | char *p, *str; | 2109 | char *p, *str; |
2016 | struct str_node *ent; | 2110 | struct str_node *ent; |
2017 | struct strlist *namelist; | 2111 | struct strlist *namelist = NULL, *unamelist = NULL; |
2018 | |||
2019 | fd = open_kprobe_events(true); | ||
2020 | if (fd < 0) | ||
2021 | return fd; | ||
2022 | 2112 | ||
2023 | /* Get current event names */ | 2113 | /* Get current event names */ |
2024 | namelist = get_probe_trace_event_names(fd, true); | 2114 | kfd = open_kprobe_events(true); |
2025 | if (namelist == NULL) | 2115 | if (kfd < 0) |
2026 | return -EINVAL; | 2116 | return kfd; |
2117 | |||
2118 | namelist = get_probe_trace_event_names(kfd, true); | ||
2119 | ufd = open_uprobe_events(true); | ||
2120 | |||
2121 | if (ufd >= 0) | ||
2122 | unamelist = get_probe_trace_event_names(ufd, true); | ||
2123 | |||
2124 | if (namelist == NULL && unamelist == NULL) | ||
2125 | goto error; | ||
2027 | 2126 | ||
2028 | strlist__for_each(ent, dellist) { | 2127 | strlist__for_each(ent, dellist) { |
2029 | str = strdup(ent->s); | 2128 | str = strdup(ent->s); |
2030 | if (str == NULL) { | 2129 | if (str == NULL) { |
2031 | ret = -ENOMEM; | 2130 | ret = -ENOMEM; |
2032 | break; | 2131 | goto error; |
2033 | } | 2132 | } |
2034 | pr_debug("Parsing: %s\n", str); | 2133 | pr_debug("Parsing: %s\n", str); |
2035 | p = strchr(str, ':'); | 2134 | p = strchr(str, ':'); |
@@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist) | |||
2041 | group = "*"; | 2140 | group = "*"; |
2042 | event = str; | 2141 | event = str; |
2043 | } | 2142 | } |
2143 | |||
2144 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | ||
2145 | if (ret < 0) { | ||
2146 | pr_err("Failed to copy event."); | ||
2147 | free(str); | ||
2148 | goto error; | ||
2149 | } | ||
2150 | |||
2044 | pr_debug("Group: %s, Event: %s\n", group, event); | 2151 | pr_debug("Group: %s, Event: %s\n", group, event); |
2045 | ret = del_trace_probe_event(fd, group, event, namelist); | 2152 | |
2153 | if (namelist) | ||
2154 | ret = del_trace_probe_event(kfd, buf, namelist); | ||
2155 | |||
2156 | if (unamelist && ret != 0) | ||
2157 | ret = del_trace_probe_event(ufd, buf, unamelist); | ||
2158 | |||
2159 | if (ret != 0) | ||
2160 | pr_info("Info: Event \"%s\" does not exist.\n", buf); | ||
2161 | |||
2046 | free(str); | 2162 | free(str); |
2047 | if (ret < 0) | ||
2048 | break; | ||
2049 | } | 2163 | } |
2050 | strlist__delete(namelist); | 2164 | |
2051 | close(fd); | 2165 | error: |
2166 | if (kfd >= 0) { | ||
2167 | if (namelist) | ||
2168 | strlist__delete(namelist); | ||
2169 | |||
2170 | close(kfd); | ||
2171 | } | ||
2172 | |||
2173 | if (ufd >= 0) { | ||
2174 | if (unamelist) | ||
2175 | strlist__delete(unamelist); | ||
2176 | |||
2177 | close(ufd); | ||
2178 | } | ||
2052 | 2179 | ||
2053 | return ret; | 2180 | return ret; |
2054 | } | 2181 | } |
2182 | |||
2055 | /* TODO: don't use a global variable for filter ... */ | 2183 | /* TODO: don't use a global variable for filter ... */ |
2056 | static struct strfilter *available_func_filter; | 2184 | static struct strfilter *available_func_filter; |
2057 | 2185 | ||
@@ -2068,30 +2196,152 @@ static int filter_available_functions(struct map *map __unused, | |||
2068 | return 1; | 2196 | return 1; |
2069 | } | 2197 | } |
2070 | 2198 | ||
2071 | int show_available_funcs(const char *target, struct strfilter *_filter) | 2199 | static int __show_available_funcs(struct map *map) |
2200 | { | ||
2201 | if (map__load(map, filter_available_functions)) { | ||
2202 | pr_err("Failed to load map.\n"); | ||
2203 | return -EINVAL; | ||
2204 | } | ||
2205 | if (!dso__sorted_by_name(map->dso, map->type)) | ||
2206 | dso__sort_by_name(map->dso, map->type); | ||
2207 | |||
2208 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | ||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
2212 | static int available_kernel_funcs(const char *module) | ||
2072 | { | 2213 | { |
2073 | struct map *map; | 2214 | struct map *map; |
2074 | int ret; | 2215 | int ret; |
2075 | 2216 | ||
2076 | setup_pager(); | ||
2077 | |||
2078 | ret = init_vmlinux(); | 2217 | ret = init_vmlinux(); |
2079 | if (ret < 0) | 2218 | if (ret < 0) |
2080 | return ret; | 2219 | return ret; |
2081 | 2220 | ||
2082 | map = kernel_get_module_map(target); | 2221 | map = kernel_get_module_map(module); |
2083 | if (!map) { | 2222 | if (!map) { |
2084 | pr_err("Failed to find %s map.\n", (target) ? : "kernel"); | 2223 | pr_err("Failed to find %s map.\n", (module) ? : "kernel"); |
2085 | return -EINVAL; | 2224 | return -EINVAL; |
2086 | } | 2225 | } |
2226 | return __show_available_funcs(map); | ||
2227 | } | ||
2228 | |||
2229 | static int available_user_funcs(const char *target) | ||
2230 | { | ||
2231 | struct map *map; | ||
2232 | int ret; | ||
2233 | |||
2234 | ret = init_user_exec(); | ||
2235 | if (ret < 0) | ||
2236 | return ret; | ||
2237 | |||
2238 | map = dso__new_map(target); | ||
2239 | ret = __show_available_funcs(map); | ||
2240 | dso__delete(map->dso); | ||
2241 | map__delete(map); | ||
2242 | return ret; | ||
2243 | } | ||
2244 | |||
2245 | int show_available_funcs(const char *target, struct strfilter *_filter, | ||
2246 | bool user) | ||
2247 | { | ||
2248 | setup_pager(); | ||
2087 | available_func_filter = _filter; | 2249 | available_func_filter = _filter; |
2250 | |||
2251 | if (!user) | ||
2252 | return available_kernel_funcs(target); | ||
2253 | |||
2254 | return available_user_funcs(target); | ||
2255 | } | ||
2256 | |||
2257 | /* | ||
2258 | * uprobe_events only accepts address: | ||
2259 | * Convert function and any offset to address | ||
2260 | */ | ||
2261 | static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | ||
2262 | { | ||
2263 | struct perf_probe_point *pp = &pev->point; | ||
2264 | struct symbol *sym; | ||
2265 | struct map *map = NULL; | ||
2266 | char *function = NULL, *name = NULL; | ||
2267 | int ret = -EINVAL; | ||
2268 | unsigned long long vaddr = 0; | ||
2269 | |||
2270 | if (!pp->function) { | ||
2271 | pr_warning("No function specified for uprobes"); | ||
2272 | goto out; | ||
2273 | } | ||
2274 | |||
2275 | function = strdup(pp->function); | ||
2276 | if (!function) { | ||
2277 | pr_warning("Failed to allocate memory by strdup.\n"); | ||
2278 | ret = -ENOMEM; | ||
2279 | goto out; | ||
2280 | } | ||
2281 | |||
2282 | name = realpath(exec, NULL); | ||
2283 | if (!name) { | ||
2284 | pr_warning("Cannot find realpath for %s.\n", exec); | ||
2285 | goto out; | ||
2286 | } | ||
2287 | map = dso__new_map(name); | ||
2288 | if (!map) { | ||
2289 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); | ||
2290 | goto out; | ||
2291 | } | ||
2292 | available_func_filter = strfilter__new(function, NULL); | ||
2088 | if (map__load(map, filter_available_functions)) { | 2293 | if (map__load(map, filter_available_functions)) { |
2089 | pr_err("Failed to load map.\n"); | 2294 | pr_err("Failed to load map.\n"); |
2090 | return -EINVAL; | 2295 | goto out; |
2091 | } | 2296 | } |
2092 | if (!dso__sorted_by_name(map->dso, map->type)) | ||
2093 | dso__sort_by_name(map->dso, map->type); | ||
2094 | 2297 | ||
2095 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | 2298 | sym = map__find_symbol_by_name(map, function, NULL); |
2096 | return 0; | 2299 | if (!sym) { |
2300 | pr_warning("Cannot find %s in DSO %s\n", function, exec); | ||
2301 | goto out; | ||
2302 | } | ||
2303 | |||
2304 | if (map->start > sym->start) | ||
2305 | vaddr = map->start; | ||
2306 | vaddr += sym->start + pp->offset + map->pgoff; | ||
2307 | pp->offset = 0; | ||
2308 | |||
2309 | if (!pev->event) { | ||
2310 | pev->event = function; | ||
2311 | function = NULL; | ||
2312 | } | ||
2313 | if (!pev->group) { | ||
2314 | char *ptr1, *ptr2; | ||
2315 | |||
2316 | pev->group = zalloc(sizeof(char *) * 64); | ||
2317 | ptr1 = strdup(basename(exec)); | ||
2318 | if (ptr1) { | ||
2319 | ptr2 = strpbrk(ptr1, "-._"); | ||
2320 | if (ptr2) | ||
2321 | *ptr2 = '\0'; | ||
2322 | e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP, | ||
2323 | ptr1); | ||
2324 | free(ptr1); | ||
2325 | } | ||
2326 | } | ||
2327 | free(pp->function); | ||
2328 | pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS); | ||
2329 | if (!pp->function) { | ||
2330 | ret = -ENOMEM; | ||
2331 | pr_warning("Failed to allocate memory by zalloc.\n"); | ||
2332 | goto out; | ||
2333 | } | ||
2334 | e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); | ||
2335 | ret = 0; | ||
2336 | |||
2337 | out: | ||
2338 | if (map) { | ||
2339 | dso__delete(map->dso); | ||
2340 | map__delete(map); | ||
2341 | } | ||
2342 | if (function) | ||
2343 | free(function); | ||
2344 | if (name) | ||
2345 | free(name); | ||
2346 | return ret; | ||
2097 | } | 2347 | } |