diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/alpha/kernel/perf_event.c linux-3.10.11-100.fc18.x86_64/arch/alpha/kernel/perf_event.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/alpha/kernel/perf_event.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/alpha/kernel/perf_event.c 2013-09-30 11:19:04.290849329 +0200 @@ -850,7 +850,7 @@ static void alpha_perf_event_irq_handler perf_sample_data_init(&data, 0, hwc->last_period); if (alpha_perf_event_set_period(event, hwc, idx)) { - if (perf_event_overflow(event, &data, regs)) { + if (perf_event_overflow(event, &data, regs, NULL)) { /* Interrupts coming too quickly; "throttle" the * counter, i.e., disable it for a little while. */ diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/arm/kernel/perf_event_v6.c linux-3.10.11-100.fc18.x86_64/arch/arm/kernel/perf_event_v6.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/arm/kernel/perf_event_v6.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/arm/kernel/perf_event_v6.c 2013-09-30 11:19:04.291849332 +0200 @@ -514,7 +514,7 @@ armv6pmu_handle_irq(int irq_num, if (!armpmu_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) cpu_pmu->disable(event); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/arm/kernel/perf_event_v7.c linux-3.10.11-100.fc18.x86_64/arch/arm/kernel/perf_event_v7.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/arm/kernel/perf_event_v7.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/arm/kernel/perf_event_v7.c 2013-09-30 11:19:04.293849338 +0200 @@ -1074,7 +1074,7 @@ static irqreturn_t armv7pmu_handle_irq(i if (!armpmu_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) cpu_pmu->disable(event); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/arm/kernel/perf_event_xscale.c linux-3.10.11-100.fc18.x86_64/arch/arm/kernel/perf_event_xscale.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/arm/kernel/perf_event_xscale.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/arm/kernel/perf_event_xscale.c 2013-09-30 11:19:04.294849341 +0200 @@ -265,7 +265,7 @@ xscale1pmu_handle_irq(int irq_num, void if (!armpmu_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) cpu_pmu->disable(event); } @@ -606,7 +606,7 @@ xscale2pmu_handle_irq(int irq_num, void if (!armpmu_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) cpu_pmu->disable(event); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/arm64/kernel/perf_event.c linux-3.10.11-100.fc18.x86_64/arch/arm64/kernel/perf_event.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/arm64/kernel/perf_event.c 2013-09-23 12:03:25.604253957 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/arm64/kernel/perf_event.c 2013-09-30 11:19:04.295849344 +0200 @@ -1063,7 +1063,7 @@ static irqreturn_t armv8pmu_handle_irq(i if (!armpmu_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) cpu_pmu->disable(hwc, idx); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/metag/kernel/perf/perf_event.c linux-3.10.11-100.fc18.x86_64/arch/metag/kernel/perf/perf_event.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/metag/kernel/perf/perf_event.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/metag/kernel/perf/perf_event.c 2013-09-30 11:19:04.296849347 +0200 @@ -789,7 +789,7 @@ static irqreturn_t metag_pmu_counter_ove * completed. Note the counter value may have been modified while it was * inactive to set it up ready for the next interrupt. */ - if (!perf_event_overflow(event, &sampledata, regs)) { + if (!perf_event_overflow(event, &sampledata, regs, NULL)) { __global_lock2(flags); counter = (counter & 0xff000000) | (metag_in32(PERF_COUNT(idx)) & 0x00ffffff); diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/mips/kernel/perf_event_mipsxx.c linux-3.10.11-100.fc18.x86_64/arch/mips/kernel/perf_event_mipsxx.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/mips/kernel/perf_event_mipsxx.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/mips/kernel/perf_event_mipsxx.c 2013-09-30 11:19:04.297849351 +0200 @@ -746,7 +746,7 @@ static void handle_associated_event(stru if (!mipspmu_event_set_period(event, hwc, idx)) return; - if (perf_event_overflow(event, data, regs)) + if (perf_event_overflow(event, data, regs, NULL)) mipsxx_pmu_disable_event(idx); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/powerpc/perf/core-book3s.c linux-3.10.11-100.fc18.x86_64/arch/powerpc/perf/core-book3s.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/powerpc/perf/core-book3s.c 2013-09-23 12:03:25.610253955 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/powerpc/perf/core-book3s.c 2013-09-30 11:19:04.297849351 +0200 @@ -1639,7 +1639,7 @@ static void record_and_restart(struct pe data.br_stack = &cpuhw->bhrb_stack; } - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) power_pmu_stop(event, 0); } } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/powerpc/perf/core-fsl-emb.c linux-3.10.11-100.fc18.x86_64/arch/powerpc/perf/core-fsl-emb.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/powerpc/perf/core-fsl-emb.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/powerpc/perf/core-fsl-emb.c 2013-09-30 11:19:04.297849351 +0200 @@ -615,7 +615,7 @@ static void record_and_restart(struct pe perf_sample_data_init(&data, 0, event->hw.last_period); - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) fsl_emb_pmu_stop(event, 0); } } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/sparc/kernel/perf_event.c linux-3.10.11-100.fc18.x86_64/arch/sparc/kernel/perf_event.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/sparc/kernel/perf_event.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/sparc/kernel/perf_event.c 2013-09-30 11:19:04.297849351 +0200 @@ -1633,7 +1633,7 @@ static int __kprobes perf_event_nmi_hand if (!sparc_perf_event_set_period(event, hwc, idx)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) sparc_pmu_stop(event, 0); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_amd_ibs.c linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_amd_ibs.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_amd_ibs.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_amd_ibs.c 2013-09-30 11:19:04.298849354 +0200 @@ -580,7 +580,7 @@ static int perf_ibs_handle_irq(struct pe data.raw = &raw; } - throttle = perf_event_overflow(event, &data, ®s); + throttle = perf_event_overflow(event, &data, ®s, NULL); out: if (throttle) perf_ibs_disable_event(perf_ibs, hwc, *config); diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event.c linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event.c 2013-09-30 11:19:04.298849354 +0200 @@ -1225,7 +1225,7 @@ int x86_pmu_handle_irq(struct pt_regs *r if (!x86_perf_event_set_period(event)) continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) x86_pmu_stop(event, 0); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_intel.c linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_intel.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_intel.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_intel.c 2013-09-30 11:19:04.298849354 +0200 @@ -1222,7 +1222,7 @@ again: if (has_branch_stack(event)) data.br_stack = &cpuc->lbr_stack; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) x86_pmu_stop(event, 0); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_intel_ds.c linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_intel_ds.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_intel_ds.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_intel_ds.c 2013-09-30 11:19:04.298849354 +0200 @@ -761,7 +761,7 @@ static void __intel_pmu_pebs_event(struc if (has_branch_stack(event)) data.br_stack = &cpuc->lbr_stack; - if (perf_event_overflow(event, &data, ®s)) + if (perf_event_overflow(event, &data, ®s, NULL)) x86_pmu_stop(event, 0); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_knc.c linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_knc.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_knc.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_knc.c 2013-09-30 11:19:04.299849357 +0200 @@ -251,7 +251,7 @@ again: perf_sample_data_init(&data, 0, event->hw.last_period); - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) x86_pmu_stop(event, 0); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_p4.c linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_p4.c --- linux-3.10.11-100.fc18.x86_64.ORG/arch/x86/kernel/cpu/perf_event_p4.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/arch/x86/kernel/cpu/perf_event_p4.c 2013-09-30 11:19:04.299849357 +0200 @@ -1037,7 +1037,7 @@ static int p4_pmu_handle_irq(struct pt_r continue; - if (perf_event_overflow(event, &data, regs)) + if (perf_event_overflow(event, &data, regs, NULL)) x86_pmu_stop(event, 0); } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/include/linux/ftrace_event.h linux-3.10.11-100.fc18.x86_64/include/linux/ftrace_event.h --- linux-3.10.11-100.fc18.x86_64.ORG/include/linux/ftrace_event.h 2013-09-23 12:03:25.714253910 +0200 +++ linux-3.10.11-100.fc18.x86_64/include/linux/ftrace_event.h 2013-09-30 11:19:04.299849357 +0200 @@ -376,10 +376,10 @@ extern void *perf_trace_buf_prepare(int static inline void perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, - u64 count, struct pt_regs *regs, void *head, - struct task_struct *task) + u64 count, struct pt_regs *regs, struct pt_regs *user_regs, + void *head, struct task_struct *task) { - perf_tp_event(addr, count, raw_data, size, regs, head, rctx, task); + perf_tp_event(addr, count, raw_data, size, regs, user_regs, head, rctx, task); } #endif diff -urp linux-3.10.11-100.fc18.x86_64.ORG/include/linux/perf_event.h linux-3.10.11-100.fc18.x86_64/include/linux/perf_event.h --- linux-3.10.11-100.fc18.x86_64.ORG/include/linux/perf_event.h 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/include/linux/perf_event.h 2013-09-30 11:19:04.299849357 +0200 @@ -602,7 +602,8 @@ extern void perf_prepare_sample(struct p extern int perf_event_overflow(struct perf_event *event, struct perf_sample_data *data, - struct pt_regs *regs); + struct pt_regs *regs, + struct pt_regs *user_regs); static inline bool is_sampling_event(struct perf_event *event) { @@ -717,7 +718,7 @@ static inline bool perf_paranoid_kernel( extern void perf_event_init(void); extern void perf_tp_event(u64 addr, u64 count, void *record, - int entry_size, struct pt_regs *regs, + int entry_size, struct pt_regs *regs, struct pt_regs *user_regs, struct hlist_head *head, int rctx, struct task_struct *task); extern void perf_bp_event(struct perf_event *event, void *data); diff -urp linux-3.10.11-100.fc18.x86_64.ORG/include/trace/events/syscalls.h linux-3.10.11-100.fc18.x86_64/include/trace/events/syscalls.h --- linux-3.10.11-100.fc18.x86_64.ORG/include/trace/events/syscalls.h 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/include/trace/events/syscalls.h 2013-09-30 12:05:15.658006437 +0200 @@ -30,6 +30,7 @@ TRACE_EVENT_FN(sys_enter, TP_fast_assign( __entry->id = id; syscall_get_arguments(current, regs, 0, 6, __entry->args); + user_regs = regs; ), TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)", @@ -56,6 +57,7 @@ TRACE_EVENT_FN(sys_exit, TP_fast_assign( __entry->id = syscall_get_nr(current, regs); __entry->ret = ret; + user_regs = regs; ), TP_printk("NR %ld = %ld", diff -urp linux-3.10.11-100.fc18.x86_64.ORG/include/trace/ftrace.h linux-3.10.11-100.fc18.x86_64/include/trace/ftrace.h --- linux-3.10.11-100.fc18.x86_64.ORG/include/trace/ftrace.h 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/include/trace/ftrace.h 2013-09-30 12:10:59.065011590 +0200 @@ -519,6 +519,8 @@ ftrace_raw_event_##call(void *__data, pr struct ftrace_raw_##call *entry; \ struct ring_buffer *buffer; \ unsigned long irq_flags; \ + /* dummy. "assign" macro param might need it to exist: */ \ + struct pt_regs __maybe_unused *user_regs; \ int __data_size; \ int pc; \ \ @@ -652,6 +654,8 @@ perf_trace_##call(void *__data, proto) struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\ struct ftrace_raw_##call *entry; \ struct pt_regs __regs; \ + /* "assign" macro parameter might overwrite it: */ \ + struct pt_regs *user_regs = NULL; \ u64 __addr = 0, __count = 1; \ struct task_struct *__task = NULL; \ struct hlist_head *head; \ @@ -681,7 +685,7 @@ perf_trace_##call(void *__data, proto) \ head = this_cpu_ptr(event_call->perf_events); \ perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ - __count, &__regs, head, __task); \ + __count, &__regs, user_regs, head, __task); \ } /* diff -urp linux-3.10.11-100.fc18.x86_64.ORG/include/uapi/linux/perf_event.h linux-3.10.11-100.fc18.x86_64/include/uapi/linux/perf_event.h --- linux-3.10.11-100.fc18.x86_64.ORG/include/uapi/linux/perf_event.h 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/include/uapi/linux/perf_event.h 2013-09-30 11:19:04.300849360 +0200 @@ -273,7 +273,10 @@ struct perf_event_attr { exclude_callchain_kernel : 1, /* exclude kernel callchains */ exclude_callchain_user : 1, /* exclude user callchains */ - __reserved_1 : 41; + sysenter_stop : 1, + sysexit_stop : 1, + + __reserved_1 : 39; union { __u32 wakeup_events; /* wakeup every n events */ @@ -304,6 +307,15 @@ struct perf_event_attr { /* Align to u64. */ __u32 __reserved_2; + + /* + * If sys{enter,exit}_stop should ignore some syscalls, + * these bitmasks specify which to ignore. Otherwise set to 0/NULL. + */ + unsigned sysenter_mask_len; + unsigned sysexit_mask_len; + unsigned long *sysenter_mask_ptr; + unsigned long *sysexit_mask_ptr; }; #define perf_flags(attr) (*(&(attr)->read_format + 1)) diff -urp linux-3.10.11-100.fc18.x86_64.ORG/kernel/events/core.c linux-3.10.11-100.fc18.x86_64/kernel/events/core.c --- linux-3.10.11-100.fc18.x86_64.ORG/kernel/events/core.c 2013-09-23 12:03:25.719253908 +0200 +++ linux-3.10.11-100.fc18.x86_64/kernel/events/core.c 2013-09-30 12:11:21.929011933 +0200 @@ -43,6 +43,7 @@ #include "internal.h" #include +#include struct remote_function_call { struct task_struct *p; @@ -2933,6 +2934,7 @@ static void free_event_rcu(struct rcu_he if (event->ns) put_pid_ns(event->ns); perf_event_free_filter(event); + kfree(event->attr.sysenter_mask_ptr); kfree(event); } @@ -4964,7 +4966,8 @@ static void perf_log_throttle(struct per static int __perf_event_overflow(struct perf_event *event, int throttle, struct perf_sample_data *data, - struct pt_regs *regs) + struct pt_regs *regs, + struct pt_regs *user_regs) { int events = atomic_read(&event->event_limit); struct hw_perf_event *hwc = &event->hw; @@ -5026,14 +5029,35 @@ static int __perf_event_overflow(struct irq_work_queue(&event->pending); } + if (!in_interrupt() && event->attr.sysexit_stop && current->ptrace && user_regs) { + if (event->attr.sysexit_mask_len != 0) { + int bits; + int scno; + + scno = syscall_get_nr(current, user_regs); + if (scno < 0) + goto stop; + bits = event->attr.sysexit_mask_len * 8; + if (scno >= bits) + goto stop; + if (!test_bit(scno, event->attr.sysexit_mask_ptr)) + goto stop; + goto skip; + } + stop: + set_tsk_thread_flag(current, TIF_SYSCALL_TRACE); + skip: ; + } + return ret; } int perf_event_overflow(struct perf_event *event, struct perf_sample_data *data, - struct pt_regs *regs) + struct pt_regs *regs, + struct pt_regs *user_regs) { - return __perf_event_overflow(event, 1, data, regs); + return __perf_event_overflow(event, 1, data, regs, user_regs); } /* @@ -5083,7 +5107,8 @@ again: static void perf_swevent_overflow(struct perf_event *event, u64 overflow, struct perf_sample_data *data, - struct pt_regs *regs) + struct pt_regs *regs, + struct pt_regs *user_regs) { struct hw_perf_event *hwc = &event->hw; int throttle = 0; @@ -5096,7 +5121,7 @@ static void perf_swevent_overflow(struct for (; overflow; overflow--) { if (__perf_event_overflow(event, throttle, - data, regs)) { + data, regs, user_regs)) { /* * We inhibit the overflow from happening when * hwc->interrupts == MAX_INTERRUPTS. @@ -5109,7 +5134,8 @@ static void perf_swevent_overflow(struct static void perf_swevent_event(struct perf_event *event, u64 nr, struct perf_sample_data *data, - struct pt_regs *regs) + struct pt_regs *regs, + struct pt_regs *user_regs) { struct hw_perf_event *hwc = &event->hw; @@ -5123,17 +5149,17 @@ static void perf_swevent_event(struct pe if ((event->attr.sample_type & PERF_SAMPLE_PERIOD) && !event->attr.freq) { data->period = nr; - return perf_swevent_overflow(event, 1, data, regs); + return perf_swevent_overflow(event, 1, data, regs, user_regs); } else data->period = event->hw.last_period; if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq) - return perf_swevent_overflow(event, 1, data, regs); + return perf_swevent_overflow(event, 1, data, regs, user_regs); if (local64_add_negative(nr, &hwc->period_left)) return; - perf_swevent_overflow(event, 0, data, regs); + perf_swevent_overflow(event, 0, data, regs, user_regs); } static int perf_exclude_event(struct perf_event *event, @@ -5223,7 +5249,8 @@ find_swevent_head(struct swevent_htable static void do_perf_sw_event(enum perf_type_id type, u32 event_id, u64 nr, struct perf_sample_data *data, - struct pt_regs *regs) + struct pt_regs *regs, + struct pt_regs *user_regs) { struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); struct perf_event *event; @@ -5236,7 +5263,7 @@ static void do_perf_sw_event(enum perf_t hlist_for_each_entry_rcu(event, head, hlist_entry) { if (perf_swevent_match(event, type, event_id, data, regs)) - perf_swevent_event(event, nr, data, regs); + perf_swevent_event(event, nr, data, regs, user_regs); } end: rcu_read_unlock(); @@ -5269,7 +5296,7 @@ void __perf_sw_event(u32 event_id, u64 n perf_sample_data_init(&data, addr, 0); - do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, &data, regs); + do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, &data, regs, NULL); perf_swevent_put_recursion_context(rctx); preempt_enable_notrace(); @@ -5514,7 +5541,8 @@ static int perf_tp_event_match(struct pe } void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, - struct pt_regs *regs, struct hlist_head *head, int rctx, + struct pt_regs *regs, struct pt_regs *user_regs, + struct hlist_head *head, int rctx, struct task_struct *task) { struct perf_sample_data data; @@ -5530,7 +5558,7 @@ void perf_tp_event(u64 addr, u64 count, hlist_for_each_entry_rcu(event, head, hlist_entry) { if (perf_tp_event_match(event, &data, regs)) - perf_swevent_event(event, count, &data, regs); + perf_swevent_event(event, count, &data, regs, user_regs); } /* @@ -5552,7 +5580,7 @@ void perf_tp_event(u64 addr, u64 count, if (event->attr.config != entry->type) continue; if (perf_tp_event_match(event, &data, regs)) - perf_swevent_event(event, count, &data, regs); + perf_swevent_event(event, count, &data, regs, user_regs); } unlock: rcu_read_unlock(); @@ -5656,7 +5684,7 @@ void perf_bp_event(struct perf_event *bp perf_sample_data_init(&sample, bp->attr.bp_addr, 0); if (!bp->hw.state && !perf_exclude_event(bp, regs)) - perf_swevent_event(bp, 1, &sample, regs); + perf_swevent_event(bp, 1, &sample, regs, NULL); } #endif @@ -5684,7 +5712,7 @@ static enum hrtimer_restart perf_swevent if (regs && !perf_exclude_event(event, regs)) { if (!(event->attr.exclude_idle && is_idle_task(current))) - if (__perf_event_overflow(event, 1, &data, regs)) + if (__perf_event_overflow(event, 1, &data, regs, NULL)) ret = HRTIMER_NORESTART; } @@ -6469,6 +6497,32 @@ static int perf_copy_attr(struct perf_ev ret = -EINVAL; } + if ((attr->sysenter_mask_len | attr->sysexit_mask_len) & (sizeof(long)-1)) + return -EINVAL; + size = attr->sysenter_mask_len + attr->sysexit_mask_len; + if (size > PAGE_SIZE) + return -EINVAL; + if (size != 0) { + unsigned long *kp = kzalloc(size, GFP_KERNEL); + if (!kp) + return -ENOMEM; + + ret = copy_from_user(kp, (void __user *)attr->sysenter_mask_ptr, attr->sysenter_mask_len); + attr->sysenter_mask_ptr = kp; + if (!ret) { + kp = (void*)kp + attr->sysenter_mask_len; + ret = copy_from_user(kp, (void __user *)attr->sysexit_mask_ptr, attr->sysexit_mask_len); + attr->sysexit_mask_ptr = kp; + } + if (ret) { + kfree(attr->sysenter_mask_ptr); + goto out; + } + } else { + attr->sysenter_mask_ptr = NULL; + attr->sysexit_mask_ptr = NULL; + } + out: return ret; diff -urp linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_event_perf.c linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_event_perf.c --- linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_event_perf.c 2013-07-01 00:13:29.000000000 +0200 +++ linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_event_perf.c 2013-09-30 11:19:04.301849363 +0200 @@ -282,7 +282,7 @@ perf_ftrace_function_call(unsigned long head = this_cpu_ptr(event_function.perf_events); perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0, - 1, ®s, head, NULL); + 1, ®s, NULL, head, NULL); #undef ENTRY_SIZE } diff -urp linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_kprobe.c linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_kprobe.c --- linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_kprobe.c 2013-09-23 12:03:25.726253905 +0200 +++ linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_kprobe.c 2013-09-30 11:19:04.301849363 +0200 @@ -1193,7 +1193,7 @@ kprobe_perf_func(struct trace_probe *tp, head = this_cpu_ptr(call->perf_events); perf_trace_buf_submit(entry, size, rctx, - entry->ip, 1, regs, head, NULL); + entry->ip, 1, regs, NULL, head, NULL); } /* Kretprobe profile handler */ @@ -1225,7 +1225,7 @@ kretprobe_perf_func(struct trace_probe * head = this_cpu_ptr(call->perf_events); perf_trace_buf_submit(entry, size, rctx, - entry->ret_ip, 1, regs, head, NULL); + entry->ret_ip, 1, regs, NULL, head, NULL); } #endif /* CONFIG_PERF_EVENTS */ diff -urp linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_syscalls.c linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_syscalls.c --- linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_syscalls.c 2013-09-23 12:03:25.726253905 +0200 +++ linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_syscalls.c 2013-09-30 11:19:04.301849363 +0200 @@ -585,7 +585,7 @@ static void perf_syscall_enter(void *ign (unsigned long *)&rec->args); head = this_cpu_ptr(sys_data->enter_event->perf_events); - perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); + perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, regs, head, NULL); } static int perf_sysenter_enable(struct ftrace_event_call *call) @@ -663,7 +663,7 @@ static void perf_syscall_exit(void *igno rec->ret = syscall_get_return_value(current, regs); head = this_cpu_ptr(sys_data->exit_event->perf_events); - perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); + perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, regs, head, NULL); } static int perf_sysexit_enable(struct ftrace_event_call *call) diff -urp linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_uprobe.c linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_uprobe.c --- linux-3.10.11-100.fc18.x86_64.ORG/kernel/trace/trace_uprobe.c 2013-09-23 12:03:25.727253904 +0200 +++ linux-3.10.11-100.fc18.x86_64/kernel/trace/trace_uprobe.c 2013-09-30 11:19:04.301849363 +0200 @@ -862,7 +862,7 @@ static void uprobe_perf_print(struct tra for (i = 0; i < tu->nr_args; i++) call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); - perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); + perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, NULL, head, NULL); out: preempt_enable(); }