diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2020-05-13 12:14:05 -0400 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2020-05-13 12:14:05 -0400 |
| commit | 4aef2ec9022b217f74d0f4c9b84081f07cc223d9 (patch) | |
| tree | edf9bb9ca1f8ab6345c156a7e87aaed28939f66c /arch/csky/kernel/probes/ftrace.c | |
| parent | 7c67f54661fcc8d141fb11abbab1739f32e13b03 (diff) | |
| parent | 37486135d3a7b03acc7755b63627a130437f066a (diff) | |
| download | linux-4aef2ec9022b217f74d0f4c9b84081f07cc223d9.tar.bz2 | |
Merge branch 'kvm-amd-fixes' into HEAD
Diffstat (limited to 'arch/csky/kernel/probes/ftrace.c')
| -rw-r--r-- | arch/csky/kernel/probes/ftrace.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/csky/kernel/probes/ftrace.c b/arch/csky/kernel/probes/ftrace.c new file mode 100644 index 000000000000..5264763d05be --- /dev/null +++ b/arch/csky/kernel/probes/ftrace.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/kprobes.h> + +int arch_check_ftrace_location(struct kprobe *p) +{ + if (ftrace_location((unsigned long)p->addr)) + p->flags |= KPROBE_FLAG_FTRACE; + return 0; +} + +/* Ftrace callback handler for kprobes -- called under preepmt disabed */ +void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *ops, struct pt_regs *regs) +{ + bool lr_saver = false; + struct kprobe *p; + struct kprobe_ctlblk *kcb; + + /* Preempt is disabled by ftrace */ + p = get_kprobe((kprobe_opcode_t *)ip); + if (!p) { + p = get_kprobe((kprobe_opcode_t *)(ip - MCOUNT_INSN_SIZE)); + if (unlikely(!p) || kprobe_disabled(p)) + return; + lr_saver = true; + } + + kcb = get_kprobe_ctlblk(); + if (kprobe_running()) { + kprobes_inc_nmissed_count(p); + } else { + unsigned long orig_ip = instruction_pointer(regs); + + if (lr_saver) + ip -= MCOUNT_INSN_SIZE; + instruction_pointer_set(regs, ip); + __this_cpu_write(current_kprobe, p); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + if (!p->pre_handler || !p->pre_handler(p, regs)) { + /* + * Emulate singlestep (and also recover regs->pc) + * as if there is a nop + */ + instruction_pointer_set(regs, + (unsigned long)p->addr + MCOUNT_INSN_SIZE); + if (unlikely(p->post_handler)) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + p->post_handler(p, regs, 0); + } + instruction_pointer_set(regs, orig_ip); + } + /* + * If pre_handler returns !0, it changes regs->pc. We have to + * skip emulating post_handler. + */ + __this_cpu_write(current_kprobe, NULL); + } +} +NOKPROBE_SYMBOL(kprobe_ftrace_handler); + +int arch_prepare_kprobe_ftrace(struct kprobe *p) +{ + p->ainsn.api.insn = NULL; + return 0; +} |