[PATCH] kprobes: Temporary disarming of reentrant probe for sparc64

This patch includes sparc64 architecture specific changes to support temporary
disarming on reentrancy of probes.

Signed-of-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Prasanna S Panchamukhi 2005-06-23 00:09:39 -07:00 committed by Linus Torvalds
parent 42cc20600a
commit e539c23314

View File

@ -65,19 +65,40 @@ void arch_remove_kprobe(struct kprobe *p)
{ {
} }
/* kprobe_status settings */
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002
static struct kprobe *current_kprobe; static struct kprobe *current_kprobe;
static unsigned long current_kprobe_orig_tnpc; static unsigned long current_kprobe_orig_tnpc;
static unsigned long current_kprobe_orig_tstate_pil; static unsigned long current_kprobe_orig_tstate_pil;
static unsigned int kprobe_status; 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 prepare_singlestep(struct kprobe *p, struct pt_regs *regs) static inline void save_previous_kprobe(void)
{
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;
}
static inline void restore_previous_kprobe(void)
{
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;
}
static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
{ {
current_kprobe_orig_tnpc = regs->tnpc; current_kprobe_orig_tnpc = regs->tnpc;
current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
current_kprobe = p;
}
static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
regs->tstate |= TSTATE_PIL; regs->tstate |= TSTATE_PIL;
/*single step inline, if it a breakpoint instruction*/ /*single step inline, if it a breakpoint instruction*/
@ -110,12 +131,18 @@ static int kprobe_handler(struct pt_regs *regs)
unlock_kprobes(); unlock_kprobes();
goto no_kprobe; goto no_kprobe;
} }
arch_disarm_kprobe(p); /* We have reentered the kprobe_handler(), since
regs->tpc = (unsigned long) p->addr; * another probe was hit while within the handler.
regs->tnpc = current_kprobe_orig_tnpc; * We here save the original kprobes variables and
regs->tstate = ((regs->tstate & ~TSTATE_PIL) | * just single step on the instruction of the new probe
current_kprobe_orig_tstate_pil); * without calling any user handlers.
ret = 1; */
save_previous_kprobe();
set_current_kprobe(p, regs);
p->nmissed++;
kprobe_status = KPROBE_REENTER;
prepare_singlestep(p, regs);
return 1;
} else { } else {
p = current_kprobe; p = current_kprobe;
if (p->break_handler && p->break_handler(p, regs)) if (p->break_handler && p->break_handler(p, regs))
@ -143,8 +170,8 @@ static int kprobe_handler(struct pt_regs *regs)
goto no_kprobe; goto no_kprobe;
} }
set_current_kprobe(p, regs);
kprobe_status = KPROBE_HIT_ACTIVE; kprobe_status = KPROBE_HIT_ACTIVE;
current_kprobe = p;
if (p->pre_handler && p->pre_handler(p, regs)) if (p->pre_handler && p->pre_handler(p, regs))
return 1; return 1;
@ -250,12 +277,20 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
if (!kprobe_running()) if (!kprobe_running())
return 0; return 0;
if (current_kprobe->post_handler) if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) {
kprobe_status = KPROBE_HIT_SSDONE;
current_kprobe->post_handler(current_kprobe, regs, 0); current_kprobe->post_handler(current_kprobe, regs, 0);
}
resume_execution(current_kprobe, regs); resume_execution(current_kprobe, regs);
/*Restore back the original saved kprobes variables and continue. */
if (kprobe_status == KPROBE_REENTER) {
restore_previous_kprobe();
goto out;
}
unlock_kprobes(); unlock_kprobes();
out:
preempt_enable_no_resched(); preempt_enable_no_resched();
return 1; return 1;
@ -397,3 +432,4 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
} }
return 0; return 0;
} }