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

perf intel-pt: Fix decoding when there are address filters

Due to errata SKL014 "Intel PT TIP.PGD May Not Have Target IP Payload",
the Intel PT decoder needs to match address filters against TIP.PGD
packets. Parse the address filters and implement the decoder's
'pgd_ip()' callback to match the IP against the filter regions.

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

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
2acee108 9f1d122b

+82
+82
tools/perf/util/intel-pt.c
··· 105 105 unsigned long num_events; 106 106 107 107 char *filter; 108 + struct addr_filters filts; 108 109 }; 109 110 110 111 enum switch_state { ··· 551 550 return 0; 552 551 } 553 552 553 + static bool intel_pt_match_pgd_ip(struct intel_pt *pt, uint64_t ip, 554 + uint64_t offset, const char *filename) 555 + { 556 + struct addr_filter *filt; 557 + bool have_filter = false; 558 + bool hit_tracestop = false; 559 + bool hit_filter = false; 560 + 561 + list_for_each_entry(filt, &pt->filts.head, list) { 562 + if (filt->start) 563 + have_filter = true; 564 + 565 + if ((filename && !filt->filename) || 566 + (!filename && filt->filename) || 567 + (filename && strcmp(filename, filt->filename))) 568 + continue; 569 + 570 + if (!(offset >= filt->addr && offset < filt->addr + filt->size)) 571 + continue; 572 + 573 + intel_pt_log("TIP.PGD ip %#"PRIx64" offset %#"PRIx64" in %s hit filter: %s offset %#"PRIx64" size %#"PRIx64"\n", 574 + ip, offset, filename ? filename : "[kernel]", 575 + filt->start ? "filter" : "stop", 576 + filt->addr, filt->size); 577 + 578 + if (filt->start) 579 + hit_filter = true; 580 + else 581 + hit_tracestop = true; 582 + } 583 + 584 + if (!hit_tracestop && !hit_filter) 585 + intel_pt_log("TIP.PGD ip %#"PRIx64" offset %#"PRIx64" in %s is not in a filter region\n", 586 + ip, offset, filename ? filename : "[kernel]"); 587 + 588 + return hit_tracestop || (have_filter && !hit_filter); 589 + } 590 + 591 + static int __intel_pt_pgd_ip(uint64_t ip, void *data) 592 + { 593 + struct intel_pt_queue *ptq = data; 594 + struct thread *thread; 595 + struct addr_location al; 596 + u8 cpumode; 597 + u64 offset; 598 + 599 + if (ip >= ptq->pt->kernel_start) 600 + return intel_pt_match_pgd_ip(ptq->pt, ip, ip, NULL); 601 + 602 + cpumode = PERF_RECORD_MISC_USER; 603 + 604 + thread = ptq->thread; 605 + if (!thread) 606 + return -EINVAL; 607 + 608 + thread__find_addr_map(thread, cpumode, MAP__FUNCTION, ip, &al); 609 + if (!al.map || !al.map->dso) 610 + return -EINVAL; 611 + 612 + offset = al.map->map_ip(al.map, ip); 613 + 614 + return intel_pt_match_pgd_ip(ptq->pt, ip, offset, 615 + al.map->dso->long_name); 616 + } 617 + 618 + static bool intel_pt_pgd_ip(uint64_t ip, void *data) 619 + { 620 + return __intel_pt_pgd_ip(ip, data) > 0; 621 + } 622 + 554 623 static bool intel_pt_get_config(struct intel_pt *pt, 555 624 struct perf_event_attr *attr, u64 *config) 556 625 { ··· 796 725 params.mtc_period = intel_pt_mtc_period(pt); 797 726 params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; 798 727 params.tsc_ctc_ratio_d = pt->tsc_ctc_ratio_d; 728 + 729 + if (pt->filts.cnt > 0) 730 + params.pgd_ip = intel_pt_pgd_ip; 799 731 800 732 if (pt->synth_opts.instructions) { 801 733 if (pt->synth_opts.period) { ··· 1850 1776 intel_pt_free_events(session); 1851 1777 session->auxtrace = NULL; 1852 1778 thread__put(pt->unknown_thread); 1779 + addr_filters__exit(&pt->filts); 1853 1780 zfree(&pt->filter); 1854 1781 free(pt); 1855 1782 } ··· 2148 2073 if (!pt) 2149 2074 return -ENOMEM; 2150 2075 2076 + addr_filters__init(&pt->filts); 2077 + 2151 2078 perf_config(intel_pt_perf_config, pt); 2152 2079 2153 2080 err = auxtrace_queues__init(&pt->queues); ··· 2224 2147 err = -EINVAL; 2225 2148 goto err_free_queues; 2226 2149 } 2150 + err = addr_filters__parse_bare_filter(&pt->filts, 2151 + filter); 2152 + if (err) 2153 + goto err_free_queues; 2227 2154 } 2228 2155 intel_pt_print_info_str("Filter string", pt->filter); 2229 2156 } ··· 2349 2268 auxtrace_queues__free(&pt->queues); 2350 2269 session->auxtrace = NULL; 2351 2270 err_free: 2271 + addr_filters__exit(&pt->filts); 2352 2272 zfree(&pt->filter); 2353 2273 free(pt); 2354 2274 return err;