diff options
| -rw-r--r-- | arch/x86/kernel/entry_32.S | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/kprobes.c | 43 | ||||
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/kprobes.c | 3 | ||||
| -rw-r--r-- | kernel/trace/Kconfig | 5 | ||||
| -rw-r--r-- | kernel/trace/Makefile | 6 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 4 |
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 | ||
| 544 | static 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 |
| 1064 | static 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 */ |
| 1057 | void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, | 1080 | void __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 | } |
| 1091 | end: | 1110 | end: |
| 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 | |||
| 98 | obj-$(CONFIG_BINFMT_ELF_FDPIC) += elfcore.o | 98 | obj-$(CONFIG_BINFMT_ELF_FDPIC) += elfcore.o |
| 99 | obj-$(CONFIG_FUNCTION_TRACER) += trace/ | 99 | obj-$(CONFIG_FUNCTION_TRACER) += trace/ |
| 100 | obj-$(CONFIG_TRACING) += trace/ | 100 | obj-$(CONFIG_TRACING) += trace/ |
| 101 | obj-$(CONFIG_X86_DS) += trace/ | 101 | obj-$(CONFIG_TRACE_CLOCK) += trace/ |
| 102 | obj-$(CONFIG_RING_BUFFER) += trace/ | 102 | obj-$(CONFIG_RING_BUFFER) += trace/ |
| 103 | obj-$(CONFIG_TRACEPOINTS) += trace/ | 103 | obj-$(CONFIG_TRACEPOINTS) += trace/ |
| 104 | obj-$(CONFIG_IRQ_WORK) += irq_work.o | 104 | obj-$(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 | |||
| 62 | config TRACER_MAX_TRACE | 62 | config TRACER_MAX_TRACE |
| 63 | bool | 63 | bool |
| 64 | 64 | ||
| 65 | config TRACE_CLOCK | ||
| 66 | bool | ||
| 67 | |||
| 65 | config RING_BUFFER | 68 | config RING_BUFFER |
| 66 | bool | 69 | bool |
| 70 | select TRACE_CLOCK | ||
| 67 | 71 | ||
| 68 | config FTRACE_NMI_ENTER | 72 | config 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 | ||
| 118 | config GENERIC_TRACER | 123 | config 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 | ||
| 20 | CFLAGS_trace_events_filter.o := -I$(src) | 20 | CFLAGS_trace_events_filter.o := -I$(src) |
| 21 | 21 | ||
| 22 | # | 22 | obj-$(CONFIG_TRACE_CLOCK) += trace_clock.o |
| 23 | # Make the trace clocks available generally: it's infrastructure | ||
| 24 | # relied on by ptrace for example: | ||
| 25 | # | ||
| 26 | obj-y += trace_clock.o | ||
| 27 | 23 | ||
| 28 | obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o | 24 | obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o |
| 29 | obj-$(CONFIG_RING_BUFFER) += ring_buffer.o | 25 | obj-$(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 | } |
