aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/entry_32.S3
-rw-r--r--arch/x86/kernel/entry_64.S4
-rw-r--r--arch/x86/kernel/kprobes.c43
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/kprobes.c3
-rw-r--r--kernel/trace/Kconfig5
-rw-r--r--kernel/trace/Makefile6
-rw-r--r--kernel/trace/trace_events.c4
8 files changed, 46 insertions, 24 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 061ac17ee974..f438a44bf8f9 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1148,7 +1148,6 @@ ENTRY(ftrace_regs_caller)
1148 * ip location, and move flags into the return ip location. 1148 * ip location, and move flags into the return ip location.
1149 */ 1149 */
1150 pushl 4(%esp) /* save return ip into ip slot */ 1150 pushl 4(%esp) /* save return ip into ip slot */
1151 subl $MCOUNT_INSN_SIZE, (%esp) /* Adjust ip */
1152 1151
1153 pushl $0 /* Load 0 into orig_ax */ 1152 pushl $0 /* Load 0 into orig_ax */
1154 pushl %gs 1153 pushl %gs
@@ -1169,6 +1168,7 @@ ENTRY(ftrace_regs_caller)
1169 movl $__KERNEL_CS,13*4(%esp) 1168 movl $__KERNEL_CS,13*4(%esp)
1170 1169
1171 movl 12*4(%esp), %eax /* Load ip (1st parameter) */ 1170 movl 12*4(%esp), %eax /* Load ip (1st parameter) */
1171 subl $MCOUNT_INSN_SIZE, %eax /* Adjust ip */
1172 movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */ 1172 movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */
1173 leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */ 1173 leal function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */
1174 pushl %esp /* Save pt_regs as 4th parameter */ 1174 pushl %esp /* Save pt_regs as 4th parameter */
@@ -1180,7 +1180,6 @@ GLOBAL(ftrace_regs_call)
1180 movl 14*4(%esp), %eax /* Move flags back into cs */ 1180 movl 14*4(%esp), %eax /* Move flags back into cs */
1181 movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */ 1181 movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */
1182 movl 12*4(%esp), %eax /* Get return ip from regs->ip */ 1182 movl 12*4(%esp), %eax /* Get return ip from regs->ip */
1183 addl $MCOUNT_INSN_SIZE, %eax
1184 movl %eax, 14*4(%esp) /* Put return ip back for ret */ 1183 movl %eax, 14*4(%esp) /* Put return ip back for ret */
1185 1184
1186 popl %ebx 1185 popl %ebx
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index ed767b747fe5..e9cc2b32bdf4 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -165,6 +165,10 @@ GLOBAL(ftrace_regs_call)
165 movq EFLAGS(%rsp), %rax 165 movq EFLAGS(%rsp), %rax
166 movq %rax, SS(%rsp) 166 movq %rax, SS(%rsp)
167 167
168 /* Handlers can change the RIP */
169 movq RIP(%rsp), %rax
170 movq %rax, SS+8(%rsp)
171
168 /* restore the rest of pt_regs */ 172 /* restore the rest of pt_regs */
169 movq R15(%rsp), %r15 173 movq R15(%rsp), %r15
170 movq R14(%rsp), %r14 174 movq R14(%rsp), %r14
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 47ae1023a93c..b7c2a85d1926 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -541,6 +541,8 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb
541 return 1; 541 return 1;
542} 542}
543 543
544static void __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
545 struct kprobe_ctlblk *kcb);
544/* 546/*
545 * Interrupts are disabled on entry as trap3 is an interrupt gate and they 547 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
546 * remain disabled throughout this function. 548 * remain disabled throughout this function.
@@ -599,6 +601,12 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
599 } else if (kprobe_running()) { 601 } else if (kprobe_running()) {
600 p = __this_cpu_read(current_kprobe); 602 p = __this_cpu_read(current_kprobe);
601 if (p->break_handler && p->break_handler(p, regs)) { 603 if (p->break_handler && p->break_handler(p, regs)) {
604#ifdef KPROBES_CAN_USE_FTRACE
605 if (kprobe_ftrace(p)) {
606 skip_singlestep(p, regs, kcb);
607 return 1;
608 }
609#endif
602 setup_singlestep(p, regs, kcb, 0); 610 setup_singlestep(p, regs, kcb, 0);
603 return 1; 611 return 1;
604 } 612 }
@@ -1053,6 +1061,21 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
1053} 1061}
1054 1062
1055#ifdef KPROBES_CAN_USE_FTRACE 1063#ifdef KPROBES_CAN_USE_FTRACE
1064static void __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
1065 struct kprobe_ctlblk *kcb)
1066{
1067 /*
1068 * Emulate singlestep (and also recover regs->ip)
1069 * as if there is a 5byte nop
1070 */
1071 regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
1072 if (unlikely(p->post_handler)) {
1073 kcb->kprobe_status = KPROBE_HIT_SSDONE;
1074 p->post_handler(p, regs, 0);
1075 }
1076 __this_cpu_write(current_kprobe, NULL);
1077}
1078
1056/* Ftrace callback handler for kprobes */ 1079/* Ftrace callback handler for kprobes */
1057void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, 1080void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
1058 struct ftrace_ops *ops, struct pt_regs *regs) 1081 struct ftrace_ops *ops, struct pt_regs *regs)
@@ -1072,21 +1095,17 @@ void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
1072 if (kprobe_running()) { 1095 if (kprobe_running()) {
1073 kprobes_inc_nmissed_count(p); 1096 kprobes_inc_nmissed_count(p);
1074 } else { 1097 } else {
1075 regs->ip += sizeof(kprobe_opcode_t); 1098 /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
1099 regs->ip = ip + sizeof(kprobe_opcode_t);
1076 1100
1077 __this_cpu_write(current_kprobe, p); 1101 __this_cpu_write(current_kprobe, p);
1078 kcb->kprobe_status = KPROBE_HIT_ACTIVE; 1102 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
1079 if (p->pre_handler) 1103 if (!p->pre_handler || !p->pre_handler(p, regs))
1080 p->pre_handler(p, regs); 1104 skip_singlestep(p, regs, kcb);
1081 1105 /*
1082 if (unlikely(p->post_handler)) { 1106 * If pre_handler returns !0, it sets regs->ip and
1083 /* Emulate singlestep as if there is a 5byte nop */ 1107 * resets current kprobe.
1084 regs->ip = ip + MCOUNT_INSN_SIZE; 1108 */
1085 kcb->kprobe_status = KPROBE_HIT_SSDONE;
1086 p->post_handler(p, regs, 0);
1087 }
1088 __this_cpu_write(current_kprobe, NULL);
1089 regs->ip = ip; /* Recover for next callback */
1090 } 1109 }
1091end: 1110end:
1092 local_irq_restore(flags); 1111 local_irq_restore(flags);
diff --git a/kernel/Makefile b/kernel/Makefile
index c0cc67ad764c..29d993be7dba 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -98,7 +98,7 @@ obj-$(CONFIG_COMPAT_BINFMT_ELF) += elfcore.o
98obj-$(CONFIG_BINFMT_ELF_FDPIC) += elfcore.o 98obj-$(CONFIG_BINFMT_ELF_FDPIC) += elfcore.o
99obj-$(CONFIG_FUNCTION_TRACER) += trace/ 99obj-$(CONFIG_FUNCTION_TRACER) += trace/
100obj-$(CONFIG_TRACING) += trace/ 100obj-$(CONFIG_TRACING) += trace/
101obj-$(CONFIG_X86_DS) += trace/ 101obj-$(CONFIG_TRACE_CLOCK) += trace/
102obj-$(CONFIG_RING_BUFFER) += trace/ 102obj-$(CONFIG_RING_BUFFER) += trace/
103obj-$(CONFIG_TRACEPOINTS) += trace/ 103obj-$(CONFIG_TRACEPOINTS) += trace/
104obj-$(CONFIG_IRQ_WORK) += irq_work.o 104obj-$(CONFIG_IRQ_WORK) += irq_work.o
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 35b4315d84f5..098f396aa409 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1418,9 +1418,6 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p,
1418 /* Given address is not on the instruction boundary */ 1418 /* Given address is not on the instruction boundary */
1419 if ((unsigned long)p->addr != ftrace_addr) 1419 if ((unsigned long)p->addr != ftrace_addr)
1420 return -EILSEQ; 1420 return -EILSEQ;
1421 /* break_handler (jprobe) can not work with ftrace */
1422 if (p->break_handler)
1423 return -EINVAL;
1424 p->flags |= KPROBE_FLAG_FTRACE; 1421 p->flags |= KPROBE_FLAG_FTRACE;
1425#else /* !KPROBES_CAN_USE_FTRACE */ 1422#else /* !KPROBES_CAN_USE_FTRACE */
1426 return -EINVAL; 1423 return -EINVAL;
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 9301a0e35e0c..4cea4f41c1d9 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -62,8 +62,12 @@ config HAVE_C_RECORDMCOUNT
62config TRACER_MAX_TRACE 62config TRACER_MAX_TRACE
63 bool 63 bool
64 64
65config TRACE_CLOCK
66 bool
67
65config RING_BUFFER 68config RING_BUFFER
66 bool 69 bool
70 select TRACE_CLOCK
67 71
68config FTRACE_NMI_ENTER 72config FTRACE_NMI_ENTER
69 bool 73 bool
@@ -114,6 +118,7 @@ config TRACING
114 select NOP_TRACER 118 select NOP_TRACER
115 select BINARY_PRINTF 119 select BINARY_PRINTF
116 select EVENT_TRACING 120 select EVENT_TRACING
121 select TRACE_CLOCK
117 122
118config GENERIC_TRACER 123config GENERIC_TRACER
119 bool 124 bool
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 837090808aac..d7e2068e4b71 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -19,11 +19,7 @@ endif
19 19
20CFLAGS_trace_events_filter.o := -I$(src) 20CFLAGS_trace_events_filter.o := -I$(src)
21 21
22# 22obj-$(CONFIG_TRACE_CLOCK) += trace_clock.o
23# Make the trace clocks available generally: it's infrastructure
24# relied on by ptrace for example:
25#
26obj-y += trace_clock.o
27 23
28obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o 24obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
29obj-$(CONFIG_RING_BUFFER) += ring_buffer.o 25obj-$(CONFIG_RING_BUFFER) += ring_buffer.o
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 6825d833a257..bbb0e63d78e9 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1646,9 +1646,11 @@ static __init void event_trace_self_tests(void)
1646 event_test_stuff(); 1646 event_test_stuff();
1647 1647
1648 ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0); 1648 ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0);
1649 if (WARN_ON_ONCE(ret)) 1649 if (WARN_ON_ONCE(ret)) {
1650 pr_warning("error disabling system %s\n", 1650 pr_warning("error disabling system %s\n",
1651 system->name); 1651 system->name);
1652 continue;
1653 }
1652 1654
1653 pr_cont("OK\n"); 1655 pr_cont("OK\n");
1654 } 1656 }