summaryrefslogtreecommitdiff
path: root/arch/ia64
diff options
context:
space:
mode:
authorAnil S Keshavamurthy <anil.s.keshavamurthy@intel.com>2005-06-23 00:09:40 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 09:45:25 -0700
commit852caccc89d3883522e87a91bfa89fd9c9cfe15a (patch)
treedbbb98df18b04f7624f72d4a80731d7309038b79 /arch/ia64
parente539c2331414e73a5a1b79fb57369d79447c1cf8 (diff)
[PATCH] Kprobes/ia64: temporary disarming of reentrant probe
This patch includes IA64 architecture specific changes(ported form i386) to support temporary disarming on reentrancy of probes. In case of reentrancy we single step without calling user handler. Signed-of-by: Anil S Keshavamurth <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/ia64')
-rw-r--r--arch/ia64/kernel/kprobes.c49
1 files changed, 43 insertions, 6 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 41e80b42d3f3..5978823d5c63 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -41,8 +41,8 @@ extern void jprobe_inst_return(void);
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002
-static struct kprobe *current_kprobe;
-static unsigned long kprobe_status;
+static struct kprobe *current_kprobe, *kprobe_prev;
+static unsigned long kprobe_status, kprobe_status_prev;
static struct pt_regs jprobe_saved_regs;
enum instruction_type {A, I, M, F, B, L, X, u};
@@ -273,6 +273,23 @@ static int valid_kprobe_addr(int template, int slot, unsigned long addr)
return 0;
}
+static inline void save_previous_kprobe(void)
+{
+ kprobe_prev = current_kprobe;
+ kprobe_status_prev = kprobe_status;
+}
+
+static inline void restore_previous_kprobe(void)
+{
+ current_kprobe = kprobe_prev;
+ kprobe_status = kprobe_status_prev;
+}
+
+static inline void set_current_kprobe(struct kprobe *p)
+{
+ current_kprobe = p;
+}
+
int arch_prepare_kprobe(struct kprobe *p)
{
unsigned long addr = (unsigned long) p->addr;
@@ -436,8 +453,18 @@ static int pre_kprobes_handler(struct die_args *args)
unlock_kprobes();
goto no_kprobe;
}
- arch_disarm_kprobe(p);
- ret = 1;
+ /* We have reentered the pre_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);
+ p->nmissed++;
+ prepare_ss(p, regs);
+ kprobe_status = KPROBE_REENTER;
+ return 1;
} else if (args->err == __IA64_BREAK_JPROBE) {
/*
* jprobe instrumented function just completed
@@ -460,7 +487,7 @@ static int pre_kprobes_handler(struct die_args *args)
}
kprobe_status = KPROBE_HIT_ACTIVE;
- current_kprobe = p;
+ set_current_kprobe(p);
if (p->pre_handler && p->pre_handler(p, regs))
/*
@@ -485,12 +512,22 @@ static int post_kprobes_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);
+ }
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();
+
+out:
preempt_enable_no_resched();
return 1;
}