提交 f215d985 编写于 作者: A Ananth N Mavinakayanahalli 提交者: Linus Torvalds

[PATCH] Kprobes: Track kprobe on a per_cpu basis - sparc64 changes

Sparc64 changes to track kprobe execution on a per-cpu basis.  We now track
the kprobe state machine independently on each cpu using an arch specific
kprobe control block.
Signed-off-by: NAnanth N Mavinakayanahalli <ananth@in.ibm.com>
Signed-off-by: NAnil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 0dc036c9
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -38,6 +38,9 @@
* - Mark that we are no longer actively in a kprobe.
*/
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
return 0;
......@@ -66,46 +69,39 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
{
}
static struct kprobe *current_kprobe;
static unsigned long current_kprobe_orig_tnpc;
static unsigned long current_kprobe_orig_tstate_pil;
static unsigned int kprobe_status;
static struct kprobe *kprobe_prev;
static unsigned long kprobe_orig_tnpc_prev;
static unsigned long kprobe_orig_tstate_pil_prev;
static unsigned int kprobe_status_prev;
static inline void save_previous_kprobe(void)
static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kprobe_status_prev = kprobe_status;
kprobe_orig_tnpc_prev = current_kprobe_orig_tnpc;
kprobe_orig_tstate_pil_prev = current_kprobe_orig_tstate_pil;
kprobe_prev = current_kprobe;
kcb->prev_kprobe.kp = kprobe_running();
kcb->prev_kprobe.status = kcb->kprobe_status;
kcb->prev_kprobe.orig_tnpc = kcb->kprobe_orig_tnpc;
kcb->prev_kprobe.orig_tstate_pil = kcb->kprobe_orig_tstate_pil;
}
static inline void restore_previous_kprobe(void)
static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kprobe_status = kprobe_status_prev;
current_kprobe_orig_tnpc = kprobe_orig_tnpc_prev;
current_kprobe_orig_tstate_pil = kprobe_orig_tstate_pil_prev;
current_kprobe = kprobe_prev;
__get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
kcb->kprobe_status = kcb->prev_kprobe.status;
kcb->kprobe_orig_tnpc = kcb->prev_kprobe.orig_tnpc;
kcb->kprobe_orig_tstate_pil = kcb->prev_kprobe.orig_tstate_pil;
}
static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
current_kprobe_orig_tnpc = regs->tnpc;
current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
current_kprobe = p;
__get_cpu_var(current_kprobe) = p;
kcb->kprobe_orig_tnpc = regs->tnpc;
kcb->kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
}
static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
regs->tstate |= TSTATE_PIL;
/*single step inline, if it a breakpoint instruction*/
if (p->opcode == BREAKPOINT_INSTRUCTION) {
regs->tpc = (unsigned long) p->addr;
regs->tnpc = current_kprobe_orig_tnpc;
regs->tnpc = kcb->kprobe_orig_tnpc;
} else {
regs->tpc = (unsigned long) &p->ainsn.insn[0];
regs->tnpc = (unsigned long) &p->ainsn.insn[1];
......@@ -117,6 +113,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
struct kprobe *p;
void *addr = (void *) regs->tpc;
int ret = 0;
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (kprobe_running()) {
/* We *are* holding lock here, so this is safe.
......@@ -124,9 +121,9 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
*/
p = get_kprobe(addr);
if (p) {
if (kprobe_status == KPROBE_HIT_SS) {
if (kcb->kprobe_status == KPROBE_HIT_SS) {
regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
current_kprobe_orig_tstate_pil);
kcb->kprobe_orig_tstate_pil);
unlock_kprobes();
goto no_kprobe;
}
......@@ -136,14 +133,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
* just single step on the instruction of the new probe
* without calling any user handlers.
*/
save_previous_kprobe();
set_current_kprobe(p, regs);
save_previous_kprobe(kcb);
set_current_kprobe(p, regs, kcb);
p->nmissed++;
kprobe_status = KPROBE_REENTER;
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_REENTER;
prepare_singlestep(p, regs, kcb);
return 1;
} else {
p = current_kprobe;
p = __get_cpu_var(current_kprobe);
if (p->break_handler && p->break_handler(p, regs))
goto ss_probe;
}
......@@ -174,14 +171,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
* in post_kprobes_handler()
*/
preempt_disable();
set_current_kprobe(p, regs);
kprobe_status = KPROBE_HIT_ACTIVE;
set_current_kprobe(p, regs, kcb);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
if (p->pre_handler && p->pre_handler(p, regs))
return 1;
ss_probe:
prepare_singlestep(p, regs);
kprobe_status = KPROBE_HIT_SS;
prepare_singlestep(p, regs, kcb);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
no_kprobe:
......@@ -262,11 +259,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
* This function prepares to return from the post-single-step
* breakpoint trap.
*/
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
static void __kprobes resume_execution(struct kprobe *p,
struct pt_regs *regs, struct kprobe_ctlblk *kcb)
{
u32 insn = p->ainsn.insn[0];
regs->tpc = current_kprobe_orig_tnpc;
regs->tpc = kcb->kprobe_orig_tnpc;
regs->tnpc = relbranch_fixup(insn,
(unsigned long) p->addr,
(unsigned long) &p->ainsn.insn[0],
......@@ -274,26 +272,30 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
retpc_fixup(regs, insn, (unsigned long) p->addr);
regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
current_kprobe_orig_tstate_pil);
kcb->kprobe_orig_tstate_pil);
}
static inline int post_kprobe_handler(struct pt_regs *regs)
{
if (!kprobe_running())
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (!cur)
return 0;
if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) {
kprobe_status = KPROBE_HIT_SSDONE;
current_kprobe->post_handler(current_kprobe, regs, 0);
if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
kcb->kprobe_status = KPROBE_HIT_SSDONE;
cur->post_handler(cur, regs, 0);
}
resume_execution(current_kprobe, regs);
resume_execution(cur, regs, kcb);
/*Restore back the original saved kprobes variables and continue. */
if (kprobe_status == KPROBE_REENTER) {
restore_previous_kprobe();
if (kcb->kprobe_status == KPROBE_REENTER) {
restore_previous_kprobe(kcb);
goto out;
}
reset_current_kprobe();
unlock_kprobes();
out:
preempt_enable_no_resched();
......@@ -304,13 +306,16 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
/* Interrupts disabled, kprobe_lock held. */
static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
if (current_kprobe->fault_handler
&& current_kprobe->fault_handler(current_kprobe, regs, trapnr))
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
return 1;
if (kprobe_status & KPROBE_HIT_SS) {
resume_execution(current_kprobe, regs);
if (kcb->kprobe_status & KPROBE_HIT_SS) {
resume_execution(cur, regs, kcb);
reset_current_kprobe();
unlock_kprobes();
preempt_enable_no_resched();
}
......@@ -370,24 +375,21 @@ asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
}
/* Jprobes support. */
static struct pt_regs jprobe_saved_regs;
static struct pt_regs *jprobe_saved_regs_location;
static struct sparc_stackf jprobe_saved_stack;
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
jprobe_saved_regs_location = regs;
memcpy(&jprobe_saved_regs, regs, sizeof(*regs));
kcb->jprobe_saved_regs_location = regs;
memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs));
/* Save a whole stack frame, this gets arguments
* pushed onto the stack after using up all the
* arg registers.
*/
memcpy(&jprobe_saved_stack,
memcpy(&(kcb->jprobe_saved_stack),
(char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
sizeof(jprobe_saved_stack));
sizeof(kcb->jprobe_saved_stack));
regs->tpc = (unsigned long) jp->entry;
regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
......@@ -411,14 +413,15 @@ extern void __show_regs(struct pt_regs * regs);
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
u32 *addr = (u32 *) regs->tpc;
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (addr == (u32 *) jprobe_return_trap_instruction) {
if (jprobe_saved_regs_location != regs) {
if (kcb->jprobe_saved_regs_location != regs) {
printk("JPROBE: Current regs (%p) does not match "
"saved regs (%p).\n",
regs, jprobe_saved_regs_location);
regs, kcb->jprobe_saved_regs_location);
printk("JPROBE: Saved registers\n");
__show_regs(jprobe_saved_regs_location);
__show_regs(kcb->jprobe_saved_regs_location);
printk("JPROBE: Current registers\n");
__show_regs(regs);
BUG();
......@@ -427,11 +430,11 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
* first so that UREG_FP is the original one for
* the stack frame restore.
*/
memcpy(regs, &jprobe_saved_regs, sizeof(*regs));
memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs));
memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
&jprobe_saved_stack,
sizeof(jprobe_saved_stack));
&(kcb->jprobe_saved_stack),
sizeof(kcb->jprobe_saved_stack));
return 1;
}
......
......@@ -3,6 +3,7 @@
#include <linux/config.h>
#include <linux/types.h>
#include <linux/percpu.h>
typedef u32 kprobe_opcode_t;
......@@ -18,6 +19,25 @@ struct arch_specific_insn {
kprobe_opcode_t insn[MAX_INSN_SIZE];
};
struct prev_kprobe {
struct kprobe *kp;
unsigned int status;
unsigned long orig_tnpc;
unsigned long orig_tstate_pil;
};
/* per-cpu kprobe control block */
struct kprobe_ctlblk {
unsigned long kprobe_status;
unsigned long kprobe_orig_tnpc;
unsigned long kprobe_orig_tstate_pil;
long *jprobe_saved_esp;
struct pt_regs jprobe_saved_regs;
struct pt_regs *jprobe_saved_regs_location;
struct sparc_stackf jprobe_saved_stack;
struct prev_kprobe prev_kprobe;
};
#ifdef CONFIG_KPROBES
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部