mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
1.8 KiB
72 lines
1.8 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Dynamic Ftrace based Kprobes Optimization |
|
* |
|
* Copyright (C) Hitachi Ltd., 2012 |
|
*/ |
|
#include <linux/kprobes.h> |
|
#include <linux/ptrace.h> |
|
#include <linux/hardirq.h> |
|
#include <linux/preempt.h> |
|
#include <linux/ftrace.h> |
|
|
|
#include "common.h" |
|
|
|
/* Ftrace callback handler for kprobes -- called under preepmt disabled */ |
|
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, |
|
struct ftrace_ops *ops, struct ftrace_regs *fregs) |
|
{ |
|
struct pt_regs *regs = ftrace_get_regs(fregs); |
|
struct kprobe *p; |
|
struct kprobe_ctlblk *kcb; |
|
int bit; |
|
|
|
bit = ftrace_test_recursion_trylock(ip, parent_ip); |
|
if (bit < 0) |
|
return; |
|
|
|
preempt_disable_notrace(); |
|
p = get_kprobe((kprobe_opcode_t *)ip); |
|
if (unlikely(!p) || kprobe_disabled(p)) |
|
goto out; |
|
|
|
kcb = get_kprobe_ctlblk(); |
|
if (kprobe_running()) { |
|
kprobes_inc_nmissed_count(p); |
|
} else { |
|
unsigned long orig_ip = regs->ip; |
|
/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ |
|
regs->ip = ip + sizeof(kprobe_opcode_t); |
|
|
|
__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->ip) |
|
* as if there is a 5byte nop |
|
*/ |
|
regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE; |
|
if (unlikely(p->post_handler)) { |
|
kcb->kprobe_status = KPROBE_HIT_SSDONE; |
|
p->post_handler(p, regs, 0); |
|
} |
|
regs->ip = orig_ip; |
|
} |
|
/* |
|
* If pre_handler returns !0, it changes regs->ip. We have to |
|
* skip emulating post_handler. |
|
*/ |
|
__this_cpu_write(current_kprobe, NULL); |
|
} |
|
out: |
|
preempt_enable_notrace(); |
|
ftrace_test_recursion_unlock(bit); |
|
} |
|
NOKPROBE_SYMBOL(kprobe_ftrace_handler); |
|
|
|
int arch_prepare_kprobe_ftrace(struct kprobe *p) |
|
{ |
|
p->ainsn.insn = NULL; |
|
p->ainsn.boostable = false; |
|
return 0; |
|
}
|
|
|