aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/core.c
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2012-08-07 09:20:37 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-08-10 10:31:26 -0400
commit4018994f3d8785275ef0e7391b75c3462c029e56 (patch)
tree661b5c488977c5150eb9d1ac4cec944309c83a16 /kernel/events/core.c
parentc5e63197db519bae1c33e41ea0342a50f39e7a93 (diff)
perf: Add ability to attach user level registers dump to sample
Introducing PERF_SAMPLE_REGS_USER sample type bit to trigger the dump of user level registers on sample. Registers we want to dump are specified by sample_regs_user bitmask. Only user level registers are dumped at the moment. Meaning the register values of the user space context as it was before the user entered the kernel for whatever reason (syscall, irq, exception, or a PMI happening in userspace). The layout of the sample_regs_user bitmap is described in asm/perf_regs.h for archs that support register dump. This is going to be useful to bring Dwarf CFI based stack unwinding on top of samples. Original-patch-by: Frederic Weisbecker <fweisbec@gmail.com> [ Dump registers ABI specification. ] Signed-off-by: Jiri Olsa <jolsa@redhat.com> Suggested-by: Stephane Eranian <eranian@google.com> Cc: "Frank Ch. Eigler" <fche@redhat.com> Cc: Arun Sharma <asharma@fb.com> Cc: Benjamin Redelings <benjamin.redelings@nescent.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Robert Richter <robert.richter@amd.com> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Ulrich Drepper <drepper@gmail.com> Link: http://lkml.kernel.org/r/1344345647-11536-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'kernel/events/core.c')
-rw-r--r--kernel/events/core.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index b7935fcec7d..d3ce97525b9 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3756,6 +3756,37 @@ int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
3756} 3756}
3757EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); 3757EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);
3758 3758
3759static void
3760perf_output_sample_regs(struct perf_output_handle *handle,
3761 struct pt_regs *regs, u64 mask)
3762{
3763 int bit;
3764
3765 for_each_set_bit(bit, (const unsigned long *) &mask,
3766 sizeof(mask) * BITS_PER_BYTE) {
3767 u64 val;
3768
3769 val = perf_reg_value(regs, bit);
3770 perf_output_put(handle, val);
3771 }
3772}
3773
3774static void perf_sample_regs_user(struct perf_regs_user *regs_user,
3775 struct pt_regs *regs)
3776{
3777 if (!user_mode(regs)) {
3778 if (current->mm)
3779 regs = task_pt_regs(current);
3780 else
3781 regs = NULL;
3782 }
3783
3784 if (regs) {
3785 regs_user->regs = regs;
3786 regs_user->abi = perf_reg_abi(current);
3787 }
3788}
3789
3759static void __perf_event_header__init_id(struct perf_event_header *header, 3790static void __perf_event_header__init_id(struct perf_event_header *header,
3760 struct perf_sample_data *data, 3791 struct perf_sample_data *data,
3761 struct perf_event *event) 3792 struct perf_event *event)
@@ -4016,6 +4047,23 @@ void perf_output_sample(struct perf_output_handle *handle,
4016 perf_output_put(handle, nr); 4047 perf_output_put(handle, nr);
4017 } 4048 }
4018 } 4049 }
4050
4051 if (sample_type & PERF_SAMPLE_REGS_USER) {
4052 u64 abi = data->regs_user.abi;
4053
4054 /*
4055 * If there are no regs to dump, notice it through
4056 * first u64 being zero (PERF_SAMPLE_REGS_ABI_NONE).
4057 */
4058 perf_output_put(handle, abi);
4059
4060 if (abi) {
4061 u64 mask = event->attr.sample_regs_user;
4062 perf_output_sample_regs(handle,
4063 data->regs_user.regs,
4064 mask);
4065 }
4066 }
4019} 4067}
4020 4068
4021void perf_prepare_sample(struct perf_event_header *header, 4069void perf_prepare_sample(struct perf_event_header *header,
@@ -4067,6 +4115,20 @@ void perf_prepare_sample(struct perf_event_header *header,
4067 } 4115 }
4068 header->size += size; 4116 header->size += size;
4069 } 4117 }
4118
4119 if (sample_type & PERF_SAMPLE_REGS_USER) {
4120 /* regs dump ABI info */
4121 int size = sizeof(u64);
4122
4123 perf_sample_regs_user(&data->regs_user, regs);
4124
4125 if (data->regs_user.regs) {
4126 u64 mask = event->attr.sample_regs_user;
4127 size += hweight64(mask) * sizeof(u64);
4128 }
4129
4130 header->size += size;
4131 }
4070} 4132}
4071 4133
4072static void perf_event_output(struct perf_event *event, 4134static void perf_event_output(struct perf_event *event,
@@ -6142,6 +6204,10 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
6142 attr->branch_sample_type = mask; 6204 attr->branch_sample_type = mask;
6143 } 6205 }
6144 } 6206 }
6207
6208 if (attr->sample_type & PERF_SAMPLE_REGS_USER)
6209 ret = perf_reg_validate(attr->sample_regs_user);
6210
6145out: 6211out:
6146 return ret; 6212 return ret;
6147 6213