diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 66 |
1 files changed, 53 insertions, 13 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c9ed7e3cf231..f7bb7ae328da 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "cpumap.h" | 16 | #include "cpumap.h" |
17 | #include "event-parse.h" | 17 | #include "event-parse.h" |
18 | #include "perf_regs.h" | 18 | #include "perf_regs.h" |
19 | #include "unwind.h" | ||
19 | 20 | ||
20 | static int perf_session__open(struct perf_session *self, bool force) | 21 | static int perf_session__open(struct perf_session *self, bool force) |
21 | { | 22 | { |
@@ -289,10 +290,11 @@ struct branch_info *machine__resolve_bstack(struct machine *self, | |||
289 | return bi; | 290 | return bi; |
290 | } | 291 | } |
291 | 292 | ||
292 | int machine__resolve_callchain(struct machine *self, | 293 | static int machine__resolve_callchain_sample(struct machine *machine, |
293 | struct thread *thread, | 294 | struct thread *thread, |
294 | struct ip_callchain *chain, | 295 | struct ip_callchain *chain, |
295 | struct symbol **parent) | 296 | struct symbol **parent) |
297 | |||
296 | { | 298 | { |
297 | u8 cpumode = PERF_RECORD_MISC_USER; | 299 | u8 cpumode = PERF_RECORD_MISC_USER; |
298 | unsigned int i; | 300 | unsigned int i; |
@@ -317,11 +319,14 @@ int machine__resolve_callchain(struct machine *self, | |||
317 | if (ip >= PERF_CONTEXT_MAX) { | 319 | if (ip >= PERF_CONTEXT_MAX) { |
318 | switch (ip) { | 320 | switch (ip) { |
319 | case PERF_CONTEXT_HV: | 321 | case PERF_CONTEXT_HV: |
320 | cpumode = PERF_RECORD_MISC_HYPERVISOR; break; | 322 | cpumode = PERF_RECORD_MISC_HYPERVISOR; |
323 | break; | ||
321 | case PERF_CONTEXT_KERNEL: | 324 | case PERF_CONTEXT_KERNEL: |
322 | cpumode = PERF_RECORD_MISC_KERNEL; break; | 325 | cpumode = PERF_RECORD_MISC_KERNEL; |
326 | break; | ||
323 | case PERF_CONTEXT_USER: | 327 | case PERF_CONTEXT_USER: |
324 | cpumode = PERF_RECORD_MISC_USER; break; | 328 | cpumode = PERF_RECORD_MISC_USER; |
329 | break; | ||
325 | default: | 330 | default: |
326 | pr_debug("invalid callchain context: " | 331 | pr_debug("invalid callchain context: " |
327 | "%"PRId64"\n", (s64) ip); | 332 | "%"PRId64"\n", (s64) ip); |
@@ -336,7 +341,7 @@ int machine__resolve_callchain(struct machine *self, | |||
336 | } | 341 | } |
337 | 342 | ||
338 | al.filtered = false; | 343 | al.filtered = false; |
339 | thread__find_addr_location(thread, self, cpumode, | 344 | thread__find_addr_location(thread, machine, cpumode, |
340 | MAP__FUNCTION, ip, &al, NULL); | 345 | MAP__FUNCTION, ip, &al, NULL); |
341 | if (al.sym != NULL) { | 346 | if (al.sym != NULL) { |
342 | if (sort__has_parent && !*parent && | 347 | if (sort__has_parent && !*parent && |
@@ -355,6 +360,40 @@ int machine__resolve_callchain(struct machine *self, | |||
355 | return 0; | 360 | return 0; |
356 | } | 361 | } |
357 | 362 | ||
363 | static int unwind_entry(struct unwind_entry *entry, void *arg) | ||
364 | { | ||
365 | struct callchain_cursor *cursor = arg; | ||
366 | return callchain_cursor_append(cursor, entry->ip, | ||
367 | entry->map, entry->sym); | ||
368 | } | ||
369 | |||
370 | int machine__resolve_callchain(struct machine *machine, | ||
371 | struct perf_evsel *evsel, | ||
372 | struct thread *thread, | ||
373 | struct perf_sample *sample, | ||
374 | struct symbol **parent) | ||
375 | |||
376 | { | ||
377 | int ret; | ||
378 | |||
379 | callchain_cursor_reset(&callchain_cursor); | ||
380 | |||
381 | ret = machine__resolve_callchain_sample(machine, thread, | ||
382 | sample->callchain, parent); | ||
383 | if (ret) | ||
384 | return ret; | ||
385 | |||
386 | /* Can we do dwarf post unwind? */ | ||
387 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | ||
388 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | ||
389 | return 0; | ||
390 | |||
391 | return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||
392 | thread, evsel->attr.sample_regs_user, | ||
393 | sample); | ||
394 | |||
395 | } | ||
396 | |||
358 | static int process_event_synth_tracing_data_stub(union perf_event *event __used, | 397 | static int process_event_synth_tracing_data_stub(union perf_event *event __used, |
359 | struct perf_session *session __used) | 398 | struct perf_session *session __used) |
360 | { | 399 | { |
@@ -1533,9 +1572,9 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1533 | return NULL; | 1572 | return NULL; |
1534 | } | 1573 | } |
1535 | 1574 | ||
1536 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | 1575 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, |
1537 | struct machine *machine, int print_sym, | 1576 | struct perf_sample *sample, struct machine *machine, |
1538 | int print_dso, int print_symoffset) | 1577 | int print_sym, int print_dso, int print_symoffset) |
1539 | { | 1578 | { |
1540 | struct addr_location al; | 1579 | struct addr_location al; |
1541 | struct callchain_cursor_node *node; | 1580 | struct callchain_cursor_node *node; |
@@ -1549,8 +1588,9 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | |||
1549 | 1588 | ||
1550 | if (symbol_conf.use_callchain && sample->callchain) { | 1589 | if (symbol_conf.use_callchain && sample->callchain) { |
1551 | 1590 | ||
1552 | if (machine__resolve_callchain(machine, al.thread, | 1591 | |
1553 | sample->callchain, NULL) != 0) { | 1592 | if (machine__resolve_callchain(machine, evsel, al.thread, |
1593 | sample, NULL) != 0) { | ||
1554 | if (verbose) | 1594 | if (verbose) |
1555 | error("Failed to resolve callchain. Skipping\n"); | 1595 | error("Failed to resolve callchain. Skipping\n"); |
1556 | return; | 1596 | return; |