aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorPrasanna S Panchamukhi <prasanna@in.ibm.com>2005-06-23 03:09:37 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:24 -0400
commit417c8da6511b54843e6b557d94d8112d80e32156 (patch)
tree427bf0c90612b9d2dfd1a3f8e9b855a4251f9e9d /arch/i386
parentea32c65cc2d2294c04e9f81d0578a6f51febfdbf (diff)
[PATCH] kprobes: Temporary disarming of reentrant probe for i386
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>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/kprobes.c62
1 files changed, 49 insertions, 13 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index b8e2bae0ab4..3762f6b35ab 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -37,12 +37,10 @@
37#include <asm/kdebug.h> 37#include <asm/kdebug.h>
38#include <asm/desc.h> 38#include <asm/desc.h>
39 39
40/* kprobe_status settings */
41#define KPROBE_HIT_ACTIVE 0x00000001
42#define KPROBE_HIT_SS 0x00000002
43
44static struct kprobe *current_kprobe; 40static struct kprobe *current_kprobe;
45static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; 41static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
42static struct kprobe *kprobe_prev;
43static unsigned long kprobe_status_prev, kprobe_old_eflags_prev, kprobe_saved_eflags_prev;
46static struct pt_regs jprobe_saved_regs; 44static struct pt_regs jprobe_saved_regs;
47static long *jprobe_saved_esp; 45static long *jprobe_saved_esp;
48/* copy of the kernel stack at the probe fire time */ 46/* copy of the kernel stack at the probe fire time */
@@ -93,6 +91,31 @@ void arch_remove_kprobe(struct kprobe *p)
93{ 91{
94} 92}
95 93
94static inline void save_previous_kprobe(void)
95{
96 kprobe_prev = current_kprobe;
97 kprobe_status_prev = kprobe_status;
98 kprobe_old_eflags_prev = kprobe_old_eflags;
99 kprobe_saved_eflags_prev = kprobe_saved_eflags;
100}
101
102static inline void restore_previous_kprobe(void)
103{
104 current_kprobe = kprobe_prev;
105 kprobe_status = kprobe_status_prev;
106 kprobe_old_eflags = kprobe_old_eflags_prev;
107 kprobe_saved_eflags = kprobe_saved_eflags_prev;
108}
109
110static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs)
111{
112 current_kprobe = p;
113 kprobe_saved_eflags = kprobe_old_eflags
114 = (regs->eflags & (TF_MASK | IF_MASK));
115 if (is_IF_modifier(p->opcode))
116 kprobe_saved_eflags &= ~IF_MASK;
117}
118
96static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 119static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
97{ 120{
98 regs->eflags |= TF_MASK; 121 regs->eflags |= TF_MASK;
@@ -184,9 +207,18 @@ static int kprobe_handler(struct pt_regs *regs)
184 unlock_kprobes(); 207 unlock_kprobes();
185 goto no_kprobe; 208 goto no_kprobe;
186 } 209 }
187 arch_disarm_kprobe(p); 210 /* We have reentered the kprobe_handler(), since
188 regs->eip = (unsigned long)p->addr; 211 * another probe was hit while within the handler.
189 ret = 1; 212 * We here save the original kprobes variables and
213 * just single step on the instruction of the new probe
214 * without calling any user handlers.
215 */
216 save_previous_kprobe();
217 set_current_kprobe(p, regs);
218 p->nmissed++;
219 prepare_singlestep(p, regs);
220 kprobe_status = KPROBE_REENTER;
221 return 1;
190 } else { 222 } else {
191 p = current_kprobe; 223 p = current_kprobe;
192 if (p->break_handler && p->break_handler(p, regs)) { 224 if (p->break_handler && p->break_handler(p, regs)) {
@@ -221,11 +253,7 @@ static int kprobe_handler(struct pt_regs *regs)
221 } 253 }
222 254
223 kprobe_status = KPROBE_HIT_ACTIVE; 255 kprobe_status = KPROBE_HIT_ACTIVE;
224 current_kprobe = p; 256 set_current_kprobe(p, regs);
225 kprobe_saved_eflags = kprobe_old_eflags
226 = (regs->eflags & (TF_MASK | IF_MASK));
227 if (is_IF_modifier(p->opcode))
228 kprobe_saved_eflags &= ~IF_MASK;
229 257
230 if (p->pre_handler && p->pre_handler(p, regs)) 258 if (p->pre_handler && p->pre_handler(p, regs))
231 /* handler has already set things up, so skip ss setup */ 259 /* handler has already set things up, so skip ss setup */
@@ -370,14 +398,22 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
370 if (!kprobe_running()) 398 if (!kprobe_running())
371 return 0; 399 return 0;
372 400
373 if (current_kprobe->post_handler) 401 if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) {
402 kprobe_status = KPROBE_HIT_SSDONE;
374 current_kprobe->post_handler(current_kprobe, regs, 0); 403 current_kprobe->post_handler(current_kprobe, regs, 0);
404 }
375 405
376 if (current_kprobe->post_handler != trampoline_post_handler) 406 if (current_kprobe->post_handler != trampoline_post_handler)
377 resume_execution(current_kprobe, regs); 407 resume_execution(current_kprobe, regs);
378 regs->eflags |= kprobe_saved_eflags; 408 regs->eflags |= kprobe_saved_eflags;
379 409
410 /*Restore back the original saved kprobes variables and continue. */
411 if (kprobe_status == KPROBE_REENTER) {
412 restore_previous_kprobe();
413 goto out;
414 }
380 unlock_kprobes(); 415 unlock_kprobes();
416out:
381 preempt_enable_no_resched(); 417 preempt_enable_no_resched();
382 418
383 /* 419 /*