[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1391683834-29868-10-git-send-email-alexander.shishkin@linux.intel.com>
Date: Thu, 6 Feb 2014 12:50:32 +0200
From: Alexander Shishkin <alexander.shishkin@...ux.intel.com>
To: Peter Zijlstra <a.p.zijlstra@...llo.nl>
Cc: Ingo Molnar <mingo@...hat.com>, linux-kernel@...r.kernel.org,
Frederic Weisbecker <fweisbec@...il.com>,
Mike Galbraith <efault@....de>,
Paul Mackerras <paulus@...ba.org>,
Stephane Eranian <eranian@...gle.com>,
Andi Kleen <ak@...ux.intel.com>,
Adrian Hunter <adrian.hunter@...el.com>,
Matt Fleming <matt.fleming@...el.com>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>
Subject: [PATCH v1 09/11] x86: perf: intel_pt: Add core dump functionality
Intel Processor Trace (PT) data can be used in process core dumps. This
is done by implementing itrace code dump related hooks that configure and
output trace data to a core file. The driver will also include the list
of PT capabilities in itrace core dump notes so that the decoder can make
assumptions about the binary stream.
Signed-off-by: Alexander Shishkin <alexander.shishkin@...ux.intel.com>
---
arch/x86/kernel/cpu/intel_pt.h | 2 +
arch/x86/kernel/cpu/perf_event_intel_pt.c | 74 +++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/arch/x86/kernel/cpu/intel_pt.h b/arch/x86/kernel/cpu/intel_pt.h
index dd69092..befde1f 100644
--- a/arch/x86/kernel/cpu/intel_pt.h
+++ b/arch/x86/kernel/cpu/intel_pt.h
@@ -84,6 +84,8 @@ enum pt_capabilities {
struct pt_pmu {
struct itrace_pmu itrace;
u32 caps[4 * PT_CPUID_LEAVES];
+ char *capstr;
+ unsigned int caplen;
};
/**
diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c
index af1482d..cb03594 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_pt.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/coredump.h>
#include <asm-generic/sizes.h>
#include <asm/perf_event.h>
@@ -88,6 +89,34 @@ static void pt_cap_set(enum pt_capabilities cap, u32 val)
pt_pmu.caps[idx] = (val << shift) & cd->mask;
}
+/**
+ * pt_cap_string - format PT capabilities into an ascii string
+ *
+ * We need to include PT capabilities in the core dump note so that the
+ * decoder knows what to expect in the binary stream.
+ */
+static void pt_cap_string(void)
+{
+ char *capstr;
+ int pos, i;
+
+ capstr = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!capstr)
+ return;
+
+ for (i = 0, pos = 0; i < ARRAY_SIZE(pt_caps) && pos < PAGE_SIZE; i++) {
+ pos += snprintf(&capstr[pos], PAGE_SIZE - pos, "%s:%x%c",
+ pt_caps[i].name, pt_cap_get(i),
+ i == ARRAY_SIZE(pt_caps) - 1 ? 0 : ',');
+ }
+
+ if (pt_pmu.capstr)
+ kfree(pt_pmu.capstr);
+
+ pt_pmu.capstr = capstr;
+ pt_pmu.caplen = pos;
+}
+
static ssize_t pt_cap_show(struct device *cdev,
struct device_attribute *attr,
char *buf)
@@ -114,6 +143,7 @@ static ssize_t pt_cap_store(struct device *cdev,
return -EINVAL;
pt_cap_set(cap, new);
+ pt_cap_string();
return size;
}
@@ -179,6 +209,7 @@ static int __init pt_pmu_hw_init(void)
attrs[i] = &de_attrs[i].attr.attr;
}
+ pt_cap_string();
pt_cap_group.attrs = attrs;
return 0;
@@ -1070,6 +1101,46 @@ out:
pt_event_start(event, 0);
}
+static size_t pt_trace_core_size(struct perf_event *event)
+{
+ return pt_pmu.caplen;
+}
+
+static unsigned int pt_core_copy(void *data, const void *src,
+ unsigned int len)
+{
+ struct coredump_params *cprm = data;
+
+ if (dump_emit(cprm, src, len))
+ return 0;
+
+ return len;
+}
+
+static void pt_trace_core_output(struct coredump_params *cprm,
+ struct perf_event *event,
+ unsigned long len)
+{
+ struct pt_buffer *buf;
+ u64 from, to;
+ int ret;
+
+ buf = itrace_priv(event);
+
+ if (!dump_emit(cprm, pt_pmu.capstr, pt_pmu.caplen))
+ return;
+
+ to = local64_read(&buf->head);
+ if (to < len)
+ from = buf->size + to - len;
+ else
+ from = to - len;
+
+ ret = pt_buffer_output(buf, from, to, pt_core_copy, cprm);
+ if (ret < 0)
+ pr_warn("%s: failed to copy trace data\n", __func__);
+}
+
static __init int pt_init(void)
{
int ret, cpu;
@@ -1097,6 +1168,9 @@ static __init int pt_init(void)
pt_pmu.itrace.free_buffer = pt_buffer_itrace_free;
pt_pmu.itrace.sample_trace = pt_trace_sampler_trace;
pt_pmu.itrace.sample_output = pt_trace_sampler_output;
+ pt_pmu.itrace.core_size = pt_trace_core_size;
+ pt_pmu.itrace.core_output = pt_trace_core_output;
+ pt_pmu.itrace.coredump_config = RTIT_CTL_TSC_EN | RTIT_CTL_DISRETC;
pt_pmu.itrace.name = "intel_pt";
ret = itrace_pmu_register(&pt_pmu.itrace);
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists