Skip to content

Commit

Permalink
[PATCH] kprobes: Temporary disarming of reentrant probe for i386
Browse files Browse the repository at this point in the history
This patch includes i386 architecture specific changes to support temporary
disarming on reentrancy of probes.

Signed-of-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Prasanna S Panchamukhi authored and Linus Torvalds committed Jun 23, 2005
1 parent ea32c65 commit 417c8da
Showing 1 changed file with 49 additions and 13 deletions.
62 changes: 49 additions & 13 deletions arch/i386/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@
#include <asm/kdebug.h>
#include <asm/desc.h>

/* kprobe_status settings */
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002

static struct kprobe *current_kprobe;
static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
static struct kprobe *kprobe_prev;
static unsigned long kprobe_status_prev, kprobe_old_eflags_prev, kprobe_saved_eflags_prev;
static struct pt_regs jprobe_saved_regs;
static long *jprobe_saved_esp;
/* copy of the kernel stack at the probe fire time */
Expand Down Expand Up @@ -93,6 +91,31 @@ void arch_remove_kprobe(struct kprobe *p)
{
}

static inline void save_previous_kprobe(void)
{
kprobe_prev = current_kprobe;
kprobe_status_prev = kprobe_status;
kprobe_old_eflags_prev = kprobe_old_eflags;
kprobe_saved_eflags_prev = kprobe_saved_eflags;
}

static inline void restore_previous_kprobe(void)
{
current_kprobe = kprobe_prev;
kprobe_status = kprobe_status_prev;
kprobe_old_eflags = kprobe_old_eflags_prev;
kprobe_saved_eflags = kprobe_saved_eflags_prev;
}

static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
{
current_kprobe = p;
kprobe_saved_eflags = kprobe_old_eflags
= (regs->eflags & (TF_MASK | IF_MASK));
if (is_IF_modifier(p->opcode))
kprobe_saved_eflags &= ~IF_MASK;
}

static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
regs->eflags |= TF_MASK;
Expand Down Expand Up @@ -184,9 +207,18 @@ static int kprobe_handler(struct pt_regs *regs)
unlock_kprobes();
goto no_kprobe;
}
arch_disarm_kprobe(p);
regs->eip = (unsigned long)p->addr;
ret = 1;
/* We have reentered the kprobe_handler(), since
* another probe was hit while within the handler.
* We here save the original kprobes variables and
* just single step on the instruction of the new probe
* without calling any user handlers.
*/
save_previous_kprobe();
set_current_kprobe(p, regs);
p->nmissed++;
prepare_singlestep(p, regs);
kprobe_status = KPROBE_REENTER;
return 1;
} else {
p = current_kprobe;
if (p->break_handler && p->break_handler(p, regs)) {
Expand Down Expand Up @@ -221,11 +253,7 @@ static int kprobe_handler(struct pt_regs *regs)
}

kprobe_status = KPROBE_HIT_ACTIVE;
current_kprobe = p;
kprobe_saved_eflags = kprobe_old_eflags
= (regs->eflags & (TF_MASK | IF_MASK));
if (is_IF_modifier(p->opcode))
kprobe_saved_eflags &= ~IF_MASK;
set_current_kprobe(p, regs);

if (p->pre_handler && p->pre_handler(p, regs))
/* handler has already set things up, so skip ss setup */
Expand Down Expand Up @@ -370,14 +398,22 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
if (!kprobe_running())
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);
}

if (current_kprobe->post_handler != trampoline_post_handler)
resume_execution(current_kprobe, regs);
regs->eflags |= kprobe_saved_eflags;

/*Restore back the original saved kprobes variables and continue. */
if (kprobe_status == KPROBE_REENTER) {
restore_previous_kprobe();
goto out;
}
unlock_kprobes();
out:
preempt_enable_no_resched();

/*
Expand Down

0 comments on commit 417c8da

Please sign in to comment.