Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf record: Add support for using symbols in address filters

Symbols come from either the DSO or /proc/kallsyms for the kernel.
Details of the functionality can be found in Documentation/perf-record.txt.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Link: http://lkml.kernel.org/r/1474641528-18776-8-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
1b36c03e cd67f99f

+857 -3
+54 -1
tools/perf/Documentation/perf-record.txt
··· 89 89 90 90 --filter=<filter>:: 91 91 Event filter. This option should follow a event selector (-e) which 92 - selects tracepoint event(s). Multiple '--filter' options are combined 92 + selects either tracepoint event(s) or a hardware trace PMU 93 + (e.g. Intel PT or CoreSight). 94 + 95 + - tracepoint filters 96 + 97 + In the case of tracepoints, multiple '--filter' options are combined 93 98 using '&&'. 99 + 100 + - address filters 101 + 102 + A hardware trace PMU advertises its ability to accept a number of 103 + address filters by specifying a non-zero value in 104 + /sys/bus/event_source/devices/<pmu>/nr_addr_filters. 105 + 106 + Address filters have the format: 107 + 108 + filter|start|stop|tracestop <start> [/ <size>] [@<file name>] 109 + 110 + Where: 111 + - 'filter': defines a region that will be traced. 112 + - 'start': defines an address at which tracing will begin. 113 + - 'stop': defines an address at which tracing will stop. 114 + - 'tracestop': defines a region in which tracing will stop. 115 + 116 + <file name> is the name of the object file, <start> is the offset to the 117 + code to trace in that file, and <size> is the size of the region to 118 + trace. 'start' and 'stop' filters need not specify a <size>. 119 + 120 + If no object file is specified then the kernel is assumed, in which case 121 + the start address must be a current kernel memory address. 122 + 123 + <start> can also be specified by providing the name of a symbol. If the 124 + symbol name is not unique, it can be disambiguated by inserting #n where 125 + 'n' selects the n'th symbol in address order. Alternately #0, #g or #G 126 + select only a global symbol. <size> can also be specified by providing 127 + the name of a symbol, in which case the size is calculated to the end 128 + of that symbol. For 'filter' and 'tracestop' filters, if <size> is 129 + omitted and <start> is a symbol, then the size is calculated to the end 130 + of that symbol. 131 + 132 + If <size> is omitted and <start> is '*', then the start and size will 133 + be calculated from the first and last symbols, i.e. to trace the whole 134 + file. 135 + 136 + If symbol names (or '*') are provided, they must be surrounded by white 137 + space. 138 + 139 + The filter passed to the kernel is not necessarily the same as entered. 140 + To see the filter that is passed, use the -v option. 141 + 142 + The kernel may not be able to configure a trace region if it is not 143 + within a single mapping. MMAP events (or /proc/<pid>/maps) can be 144 + examined to determine if that is a possibility. 145 + 146 + Multiple filters can be separated with space or comma. 94 147 95 148 --exclude-perf:: 96 149 Don't record events issued by perf itself. This option should follow
+12 -2
tools/perf/builtin-record.c
··· 1581 1581 if (err) 1582 1582 goto out; 1583 1583 1584 + /* 1585 + * Allow aliases to facilitate the lookup of symbols for address 1586 + * filters. Refer to auxtrace_parse_filters(). 1587 + */ 1588 + symbol_conf.allow_aliases = true; 1589 + 1590 + symbol__init(NULL); 1591 + 1592 + err = auxtrace_parse_filters(rec->evlist); 1593 + if (err) 1594 + goto out; 1595 + 1584 1596 if (dry_run) 1585 1597 goto out; 1586 1598 ··· 1605 1593 } 1606 1594 1607 1595 err = -ENOMEM; 1608 - 1609 - symbol__init(NULL); 1610 1596 1611 1597 if (symbol_conf.kptr_restrict) 1612 1598 pr_warning(
+737
tools/perf/util/auxtrace.c
··· 16 16 #include <sys/types.h> 17 17 #include <sys/mman.h> 18 18 #include <stdbool.h> 19 + #include <ctype.h> 20 + #include <string.h> 21 + #include <limits.h> 22 + #include <errno.h> 19 23 20 24 #include <linux/kernel.h> 21 25 #include <linux/perf_event.h> ··· 39 35 #include "../perf.h" 40 36 #include "util.h" 41 37 #include "evlist.h" 38 + #include "dso.h" 39 + #include "map.h" 40 + #include "pmu.h" 41 + #include "evsel.h" 42 42 #include "cpumap.h" 43 43 #include "thread_map.h" 44 44 #include "asm/bug.h" 45 + #include "symbol/kallsyms.h" 45 46 #include "auxtrace.h" 46 47 47 48 #include <linux/hash.h> ··· 1407 1398 } 1408 1399 1409 1400 return NULL; 1401 + } 1402 + 1403 + static void addr_filter__free_str(struct addr_filter *filt) 1404 + { 1405 + free(filt->str); 1406 + filt->action = NULL; 1407 + filt->sym_from = NULL; 1408 + filt->sym_to = NULL; 1409 + filt->filename = NULL; 1410 + filt->str = NULL; 1411 + } 1412 + 1413 + static struct addr_filter *addr_filter__new(void) 1414 + { 1415 + struct addr_filter *filt = zalloc(sizeof(*filt)); 1416 + 1417 + if (filt) 1418 + INIT_LIST_HEAD(&filt->list); 1419 + 1420 + return filt; 1421 + } 1422 + 1423 + static void addr_filter__free(struct addr_filter *filt) 1424 + { 1425 + if (filt) 1426 + addr_filter__free_str(filt); 1427 + free(filt); 1428 + } 1429 + 1430 + static void addr_filters__add(struct addr_filters *filts, 1431 + struct addr_filter *filt) 1432 + { 1433 + list_add_tail(&filt->list, &filts->head); 1434 + filts->cnt += 1; 1435 + } 1436 + 1437 + static void addr_filters__del(struct addr_filters *filts, 1438 + struct addr_filter *filt) 1439 + { 1440 + list_del_init(&filt->list); 1441 + filts->cnt -= 1; 1442 + } 1443 + 1444 + void addr_filters__init(struct addr_filters *filts) 1445 + { 1446 + INIT_LIST_HEAD(&filts->head); 1447 + filts->cnt = 0; 1448 + } 1449 + 1450 + void addr_filters__exit(struct addr_filters *filts) 1451 + { 1452 + struct addr_filter *filt, *n; 1453 + 1454 + list_for_each_entry_safe(filt, n, &filts->head, list) { 1455 + addr_filters__del(filts, filt); 1456 + addr_filter__free(filt); 1457 + } 1458 + } 1459 + 1460 + static int parse_num_or_str(char **inp, u64 *num, const char **str, 1461 + const char *str_delim) 1462 + { 1463 + *inp += strspn(*inp, " "); 1464 + 1465 + if (isdigit(**inp)) { 1466 + char *endptr; 1467 + 1468 + if (!num) 1469 + return -EINVAL; 1470 + errno = 0; 1471 + *num = strtoull(*inp, &endptr, 0); 1472 + if (errno) 1473 + return -errno; 1474 + if (endptr == *inp) 1475 + return -EINVAL; 1476 + *inp = endptr; 1477 + } else { 1478 + size_t n; 1479 + 1480 + if (!str) 1481 + return -EINVAL; 1482 + *inp += strspn(*inp, " "); 1483 + *str = *inp; 1484 + n = strcspn(*inp, str_delim); 1485 + if (!n) 1486 + return -EINVAL; 1487 + *inp += n; 1488 + if (**inp) { 1489 + **inp = '\0'; 1490 + *inp += 1; 1491 + } 1492 + } 1493 + return 0; 1494 + } 1495 + 1496 + static int parse_action(struct addr_filter *filt) 1497 + { 1498 + if (!strcmp(filt->action, "filter")) { 1499 + filt->start = true; 1500 + filt->range = true; 1501 + } else if (!strcmp(filt->action, "start")) { 1502 + filt->start = true; 1503 + } else if (!strcmp(filt->action, "stop")) { 1504 + filt->start = false; 1505 + } else if (!strcmp(filt->action, "tracestop")) { 1506 + filt->start = false; 1507 + filt->range = true; 1508 + filt->action += 5; /* Change 'tracestop' to 'stop' */ 1509 + } else { 1510 + return -EINVAL; 1511 + } 1512 + return 0; 1513 + } 1514 + 1515 + static int parse_sym_idx(char **inp, int *idx) 1516 + { 1517 + *idx = -1; 1518 + 1519 + *inp += strspn(*inp, " "); 1520 + 1521 + if (**inp != '#') 1522 + return 0; 1523 + 1524 + *inp += 1; 1525 + 1526 + if (**inp == 'g' || **inp == 'G') { 1527 + *inp += 1; 1528 + *idx = 0; 1529 + } else { 1530 + unsigned long num; 1531 + char *endptr; 1532 + 1533 + errno = 0; 1534 + num = strtoul(*inp, &endptr, 0); 1535 + if (errno) 1536 + return -errno; 1537 + if (endptr == *inp || num > INT_MAX) 1538 + return -EINVAL; 1539 + *inp = endptr; 1540 + *idx = num; 1541 + } 1542 + 1543 + return 0; 1544 + } 1545 + 1546 + static int parse_addr_size(char **inp, u64 *num, const char **str, int *idx) 1547 + { 1548 + int err = parse_num_or_str(inp, num, str, " "); 1549 + 1550 + if (!err && *str) 1551 + err = parse_sym_idx(inp, idx); 1552 + 1553 + return err; 1554 + } 1555 + 1556 + static int parse_one_filter(struct addr_filter *filt, const char **filter_inp) 1557 + { 1558 + char *fstr; 1559 + int err; 1560 + 1561 + filt->str = fstr = strdup(*filter_inp); 1562 + if (!fstr) 1563 + return -ENOMEM; 1564 + 1565 + err = parse_num_or_str(&fstr, NULL, &filt->action, " "); 1566 + if (err) 1567 + goto out_err; 1568 + 1569 + err = parse_action(filt); 1570 + if (err) 1571 + goto out_err; 1572 + 1573 + err = parse_addr_size(&fstr, &filt->addr, &filt->sym_from, 1574 + &filt->sym_from_idx); 1575 + if (err) 1576 + goto out_err; 1577 + 1578 + fstr += strspn(fstr, " "); 1579 + 1580 + if (*fstr == '/') { 1581 + fstr += 1; 1582 + err = parse_addr_size(&fstr, &filt->size, &filt->sym_to, 1583 + &filt->sym_to_idx); 1584 + if (err) 1585 + goto out_err; 1586 + filt->range = true; 1587 + } 1588 + 1589 + fstr += strspn(fstr, " "); 1590 + 1591 + if (*fstr == '@') { 1592 + fstr += 1; 1593 + err = parse_num_or_str(&fstr, NULL, &filt->filename, " ,"); 1594 + if (err) 1595 + goto out_err; 1596 + } 1597 + 1598 + fstr += strspn(fstr, " ,"); 1599 + 1600 + *filter_inp += fstr - filt->str; 1601 + 1602 + return 0; 1603 + 1604 + out_err: 1605 + addr_filter__free_str(filt); 1606 + 1607 + return err; 1608 + } 1609 + 1610 + int addr_filters__parse_bare_filter(struct addr_filters *filts, 1611 + const char *filter) 1612 + { 1613 + struct addr_filter *filt; 1614 + const char *fstr = filter; 1615 + int err; 1616 + 1617 + while (*fstr) { 1618 + filt = addr_filter__new(); 1619 + err = parse_one_filter(filt, &fstr); 1620 + if (err) { 1621 + addr_filter__free(filt); 1622 + addr_filters__exit(filts); 1623 + return err; 1624 + } 1625 + addr_filters__add(filts, filt); 1626 + } 1627 + 1628 + return 0; 1629 + } 1630 + 1631 + struct sym_args { 1632 + const char *name; 1633 + u64 start; 1634 + u64 size; 1635 + int idx; 1636 + int cnt; 1637 + bool started; 1638 + bool global; 1639 + bool selected; 1640 + bool duplicate; 1641 + bool near; 1642 + }; 1643 + 1644 + static bool kern_sym_match(struct sym_args *args, const char *name, char type) 1645 + { 1646 + /* A function with the same name, and global or the n'th found or any */ 1647 + return symbol_type__is_a(type, MAP__FUNCTION) && 1648 + !strcmp(name, args->name) && 1649 + ((args->global && isupper(type)) || 1650 + (args->selected && ++(args->cnt) == args->idx) || 1651 + (!args->global && !args->selected)); 1652 + } 1653 + 1654 + static int find_kern_sym_cb(void *arg, const char *name, char type, u64 start) 1655 + { 1656 + struct sym_args *args = arg; 1657 + 1658 + if (args->started) { 1659 + if (!args->size) 1660 + args->size = start - args->start; 1661 + if (args->selected) { 1662 + if (args->size) 1663 + return 1; 1664 + } else if (kern_sym_match(args, name, type)) { 1665 + args->duplicate = true; 1666 + return 1; 1667 + } 1668 + } else if (kern_sym_match(args, name, type)) { 1669 + args->started = true; 1670 + args->start = start; 1671 + } 1672 + 1673 + return 0; 1674 + } 1675 + 1676 + static int print_kern_sym_cb(void *arg, const char *name, char type, u64 start) 1677 + { 1678 + struct sym_args *args = arg; 1679 + 1680 + if (kern_sym_match(args, name, type)) { 1681 + pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 1682 + ++args->cnt, start, type, name); 1683 + args->near = true; 1684 + } else if (args->near) { 1685 + args->near = false; 1686 + pr_err("\t\twhich is near\t\t%s\n", name); 1687 + } 1688 + 1689 + return 0; 1690 + } 1691 + 1692 + static int sym_not_found_error(const char *sym_name, int idx) 1693 + { 1694 + if (idx > 0) { 1695 + pr_err("N'th occurrence (N=%d) of symbol '%s' not found.\n", 1696 + idx, sym_name); 1697 + } else if (!idx) { 1698 + pr_err("Global symbol '%s' not found.\n", sym_name); 1699 + } else { 1700 + pr_err("Symbol '%s' not found.\n", sym_name); 1701 + } 1702 + pr_err("Note that symbols must be functions.\n"); 1703 + 1704 + return -EINVAL; 1705 + } 1706 + 1707 + static int find_kern_sym(const char *sym_name, u64 *start, u64 *size, int idx) 1708 + { 1709 + struct sym_args args = { 1710 + .name = sym_name, 1711 + .idx = idx, 1712 + .global = !idx, 1713 + .selected = idx > 0, 1714 + }; 1715 + int err; 1716 + 1717 + *start = 0; 1718 + *size = 0; 1719 + 1720 + err = kallsyms__parse("/proc/kallsyms", &args, find_kern_sym_cb); 1721 + if (err < 0) { 1722 + pr_err("Failed to parse /proc/kallsyms\n"); 1723 + return err; 1724 + } 1725 + 1726 + if (args.duplicate) { 1727 + pr_err("Multiple kernel symbols with name '%s'\n", sym_name); 1728 + args.cnt = 0; 1729 + kallsyms__parse("/proc/kallsyms", &args, print_kern_sym_cb); 1730 + pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 1731 + sym_name); 1732 + pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 1733 + return -EINVAL; 1734 + } 1735 + 1736 + if (!args.started) { 1737 + pr_err("Kernel symbol lookup: "); 1738 + return sym_not_found_error(sym_name, idx); 1739 + } 1740 + 1741 + *start = args.start; 1742 + *size = args.size; 1743 + 1744 + return 0; 1745 + } 1746 + 1747 + static int find_entire_kern_cb(void *arg, const char *name __maybe_unused, 1748 + char type, u64 start) 1749 + { 1750 + struct sym_args *args = arg; 1751 + 1752 + if (!symbol_type__is_a(type, MAP__FUNCTION)) 1753 + return 0; 1754 + 1755 + if (!args->started) { 1756 + args->started = true; 1757 + args->start = start; 1758 + } 1759 + /* Don't know exactly where the kernel ends, so we add a page */ 1760 + args->size = round_up(start, page_size) + page_size - args->start; 1761 + 1762 + return 0; 1763 + } 1764 + 1765 + static int addr_filter__entire_kernel(struct addr_filter *filt) 1766 + { 1767 + struct sym_args args = { .started = false }; 1768 + int err; 1769 + 1770 + err = kallsyms__parse("/proc/kallsyms", &args, find_entire_kern_cb); 1771 + if (err < 0 || !args.started) { 1772 + pr_err("Failed to parse /proc/kallsyms\n"); 1773 + return err; 1774 + } 1775 + 1776 + filt->addr = args.start; 1777 + filt->size = args.size; 1778 + 1779 + return 0; 1780 + } 1781 + 1782 + static int check_end_after_start(struct addr_filter *filt, u64 start, u64 size) 1783 + { 1784 + if (start + size >= filt->addr) 1785 + return 0; 1786 + 1787 + if (filt->sym_from) { 1788 + pr_err("Symbol '%s' (0x%"PRIx64") comes before '%s' (0x%"PRIx64")\n", 1789 + filt->sym_to, start, filt->sym_from, filt->addr); 1790 + } else { 1791 + pr_err("Symbol '%s' (0x%"PRIx64") comes before address 0x%"PRIx64")\n", 1792 + filt->sym_to, start, filt->addr); 1793 + } 1794 + 1795 + return -EINVAL; 1796 + } 1797 + 1798 + static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) 1799 + { 1800 + bool no_size = false; 1801 + u64 start, size; 1802 + int err; 1803 + 1804 + if (symbol_conf.kptr_restrict) { 1805 + pr_err("Kernel addresses are restricted. Unable to resolve kernel symbols.\n"); 1806 + return -EINVAL; 1807 + } 1808 + 1809 + if (filt->sym_from && !strcmp(filt->sym_from, "*")) 1810 + return addr_filter__entire_kernel(filt); 1811 + 1812 + if (filt->sym_from) { 1813 + err = find_kern_sym(filt->sym_from, &start, &size, 1814 + filt->sym_from_idx); 1815 + if (err) 1816 + return err; 1817 + filt->addr = start; 1818 + if (filt->range && !filt->size && !filt->sym_to) { 1819 + filt->size = size; 1820 + no_size = !!size; 1821 + } 1822 + } 1823 + 1824 + if (filt->sym_to) { 1825 + err = find_kern_sym(filt->sym_to, &start, &size, 1826 + filt->sym_to_idx); 1827 + if (err) 1828 + return err; 1829 + 1830 + err = check_end_after_start(filt, start, size); 1831 + if (err) 1832 + return err; 1833 + filt->size = start + size - filt->addr; 1834 + no_size = !!size; 1835 + } 1836 + 1837 + /* The very last symbol in kallsyms does not imply a particular size */ 1838 + if (no_size) { 1839 + pr_err("Cannot determine size of symbol '%s'\n", 1840 + filt->sym_to ? filt->sym_to : filt->sym_from); 1841 + return -EINVAL; 1842 + } 1843 + 1844 + return 0; 1845 + } 1846 + 1847 + static struct dso *load_dso(const char *name) 1848 + { 1849 + struct map *map; 1850 + struct dso *dso; 1851 + 1852 + map = dso__new_map(name); 1853 + if (!map) 1854 + return NULL; 1855 + 1856 + map__load(map); 1857 + 1858 + dso = dso__get(map->dso); 1859 + 1860 + map__put(map); 1861 + 1862 + return dso; 1863 + } 1864 + 1865 + static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt, 1866 + int idx) 1867 + { 1868 + /* Same name, and global or the n'th found or any */ 1869 + return !arch__compare_symbol_names(name, sym->name) && 1870 + ((!idx && sym->binding == STB_GLOBAL) || 1871 + (idx > 0 && ++*cnt == idx) || 1872 + idx < 0); 1873 + } 1874 + 1875 + static void print_duplicate_syms(struct dso *dso, const char *sym_name) 1876 + { 1877 + struct symbol *sym; 1878 + bool near = false; 1879 + int cnt = 0; 1880 + 1881 + pr_err("Multiple symbols with name '%s'\n", sym_name); 1882 + 1883 + sym = dso__first_symbol(dso, MAP__FUNCTION); 1884 + while (sym) { 1885 + if (dso_sym_match(sym, sym_name, &cnt, -1)) { 1886 + pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 1887 + ++cnt, sym->start, 1888 + sym->binding == STB_GLOBAL ? 'g' : 1889 + sym->binding == STB_LOCAL ? 'l' : 'w', 1890 + sym->name); 1891 + near = true; 1892 + } else if (near) { 1893 + near = false; 1894 + pr_err("\t\twhich is near\t\t%s\n", sym->name); 1895 + } 1896 + sym = dso__next_symbol(sym); 1897 + } 1898 + 1899 + pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 1900 + sym_name); 1901 + pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 1902 + } 1903 + 1904 + static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start, 1905 + u64 *size, int idx) 1906 + { 1907 + struct symbol *sym; 1908 + int cnt = 0; 1909 + 1910 + *start = 0; 1911 + *size = 0; 1912 + 1913 + sym = dso__first_symbol(dso, MAP__FUNCTION); 1914 + while (sym) { 1915 + if (*start) { 1916 + if (!*size) 1917 + *size = sym->start - *start; 1918 + if (idx > 0) { 1919 + if (*size) 1920 + return 1; 1921 + } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 1922 + print_duplicate_syms(dso, sym_name); 1923 + return -EINVAL; 1924 + } 1925 + } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 1926 + *start = sym->start; 1927 + *size = sym->end - sym->start; 1928 + } 1929 + sym = dso__next_symbol(sym); 1930 + } 1931 + 1932 + if (!*start) 1933 + return sym_not_found_error(sym_name, idx); 1934 + 1935 + return 0; 1936 + } 1937 + 1938 + static int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso) 1939 + { 1940 + struct symbol *first_sym = dso__first_symbol(dso, MAP__FUNCTION); 1941 + struct symbol *last_sym = dso__last_symbol(dso, MAP__FUNCTION); 1942 + 1943 + if (!first_sym || !last_sym) { 1944 + pr_err("Failed to determine filter for %s\nNo symbols found.\n", 1945 + filt->filename); 1946 + return -EINVAL; 1947 + } 1948 + 1949 + filt->addr = first_sym->start; 1950 + filt->size = last_sym->end - first_sym->start; 1951 + 1952 + return 0; 1953 + } 1954 + 1955 + static int addr_filter__resolve_syms(struct addr_filter *filt) 1956 + { 1957 + u64 start, size; 1958 + struct dso *dso; 1959 + int err = 0; 1960 + 1961 + if (!filt->sym_from && !filt->sym_to) 1962 + return 0; 1963 + 1964 + if (!filt->filename) 1965 + return addr_filter__resolve_kernel_syms(filt); 1966 + 1967 + dso = load_dso(filt->filename); 1968 + if (!dso) { 1969 + pr_err("Failed to load symbols from: %s\n", filt->filename); 1970 + return -EINVAL; 1971 + } 1972 + 1973 + if (filt->sym_from && !strcmp(filt->sym_from, "*")) { 1974 + err = addr_filter__entire_dso(filt, dso); 1975 + goto put_dso; 1976 + } 1977 + 1978 + if (filt->sym_from) { 1979 + err = find_dso_sym(dso, filt->sym_from, &start, &size, 1980 + filt->sym_from_idx); 1981 + if (err) 1982 + goto put_dso; 1983 + filt->addr = start; 1984 + if (filt->range && !filt->size && !filt->sym_to) 1985 + filt->size = size; 1986 + } 1987 + 1988 + if (filt->sym_to) { 1989 + err = find_dso_sym(dso, filt->sym_to, &start, &size, 1990 + filt->sym_to_idx); 1991 + if (err) 1992 + goto put_dso; 1993 + 1994 + err = check_end_after_start(filt, start, size); 1995 + if (err) 1996 + return err; 1997 + 1998 + filt->size = start + size - filt->addr; 1999 + } 2000 + 2001 + put_dso: 2002 + dso__put(dso); 2003 + 2004 + return err; 2005 + } 2006 + 2007 + static char *addr_filter__to_str(struct addr_filter *filt) 2008 + { 2009 + char filename_buf[PATH_MAX]; 2010 + const char *at = ""; 2011 + const char *fn = ""; 2012 + char *filter; 2013 + int err; 2014 + 2015 + if (filt->filename) { 2016 + at = "@"; 2017 + fn = realpath(filt->filename, filename_buf); 2018 + if (!fn) 2019 + return NULL; 2020 + } 2021 + 2022 + if (filt->range) { 2023 + err = asprintf(&filter, "%s 0x%"PRIx64"/0x%"PRIx64"%s%s", 2024 + filt->action, filt->addr, filt->size, at, fn); 2025 + } else { 2026 + err = asprintf(&filter, "%s 0x%"PRIx64"%s%s", 2027 + filt->action, filt->addr, at, fn); 2028 + } 2029 + 2030 + return err < 0 ? NULL : filter; 2031 + } 2032 + 2033 + static int parse_addr_filter(struct perf_evsel *evsel, const char *filter, 2034 + int max_nr) 2035 + { 2036 + struct addr_filters filts; 2037 + struct addr_filter *filt; 2038 + int err; 2039 + 2040 + addr_filters__init(&filts); 2041 + 2042 + err = addr_filters__parse_bare_filter(&filts, filter); 2043 + if (err) 2044 + goto out_exit; 2045 + 2046 + if (filts.cnt > max_nr) { 2047 + pr_err("Error: number of address filters (%d) exceeds maximum (%d)\n", 2048 + filts.cnt, max_nr); 2049 + err = -EINVAL; 2050 + goto out_exit; 2051 + } 2052 + 2053 + list_for_each_entry(filt, &filts.head, list) { 2054 + char *new_filter; 2055 + 2056 + err = addr_filter__resolve_syms(filt); 2057 + if (err) 2058 + goto out_exit; 2059 + 2060 + new_filter = addr_filter__to_str(filt); 2061 + if (!new_filter) { 2062 + err = -ENOMEM; 2063 + goto out_exit; 2064 + } 2065 + 2066 + if (perf_evsel__append_addr_filter(evsel, new_filter)) { 2067 + err = -ENOMEM; 2068 + goto out_exit; 2069 + } 2070 + } 2071 + 2072 + out_exit: 2073 + addr_filters__exit(&filts); 2074 + 2075 + if (err) { 2076 + pr_err("Failed to parse address filter: '%s'\n", filter); 2077 + pr_err("Filter format is: filter|start|stop|tracestop <start symbol or address> [/ <end symbol or size>] [@<file name>]\n"); 2078 + pr_err("Where multiple filters are separated by space or comma.\n"); 2079 + } 2080 + 2081 + return err; 2082 + } 2083 + 2084 + static struct perf_pmu *perf_evsel__find_pmu(struct perf_evsel *evsel) 2085 + { 2086 + struct perf_pmu *pmu = NULL; 2087 + 2088 + while ((pmu = perf_pmu__scan(pmu)) != NULL) { 2089 + if (pmu->type == evsel->attr.type) 2090 + break; 2091 + } 2092 + 2093 + return pmu; 2094 + } 2095 + 2096 + static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) 2097 + { 2098 + struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); 2099 + int nr_addr_filters = 0; 2100 + 2101 + if (!pmu) 2102 + return 0; 2103 + 2104 + perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters); 2105 + 2106 + return nr_addr_filters; 2107 + } 2108 + 2109 + int auxtrace_parse_filters(struct perf_evlist *evlist) 2110 + { 2111 + struct perf_evsel *evsel; 2112 + char *filter; 2113 + int err, max_nr; 2114 + 2115 + evlist__for_each_entry(evlist, evsel) { 2116 + filter = evsel->filter; 2117 + max_nr = perf_evsel__nr_addr_filter(evsel); 2118 + if (!filter || !max_nr) 2119 + continue; 2120 + evsel->filter = NULL; 2121 + err = parse_addr_filter(evsel, filter, max_nr); 2122 + free(filter); 2123 + if (err) 2124 + return err; 2125 + pr_debug("Address filter: %s\n", evsel->filter); 2126 + } 2127 + 2128 + return 0; 1410 2129 }
+54
tools/perf/util/auxtrace.h
··· 318 318 unsigned int alignment; 319 319 }; 320 320 321 + /** 322 + * struct addr_filter - address filter. 323 + * @list: list node 324 + * @range: true if it is a range filter 325 + * @start: true if action is 'filter' or 'start' 326 + * @action: 'filter', 'start' or 'stop' ('tracestop' is accepted but converted 327 + * to 'stop') 328 + * @sym_from: symbol name for the filter address 329 + * @sym_to: symbol name that determines the filter size 330 + * @sym_from_idx: selects n'th from symbols with the same name (0 means global 331 + * and less than 0 means symbol must be unique) 332 + * @sym_to_idx: same as @sym_from_idx but for @sym_to 333 + * @addr: filter address 334 + * @size: filter region size (for range filters) 335 + * @filename: DSO file name or NULL for the kernel 336 + * @str: allocated string that contains the other string members 337 + */ 338 + struct addr_filter { 339 + struct list_head list; 340 + bool range; 341 + bool start; 342 + const char *action; 343 + const char *sym_from; 344 + const char *sym_to; 345 + int sym_from_idx; 346 + int sym_to_idx; 347 + u64 addr; 348 + u64 size; 349 + const char *filename; 350 + char *str; 351 + }; 352 + 353 + /** 354 + * struct addr_filters - list of address filters. 355 + * @head: list of address filters 356 + * @cnt: number of address filters 357 + */ 358 + struct addr_filters { 359 + struct list_head head; 360 + int cnt; 361 + }; 362 + 321 363 #ifdef HAVE_AUXTRACE_SUPPORT 322 364 323 365 /* ··· 524 482 union perf_event *event); 525 483 void events_stats__auxtrace_error_warn(const struct events_stats *stats); 526 484 485 + void addr_filters__init(struct addr_filters *filts); 486 + void addr_filters__exit(struct addr_filters *filts); 487 + int addr_filters__parse_bare_filter(struct addr_filters *filts, 488 + const char *filter); 489 + int auxtrace_parse_filters(struct perf_evlist *evlist); 490 + 527 491 static inline int auxtrace__process_event(struct perf_session *session, 528 492 union perf_event *event, 529 493 struct perf_sample *sample, ··· 686 638 static inline 687 639 void auxtrace_index__free(struct list_head *head __maybe_unused) 688 640 { 641 + } 642 + 643 + static inline 644 + int auxtrace_parse_filters(struct perf_evlist *evlist __maybe_unused) 645 + { 646 + return 0; 689 647 } 690 648 691 649 int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,