aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2016-09-23 10:38:48 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-09-29 10:17:06 -0400
commit2acee108f58045d07475516852d4282ab73904dc (patch)
tree64891314c8a010ffc5b1983b6d41080b211b65b8 /tools
parent9f1d122b528ef3ffcef1bdcf6a3dddf9450a864e (diff)
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/intel-pt.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index c9fec19a7914..dc041d4368c8 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -105,6 +105,7 @@ struct intel_pt {
105 unsigned long num_events; 105 unsigned long num_events;
106 106
107 char *filter; 107 char *filter;
108 struct addr_filters filts;
108}; 109};
109 110
110enum switch_state { 111enum switch_state {
@@ -550,6 +551,76 @@ out_no_cache:
550 return 0; 551 return 0;
551} 552}
552 553
554static bool intel_pt_match_pgd_ip(struct intel_pt *pt, uint64_t ip,
555 uint64_t offset, const char *filename)
556{
557 struct addr_filter *filt;
558 bool have_filter = false;
559 bool hit_tracestop = false;
560 bool hit_filter = false;
561
562 list_for_each_entry(filt, &pt->filts.head, list) {
563 if (filt->start)
564 have_filter = true;
565
566 if ((filename && !filt->filename) ||
567 (!filename && filt->filename) ||
568 (filename && strcmp(filename, filt->filename)))
569 continue;
570
571 if (!(offset >= filt->addr && offset < filt->addr + filt->size))
572 continue;
573
574 intel_pt_log("TIP.PGD ip %#"PRIx64" offset %#"PRIx64" in %s hit filter: %s offset %#"PRIx64" size %#"PRIx64"\n",
575 ip, offset, filename ? filename : "[kernel]",
576 filt->start ? "filter" : "stop",
577 filt->addr, filt->size);
578
579 if (filt->start)
580 hit_filter = true;
581 else
582 hit_tracestop = true;
583 }
584
585 if (!hit_tracestop && !hit_filter)
586 intel_pt_log("TIP.PGD ip %#"PRIx64" offset %#"PRIx64" in %s is not in a filter region\n",
587 ip, offset, filename ? filename : "[kernel]");
588
589 return hit_tracestop || (have_filter && !hit_filter);
590}
591
592static int __intel_pt_pgd_ip(uint64_t ip, void *data)
593{
594 struct intel_pt_queue *ptq = data;
595 struct thread *thread;
596 struct addr_location al;
597 u8 cpumode;
598 u64 offset;
599
600 if (ip >= ptq->pt->kernel_start)
601 return intel_pt_match_pgd_ip(ptq->pt, ip, ip, NULL);
602
603 cpumode = PERF_RECORD_MISC_USER;
604
605 thread = ptq->thread;
606 if (!thread)
607 return -EINVAL;
608
609 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, ip, &al);
610 if (!al.map || !al.map->dso)
611 return -EINVAL;
612
613 offset = al.map->map_ip(al.map, ip);
614
615 return intel_pt_match_pgd_ip(ptq->pt, ip, offset,
616 al.map->dso->long_name);
617}
618
619static bool intel_pt_pgd_ip(uint64_t ip, void *data)
620{
621 return __intel_pt_pgd_ip(ip, data) > 0;
622}
623
553static bool intel_pt_get_config(struct intel_pt *pt, 624static bool intel_pt_get_config(struct intel_pt *pt,
554 struct perf_event_attr *attr, u64 *config) 625 struct perf_event_attr *attr, u64 *config)
555{ 626{
@@ -726,6 +797,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
726 params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; 797 params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n;
727 params.tsc_ctc_ratio_d = pt->tsc_ctc_ratio_d; 798 params.tsc_ctc_ratio_d = pt->tsc_ctc_ratio_d;
728 799
800 if (pt->filts.cnt > 0)
801 params.pgd_ip = intel_pt_pgd_ip;
802
729 if (pt->synth_opts.instructions) { 803 if (pt->synth_opts.instructions) {
730 if (pt->synth_opts.period) { 804 if (pt->synth_opts.period) {
731 switch (pt->synth_opts.period_type) { 805 switch (pt->synth_opts.period_type) {
@@ -1776,6 +1850,7 @@ static void intel_pt_free(struct perf_session *session)
1776 intel_pt_free_events(session); 1850 intel_pt_free_events(session);
1777 session->auxtrace = NULL; 1851 session->auxtrace = NULL;
1778 thread__put(pt->unknown_thread); 1852 thread__put(pt->unknown_thread);
1853 addr_filters__exit(&pt->filts);
1779 zfree(&pt->filter); 1854 zfree(&pt->filter);
1780 free(pt); 1855 free(pt);
1781} 1856}
@@ -2073,6 +2148,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
2073 if (!pt) 2148 if (!pt)
2074 return -ENOMEM; 2149 return -ENOMEM;
2075 2150
2151 addr_filters__init(&pt->filts);
2152
2076 perf_config(intel_pt_perf_config, pt); 2153 perf_config(intel_pt_perf_config, pt);
2077 2154
2078 err = auxtrace_queues__init(&pt->queues); 2155 err = auxtrace_queues__init(&pt->queues);
@@ -2147,6 +2224,10 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
2147 err = -EINVAL; 2224 err = -EINVAL;
2148 goto err_free_queues; 2225 goto err_free_queues;
2149 } 2226 }
2227 err = addr_filters__parse_bare_filter(&pt->filts,
2228 filter);
2229 if (err)
2230 goto err_free_queues;
2150 } 2231 }
2151 intel_pt_print_info_str("Filter string", pt->filter); 2232 intel_pt_print_info_str("Filter string", pt->filter);
2152 } 2233 }
@@ -2268,6 +2349,7 @@ err_free_queues:
2268 auxtrace_queues__free(&pt->queues); 2349 auxtrace_queues__free(&pt->queues);
2269 session->auxtrace = NULL; 2350 session->auxtrace = NULL;
2270err_free: 2351err_free:
2352 addr_filters__exit(&pt->filts);
2271 zfree(&pt->filter); 2353 zfree(&pt->filter);
2272 free(pt); 2354 free(pt);
2273 return err; 2355 return err;