diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/Makefile | 21 | ||||
| -rw-r--r-- | tools/perf/builtin-lock.c | 8 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 14 | ||||
| -rw-r--r-- | tools/perf/builtin-record.c | 23 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 15 | ||||
| -rw-r--r-- | tools/perf/builtin-sched.c | 24 | ||||
| -rw-r--r-- | tools/perf/builtin-stat.c | 7 | ||||
| -rw-r--r-- | tools/perf/util/config.c | 32 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.c | 210 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.h | 11 | ||||
| -rw-r--r-- | tools/perf/util/evlist.c | 24 | ||||
| -rw-r--r-- | tools/perf/util/evlist.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 19 | ||||
| -rw-r--r-- | tools/perf/util/include/linux/compiler.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 8 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 12 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 231 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/python.c | 115 | ||||
| -rw-r--r-- | tools/perf/util/setup.py | 21 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 68 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/top.c | 1 |
23 files changed, 662 insertions, 209 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 56d62d3fb167..3b8f7b80376b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -181,9 +181,9 @@ strip-libs = $(filter-out -l%,$(1)) | |||
| 181 | 181 | ||
| 182 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) | 182 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) |
| 183 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 183 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
| 184 | --quiet build_ext \ | 184 | --quiet build_ext; \ |
| 185 | --build-lib='$(OUTPUT)python' \ | 185 | mkdir -p $(OUTPUT)python && \ |
| 186 | --build-temp='$(OUTPUT)python/temp' | 186 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ |
| 187 | # | 187 | # |
| 188 | # No Perl scripts right now: | 188 | # No Perl scripts right now: |
| 189 | # | 189 | # |
| @@ -509,9 +509,13 @@ else | |||
| 509 | 509 | ||
| 510 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 510 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
| 511 | 511 | ||
| 512 | python-clean := $(PYTHON_WORD) util/setup.py clean \ | 512 | # python extension build directories |
| 513 | --build-lib='$(OUTPUT)python' \ | 513 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
| 514 | --build-temp='$(OUTPUT)python/temp' | 514 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ |
| 515 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
| 516 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
| 517 | |||
| 518 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
| 515 | 519 | ||
| 516 | ifdef NO_LIBPYTHON | 520 | ifdef NO_LIBPYTHON |
| 517 | $(call disable-python) | 521 | $(call disable-python) |
| @@ -868,6 +872,9 @@ install: all | |||
| 868 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' | 872 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' |
| 869 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 873 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
| 870 | 874 | ||
| 875 | install-python_ext: | ||
| 876 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | ||
| 877 | |||
| 871 | install-doc: | 878 | install-doc: |
| 872 | $(MAKE) -C Documentation install | 879 | $(MAKE) -C Documentation install |
| 873 | 880 | ||
| @@ -895,7 +902,7 @@ quick-install-html: | |||
| 895 | ### Cleaning rules | 902 | ### Cleaning rules |
| 896 | 903 | ||
| 897 | clean: | 904 | clean: |
| 898 | $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive} | 905 | $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) |
| 899 | $(RM) $(ALL_PROGRAMS) perf | 906 | $(RM) $(ALL_PROGRAMS) perf |
| 900 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* | 907 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* |
| 901 | $(MAKE) -C Documentation/ clean | 908 | $(MAKE) -C Documentation/ clean |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 9ac05aafd9b2..899080ace267 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
| @@ -942,10 +942,10 @@ static const char *record_args[] = { | |||
| 942 | "-f", | 942 | "-f", |
| 943 | "-m", "1024", | 943 | "-m", "1024", |
| 944 | "-c", "1", | 944 | "-c", "1", |
| 945 | "-e", "lock:lock_acquire:r", | 945 | "-e", "lock:lock_acquire", |
| 946 | "-e", "lock:lock_acquired:r", | 946 | "-e", "lock:lock_acquired", |
| 947 | "-e", "lock:lock_contended:r", | 947 | "-e", "lock:lock_contended", |
| 948 | "-e", "lock:lock_release:r", | 948 | "-e", "lock:lock_release", |
| 949 | }; | 949 | }; |
| 950 | 950 | ||
| 951 | static int __cmd_record(int argc, const char **argv) | 951 | static int __cmd_record(int argc, const char **argv) |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 5f2a5c7046df..710ae3d0a489 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used, | |||
| 134 | { | 134 | { |
| 135 | int ret = 0; | 135 | int ret = 0; |
| 136 | 136 | ||
| 137 | if (str) | 137 | if (!str) |
| 138 | ret = parse_line_range_desc(str, ¶ms.line_range); | 138 | return 0; |
| 139 | INIT_LIST_HEAD(¶ms.line_range.line_list); | 139 | |
| 140 | if (params.show_lines) { | ||
| 141 | pr_warning("Warning: more than one --line options are" | ||
| 142 | " detected. Only the first one is valid.\n"); | ||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 140 | params.show_lines = true; | 146 | params.show_lines = true; |
| 147 | ret = parse_line_range_desc(str, ¶ms.line_range); | ||
| 148 | INIT_LIST_HEAD(¶ms.line_range.line_list); | ||
| 141 | 149 | ||
| 142 | return ret; | 150 | return ret; |
| 143 | } | 151 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 80dc5b790e47..6b0519f885e4 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -30,8 +30,6 @@ | |||
| 30 | #include <sched.h> | 30 | #include <sched.h> |
| 31 | #include <sys/mman.h> | 31 | #include <sys/mman.h> |
| 32 | 32 | ||
| 33 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | ||
| 34 | |||
| 35 | enum write_mode_t { | 33 | enum write_mode_t { |
| 36 | WRITE_FORCE, | 34 | WRITE_FORCE, |
| 37 | WRITE_APPEND | 35 | WRITE_APPEND |
| @@ -47,7 +45,7 @@ static int freq = 1000; | |||
| 47 | static int output; | 45 | static int output; |
| 48 | static int pipe_output = 0; | 46 | static int pipe_output = 0; |
| 49 | static const char *output_name = NULL; | 47 | static const char *output_name = NULL; |
| 50 | static int group = 0; | 48 | static bool group = false; |
| 51 | static int realtime_prio = 0; | 49 | static int realtime_prio = 0; |
| 52 | static bool nodelay = false; | 50 | static bool nodelay = false; |
| 53 | static bool raw_samples = false; | 51 | static bool raw_samples = false; |
| @@ -438,7 +436,6 @@ static void mmap_read_all(void) | |||
| 438 | 436 | ||
| 439 | static int __cmd_record(int argc, const char **argv) | 437 | static int __cmd_record(int argc, const char **argv) |
| 440 | { | 438 | { |
| 441 | int i; | ||
| 442 | struct stat st; | 439 | struct stat st; |
| 443 | int flags; | 440 | int flags; |
| 444 | int err; | 441 | int err; |
| @@ -682,7 +679,6 @@ static int __cmd_record(int argc, const char **argv) | |||
| 682 | 679 | ||
| 683 | for (;;) { | 680 | for (;;) { |
| 684 | int hits = samples; | 681 | int hits = samples; |
| 685 | int thread; | ||
| 686 | 682 | ||
| 687 | mmap_read_all(); | 683 | mmap_read_all(); |
| 688 | 684 | ||
| @@ -693,19 +689,8 @@ static int __cmd_record(int argc, const char **argv) | |||
| 693 | waking++; | 689 | waking++; |
| 694 | } | 690 | } |
| 695 | 691 | ||
| 696 | if (done) { | 692 | if (done) |
| 697 | for (i = 0; i < evsel_list->cpus->nr; i++) { | 693 | perf_evlist__disable(evsel_list); |
| 698 | struct perf_evsel *pos; | ||
| 699 | |||
| 700 | list_for_each_entry(pos, &evsel_list->entries, node) { | ||
| 701 | for (thread = 0; | ||
| 702 | thread < evsel_list->threads->nr; | ||
| 703 | thread++) | ||
| 704 | ioctl(FD(pos, i, thread), | ||
| 705 | PERF_EVENT_IOC_DISABLE); | ||
| 706 | } | ||
| 707 | } | ||
| 708 | } | ||
| 709 | } | 694 | } |
| 710 | 695 | ||
| 711 | if (quiet || signr == SIGUSR1) | 696 | if (quiet || signr == SIGUSR1) |
| @@ -768,6 +753,8 @@ const struct option record_options[] = { | |||
| 768 | "child tasks do not inherit counters"), | 753 | "child tasks do not inherit counters"), |
| 769 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), | 754 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), |
| 770 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), | 755 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), |
| 756 | OPT_BOOLEAN(0, "group", &group, | ||
| 757 | "put the counters into a counter group"), | ||
| 771 | OPT_BOOLEAN('g', "call-graph", &call_graph, | 758 | OPT_BOOLEAN('g', "call-graph", &call_graph, |
| 772 | "do call-graph (stack chain/backtrace) recording"), | 759 | "do call-graph (stack chain/backtrace) recording"), |
| 773 | OPT_INCR('v', "verbose", &verbose, | 760 | OPT_INCR('v', "verbose", &verbose, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f854efda7686..d7ff277bdb78 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -162,23 +162,22 @@ static int perf_session__setup_sample_type(struct perf_session *self) | |||
| 162 | { | 162 | { |
| 163 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { | 163 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { |
| 164 | if (sort__has_parent) { | 164 | if (sort__has_parent) { |
| 165 | fprintf(stderr, "selected --sort parent, but no" | 165 | ui__warning("Selected --sort parent, but no " |
| 166 | " callchain data. Did you call" | 166 | "callchain data. Did you call " |
| 167 | " perf record without -g?\n"); | 167 | "'perf record' without -g?\n"); |
| 168 | return -EINVAL; | 168 | return -EINVAL; |
| 169 | } | 169 | } |
| 170 | if (symbol_conf.use_callchain) { | 170 | if (symbol_conf.use_callchain) { |
| 171 | fprintf(stderr, "selected -g but no callchain data." | 171 | ui__warning("Selected -g but no callchain data. Did " |
| 172 | " Did you call perf record without" | 172 | "you call 'perf record' without -g?\n"); |
| 173 | " -g?\n"); | ||
| 174 | return -1; | 173 | return -1; |
| 175 | } | 174 | } |
| 176 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && | 175 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && |
| 177 | !symbol_conf.use_callchain) { | 176 | !symbol_conf.use_callchain) { |
| 178 | symbol_conf.use_callchain = true; | 177 | symbol_conf.use_callchain = true; |
| 179 | if (callchain_register_param(&callchain_param) < 0) { | 178 | if (callchain_register_param(&callchain_param) < 0) { |
| 180 | fprintf(stderr, "Can't register callchain" | 179 | ui__warning("Can't register callchain " |
| 181 | " params\n"); | 180 | "params.\n"); |
| 182 | return -EINVAL; | 181 | return -EINVAL; |
| 183 | } | 182 | } |
| 184 | } | 183 | } |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index dcfe8873c9a1..5177964943e7 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = { | |||
| 1637 | .ordered_samples = true, | 1637 | .ordered_samples = true, |
| 1638 | }; | 1638 | }; |
| 1639 | 1639 | ||
| 1640 | static int read_events(void) | 1640 | static void read_events(bool destroy, struct perf_session **psession) |
| 1641 | { | 1641 | { |
| 1642 | int err = -EINVAL; | 1642 | int err = -EINVAL; |
| 1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
| 1644 | 0, false, &event_ops); | 1644 | 0, false, &event_ops); |
| 1645 | if (session == NULL) | 1645 | if (session == NULL) |
| 1646 | return -ENOMEM; | 1646 | die("No Memory"); |
| 1647 | 1647 | ||
| 1648 | if (perf_session__has_traces(session, "record -R")) { | 1648 | if (perf_session__has_traces(session, "record -R")) { |
| 1649 | err = perf_session__process_events(session, &event_ops); | 1649 | err = perf_session__process_events(session, &event_ops); |
| 1650 | if (err) | ||
| 1651 | die("Failed to process events, error %d", err); | ||
| 1652 | |||
| 1650 | nr_events = session->hists.stats.nr_events[0]; | 1653 | nr_events = session->hists.stats.nr_events[0]; |
| 1651 | nr_lost_events = session->hists.stats.total_lost; | 1654 | nr_lost_events = session->hists.stats.total_lost; |
| 1652 | nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; | 1655 | nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; |
| 1653 | } | 1656 | } |
| 1654 | 1657 | ||
| 1655 | perf_session__delete(session); | 1658 | if (destroy) |
| 1656 | return err; | 1659 | perf_session__delete(session); |
| 1660 | |||
| 1661 | if (psession) | ||
| 1662 | *psession = session; | ||
| 1657 | } | 1663 | } |
| 1658 | 1664 | ||
| 1659 | static void print_bad_events(void) | 1665 | static void print_bad_events(void) |
| @@ -1689,9 +1695,10 @@ static void print_bad_events(void) | |||
| 1689 | static void __cmd_lat(void) | 1695 | static void __cmd_lat(void) |
| 1690 | { | 1696 | { |
| 1691 | struct rb_node *next; | 1697 | struct rb_node *next; |
| 1698 | struct perf_session *session; | ||
| 1692 | 1699 | ||
| 1693 | setup_pager(); | 1700 | setup_pager(); |
| 1694 | read_events(); | 1701 | read_events(false, &session); |
| 1695 | sort_lat(); | 1702 | sort_lat(); |
| 1696 | 1703 | ||
| 1697 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); | 1704 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); |
| @@ -1717,6 +1724,7 @@ static void __cmd_lat(void) | |||
| 1717 | print_bad_events(); | 1724 | print_bad_events(); |
| 1718 | printf("\n"); | 1725 | printf("\n"); |
| 1719 | 1726 | ||
| 1727 | perf_session__delete(session); | ||
| 1720 | } | 1728 | } |
| 1721 | 1729 | ||
| 1722 | static struct trace_sched_handler map_ops = { | 1730 | static struct trace_sched_handler map_ops = { |
| @@ -1731,7 +1739,7 @@ static void __cmd_map(void) | |||
| 1731 | max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1739 | max_cpu = sysconf(_SC_NPROCESSORS_CONF); |
| 1732 | 1740 | ||
| 1733 | setup_pager(); | 1741 | setup_pager(); |
| 1734 | read_events(); | 1742 | read_events(true, NULL); |
| 1735 | print_bad_events(); | 1743 | print_bad_events(); |
| 1736 | } | 1744 | } |
| 1737 | 1745 | ||
| @@ -1744,7 +1752,7 @@ static void __cmd_replay(void) | |||
| 1744 | 1752 | ||
| 1745 | test_calibrations(); | 1753 | test_calibrations(); |
| 1746 | 1754 | ||
| 1747 | read_events(); | 1755 | read_events(true, NULL); |
| 1748 | 1756 | ||
| 1749 | printf("nr_run_events: %ld\n", nr_run_events); | 1757 | printf("nr_run_events: %ld\n", nr_run_events); |
| 1750 | printf("nr_sleep_events: %ld\n", nr_sleep_events); | 1758 | printf("nr_sleep_events: %ld\n", nr_sleep_events); |
| @@ -1769,7 +1777,7 @@ static void __cmd_replay(void) | |||
| 1769 | 1777 | ||
| 1770 | 1778 | ||
| 1771 | static const char * const sched_usage[] = { | 1779 | static const char * const sched_usage[] = { |
| 1772 | "perf sched [<options>] {record|latency|map|replay|trace}", | 1780 | "perf sched [<options>] {record|latency|map|replay|script}", |
| 1773 | NULL | 1781 | NULL |
| 1774 | }; | 1782 | }; |
| 1775 | 1783 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1ad04ce29c34..5deb17d9e795 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -193,6 +193,7 @@ static int big_num_opt = -1; | |||
| 193 | static const char *cpu_list; | 193 | static const char *cpu_list; |
| 194 | static const char *csv_sep = NULL; | 194 | static const char *csv_sep = NULL; |
| 195 | static bool csv_output = false; | 195 | static bool csv_output = false; |
| 196 | static bool group = false; | ||
| 196 | 197 | ||
| 197 | static volatile int done = 0; | 198 | static volatile int done = 0; |
| 198 | 199 | ||
| @@ -280,14 +281,14 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
| 280 | attr->inherit = !no_inherit; | 281 | attr->inherit = !no_inherit; |
| 281 | 282 | ||
| 282 | if (system_wide) | 283 | if (system_wide) |
| 283 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); | 284 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group); |
| 284 | 285 | ||
| 285 | if (target_pid == -1 && target_tid == -1) { | 286 | if (target_pid == -1 && target_tid == -1) { |
| 286 | attr->disabled = 1; | 287 | attr->disabled = 1; |
| 287 | attr->enable_on_exec = 1; | 288 | attr->enable_on_exec = 1; |
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); | 291 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, group); |
| 291 | } | 292 | } |
| 292 | 293 | ||
| 293 | /* | 294 | /* |
| @@ -1043,6 +1044,8 @@ static const struct option options[] = { | |||
| 1043 | "stat events on existing thread id"), | 1044 | "stat events on existing thread id"), |
| 1044 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1045 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
| 1045 | "system-wide collection from all CPUs"), | 1046 | "system-wide collection from all CPUs"), |
| 1047 | OPT_BOOLEAN('g', "group", &group, | ||
| 1048 | "put the counters into a counter group"), | ||
| 1046 | OPT_BOOLEAN('c', "scale", &scale, | 1049 | OPT_BOOLEAN('c', "scale", &scale, |
| 1047 | "scale/normalize counters"), | 1050 | "scale/normalize counters"), |
| 1048 | OPT_INCR('v', "verbose", &verbose, | 1051 | OPT_INCR('v', "verbose", &verbose, |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index e02d78cae70f..fe02903f7d0f 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
| @@ -399,7 +399,6 @@ static int perf_config_global(void) | |||
| 399 | int perf_config(config_fn_t fn, void *data) | 399 | int perf_config(config_fn_t fn, void *data) |
| 400 | { | 400 | { |
| 401 | int ret = 0, found = 0; | 401 | int ret = 0, found = 0; |
| 402 | char *repo_config = NULL; | ||
| 403 | const char *home = NULL; | 402 | const char *home = NULL; |
| 404 | 403 | ||
| 405 | /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ | 404 | /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ |
| @@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data) | |||
| 414 | home = getenv("HOME"); | 413 | home = getenv("HOME"); |
| 415 | if (perf_config_global() && home) { | 414 | if (perf_config_global() && home) { |
| 416 | char *user_config = strdup(mkpath("%s/.perfconfig", home)); | 415 | char *user_config = strdup(mkpath("%s/.perfconfig", home)); |
| 417 | if (!access(user_config, R_OK)) { | 416 | struct stat st; |
| 418 | ret += perf_config_from_file(fn, user_config, data); | 417 | |
| 419 | found += 1; | 418 | if (user_config == NULL) { |
| 419 | warning("Not enough memory to process %s/.perfconfig, " | ||
| 420 | "ignoring it.", home); | ||
| 421 | goto out; | ||
| 420 | } | 422 | } |
| 421 | free(user_config); | ||
| 422 | } | ||
| 423 | 423 | ||
| 424 | repo_config = perf_pathdup("config"); | 424 | if (stat(user_config, &st) < 0) |
| 425 | if (!access(repo_config, R_OK)) { | 425 | goto out_free; |
| 426 | ret += perf_config_from_file(fn, repo_config, data); | 426 | |
| 427 | if (st.st_uid && (st.st_uid != geteuid())) { | ||
| 428 | warning("File %s not owned by current user or root, " | ||
| 429 | "ignoring it.", user_config); | ||
| 430 | goto out_free; | ||
| 431 | } | ||
| 432 | |||
| 433 | if (!st.st_size) | ||
| 434 | goto out_free; | ||
| 435 | |||
| 436 | ret += perf_config_from_file(fn, user_config, data); | ||
| 427 | found += 1; | 437 | found += 1; |
| 438 | out_free: | ||
| 439 | free(user_config); | ||
| 428 | } | 440 | } |
| 429 | free(repo_config); | 441 | out: |
| 430 | if (found == 0) | 442 | if (found == 0) |
| 431 | return -1; | 443 | return -1; |
| 432 | return ret; | 444 | return ret; |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index fddf40f30d3e..ee51e9b4dc09 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
| @@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, | |||
| 96 | return *lineno ?: -ENOENT; | 96 | return *lineno ?: -ENOENT; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); | ||
| 100 | |||
| 101 | /** | ||
| 102 | * cu_walk_functions_at - Walk on function DIEs at given address | ||
| 103 | * @cu_die: A CU DIE | ||
| 104 | * @addr: An address | ||
| 105 | * @callback: A callback which called with found DIEs | ||
| 106 | * @data: A user data | ||
| 107 | * | ||
| 108 | * Walk on function DIEs at given @addr in @cu_die. Passed DIEs | ||
| 109 | * should be subprogram or inlined-subroutines. | ||
| 110 | */ | ||
| 111 | int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
| 112 | int (*callback)(Dwarf_Die *, void *), void *data) | ||
| 113 | { | ||
| 114 | Dwarf_Die die_mem; | ||
| 115 | Dwarf_Die *sc_die; | ||
| 116 | int ret = -ENOENT; | ||
| 117 | |||
| 118 | /* Inlined function could be recursive. Trace it until fail */ | ||
| 119 | for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); | ||
| 120 | sc_die != NULL; | ||
| 121 | sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, | ||
| 122 | &die_mem)) { | ||
| 123 | ret = callback(sc_die, data); | ||
| 124 | if (ret) | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | |||
| 128 | return ret; | ||
| 129 | |||
| 130 | } | ||
| 131 | |||
| 99 | /** | 132 | /** |
| 100 | * die_compare_name - Compare diename and tname | 133 | * die_compare_name - Compare diename and tname |
| 101 | * @dw_die: a DIE | 134 | * @dw_die: a DIE |
| @@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | |||
| 198 | return 0; | 231 | return 0; |
| 199 | } | 232 | } |
| 200 | 233 | ||
| 234 | /* Get attribute and translate it as a sdata */ | ||
| 235 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, | ||
| 236 | Dwarf_Sword *result) | ||
| 237 | { | ||
| 238 | Dwarf_Attribute attr; | ||
| 239 | |||
| 240 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
| 241 | dwarf_formsdata(&attr, result) != 0) | ||
| 242 | return -ENOENT; | ||
| 243 | |||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 201 | /** | 247 | /** |
| 202 | * die_is_signed_type - Check whether a type DIE is signed or not | 248 | * die_is_signed_type - Check whether a type DIE is signed or not |
| 203 | * @tp_die: a DIE of a type | 249 | * @tp_die: a DIE of a type |
| @@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | |||
| 250 | return 0; | 296 | return 0; |
| 251 | } | 297 | } |
| 252 | 298 | ||
| 299 | /* Get the call file index number in CU DIE */ | ||
| 300 | static int die_get_call_fileno(Dwarf_Die *in_die) | ||
| 301 | { | ||
| 302 | Dwarf_Sword idx; | ||
| 303 | |||
| 304 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) | ||
| 305 | return (int)idx; | ||
| 306 | else | ||
| 307 | return -ENOENT; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* Get the declared file index number in CU DIE */ | ||
| 311 | static int die_get_decl_fileno(Dwarf_Die *pdie) | ||
| 312 | { | ||
| 313 | Dwarf_Sword idx; | ||
| 314 | |||
| 315 | if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0) | ||
| 316 | return (int)idx; | ||
| 317 | else | ||
| 318 | return -ENOENT; | ||
| 319 | } | ||
| 320 | |||
| 321 | /** | ||
| 322 | * die_get_call_file - Get callsite file name of inlined function instance | ||
| 323 | * @in_die: a DIE of an inlined function instance | ||
| 324 | * | ||
| 325 | * Get call-site file name of @in_die. This means from which file the inline | ||
| 326 | * function is called. | ||
| 327 | */ | ||
| 328 | const char *die_get_call_file(Dwarf_Die *in_die) | ||
| 329 | { | ||
| 330 | Dwarf_Die cu_die; | ||
| 331 | Dwarf_Files *files; | ||
| 332 | int idx; | ||
| 333 | |||
| 334 | idx = die_get_call_fileno(in_die); | ||
| 335 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || | ||
| 336 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) | ||
| 337 | return NULL; | ||
| 338 | |||
| 339 | return dwarf_filesrc(files, idx, NULL, NULL); | ||
| 340 | } | ||
| 341 | |||
| 342 | |||
| 253 | /** | 343 | /** |
| 254 | * die_find_child - Generic DIE search function in DIE tree | 344 | * die_find_child - Generic DIE search function in DIE tree |
| 255 | * @rt_die: a root DIE | 345 | * @rt_die: a root DIE |
| @@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
| 374 | return die_mem; | 464 | return die_mem; |
| 375 | } | 465 | } |
| 376 | 466 | ||
| 467 | struct __instance_walk_param { | ||
| 468 | void *addr; | ||
| 469 | int (*callback)(Dwarf_Die *, void *); | ||
| 470 | void *data; | ||
| 471 | int retval; | ||
| 472 | }; | ||
| 473 | |||
| 474 | static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) | ||
| 475 | { | ||
| 476 | struct __instance_walk_param *iwp = data; | ||
| 477 | Dwarf_Attribute attr_mem; | ||
| 478 | Dwarf_Die origin_mem; | ||
| 479 | Dwarf_Attribute *attr; | ||
| 480 | Dwarf_Die *origin; | ||
| 481 | int tmp; | ||
| 482 | |||
| 483 | attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); | ||
| 484 | if (attr == NULL) | ||
| 485 | return DIE_FIND_CB_CONTINUE; | ||
| 486 | |||
| 487 | origin = dwarf_formref_die(attr, &origin_mem); | ||
| 488 | if (origin == NULL || origin->addr != iwp->addr) | ||
| 489 | return DIE_FIND_CB_CONTINUE; | ||
| 490 | |||
| 491 | /* Ignore redundant instances */ | ||
| 492 | if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) { | ||
| 493 | dwarf_decl_line(origin, &tmp); | ||
| 494 | if (die_get_call_lineno(inst) == tmp) { | ||
| 495 | tmp = die_get_decl_fileno(origin); | ||
| 496 | if (die_get_call_fileno(inst) == tmp) | ||
| 497 | return DIE_FIND_CB_CONTINUE; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | iwp->retval = iwp->callback(inst, iwp->data); | ||
| 502 | |||
| 503 | return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; | ||
| 504 | } | ||
| 505 | |||
| 506 | /** | ||
| 507 | * die_walk_instances - Walk on instances of given DIE | ||
| 508 | * @or_die: an abstract original DIE | ||
| 509 | * @callback: a callback function which is called with instance DIE | ||
| 510 | * @data: user data | ||
| 511 | * | ||
| 512 | * Walk on the instances of give @in_die. @in_die must be an inlined function | ||
| 513 | * declartion. This returns the return value of @callback if it returns | ||
| 514 | * non-zero value, or -ENOENT if there is no instance. | ||
| 515 | */ | ||
| 516 | int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), | ||
| 517 | void *data) | ||
| 518 | { | ||
| 519 | Dwarf_Die cu_die; | ||
| 520 | Dwarf_Die die_mem; | ||
| 521 | struct __instance_walk_param iwp = { | ||
| 522 | .addr = or_die->addr, | ||
| 523 | .callback = callback, | ||
| 524 | .data = data, | ||
| 525 | .retval = -ENOENT, | ||
| 526 | }; | ||
| 527 | |||
| 528 | if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) | ||
| 529 | return -ENOENT; | ||
| 530 | |||
| 531 | die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); | ||
| 532 | |||
| 533 | return iwp.retval; | ||
| 534 | } | ||
| 535 | |||
| 377 | /* Line walker internal parameters */ | 536 | /* Line walker internal parameters */ |
| 378 | struct __line_walk_param { | 537 | struct __line_walk_param { |
| 379 | const char *fname; | 538 | bool recursive; |
| 380 | line_walk_callback_t callback; | 539 | line_walk_callback_t callback; |
| 381 | void *data; | 540 | void *data; |
| 382 | int retval; | 541 | int retval; |
| @@ -385,39 +544,56 @@ struct __line_walk_param { | |||
| 385 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | 544 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) |
| 386 | { | 545 | { |
| 387 | struct __line_walk_param *lw = data; | 546 | struct __line_walk_param *lw = data; |
| 388 | Dwarf_Addr addr; | 547 | Dwarf_Addr addr = 0; |
| 548 | const char *fname; | ||
| 389 | int lineno; | 549 | int lineno; |
| 390 | 550 | ||
| 391 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | 551 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { |
| 552 | fname = die_get_call_file(in_die); | ||
| 392 | lineno = die_get_call_lineno(in_die); | 553 | lineno = die_get_call_lineno(in_die); |
| 393 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | 554 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { |
| 394 | lw->retval = lw->callback(lw->fname, lineno, addr, | 555 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
| 395 | lw->data); | ||
| 396 | if (lw->retval != 0) | 556 | if (lw->retval != 0) |
| 397 | return DIE_FIND_CB_END; | 557 | return DIE_FIND_CB_END; |
| 398 | } | 558 | } |
| 399 | } | 559 | } |
| 400 | return DIE_FIND_CB_SIBLING; | 560 | if (!lw->recursive) |
| 561 | /* Don't need to search recursively */ | ||
| 562 | return DIE_FIND_CB_SIBLING; | ||
| 563 | |||
| 564 | if (addr) { | ||
| 565 | fname = dwarf_decl_file(in_die); | ||
| 566 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { | ||
| 567 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | ||
| 568 | if (lw->retval != 0) | ||
| 569 | return DIE_FIND_CB_END; | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | /* Continue to search nested inlined function call-sites */ | ||
| 574 | return DIE_FIND_CB_CONTINUE; | ||
| 401 | } | 575 | } |
| 402 | 576 | ||
| 403 | /* Walk on lines of blocks included in given DIE */ | 577 | /* Walk on lines of blocks included in given DIE */ |
| 404 | static int __die_walk_funclines(Dwarf_Die *sp_die, | 578 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, |
| 405 | line_walk_callback_t callback, void *data) | 579 | line_walk_callback_t callback, void *data) |
| 406 | { | 580 | { |
| 407 | struct __line_walk_param lw = { | 581 | struct __line_walk_param lw = { |
| 582 | .recursive = recursive, | ||
| 408 | .callback = callback, | 583 | .callback = callback, |
| 409 | .data = data, | 584 | .data = data, |
| 410 | .retval = 0, | 585 | .retval = 0, |
| 411 | }; | 586 | }; |
| 412 | Dwarf_Die die_mem; | 587 | Dwarf_Die die_mem; |
| 413 | Dwarf_Addr addr; | 588 | Dwarf_Addr addr; |
| 589 | const char *fname; | ||
| 414 | int lineno; | 590 | int lineno; |
| 415 | 591 | ||
| 416 | /* Handle function declaration line */ | 592 | /* Handle function declaration line */ |
| 417 | lw.fname = dwarf_decl_file(sp_die); | 593 | fname = dwarf_decl_file(sp_die); |
| 418 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | 594 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && |
| 419 | dwarf_entrypc(sp_die, &addr) == 0) { | 595 | dwarf_entrypc(sp_die, &addr) == 0) { |
| 420 | lw.retval = callback(lw.fname, lineno, addr, data); | 596 | lw.retval = callback(fname, lineno, addr, data); |
| 421 | if (lw.retval != 0) | 597 | if (lw.retval != 0) |
| 422 | goto done; | 598 | goto done; |
| 423 | } | 599 | } |
| @@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
| 430 | { | 606 | { |
| 431 | struct __line_walk_param *lw = data; | 607 | struct __line_walk_param *lw = data; |
| 432 | 608 | ||
| 433 | lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); | 609 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); |
| 434 | if (lw->retval != 0) | 610 | if (lw->retval != 0) |
| 435 | return DWARF_CB_ABORT; | 611 | return DWARF_CB_ABORT; |
| 436 | 612 | ||
| @@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
| 439 | 615 | ||
| 440 | /** | 616 | /** |
| 441 | * die_walk_lines - Walk on lines inside given DIE | 617 | * die_walk_lines - Walk on lines inside given DIE |
| 442 | * @rt_die: a root DIE (CU or subprogram) | 618 | * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) |
| 443 | * @callback: callback routine | 619 | * @callback: callback routine |
| 444 | * @data: user data | 620 | * @data: user data |
| 445 | * | 621 | * |
| @@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
| 460 | size_t nlines, i; | 636 | size_t nlines, i; |
| 461 | 637 | ||
| 462 | /* Get the CU die */ | 638 | /* Get the CU die */ |
| 463 | if (dwarf_tag(rt_die) == DW_TAG_subprogram) | 639 | if (dwarf_tag(rt_die) != DW_TAG_compile_unit) |
| 464 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); | 640 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); |
| 465 | else | 641 | else |
| 466 | cu_die = rt_die; | 642 | cu_die = rt_die; |
| 467 | if (!cu_die) { | 643 | if (!cu_die) { |
| 468 | pr_debug2("Failed to get CU from subprogram\n"); | 644 | pr_debug2("Failed to get CU from given DIE.\n"); |
| 469 | return -EINVAL; | 645 | return -EINVAL; |
| 470 | } | 646 | } |
| 471 | 647 | ||
| @@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
| 509 | * subroutines. We have to check functions list or given function. | 685 | * subroutines. We have to check functions list or given function. |
| 510 | */ | 686 | */ |
| 511 | if (rt_die != cu_die) | 687 | if (rt_die != cu_die) |
| 512 | ret = __die_walk_funclines(rt_die, callback, data); | 688 | /* |
| 689 | * Don't need walk functions recursively, because nested | ||
| 690 | * inlined functions don't have lines of the specified DIE. | ||
| 691 | */ | ||
| 692 | ret = __die_walk_funclines(rt_die, false, callback, data); | ||
| 513 | else { | 693 | else { |
| 514 | struct __line_walk_param param = { | 694 | struct __line_walk_param param = { |
| 515 | .callback = callback, | 695 | .callback = callback, |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bc3b21167e70..6ce1717784b7 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
| @@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); | |||
| 34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | 34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, |
| 35 | const char **fname, int *lineno); | 35 | const char **fname, int *lineno); |
| 36 | 36 | ||
| 37 | /* Walk on funcitons at given address */ | ||
| 38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
| 39 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
| 40 | |||
| 37 | /* Compare diename and tname */ | 41 | /* Compare diename and tname */ |
| 38 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
| 39 | 43 | ||
| 40 | /* Get callsite line number of inline-function instance */ | 44 | /* Get callsite line number of inline-function instance */ |
| 41 | extern int die_get_call_lineno(Dwarf_Die *in_die); | 45 | extern int die_get_call_lineno(Dwarf_Die *in_die); |
| 42 | 46 | ||
| 47 | /* Get callsite file name of inlined function instance */ | ||
| 48 | extern const char *die_get_call_file(Dwarf_Die *in_die); | ||
| 49 | |||
| 43 | /* Get type die */ | 50 | /* Get type die */ |
| 44 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 51 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
| 45 | 52 | ||
| @@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
| 73 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
| 74 | Dwarf_Die *die_mem); | 81 | Dwarf_Die *die_mem); |
| 75 | 82 | ||
| 83 | /* Walk on the instances of given DIE */ | ||
| 84 | extern int die_walk_instances(Dwarf_Die *in_die, | ||
| 85 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
| 86 | |||
| 76 | /* Walker on lines (Note: line number will not be sorted) */ | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
| 77 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
| 78 | Dwarf_Addr addr, void *data); | 89 | Dwarf_Addr addr, void *data); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b021ea9265c3..c12bd476c6f7 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -85,10 +85,32 @@ int perf_evlist__add_default(struct perf_evlist *evlist) | |||
| 85 | struct perf_evsel *evsel = perf_evsel__new(&attr, 0); | 85 | struct perf_evsel *evsel = perf_evsel__new(&attr, 0); |
| 86 | 86 | ||
| 87 | if (evsel == NULL) | 87 | if (evsel == NULL) |
| 88 | return -ENOMEM; | 88 | goto error; |
| 89 | |||
| 90 | /* use strdup() because free(evsel) assumes name is allocated */ | ||
| 91 | evsel->name = strdup("cycles"); | ||
| 92 | if (!evsel->name) | ||
| 93 | goto error_free; | ||
| 89 | 94 | ||
| 90 | perf_evlist__add(evlist, evsel); | 95 | perf_evlist__add(evlist, evsel); |
| 91 | return 0; | 96 | return 0; |
| 97 | error_free: | ||
| 98 | perf_evsel__delete(evsel); | ||
| 99 | error: | ||
| 100 | return -ENOMEM; | ||
| 101 | } | ||
| 102 | |||
| 103 | void perf_evlist__disable(struct perf_evlist *evlist) | ||
| 104 | { | ||
| 105 | int cpu, thread; | ||
| 106 | struct perf_evsel *pos; | ||
| 107 | |||
| 108 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | ||
| 109 | list_for_each_entry(pos, &evlist->entries, node) { | ||
| 110 | for (thread = 0; thread < evlist->threads->nr; thread++) | ||
| 111 | ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE); | ||
| 112 | } | ||
| 113 | } | ||
| 92 | } | 114 | } |
| 93 | 115 | ||
| 94 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 116 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index b2b862374f37..ce85ae9ae57a 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -53,6 +53,8 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist); | |||
| 53 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); | 53 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); |
| 54 | void perf_evlist__munmap(struct perf_evlist *evlist); | 54 | void perf_evlist__munmap(struct perf_evlist *evlist); |
| 55 | 55 | ||
| 56 | void perf_evlist__disable(struct perf_evlist *evlist); | ||
| 57 | |||
| 56 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | 58 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, |
| 57 | struct cpu_map *cpus, | 59 | struct cpu_map *cpus, |
| 58 | struct thread_map *threads) | 60 | struct thread_map *threads) |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index cb2959a3fb43..b6c1ad123ca9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -189,8 +189,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
| 189 | const char *name, bool is_kallsyms) | 189 | const char *name, bool is_kallsyms) |
| 190 | { | 190 | { |
| 191 | const size_t size = PATH_MAX; | 191 | const size_t size = PATH_MAX; |
| 192 | char *realname, *filename = malloc(size), | 192 | char *realname, *filename = zalloc(size), |
| 193 | *linkname = malloc(size), *targetname; | 193 | *linkname = zalloc(size), *targetname; |
| 194 | int len, err = -1; | 194 | int len, err = -1; |
| 195 | 195 | ||
| 196 | if (is_kallsyms) { | 196 | if (is_kallsyms) { |
| @@ -254,8 +254,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | |||
| 254 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | 254 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) |
| 255 | { | 255 | { |
| 256 | const size_t size = PATH_MAX; | 256 | const size_t size = PATH_MAX; |
| 257 | char *filename = malloc(size), | 257 | char *filename = zalloc(size), |
| 258 | *linkname = malloc(size); | 258 | *linkname = zalloc(size); |
| 259 | int err = -1; | 259 | int err = -1; |
| 260 | 260 | ||
| 261 | if (filename == NULL || linkname == NULL) | 261 | if (filename == NULL || linkname == NULL) |
| @@ -726,7 +726,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | |||
| 726 | return -1; | 726 | return -1; |
| 727 | 727 | ||
| 728 | bev.header = old_bev.header; | 728 | bev.header = old_bev.header; |
| 729 | bev.pid = 0; | 729 | |
| 730 | /* | ||
| 731 | * As the pid is the missing value, we need to fill | ||
| 732 | * it properly. The header.misc value give us nice hint. | ||
| 733 | */ | ||
| 734 | bev.pid = HOST_KERNEL_ID; | ||
| 735 | if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || | ||
| 736 | bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) | ||
| 737 | bev.pid = DEFAULT_GUEST_KERNEL_ID; | ||
| 738 | |||
| 730 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | 739 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); |
| 731 | __event_process_build_id(&bev, filename, session); | 740 | __event_process_build_id(&bev, filename, session); |
| 732 | 741 | ||
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h index 791f9dd27ebf..547628e97f3d 100644 --- a/tools/perf/util/include/linux/compiler.h +++ b/tools/perf/util/include/linux/compiler.h | |||
| @@ -5,7 +5,9 @@ | |||
| 5 | #define __always_inline inline | 5 | #define __always_inline inline |
| 6 | #endif | 6 | #endif |
| 7 | #define __user | 7 | #define __user |
| 8 | #ifndef __attribute_const__ | ||
| 8 | #define __attribute_const__ | 9 | #define __attribute_const__ |
| 10 | #endif | ||
| 9 | 11 | ||
| 10 | #define __used __attribute__((__unused__)) | 12 | #define __used __attribute__((__unused__)) |
| 11 | 13 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4ea7e19f5251..928918b796b2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -697,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr) | |||
| 697 | return EVT_FAILED; | 697 | return EVT_FAILED; |
| 698 | n = hex2u64(str + 1, &config); | 698 | n = hex2u64(str + 1, &config); |
| 699 | if (n > 0) { | 699 | if (n > 0) { |
| 700 | *strp = str + n + 1; | 700 | const char *end = str + n + 1; |
| 701 | if (*end != '\0' && *end != ',' && *end != ':') | ||
| 702 | return EVT_FAILED; | ||
| 703 | |||
| 704 | *strp = end; | ||
| 701 | attr->type = PERF_TYPE_RAW; | 705 | attr->type = PERF_TYPE_RAW; |
| 702 | attr->config = config; | 706 | attr->config = config; |
| 703 | return EVT_HANDLED; | 707 | return EVT_HANDLED; |
| @@ -1097,6 +1101,4 @@ void print_events(const char *event_glob) | |||
| 1097 | printf("\n"); | 1101 | printf("\n"); |
| 1098 | 1102 | ||
| 1099 | print_tracepoint_events(NULL, NULL); | 1103 | print_tracepoint_events(NULL, NULL); |
| 1100 | |||
| 1101 | exit(129); | ||
| 1102 | } | 1104 | } |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b82d54fa2c56..1c7bfa5fe0a8 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -1820,11 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
| 1820 | ret = -ENOMEM; | 1820 | ret = -ENOMEM; |
| 1821 | goto error; | 1821 | goto error; |
| 1822 | } | 1822 | } |
| 1823 | tev->point.module = strdup(module); | 1823 | |
| 1824 | if (tev->point.module == NULL) { | 1824 | if (module) { |
| 1825 | ret = -ENOMEM; | 1825 | tev->point.module = strdup(module); |
| 1826 | goto error; | 1826 | if (tev->point.module == NULL) { |
| 1827 | ret = -ENOMEM; | ||
| 1828 | goto error; | ||
| 1829 | } | ||
| 1827 | } | 1830 | } |
| 1831 | |||
| 1828 | tev->point.offset = pev->point.offset; | 1832 | tev->point.offset = pev->point.offset; |
| 1829 | tev->point.retprobe = pev->point.retprobe; | 1833 | tev->point.retprobe = pev->point.retprobe; |
| 1830 | tev->nargs = pev->nargs; | 1834 | tev->nargs = pev->nargs; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3e44a3e36519..555fc3864b90 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
| 612 | return ret; | 612 | return ret; |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | /* Find a variable in a subprogram die */ | 615 | /* Find a variable in a scope DIE */ |
| 616 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
| 617 | { | 617 | { |
| 618 | Dwarf_Die vr_die, *scopes; | 618 | Dwarf_Die vr_die; |
| 619 | char buf[32], *ptr; | 619 | char buf[32], *ptr; |
| 620 | int ret, nscopes; | 620 | int ret = 0; |
| 621 | 621 | ||
| 622 | if (!is_c_varname(pf->pvar->var)) { | 622 | if (!is_c_varname(pf->pvar->var)) { |
| 623 | /* Copy raw parameters */ | 623 | /* Copy raw parameters */ |
| @@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 652 | if (pf->tvar->name == NULL) | 652 | if (pf->tvar->name == NULL) |
| 653 | return -ENOMEM; | 653 | return -ENOMEM; |
| 654 | 654 | ||
| 655 | pr_debug("Searching '%s' variable in context.\n", | 655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); |
| 656 | pf->pvar->var); | ||
| 657 | /* Search child die for local variables and parameters. */ | 656 | /* Search child die for local variables and parameters. */ |
| 658 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) | 657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { |
| 659 | ret = convert_variable(&vr_die, pf); | 658 | /* Search again in global variables */ |
| 660 | else { | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
| 661 | /* Search upper class */ | 660 | ret = -ENOENT; |
| 662 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | ||
| 663 | while (nscopes-- > 1) { | ||
| 664 | pr_debug("Searching variables in %s\n", | ||
| 665 | dwarf_diename(&scopes[nscopes])); | ||
| 666 | /* We should check this scope, so give dummy address */ | ||
| 667 | if (die_find_variable_at(&scopes[nscopes], | ||
| 668 | pf->pvar->var, 0, | ||
| 669 | &vr_die)) { | ||
| 670 | ret = convert_variable(&vr_die, pf); | ||
| 671 | goto found; | ||
| 672 | } | ||
| 673 | } | ||
| 674 | if (scopes) | ||
| 675 | free(scopes); | ||
| 676 | ret = -ENOENT; | ||
| 677 | } | 661 | } |
| 678 | found: | 662 | if (ret == 0) |
| 663 | ret = convert_variable(&vr_die, pf); | ||
| 664 | |||
| 679 | if (ret < 0) | 665 | if (ret < 0) |
| 680 | pr_warning("Failed to find '%s' in this function.\n", | 666 | pr_warning("Failed to find '%s' in this function.\n", |
| 681 | pf->pvar->var); | 667 | pf->pvar->var); |
| @@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | |||
| 718 | return 0; | 704 | return 0; |
| 719 | } | 705 | } |
| 720 | 706 | ||
| 721 | /* Call probe_finder callback with real subprogram DIE */ | 707 | /* Call probe_finder callback with scope DIE */ |
| 722 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | 708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
| 723 | { | 709 | { |
| 724 | Dwarf_Die die_mem; | ||
| 725 | Dwarf_Attribute fb_attr; | 710 | Dwarf_Attribute fb_attr; |
| 726 | size_t nops; | 711 | size_t nops; |
| 727 | int ret; | 712 | int ret; |
| 728 | 713 | ||
| 729 | /* If no real subprogram, find a real one */ | 714 | if (!sc_die) { |
| 730 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 715 | pr_err("Caller must pass a scope DIE. Program error.\n"); |
| 731 | sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem); | 716 | return -EINVAL; |
| 732 | if (!sp_die) { | 717 | } |
| 718 | |||
| 719 | /* If not a real subprogram, find a real one */ | ||
| 720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | ||
| 721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | ||
| 733 | pr_warning("Failed to find probe point in any " | 722 | pr_warning("Failed to find probe point in any " |
| 734 | "functions.\n"); | 723 | "functions.\n"); |
| 735 | return -ENOENT; | 724 | return -ENOENT; |
| 736 | } | 725 | } |
| 737 | } | 726 | } else |
| 727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); | ||
| 738 | 728 | ||
| 739 | /* Get the frame base attribute/ops */ | 729 | /* Get the frame base attribute/ops from subprogram */ |
| 740 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
| 741 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
| 742 | if (ret <= 0 || nops == 0) { | 732 | if (ret <= 0 || nops == 0) { |
| 743 | pf->fb_ops = NULL; | 733 | pf->fb_ops = NULL; |
| @@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 755 | } | 745 | } |
| 756 | 746 | ||
| 757 | /* Call finder's callback handler */ | 747 | /* Call finder's callback handler */ |
| 758 | ret = pf->callback(sp_die, pf); | 748 | ret = pf->callback(sc_die, pf); |
| 759 | 749 | ||
| 760 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
| 761 | pf->fb_ops = NULL; | 751 | pf->fb_ops = NULL; |
| @@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 763 | return ret; | 753 | return ret; |
| 764 | } | 754 | } |
| 765 | 755 | ||
| 756 | struct find_scope_param { | ||
| 757 | const char *function; | ||
| 758 | const char *file; | ||
| 759 | int line; | ||
| 760 | int diff; | ||
| 761 | Dwarf_Die *die_mem; | ||
| 762 | bool found; | ||
| 763 | }; | ||
| 764 | |||
| 765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) | ||
| 766 | { | ||
| 767 | struct find_scope_param *fsp = data; | ||
| 768 | const char *file; | ||
| 769 | int lno; | ||
| 770 | |||
| 771 | /* Skip if declared file name does not match */ | ||
| 772 | if (fsp->file) { | ||
| 773 | file = dwarf_decl_file(fn_die); | ||
| 774 | if (!file || strcmp(fsp->file, file) != 0) | ||
| 775 | return 0; | ||
| 776 | } | ||
| 777 | /* If the function name is given, that's what user expects */ | ||
| 778 | if (fsp->function) { | ||
| 779 | if (die_compare_name(fn_die, fsp->function)) { | ||
| 780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
| 781 | fsp->found = true; | ||
| 782 | return 1; | ||
| 783 | } | ||
| 784 | } else { | ||
| 785 | /* With the line number, find the nearest declared DIE */ | ||
| 786 | dwarf_decl_line(fn_die, &lno); | ||
| 787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { | ||
| 788 | /* Keep a candidate and continue */ | ||
| 789 | fsp->diff = fsp->line - lno; | ||
| 790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
| 791 | fsp->found = true; | ||
| 792 | } | ||
| 793 | } | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | /* Find an appropriate scope fits to given conditions */ | ||
| 798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) | ||
| 799 | { | ||
| 800 | struct find_scope_param fsp = { | ||
| 801 | .function = pf->pev->point.function, | ||
| 802 | .file = pf->fname, | ||
| 803 | .line = pf->lno, | ||
| 804 | .diff = INT_MAX, | ||
| 805 | .die_mem = die_mem, | ||
| 806 | .found = false, | ||
| 807 | }; | ||
| 808 | |||
| 809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); | ||
| 810 | |||
| 811 | return fsp.found ? die_mem : NULL; | ||
| 812 | } | ||
| 813 | |||
| 766 | static int probe_point_line_walker(const char *fname, int lineno, | 814 | static int probe_point_line_walker(const char *fname, int lineno, |
| 767 | Dwarf_Addr addr, void *data) | 815 | Dwarf_Addr addr, void *data) |
| 768 | { | 816 | { |
| 769 | struct probe_finder *pf = data; | 817 | struct probe_finder *pf = data; |
| 818 | Dwarf_Die *sc_die, die_mem; | ||
| 770 | int ret; | 819 | int ret; |
| 771 | 820 | ||
| 772 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) | 821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
| 773 | return 0; | 822 | return 0; |
| 774 | 823 | ||
| 775 | pf->addr = addr; | 824 | pf->addr = addr; |
| 776 | ret = call_probe_finder(NULL, pf); | 825 | sc_die = find_best_scope(pf, &die_mem); |
| 826 | if (!sc_die) { | ||
| 827 | pr_warning("Failed to find scope of probe point.\n"); | ||
| 828 | return -ENOENT; | ||
| 829 | } | ||
| 830 | |||
| 831 | ret = call_probe_finder(sc_die, pf); | ||
| 777 | 832 | ||
| 778 | /* Continue if no error, because the line will be in inline function */ | 833 | /* Continue if no error, because the line will be in inline function */ |
| 779 | return ret < 0 ? ret : 0; | 834 | return ret < 0 ? ret : 0; |
| @@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
| 827 | Dwarf_Addr addr, void *data) | 882 | Dwarf_Addr addr, void *data) |
| 828 | { | 883 | { |
| 829 | struct probe_finder *pf = data; | 884 | struct probe_finder *pf = data; |
| 885 | Dwarf_Die *sc_die, die_mem; | ||
| 830 | int ret; | 886 | int ret; |
| 831 | 887 | ||
| 832 | if (!line_list__has_line(&pf->lcache, lineno) || | 888 | if (!line_list__has_line(&pf->lcache, lineno) || |
| @@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
| 836 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | 892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", |
| 837 | lineno, (unsigned long long)addr); | 893 | lineno, (unsigned long long)addr); |
| 838 | pf->addr = addr; | 894 | pf->addr = addr; |
| 839 | ret = call_probe_finder(NULL, pf); | 895 | pf->lno = lineno; |
| 896 | sc_die = find_best_scope(pf, &die_mem); | ||
| 897 | if (!sc_die) { | ||
| 898 | pr_warning("Failed to find scope of probe point.\n"); | ||
| 899 | return -ENOENT; | ||
| 900 | } | ||
| 901 | |||
| 902 | ret = call_probe_finder(sc_die, pf); | ||
| 840 | 903 | ||
| 841 | /* | 904 | /* |
| 842 | * Continue if no error, because the lazy pattern will match | 905 | * Continue if no error, because the lazy pattern will match |
| @@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 861 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
| 862 | } | 925 | } |
| 863 | 926 | ||
| 864 | /* Callback parameter with return value */ | ||
| 865 | struct dwarf_callback_param { | ||
| 866 | void *data; | ||
| 867 | int retval; | ||
| 868 | }; | ||
| 869 | |||
| 870 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
| 871 | { | 928 | { |
| 872 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
| 873 | struct probe_finder *pf = param->data; | ||
| 874 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
| 875 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
| 932 | int ret; | ||
| 876 | 933 | ||
| 877 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
| 878 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
| 879 | else { | 936 | else { |
| 880 | /* Get probe address */ | 937 | /* Get probe address */ |
| 881 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
| 882 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
| 883 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
| 884 | param->retval = -ENOENT; | 941 | return -ENOENT; |
| 885 | return DWARF_CB_ABORT; | ||
| 886 | } | 942 | } |
| 887 | pf->addr = addr; | 943 | pf->addr = addr; |
| 888 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
| 889 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
| 890 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
| 891 | 947 | ||
| 892 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
| 893 | if (param->retval < 0) | ||
| 894 | return DWARF_CB_ABORT; | ||
| 895 | } | 949 | } |
| 896 | 950 | ||
| 897 | return DWARF_CB_OK; | 951 | return ret; |
| 898 | } | 952 | } |
| 899 | 953 | ||
| 954 | /* Callback parameter with return value for libdw */ | ||
| 955 | struct dwarf_callback_param { | ||
| 956 | void *data; | ||
| 957 | int retval; | ||
| 958 | }; | ||
| 959 | |||
| 900 | /* Search function from function name */ | 960 | /* Search function from function name */ |
| 901 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
| 902 | { | 962 | { |
| @@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
| 933 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
| 934 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
| 935 | } | 995 | } |
| 936 | } else { | 996 | } else |
| 937 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
| 938 | .retval = 0}; | ||
| 939 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
| 940 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
| 941 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
| 942 | param->retval = _param.retval; | ||
| 943 | } | ||
| 944 | 1000 | ||
| 945 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
| 946 | } | 1002 | } |
| @@ -1060,7 +1116,7 @@ found: | |||
| 1060 | } | 1116 | } |
| 1061 | 1117 | ||
| 1062 | /* Add a found probe point into trace event list */ | 1118 | /* Add a found probe point into trace event list */ |
| 1063 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | 1119 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
| 1064 | { | 1120 | { |
| 1065 | struct trace_event_finder *tf = | 1121 | struct trace_event_finder *tf = |
| 1066 | container_of(pf, struct trace_event_finder, pf); | 1122 | container_of(pf, struct trace_event_finder, pf); |
| @@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 1075 | } | 1131 | } |
| 1076 | tev = &tf->tevs[tf->ntevs++]; | 1132 | tev = &tf->tevs[tf->ntevs++]; |
| 1077 | 1133 | ||
| 1078 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1134 | /* Trace point should be converted from subprogram DIE */ |
| 1079 | &tev->point); | 1135 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
| 1136 | pf->pev->point.retprobe, &tev->point); | ||
| 1080 | if (ret < 0) | 1137 | if (ret < 0) |
| 1081 | return ret; | 1138 | return ret; |
| 1082 | 1139 | ||
| @@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 1091 | for (i = 0; i < pf->pev->nargs; i++) { | 1148 | for (i = 0; i < pf->pev->nargs; i++) { |
| 1092 | pf->pvar = &pf->pev->args[i]; | 1149 | pf->pvar = &pf->pev->args[i]; |
| 1093 | pf->tvar = &tev->args[i]; | 1150 | pf->tvar = &tev->args[i]; |
| 1094 | ret = find_variable(sp_die, pf); | 1151 | /* Variable should be found from scope DIE */ |
| 1152 | ret = find_variable(sc_die, pf); | ||
| 1095 | if (ret != 0) | 1153 | if (ret != 0) |
| 1096 | return ret; | 1154 | return ret; |
| 1097 | } | 1155 | } |
| @@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
| 1159 | } | 1217 | } |
| 1160 | 1218 | ||
| 1161 | /* Add a found vars into available variables list */ | 1219 | /* Add a found vars into available variables list */ |
| 1162 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | 1220 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
| 1163 | { | 1221 | { |
| 1164 | struct available_var_finder *af = | 1222 | struct available_var_finder *af = |
| 1165 | container_of(pf, struct available_var_finder, pf); | 1223 | container_of(pf, struct available_var_finder, pf); |
| 1166 | struct variable_list *vl; | 1224 | struct variable_list *vl; |
| 1167 | Dwarf_Die die_mem, *scopes = NULL; | 1225 | Dwarf_Die die_mem; |
| 1168 | int ret, nscopes; | 1226 | int ret; |
| 1169 | 1227 | ||
| 1170 | /* Check number of tevs */ | 1228 | /* Check number of tevs */ |
| 1171 | if (af->nvls == af->max_vls) { | 1229 | if (af->nvls == af->max_vls) { |
| @@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 1174 | } | 1232 | } |
| 1175 | vl = &af->vls[af->nvls++]; | 1233 | vl = &af->vls[af->nvls++]; |
| 1176 | 1234 | ||
| 1177 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1235 | /* Trace point should be converted from subprogram DIE */ |
| 1178 | &vl->point); | 1236 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
| 1237 | pf->pev->point.retprobe, &vl->point); | ||
| 1179 | if (ret < 0) | 1238 | if (ret < 0) |
| 1180 | return ret; | 1239 | return ret; |
| 1181 | 1240 | ||
| @@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 1187 | if (vl->vars == NULL) | 1246 | if (vl->vars == NULL) |
| 1188 | return -ENOMEM; | 1247 | return -ENOMEM; |
| 1189 | af->child = true; | 1248 | af->child = true; |
| 1190 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); | 1249 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
| 1191 | 1250 | ||
| 1192 | /* Find external variables */ | 1251 | /* Find external variables */ |
| 1193 | if (!af->externs) | 1252 | if (!af->externs) |
| 1194 | goto out; | 1253 | goto out; |
| 1195 | /* Don't need to search child DIE for externs. */ | 1254 | /* Don't need to search child DIE for externs. */ |
| 1196 | af->child = false; | 1255 | af->child = false; |
| 1197 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 1256 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
| 1198 | while (nscopes-- > 1) | ||
| 1199 | die_find_child(&scopes[nscopes], collect_variables_cb, | ||
| 1200 | (void *)af, &die_mem); | ||
| 1201 | if (scopes) | ||
| 1202 | free(scopes); | ||
| 1203 | 1257 | ||
| 1204 | out: | 1258 | out: |
| 1205 | if (strlist__empty(vl->vars)) { | 1259 | if (strlist__empty(vl->vars)) { |
| @@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
| 1391 | 1445 | ||
| 1392 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
| 1393 | { | 1447 | { |
| 1394 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
| 1395 | 1449 | ||
| 1396 | param->retval = find_line_range_by_line(in_die, param->data); | 1450 | /* |
| 1397 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1451 | * We have to check all instances of inlined function, because |
| 1452 | * some execution paths can be optimized out depends on the | ||
| 1453 | * function argument of instances | ||
| 1454 | */ | ||
| 1455 | return 0; | ||
| 1398 | } | 1456 | } |
| 1399 | 1457 | ||
| 1400 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
| @@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
| 1422 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
| 1423 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
| 1424 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
| 1425 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
| 1426 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
| 1427 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
| 1428 | _param.retval = 0; | 1486 | else |
| 1429 | dwarf_func_inline_instances(sp_die, | ||
| 1430 | line_range_inline_cb, | ||
| 1431 | &_param); | ||
| 1432 | param->retval = _param.retval; | ||
| 1433 | } else | ||
| 1434 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
| 1435 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
| 1436 | } | 1489 | } |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index c478b42a2473..1132c8f0ce89 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
| @@ -57,7 +57,7 @@ struct probe_finder { | |||
| 57 | struct perf_probe_event *pev; /* Target probe event */ | 57 | struct perf_probe_event *pev; /* Target probe event */ |
| 58 | 58 | ||
| 59 | /* Callback when a probe point is found */ | 59 | /* Callback when a probe point is found */ |
| 60 | int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); | 60 | int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf); |
| 61 | 61 | ||
| 62 | /* For function searching */ | 62 | /* For function searching */ |
| 63 | int lno; /* Line number */ | 63 | int lno; /* Line number */ |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 8e0b5a39d8a7..cbc8f215d4b7 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
| @@ -187,16 +187,119 @@ static PyTypeObject pyrf_throttle_event__type = { | |||
| 187 | .tp_repr = (reprfunc)pyrf_throttle_event__repr, | 187 | .tp_repr = (reprfunc)pyrf_throttle_event__repr, |
| 188 | }; | 188 | }; |
| 189 | 189 | ||
| 190 | static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object."); | ||
| 191 | |||
| 192 | static PyMemberDef pyrf_lost_event__members[] = { | ||
| 193 | sample_members | ||
| 194 | member_def(lost_event, id, T_ULONGLONG, "event id"), | ||
| 195 | member_def(lost_event, lost, T_ULONGLONG, "number of lost events"), | ||
| 196 | { .name = NULL, }, | ||
| 197 | }; | ||
| 198 | |||
| 199 | static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent) | ||
| 200 | { | ||
| 201 | PyObject *ret; | ||
| 202 | char *s; | ||
| 203 | |||
| 204 | if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", " | ||
| 205 | "lost: %#" PRIx64 " }", | ||
| 206 | pevent->event.lost.id, pevent->event.lost.lost) < 0) { | ||
| 207 | ret = PyErr_NoMemory(); | ||
| 208 | } else { | ||
| 209 | ret = PyString_FromString(s); | ||
| 210 | free(s); | ||
| 211 | } | ||
| 212 | return ret; | ||
| 213 | } | ||
| 214 | |||
| 215 | static PyTypeObject pyrf_lost_event__type = { | ||
| 216 | PyVarObject_HEAD_INIT(NULL, 0) | ||
| 217 | .tp_name = "perf.lost_event", | ||
| 218 | .tp_basicsize = sizeof(struct pyrf_event), | ||
| 219 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
| 220 | .tp_doc = pyrf_lost_event__doc, | ||
| 221 | .tp_members = pyrf_lost_event__members, | ||
| 222 | .tp_repr = (reprfunc)pyrf_lost_event__repr, | ||
| 223 | }; | ||
| 224 | |||
| 225 | static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); | ||
| 226 | |||
| 227 | static PyMemberDef pyrf_read_event__members[] = { | ||
| 228 | sample_members | ||
| 229 | member_def(read_event, pid, T_UINT, "event pid"), | ||
| 230 | member_def(read_event, tid, T_UINT, "event tid"), | ||
| 231 | { .name = NULL, }, | ||
| 232 | }; | ||
| 233 | |||
| 234 | static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent) | ||
| 235 | { | ||
| 236 | return PyString_FromFormat("{ type: read, pid: %u, tid: %u }", | ||
| 237 | pevent->event.read.pid, | ||
| 238 | pevent->event.read.tid); | ||
| 239 | /* | ||
| 240 | * FIXME: return the array of read values, | ||
| 241 | * making this method useful ;-) | ||
| 242 | */ | ||
| 243 | } | ||
| 244 | |||
| 245 | static PyTypeObject pyrf_read_event__type = { | ||
| 246 | PyVarObject_HEAD_INIT(NULL, 0) | ||
| 247 | .tp_name = "perf.read_event", | ||
| 248 | .tp_basicsize = sizeof(struct pyrf_event), | ||
| 249 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
| 250 | .tp_doc = pyrf_read_event__doc, | ||
| 251 | .tp_members = pyrf_read_event__members, | ||
| 252 | .tp_repr = (reprfunc)pyrf_read_event__repr, | ||
| 253 | }; | ||
| 254 | |||
| 255 | static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object."); | ||
| 256 | |||
| 257 | static PyMemberDef pyrf_sample_event__members[] = { | ||
| 258 | sample_members | ||
| 259 | member_def(perf_event_header, type, T_UINT, "event type"), | ||
| 260 | { .name = NULL, }, | ||
| 261 | }; | ||
| 262 | |||
| 263 | static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) | ||
| 264 | { | ||
| 265 | PyObject *ret; | ||
| 266 | char *s; | ||
| 267 | |||
| 268 | if (asprintf(&s, "{ type: sample }") < 0) { | ||
| 269 | ret = PyErr_NoMemory(); | ||
| 270 | } else { | ||
| 271 | ret = PyString_FromString(s); | ||
| 272 | free(s); | ||
| 273 | } | ||
| 274 | return ret; | ||
| 275 | } | ||
| 276 | |||
| 277 | static PyTypeObject pyrf_sample_event__type = { | ||
| 278 | PyVarObject_HEAD_INIT(NULL, 0) | ||
| 279 | .tp_name = "perf.sample_event", | ||
| 280 | .tp_basicsize = sizeof(struct pyrf_event), | ||
| 281 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
| 282 | .tp_doc = pyrf_sample_event__doc, | ||
| 283 | .tp_members = pyrf_sample_event__members, | ||
| 284 | .tp_repr = (reprfunc)pyrf_sample_event__repr, | ||
| 285 | }; | ||
| 286 | |||
| 190 | static int pyrf_event__setup_types(void) | 287 | static int pyrf_event__setup_types(void) |
| 191 | { | 288 | { |
| 192 | int err; | 289 | int err; |
| 193 | pyrf_mmap_event__type.tp_new = | 290 | pyrf_mmap_event__type.tp_new = |
| 194 | pyrf_task_event__type.tp_new = | 291 | pyrf_task_event__type.tp_new = |
| 195 | pyrf_comm_event__type.tp_new = | 292 | pyrf_comm_event__type.tp_new = |
| 293 | pyrf_lost_event__type.tp_new = | ||
| 294 | pyrf_read_event__type.tp_new = | ||
| 295 | pyrf_sample_event__type.tp_new = | ||
| 196 | pyrf_throttle_event__type.tp_new = PyType_GenericNew; | 296 | pyrf_throttle_event__type.tp_new = PyType_GenericNew; |
| 197 | err = PyType_Ready(&pyrf_mmap_event__type); | 297 | err = PyType_Ready(&pyrf_mmap_event__type); |
| 198 | if (err < 0) | 298 | if (err < 0) |
| 199 | goto out; | 299 | goto out; |
| 300 | err = PyType_Ready(&pyrf_lost_event__type); | ||
| 301 | if (err < 0) | ||
| 302 | goto out; | ||
| 200 | err = PyType_Ready(&pyrf_task_event__type); | 303 | err = PyType_Ready(&pyrf_task_event__type); |
| 201 | if (err < 0) | 304 | if (err < 0) |
| 202 | goto out; | 305 | goto out; |
| @@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void) | |||
| 206 | err = PyType_Ready(&pyrf_throttle_event__type); | 309 | err = PyType_Ready(&pyrf_throttle_event__type); |
| 207 | if (err < 0) | 310 | if (err < 0) |
| 208 | goto out; | 311 | goto out; |
| 312 | err = PyType_Ready(&pyrf_read_event__type); | ||
| 313 | if (err < 0) | ||
| 314 | goto out; | ||
| 315 | err = PyType_Ready(&pyrf_sample_event__type); | ||
| 316 | if (err < 0) | ||
| 317 | goto out; | ||
| 209 | out: | 318 | out: |
| 210 | return err; | 319 | return err; |
| 211 | } | 320 | } |
| 212 | 321 | ||
| 213 | static PyTypeObject *pyrf_event__type[] = { | 322 | static PyTypeObject *pyrf_event__type[] = { |
| 214 | [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, | 323 | [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, |
| 215 | [PERF_RECORD_LOST] = &pyrf_mmap_event__type, | 324 | [PERF_RECORD_LOST] = &pyrf_lost_event__type, |
| 216 | [PERF_RECORD_COMM] = &pyrf_comm_event__type, | 325 | [PERF_RECORD_COMM] = &pyrf_comm_event__type, |
| 217 | [PERF_RECORD_EXIT] = &pyrf_task_event__type, | 326 | [PERF_RECORD_EXIT] = &pyrf_task_event__type, |
| 218 | [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, | 327 | [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, |
| 219 | [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, | 328 | [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, |
| 220 | [PERF_RECORD_FORK] = &pyrf_task_event__type, | 329 | [PERF_RECORD_FORK] = &pyrf_task_event__type, |
| 221 | [PERF_RECORD_READ] = &pyrf_mmap_event__type, | 330 | [PERF_RECORD_READ] = &pyrf_read_event__type, |
| 222 | [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type, | 331 | [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type, |
| 223 | }; | 332 | }; |
| 224 | 333 | ||
| 225 | static PyObject *pyrf_event__new(union perf_event *event) | 334 | static PyObject *pyrf_event__new(union perf_event *event) |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index bbc982f5dd8b..95d370074928 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
| @@ -3,9 +3,27 @@ | |||
| 3 | from distutils.core import setup, Extension | 3 | from distutils.core import setup, Extension |
| 4 | from os import getenv | 4 | from os import getenv |
| 5 | 5 | ||
| 6 | from distutils.command.build_ext import build_ext as _build_ext | ||
| 7 | from distutils.command.install_lib import install_lib as _install_lib | ||
| 8 | |||
| 9 | class build_ext(_build_ext): | ||
| 10 | def finalize_options(self): | ||
| 11 | _build_ext.finalize_options(self) | ||
| 12 | self.build_lib = build_lib | ||
| 13 | self.build_temp = build_tmp | ||
| 14 | |||
| 15 | class install_lib(_install_lib): | ||
| 16 | def finalize_options(self): | ||
| 17 | _install_lib.finalize_options(self) | ||
| 18 | self.build_dir = build_lib | ||
| 19 | |||
| 20 | |||
| 6 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] | 21 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] |
| 7 | cflags += getenv('CFLAGS', '').split() | 22 | cflags += getenv('CFLAGS', '').split() |
| 8 | 23 | ||
| 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | ||
| 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | ||
| 26 | |||
| 9 | perf = Extension('perf', | 27 | perf = Extension('perf', |
| 10 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', | 28 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', |
| 11 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', | 29 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', |
| @@ -21,4 +39,5 @@ setup(name='perf', | |||
| 21 | author_email='acme@redhat.com', | 39 | author_email='acme@redhat.com', |
| 22 | license='GPLv2', | 40 | license='GPLv2', |
| 23 | url='http://perf.wiki.kernel.org', | 41 | url='http://perf.wiki.kernel.org', |
| 24 | ext_modules=[perf]) | 42 | ext_modules=[perf], |
| 43 | cmdclass={'build_ext': build_ext, 'install_lib': install_lib}) | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index eec196329fd9..469c0264ed29 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -1504,6 +1504,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
| 1504 | dso->adjust_symbols = 0; | 1504 | dso->adjust_symbols = 0; |
| 1505 | 1505 | ||
| 1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { | 1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
| 1507 | struct stat st; | ||
| 1508 | |||
| 1509 | if (lstat(dso->name, &st) < 0) | ||
| 1510 | return -1; | ||
| 1511 | |||
| 1512 | if (st.st_uid && (st.st_uid != geteuid())) { | ||
| 1513 | pr_warning("File %s not owned by current user or root, " | ||
| 1514 | "ignoring it.\n", dso->name); | ||
| 1515 | return -1; | ||
| 1516 | } | ||
| 1517 | |||
| 1507 | ret = dso__load_perf_map(dso, map, filter); | 1518 | ret = dso__load_perf_map(dso, map, filter); |
| 1508 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : | 1519 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : |
| 1509 | SYMTAB__NOT_FOUND; | 1520 | SYMTAB__NOT_FOUND; |
| @@ -2170,27 +2181,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | |||
| 2170 | return ret; | 2181 | return ret; |
| 2171 | } | 2182 | } |
| 2172 | 2183 | ||
| 2173 | struct dso *dso__new_kernel(const char *name) | 2184 | static struct dso* |
| 2185 | dso__kernel_findnew(struct machine *machine, const char *name, | ||
| 2186 | const char *short_name, int dso_type) | ||
| 2174 | { | 2187 | { |
| 2175 | struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); | 2188 | /* |
| 2176 | 2189 | * The kernel dso could be created by build_id processing. | |
| 2177 | if (dso != NULL) { | 2190 | */ |
| 2178 | dso__set_short_name(dso, "[kernel]"); | 2191 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); |
| 2179 | dso->kernel = DSO_TYPE_KERNEL; | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | return dso; | ||
| 2183 | } | ||
| 2184 | 2192 | ||
| 2185 | static struct dso *dso__new_guest_kernel(struct machine *machine, | 2193 | /* |
| 2186 | const char *name) | 2194 | * We need to run this in all cases, since during the build_id |
| 2187 | { | 2195 | * processing we had no idea this was the kernel dso. |
| 2188 | char bf[PATH_MAX]; | 2196 | */ |
| 2189 | struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, | ||
| 2190 | sizeof(bf))); | ||
| 2191 | if (dso != NULL) { | 2197 | if (dso != NULL) { |
| 2192 | dso__set_short_name(dso, "[guest.kernel]"); | 2198 | dso__set_short_name(dso, short_name); |
| 2193 | dso->kernel = DSO_TYPE_GUEST_KERNEL; | 2199 | dso->kernel = dso_type; |
| 2194 | } | 2200 | } |
| 2195 | 2201 | ||
| 2196 | return dso; | 2202 | return dso; |
| @@ -2208,24 +2214,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | |||
| 2208 | dso->has_build_id = true; | 2214 | dso->has_build_id = true; |
| 2209 | } | 2215 | } |
| 2210 | 2216 | ||
| 2211 | static struct dso *machine__create_kernel(struct machine *machine) | 2217 | static struct dso *machine__get_kernel(struct machine *machine) |
| 2212 | { | 2218 | { |
| 2213 | const char *vmlinux_name = NULL; | 2219 | const char *vmlinux_name = NULL; |
| 2214 | struct dso *kernel; | 2220 | struct dso *kernel; |
| 2215 | 2221 | ||
| 2216 | if (machine__is_host(machine)) { | 2222 | if (machine__is_host(machine)) { |
| 2217 | vmlinux_name = symbol_conf.vmlinux_name; | 2223 | vmlinux_name = symbol_conf.vmlinux_name; |
| 2218 | kernel = dso__new_kernel(vmlinux_name); | 2224 | if (!vmlinux_name) |
| 2225 | vmlinux_name = "[kernel.kallsyms]"; | ||
| 2226 | |||
| 2227 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
| 2228 | "[kernel]", | ||
| 2229 | DSO_TYPE_KERNEL); | ||
| 2219 | } else { | 2230 | } else { |
| 2231 | char bf[PATH_MAX]; | ||
| 2232 | |||
| 2220 | if (machine__is_default_guest(machine)) | 2233 | if (machine__is_default_guest(machine)) |
| 2221 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | 2234 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; |
| 2222 | kernel = dso__new_guest_kernel(machine, vmlinux_name); | 2235 | if (!vmlinux_name) |
| 2236 | vmlinux_name = machine__mmap_name(machine, bf, | ||
| 2237 | sizeof(bf)); | ||
| 2238 | |||
| 2239 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
| 2240 | "[guest.kernel]", | ||
| 2241 | DSO_TYPE_GUEST_KERNEL); | ||
| 2223 | } | 2242 | } |
| 2224 | 2243 | ||
| 2225 | if (kernel != NULL) { | 2244 | if (kernel != NULL && (!kernel->has_build_id)) |
| 2226 | dso__read_running_kernel_build_id(kernel, machine); | 2245 | dso__read_running_kernel_build_id(kernel, machine); |
| 2227 | dsos__add(&machine->kernel_dsos, kernel); | 2246 | |
| 2228 | } | ||
| 2229 | return kernel; | 2247 | return kernel; |
| 2230 | } | 2248 | } |
| 2231 | 2249 | ||
| @@ -2329,7 +2347,7 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
| 2329 | 2347 | ||
| 2330 | int machine__create_kernel_maps(struct machine *machine) | 2348 | int machine__create_kernel_maps(struct machine *machine) |
| 2331 | { | 2349 | { |
| 2332 | struct dso *kernel = machine__create_kernel(machine); | 2350 | struct dso *kernel = machine__get_kernel(machine); |
| 2333 | 2351 | ||
| 2334 | if (kernel == NULL || | 2352 | if (kernel == NULL || |
| 2335 | __machine__create_kernel_maps(machine, kernel) < 0) | 2353 | __machine__create_kernel_maps(machine, kernel) < 0) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 325ee36a9d29..4f377d92e75a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -155,7 +155,6 @@ struct dso { | |||
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | struct dso *dso__new(const char *name); | 157 | struct dso *dso__new(const char *name); |
| 158 | struct dso *dso__new_kernel(const char *name); | ||
| 159 | void dso__delete(struct dso *dso); | 158 | void dso__delete(struct dso *dso); |
| 160 | 159 | ||
| 161 | int dso__name_len(const struct dso *dso); | 160 | int dso__name_len(const struct dso *dso); |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c index 5a06538532af..88403cf8396a 100644 --- a/tools/perf/util/ui/browsers/top.c +++ b/tools/perf/util/ui/browsers/top.c | |||
| @@ -208,6 +208,5 @@ int perf_top__tui_browser(struct perf_top *top) | |||
| 208 | }, | 208 | }, |
| 209 | }; | 209 | }; |
| 210 | 210 | ||
| 211 | ui_helpline__push("Press <- or ESC to exit"); | ||
| 212 | return perf_top_browser__run(&browser); | 211 | return perf_top_browser__run(&browser); |
| 213 | } | 212 | } |
