diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-04-19 01:55:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-04-19 01:56:17 -0400 |
commit | 68d2cf25d39324c54b5e42de7915c623a0917abe (patch) | |
tree | ff1291450d7e6630bc77ec1363c3db8d74fa58b0 /tools/perf | |
parent | 176fcc5c5f0131504a55e1e1d35389c49a9177c2 (diff) | |
parent | 5d2cd90922c778908bd0cd669e572a5b5eafd737 (diff) |
Merge branch 'perf/urgent' into perf/core
Merge reason: we'll be queueing up dependent changes.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile | 8 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 13 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 7 | ||||
-rw-r--r-- | tools/perf/builtin-test.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 3 | ||||
-rw-r--r-- | tools/perf/util/cgroup.c | 2 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 14 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 27 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 6 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 19 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 159 | ||||
-rw-r--r-- | tools/perf/util/python.c | 9 | ||||
-rw-r--r-- | tools/perf/util/setup.py | 7 | ||||
-rw-r--r-- | tools/perf/util/string.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 2 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 6 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 2 |
17 files changed, 180 insertions, 116 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 158c30e8210c..207dee5c5b16 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -165,8 +165,12 @@ grep-libs = $(filter -l%,$(1)) | |||
165 | strip-libs = $(filter-out -l%,$(1)) | 165 | strip-libs = $(filter-out -l%,$(1)) |
166 | 166 | ||
167 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) | 167 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) |
168 | $(QUIET_GEN)python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \ | 168 | $(QUIET_GEN)( \ |
169 | --build-temp='$(OUTPUT)python/temp' | 169 | export CFLAGS="$(BASIC_CFLAGS)"; \ |
170 | python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \ | ||
171 | --build-temp='$(OUTPUT)python/temp' \ | ||
172 | ) | ||
173 | |||
170 | # | 174 | # |
171 | # No Perl scripts right now: | 175 | # No Perl scripts right now: |
172 | # | 176 | # |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index db6adecf46f1..416538248a4b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -41,7 +41,7 @@ static u64 user_interval = ULLONG_MAX; | |||
41 | static u64 default_interval = 0; | 41 | static u64 default_interval = 0; |
42 | 42 | ||
43 | static unsigned int page_size; | 43 | static unsigned int page_size; |
44 | static unsigned int mmap_pages = 128; | 44 | static unsigned int mmap_pages = UINT_MAX; |
45 | static unsigned int user_freq = UINT_MAX; | 45 | static unsigned int user_freq = UINT_MAX; |
46 | static int freq = 1000; | 46 | static int freq = 1000; |
47 | static int output; | 47 | static int output; |
@@ -163,6 +163,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) | |||
163 | struct perf_event_attr *attr = &evsel->attr; | 163 | struct perf_event_attr *attr = &evsel->attr; |
164 | int track = !evsel->idx; /* only the first counter needs these */ | 164 | int track = !evsel->idx; /* only the first counter needs these */ |
165 | 165 | ||
166 | attr->inherit = !no_inherit; | ||
166 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 167 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
167 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 168 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
168 | PERF_FORMAT_ID; | 169 | PERF_FORMAT_ID; |
@@ -251,6 +252,9 @@ static void open_counters(struct perf_evlist *evlist) | |||
251 | { | 252 | { |
252 | struct perf_evsel *pos; | 253 | struct perf_evsel *pos; |
253 | 254 | ||
255 | if (evlist->cpus->map[0] < 0) | ||
256 | no_inherit = true; | ||
257 | |||
254 | list_for_each_entry(pos, &evlist->entries, node) { | 258 | list_for_each_entry(pos, &evlist->entries, node) { |
255 | struct perf_event_attr *attr = &pos->attr; | 259 | struct perf_event_attr *attr = &pos->attr; |
256 | /* | 260 | /* |
@@ -271,8 +275,7 @@ static void open_counters(struct perf_evlist *evlist) | |||
271 | retry_sample_id: | 275 | retry_sample_id: |
272 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | 276 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; |
273 | try_again: | 277 | try_again: |
274 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, | 278 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { |
275 | !no_inherit) < 0) { | ||
276 | int err = errno; | 279 | int err = errno; |
277 | 280 | ||
278 | if (err == EPERM || err == EACCES) { | 281 | if (err == EPERM || err == EACCES) { |
@@ -513,6 +516,10 @@ static int __cmd_record(int argc, const char **argv) | |||
513 | if (have_tracepoints(&evsel_list->entries)) | 516 | if (have_tracepoints(&evsel_list->entries)) |
514 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); | 517 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); |
515 | 518 | ||
519 | /* 512 kiB: default amount of unprivileged mlocked memory */ | ||
520 | if (mmap_pages == UINT_MAX) | ||
521 | mmap_pages = (512 * 1024) / page_size; | ||
522 | |||
516 | if (forks) { | 523 | if (forks) { |
517 | child_pid = fork(); | 524 | child_pid = fork(); |
518 | if (child_pid < 0) { | 525 | if (child_pid < 0) { |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e2109f9b43eb..03f0e45f1479 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -167,16 +167,17 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
167 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 167 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
168 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 168 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
169 | 169 | ||
170 | attr->inherit = !no_inherit; | ||
171 | |||
170 | if (system_wide) | 172 | if (system_wide) |
171 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false); | 173 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); |
172 | 174 | ||
173 | attr->inherit = !no_inherit; | ||
174 | if (target_pid == -1 && target_tid == -1) { | 175 | if (target_pid == -1 && target_tid == -1) { |
175 | attr->disabled = 1; | 176 | attr->disabled = 1; |
176 | attr->enable_on_exec = 1; | 177 | attr->enable_on_exec = 1; |
177 | } | 178 | } |
178 | 179 | ||
179 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false); | 180 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); |
180 | } | 181 | } |
181 | 182 | ||
182 | /* | 183 | /* |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 1b2106c58f66..11e3c8458362 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -290,7 +290,7 @@ static int test__open_syscall_event(void) | |||
290 | goto out_thread_map_delete; | 290 | goto out_thread_map_delete; |
291 | } | 291 | } |
292 | 292 | ||
293 | if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) { | 293 | if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { |
294 | pr_debug("failed to open counter: %s, " | 294 | pr_debug("failed to open counter: %s, " |
295 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 295 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
296 | strerror(errno)); | 296 | strerror(errno)); |
@@ -303,7 +303,7 @@ static int test__open_syscall_event(void) | |||
303 | } | 303 | } |
304 | 304 | ||
305 | if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) { | 305 | if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) { |
306 | pr_debug("perf_evsel__open_read_on_cpu\n"); | 306 | pr_debug("perf_evsel__read_on_cpu\n"); |
307 | goto out_close_fd; | 307 | goto out_close_fd; |
308 | } | 308 | } |
309 | 309 | ||
@@ -365,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void) | |||
365 | goto out_thread_map_delete; | 365 | goto out_thread_map_delete; |
366 | } | 366 | } |
367 | 367 | ||
368 | if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) { | 368 | if (perf_evsel__open(evsel, cpus, threads, false) < 0) { |
369 | pr_debug("failed to open counter: %s, " | 369 | pr_debug("failed to open counter: %s, " |
370 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 370 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
371 | strerror(errno)); | 371 | strerror(errno)); |
@@ -418,7 +418,7 @@ static int test__open_syscall_event_on_all_cpus(void) | |||
418 | continue; | 418 | continue; |
419 | 419 | ||
420 | if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { | 420 | if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { |
421 | pr_debug("perf_evsel__open_read_on_cpu\n"); | 421 | pr_debug("perf_evsel__read_on_cpu\n"); |
422 | err = -1; | 422 | err = -1; |
423 | break; | 423 | break; |
424 | } | 424 | } |
@@ -529,7 +529,7 @@ static int test__basic_mmap(void) | |||
529 | 529 | ||
530 | perf_evlist__add(evlist, evsels[i]); | 530 | perf_evlist__add(evlist, evsels[i]); |
531 | 531 | ||
532 | if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) { | 532 | if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { |
533 | pr_debug("failed to open counter: %s, " | 533 | pr_debug("failed to open counter: %s, " |
534 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 534 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
535 | strerror(errno)); | 535 | strerror(errno)); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fc1273e976c5..7e3d6e310bf8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -845,9 +845,10 @@ static void start_counters(struct perf_evlist *evlist) | |||
845 | } | 845 | } |
846 | 846 | ||
847 | attr->mmap = 1; | 847 | attr->mmap = 1; |
848 | attr->inherit = inherit; | ||
848 | try_again: | 849 | try_again: |
849 | if (perf_evsel__open(counter, top.evlist->cpus, | 850 | if (perf_evsel__open(counter, top.evlist->cpus, |
850 | top.evlist->threads, group, inherit) < 0) { | 851 | top.evlist->threads, group) < 0) { |
851 | int err = errno; | 852 | int err = errno; |
852 | 853 | ||
853 | if (err == EPERM || err == EACCES) { | 854 | if (err == EPERM || err == EACCES) { |
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 9fea75535221..96bee5c46008 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c | |||
@@ -13,7 +13,7 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen) | |||
13 | { | 13 | { |
14 | FILE *fp; | 14 | FILE *fp; |
15 | char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; | 15 | char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; |
16 | char *token, *saved_ptr; | 16 | char *token, *saved_ptr = NULL; |
17 | int found = 0; | 17 | int found = 0; |
18 | 18 | ||
19 | fp = fopen("/proc/mounts", "r"); | 19 | fp = fopen("/proc/mounts", "r"); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d852cefa20de..45da8d186b49 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "evlist.h" | 12 | #include "evlist.h" |
13 | #include "evsel.h" | 13 | #include "evsel.h" |
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "debug.h" | ||
15 | 16 | ||
16 | #include <sys/mman.h> | 17 | #include <sys/mman.h> |
17 | 18 | ||
@@ -250,15 +251,19 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | |||
250 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 251 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
251 | } | 252 | } |
252 | 253 | ||
253 | static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot, | 254 | static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel, |
254 | int mask, int fd) | 255 | int cpu, int prot, int mask, int fd) |
255 | { | 256 | { |
256 | evlist->mmap[cpu].prev = 0; | 257 | evlist->mmap[cpu].prev = 0; |
257 | evlist->mmap[cpu].mask = mask; | 258 | evlist->mmap[cpu].mask = mask; |
258 | evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot, | 259 | evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot, |
259 | MAP_SHARED, fd, 0); | 260 | MAP_SHARED, fd, 0); |
260 | if (evlist->mmap[cpu].base == MAP_FAILED) | 261 | if (evlist->mmap[cpu].base == MAP_FAILED) { |
262 | if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit) | ||
263 | ui__warning("Inherit is not allowed on per-task " | ||
264 | "events using mmap.\n"); | ||
261 | return -1; | 265 | return -1; |
266 | } | ||
262 | 267 | ||
263 | perf_evlist__add_pollfd(evlist, fd); | 268 | perf_evlist__add_pollfd(evlist, fd); |
264 | return 0; | 269 | return 0; |
@@ -312,7 +317,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) | |||
312 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, | 317 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, |
313 | FD(first_evsel, cpu, 0)) != 0) | 318 | FD(first_evsel, cpu, 0)) != 0) |
314 | goto out_unmap; | 319 | goto out_unmap; |
315 | } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0) | 320 | } else if (__perf_evlist__mmap(evlist, evsel, cpu, |
321 | prot, mask, fd) < 0) | ||
316 | goto out_unmap; | 322 | goto out_unmap; |
317 | 323 | ||
318 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 324 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 662596afd7f1..d6fd59beb860 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -175,7 +175,7 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
175 | } | 175 | } |
176 | 176 | ||
177 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 177 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
178 | struct thread_map *threads, bool group, bool inherit) | 178 | struct thread_map *threads, bool group) |
179 | { | 179 | { |
180 | int cpu, thread; | 180 | int cpu, thread; |
181 | unsigned long flags = 0; | 181 | unsigned long flags = 0; |
@@ -192,19 +192,6 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
192 | 192 | ||
193 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 193 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
194 | int group_fd = -1; | 194 | int group_fd = -1; |
195 | /* | ||
196 | * Don't allow mmap() of inherited per-task counters. This | ||
197 | * would create a performance issue due to all children writing | ||
198 | * to the same buffer. | ||
199 | * | ||
200 | * FIXME: | ||
201 | * Proper fix is not to pass 'inherit' to perf_evsel__open*, | ||
202 | * but a 'flags' parameter, with 'group' folded there as well, | ||
203 | * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if | ||
204 | * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is | ||
205 | * set. Lets go for the minimal fix first tho. | ||
206 | */ | ||
207 | evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit; | ||
208 | 195 | ||
209 | for (thread = 0; thread < threads->nr; thread++) { | 196 | for (thread = 0; thread < threads->nr; thread++) { |
210 | 197 | ||
@@ -253,7 +240,7 @@ static struct { | |||
253 | }; | 240 | }; |
254 | 241 | ||
255 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 242 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
256 | struct thread_map *threads, bool group, bool inherit) | 243 | struct thread_map *threads, bool group) |
257 | { | 244 | { |
258 | if (cpus == NULL) { | 245 | if (cpus == NULL) { |
259 | /* Work around old compiler warnings about strict aliasing */ | 246 | /* Work around old compiler warnings about strict aliasing */ |
@@ -263,19 +250,19 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
263 | if (threads == NULL) | 250 | if (threads == NULL) |
264 | threads = &empty_thread_map.map; | 251 | threads = &empty_thread_map.map; |
265 | 252 | ||
266 | return __perf_evsel__open(evsel, cpus, threads, group, inherit); | 253 | return __perf_evsel__open(evsel, cpus, threads, group); |
267 | } | 254 | } |
268 | 255 | ||
269 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 256 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
270 | struct cpu_map *cpus, bool group, bool inherit) | 257 | struct cpu_map *cpus, bool group) |
271 | { | 258 | { |
272 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit); | 259 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); |
273 | } | 260 | } |
274 | 261 | ||
275 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 262 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
276 | struct thread_map *threads, bool group, bool inherit) | 263 | struct thread_map *threads, bool group) |
277 | { | 264 | { |
278 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); | 265 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); |
279 | } | 266 | } |
280 | 267 | ||
281 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | 268 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6710ab538342..f79bb2c09a6c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -81,11 +81,11 @@ void perf_evsel__free_id(struct perf_evsel *evsel); | |||
81 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 81 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
82 | 82 | ||
83 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 83 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
84 | struct cpu_map *cpus, bool group, bool inherit); | 84 | struct cpu_map *cpus, bool group); |
85 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 85 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
86 | struct thread_map *threads, bool group, bool inherit); | 86 | struct thread_map *threads, bool group); |
87 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 87 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
88 | struct thread_map *threads, bool group, bool inherit); | 88 | struct thread_map *threads, bool group); |
89 | 89 | ||
90 | #define perf_evsel__match(evsel, t, c) \ | 90 | #define perf_evsel__match(evsel, t, c) \ |
91 | (evsel->attr.type == PERF_TYPE_##t && \ | 91 | (evsel->attr.type == PERF_TYPE_##t && \ |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5ddee66020a7..f0223166e761 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -234,7 +234,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
234 | 234 | ||
235 | /* Searching trace events corresponding to probe event */ | 235 | /* Searching trace events corresponding to probe event */ |
236 | ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); | 236 | ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); |
237 | close(fd); | ||
238 | 237 | ||
239 | if (ntevs > 0) { /* Succeeded to find trace events */ | 238 | if (ntevs > 0) { /* Succeeded to find trace events */ |
240 | pr_debug("find %d probe_trace_events.\n", ntevs); | 239 | pr_debug("find %d probe_trace_events.\n", ntevs); |
@@ -388,7 +387,6 @@ int show_line_range(struct line_range *lr, const char *module) | |||
388 | } | 387 | } |
389 | 388 | ||
390 | ret = find_line_range(fd, lr); | 389 | ret = find_line_range(fd, lr); |
391 | close(fd); | ||
392 | if (ret == 0) { | 390 | if (ret == 0) { |
393 | pr_warning("Specified source line is not found.\n"); | 391 | pr_warning("Specified source line is not found.\n"); |
394 | return -ENOENT; | 392 | return -ENOENT; |
@@ -512,19 +510,18 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
512 | if (ret < 0) | 510 | if (ret < 0) |
513 | return ret; | 511 | return ret; |
514 | 512 | ||
515 | fd = open_vmlinux(module); | ||
516 | if (fd < 0) { | ||
517 | pr_warning("Failed to open debug information file.\n"); | ||
518 | return fd; | ||
519 | } | ||
520 | |||
521 | setup_pager(); | 513 | setup_pager(); |
522 | 514 | ||
523 | for (i = 0; i < npevs && ret >= 0; i++) | 515 | for (i = 0; i < npevs && ret >= 0; i++) { |
516 | fd = open_vmlinux(module); | ||
517 | if (fd < 0) { | ||
518 | pr_warning("Failed to open debug information file.\n"); | ||
519 | ret = fd; | ||
520 | break; | ||
521 | } | ||
524 | ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, | 522 | ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, |
525 | externs); | 523 | externs); |
526 | 524 | } | |
527 | close(fd); | ||
528 | return ret; | 525 | return ret; |
529 | } | 526 | } |
530 | 527 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ff416b85f7e8..a7c7145a8d4f 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -273,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die) | |||
273 | return dwarf_formstring(&attr); | 273 | return dwarf_formstring(&attr); |
274 | } | 274 | } |
275 | 275 | ||
276 | /* Get a line number and file name for given address */ | ||
277 | static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | ||
278 | const char **fname, int *lineno) | ||
279 | { | ||
280 | Dwarf_Line *line; | ||
281 | Dwarf_Addr laddr; | ||
282 | |||
283 | line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr); | ||
284 | if (line && dwarf_lineaddr(line, &laddr) == 0 && | ||
285 | addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) { | ||
286 | *fname = dwarf_linesrc(line, NULL, NULL); | ||
287 | if (!*fname) | ||
288 | /* line number is useless without filename */ | ||
289 | *lineno = 0; | ||
290 | } | ||
291 | |||
292 | return *lineno ?: -ENOENT; | ||
293 | } | ||
294 | |||
276 | /* Compare diename and tname */ | 295 | /* Compare diename and tname */ |
277 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 296 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) |
278 | { | 297 | { |
@@ -497,7 +516,20 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | |||
497 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 516 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
498 | Dwarf_Die *die_mem) | 517 | Dwarf_Die *die_mem) |
499 | { | 518 | { |
500 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | 519 | Dwarf_Die tmp_die; |
520 | |||
521 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); | ||
522 | if (!sp_die) | ||
523 | return NULL; | ||
524 | |||
525 | /* Inlined function could be recursive. Trace it until fail */ | ||
526 | while (sp_die) { | ||
527 | memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); | ||
528 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, | ||
529 | &tmp_die); | ||
530 | } | ||
531 | |||
532 | return die_mem; | ||
501 | } | 533 | } |
502 | 534 | ||
503 | /* Walker on lines (Note: line number will not be sorted) */ | 535 | /* Walker on lines (Note: line number will not be sorted) */ |
@@ -1395,6 +1427,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
1395 | !die_compare_name(sp_die, pp->function)) | 1427 | !die_compare_name(sp_die, pp->function)) |
1396 | return DWARF_CB_OK; | 1428 | return DWARF_CB_OK; |
1397 | 1429 | ||
1430 | /* Check declared file */ | ||
1431 | if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) | ||
1432 | return DWARF_CB_OK; | ||
1433 | |||
1398 | pf->fname = dwarf_decl_file(sp_die); | 1434 | pf->fname = dwarf_decl_file(sp_die); |
1399 | if (pp->line) { /* Function relative line */ | 1435 | if (pp->line) { /* Function relative line */ |
1400 | dwarf_decl_line(sp_die, &pf->lno); | 1436 | dwarf_decl_line(sp_die, &pf->lno); |
@@ -1483,6 +1519,7 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1483 | if (!dbg) { | 1519 | if (!dbg) { |
1484 | pr_warning("No debug information found in the vmlinux - " | 1520 | pr_warning("No debug information found in the vmlinux - " |
1485 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1521 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
1522 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
1486 | return -EBADF; | 1523 | return -EBADF; |
1487 | } | 1524 | } |
1488 | 1525 | ||
@@ -1741,11 +1778,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1741 | Dwarf_Die cudie, spdie, indie; | 1778 | Dwarf_Die cudie, spdie, indie; |
1742 | Dwarf *dbg = NULL; | 1779 | Dwarf *dbg = NULL; |
1743 | Dwfl *dwfl = NULL; | 1780 | Dwfl *dwfl = NULL; |
1744 | Dwarf_Line *line; | 1781 | Dwarf_Addr _addr, baseaddr, bias = 0; |
1745 | Dwarf_Addr laddr, eaddr, bias = 0; | 1782 | const char *fname = NULL, *func = NULL, *tmp; |
1746 | const char *tmp; | 1783 | int baseline = 0, lineno = 0, ret = 0; |
1747 | int lineno, ret = 0; | ||
1748 | bool found = false; | ||
1749 | 1784 | ||
1750 | /* Open the live linux kernel */ | 1785 | /* Open the live linux kernel */ |
1751 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); | 1786 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); |
@@ -1766,68 +1801,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1766 | goto end; | 1801 | goto end; |
1767 | } | 1802 | } |
1768 | 1803 | ||
1769 | /* Find a corresponding line */ | 1804 | /* Find a corresponding line (filename and lineno) */ |
1770 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | 1805 | cu_find_lineinfo(&cudie, addr, &fname, &lineno); |
1771 | if (line) { | 1806 | /* Don't care whether it failed or not */ |
1772 | if (dwarf_lineaddr(line, &laddr) == 0 && | ||
1773 | (Dwarf_Addr)addr == laddr && | ||
1774 | dwarf_lineno(line, &lineno) == 0) { | ||
1775 | tmp = dwarf_linesrc(line, NULL, NULL); | ||
1776 | if (tmp) { | ||
1777 | ppt->line = lineno; | ||
1778 | ppt->file = strdup(tmp); | ||
1779 | if (ppt->file == NULL) { | ||
1780 | ret = -ENOMEM; | ||
1781 | goto end; | ||
1782 | } | ||
1783 | found = true; | ||
1784 | } | ||
1785 | } | ||
1786 | } | ||
1787 | 1807 | ||
1788 | /* Find a corresponding function */ | 1808 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1789 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1809 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1810 | /* Get function entry information */ | ||
1790 | tmp = dwarf_diename(&spdie); | 1811 | tmp = dwarf_diename(&spdie); |
1791 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) | 1812 | if (!tmp || |
1792 | goto end; | 1813 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
1793 | 1814 | dwarf_decl_line(&spdie, &baseline) != 0) | |
1794 | if (ppt->line) { | 1815 | goto post; |
1795 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1816 | func = tmp; |
1796 | &indie)) { | 1817 | |
1797 | /* addr in an inline function */ | 1818 | if (addr == (unsigned long)baseaddr) |
1819 | /* Function entry - Relative line number is 0 */ | ||
1820 | lineno = baseline; | ||
1821 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | ||
1822 | &indie)) { | ||
1823 | if (dwarf_entrypc(&indie, &_addr) == 0 && | ||
1824 | _addr == addr) | ||
1825 | /* | ||
1826 | * addr is at an inline function entry. | ||
1827 | * In this case, lineno should be the call-site | ||
1828 | * line number. | ||
1829 | */ | ||
1830 | lineno = die_get_call_lineno(&indie); | ||
1831 | else { | ||
1832 | /* | ||
1833 | * addr is in an inline function body. | ||
1834 | * Since lineno points one of the lines | ||
1835 | * of the inline function, baseline should | ||
1836 | * be the entry line of the inline function. | ||
1837 | */ | ||
1798 | tmp = dwarf_diename(&indie); | 1838 | tmp = dwarf_diename(&indie); |
1799 | if (!tmp) | 1839 | if (tmp && |
1800 | goto end; | 1840 | dwarf_decl_line(&spdie, &baseline) == 0) |
1801 | ret = dwarf_decl_line(&indie, &lineno); | 1841 | func = tmp; |
1802 | } else { | ||
1803 | if (eaddr == addr) { /* Function entry */ | ||
1804 | lineno = ppt->line; | ||
1805 | ret = 0; | ||
1806 | } else | ||
1807 | ret = dwarf_decl_line(&spdie, &lineno); | ||
1808 | } | ||
1809 | if (ret == 0) { | ||
1810 | /* Make a relative line number */ | ||
1811 | ppt->line -= lineno; | ||
1812 | goto found; | ||
1813 | } | 1842 | } |
1814 | } | 1843 | } |
1815 | /* We don't have a line number, let's use offset */ | 1844 | } |
1816 | ppt->offset = addr - (unsigned long)eaddr; | 1845 | |
1817 | found: | 1846 | post: |
1818 | ppt->function = strdup(tmp); | 1847 | /* Make a relative line number or an offset */ |
1848 | if (lineno) | ||
1849 | ppt->line = lineno - baseline; | ||
1850 | else if (func) | ||
1851 | ppt->offset = addr - (unsigned long)baseaddr; | ||
1852 | |||
1853 | /* Duplicate strings */ | ||
1854 | if (func) { | ||
1855 | ppt->function = strdup(func); | ||
1819 | if (ppt->function == NULL) { | 1856 | if (ppt->function == NULL) { |
1820 | ret = -ENOMEM; | 1857 | ret = -ENOMEM; |
1821 | goto end; | 1858 | goto end; |
1822 | } | 1859 | } |
1823 | found = true; | ||
1824 | } | 1860 | } |
1825 | 1861 | if (fname) { | |
1862 | ppt->file = strdup(fname); | ||
1863 | if (ppt->file == NULL) { | ||
1864 | if (ppt->function) { | ||
1865 | free(ppt->function); | ||
1866 | ppt->function = NULL; | ||
1867 | } | ||
1868 | ret = -ENOMEM; | ||
1869 | goto end; | ||
1870 | } | ||
1871 | } | ||
1826 | end: | 1872 | end: |
1827 | if (dwfl) | 1873 | if (dwfl) |
1828 | dwfl_end(dwfl); | 1874 | dwfl_end(dwfl); |
1829 | if (ret >= 0) | 1875 | if (ret == 0 && (fname || func)) |
1830 | ret = found ? 1 : 0; | 1876 | ret = 1; /* Found a point */ |
1831 | return ret; | 1877 | return ret; |
1832 | } | 1878 | } |
1833 | 1879 | ||
@@ -1895,6 +1941,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1895 | struct line_finder *lf = param->data; | 1941 | struct line_finder *lf = param->data; |
1896 | struct line_range *lr = lf->lr; | 1942 | struct line_range *lr = lf->lr; |
1897 | 1943 | ||
1944 | /* Check declared file */ | ||
1945 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) | ||
1946 | return DWARF_CB_OK; | ||
1947 | |||
1898 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1948 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1899 | die_compare_name(sp_die, lr->function)) { | 1949 | die_compare_name(sp_die, lr->function)) { |
1900 | lf->fname = dwarf_decl_file(sp_die); | 1950 | lf->fname = dwarf_decl_file(sp_die); |
@@ -1947,6 +1997,7 @@ int find_line_range(int fd, struct line_range *lr) | |||
1947 | if (!dbg) { | 1997 | if (!dbg) { |
1948 | pr_warning("No debug information found in the vmlinux - " | 1998 | pr_warning("No debug information found in the vmlinux - " |
1949 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 1999 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
2000 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
1950 | return -EBADF; | 2001 | return -EBADF; |
1951 | } | 2002 | } |
1952 | 2003 | ||
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index a9f2d7e1204d..f5e38451fdc5 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -498,11 +498,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, | |||
498 | struct cpu_map *cpus = NULL; | 498 | struct cpu_map *cpus = NULL; |
499 | struct thread_map *threads = NULL; | 499 | struct thread_map *threads = NULL; |
500 | PyObject *pcpus = NULL, *pthreads = NULL; | 500 | PyObject *pcpus = NULL, *pthreads = NULL; |
501 | int group = 0, overwrite = 0; | 501 | int group = 0, inherit = 0; |
502 | static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL}; | 502 | static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL}; |
503 | 503 | ||
504 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, | 504 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, |
505 | &pcpus, &pthreads, &group, &overwrite)) | 505 | &pcpus, &pthreads, &group, &inherit)) |
506 | return NULL; | 506 | return NULL; |
507 | 507 | ||
508 | if (pthreads != NULL) | 508 | if (pthreads != NULL) |
@@ -511,7 +511,8 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, | |||
511 | if (pcpus != NULL) | 511 | if (pcpus != NULL) |
512 | cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; | 512 | cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; |
513 | 513 | ||
514 | if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) { | 514 | evsel->attr.inherit = inherit; |
515 | if (perf_evsel__open(evsel, cpus, threads, group) < 0) { | ||
515 | PyErr_SetFromErrno(PyExc_OSError); | 516 | PyErr_SetFromErrno(PyExc_OSError); |
516 | return NULL; | 517 | return NULL; |
517 | } | 518 | } |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index e24ffadb20b2..bbc982f5dd8b 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -1,13 +1,18 @@ | |||
1 | #!/usr/bin/python2 | 1 | #!/usr/bin/python2 |
2 | 2 | ||
3 | from distutils.core import setup, Extension | 3 | from distutils.core import setup, Extension |
4 | from os import getenv | ||
5 | |||
6 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] | ||
7 | cflags += getenv('CFLAGS', '').split() | ||
4 | 8 | ||
5 | perf = Extension('perf', | 9 | perf = Extension('perf', |
6 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', | 10 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', |
7 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', | 11 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', |
8 | 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], | 12 | 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], |
9 | include_dirs = ['util/include'], | 13 | include_dirs = ['util/include'], |
10 | extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings']) | 14 | extra_compile_args = cflags, |
15 | ) | ||
11 | 16 | ||
12 | setup(name='perf', | 17 | setup(name='perf', |
13 | version='0.1', | 18 | version='0.1', |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 8fc0bd3a3a4a..b9a985dadd08 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -85,7 +85,7 @@ out: | |||
85 | 85 | ||
86 | /* | 86 | /* |
87 | * Helper function for splitting a string into an argv-like array. | 87 | * Helper function for splitting a string into an argv-like array. |
88 | * originaly copied from lib/argv_split.c | 88 | * originally copied from lib/argv_split.c |
89 | */ | 89 | */ |
90 | static const char *skip_sep(const char *cp) | 90 | static const char *skip_sep(const char *cp) |
91 | { | 91 | { |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8f73907a959e..f06c10f092ba 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -2406,6 +2406,8 @@ int symbol__init(void) | |||
2406 | if (symbol_conf.initialized) | 2406 | if (symbol_conf.initialized) |
2407 | return 0; | 2407 | return 0; |
2408 | 2408 | ||
2409 | symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); | ||
2410 | |||
2409 | elf_version(EV_CURRENT); | 2411 | elf_version(EV_CURRENT); |
2410 | if (symbol_conf.sort_by_name) | 2412 | if (symbol_conf.sort_by_name) |
2411 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - | 2413 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 8c17a8730e4a..15633d608133 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -256,10 +256,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
256 | int refresh) | 256 | int refresh) |
257 | { | 257 | { |
258 | struct objdump_line *pos, *n; | 258 | struct objdump_line *pos, *n; |
259 | struct annotation *notes = symbol__annotation(sym); | 259 | struct annotation *notes; |
260 | struct annotate_browser browser = { | 260 | struct annotate_browser browser = { |
261 | .b = { | 261 | .b = { |
262 | .entries = ¬es->src->source, | ||
263 | .refresh = ui_browser__list_head_refresh, | 262 | .refresh = ui_browser__list_head_refresh, |
264 | .seek = ui_browser__list_head_seek, | 263 | .seek = ui_browser__list_head_seek, |
265 | .write = annotate_browser__write, | 264 | .write = annotate_browser__write, |
@@ -281,6 +280,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
281 | 280 | ||
282 | ui_helpline__push("Press <- or ESC to exit"); | 281 | ui_helpline__push("Press <- or ESC to exit"); |
283 | 282 | ||
283 | notes = symbol__annotation(sym); | ||
284 | |||
284 | list_for_each_entry(pos, ¬es->src->source, node) { | 285 | list_for_each_entry(pos, ¬es->src->source, node) { |
285 | struct objdump_line_rb_node *rbpos; | 286 | struct objdump_line_rb_node *rbpos; |
286 | size_t line_len = strlen(pos->line); | 287 | size_t line_len = strlen(pos->line); |
@@ -291,6 +292,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
291 | rbpos->idx = browser.b.nr_entries++; | 292 | rbpos->idx = browser.b.nr_entries++; |
292 | } | 293 | } |
293 | 294 | ||
295 | browser.b.entries = ¬es->src->source, | ||
294 | browser.b.width += 18; /* Percentage */ | 296 | browser.b.width += 18; /* Percentage */ |
295 | ret = annotate_browser__run(&browser, evidx, refresh); | 297 | ret = annotate_browser__run(&browser, evidx, refresh); |
296 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | 298 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 798efdca3ead..5d767c622dfc 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -851,7 +851,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
851 | goto out_free_stack; | 851 | goto out_free_stack; |
852 | case 'a': | 852 | case 'a': |
853 | if (browser->selection == NULL || | 853 | if (browser->selection == NULL || |
854 | browser->selection->map == NULL || | 854 | browser->selection->sym == NULL || |
855 | browser->selection->map->dso->annotate_warned) | 855 | browser->selection->map->dso->annotate_warned) |
856 | continue; | 856 | continue; |
857 | goto do_annotate; | 857 | goto do_annotate; |