This is the mail archive of the systemtap@sources.redhat.com mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: reentrant probes


> > Queue the work thread to the workqueue for rearming the probe.
> > Since flushing the instruction cache within the interrupt handler is
> > not safe, we queue the work to be handled outside the interrupt
> context.
> > The worker thread just rearms it by writting int3. Also removes the
> kprobe from
> > the  disarm list and adds it to the kprobes list.
> > 
> > But there will a small window between the probe being disarmed and
> > rearmed, were the disarmed probes will be missed.
> > 
> 
> 
> I like this idea of arming and disarming the probes.  Though it will be
> nice to have this through /proc or some such user interface.  A user
> should be able to specify which probes need to be disarmed/deactivated
> temporarily (without unregistering them).  I think it also will be
> useful to let user (probe writer) specify if a specific probe is to be
> marked not reentrant.  And in this case, basically you don't execute the
> pre and post handler.  The original instruction will execute as part of
> int3 handling.
> 

Another alternative approach to disarm the probes temporarily is 
to handle the new probe by single stepping without calling the registered user 
handlers. Please find the patch below. Thanks to Suparna for suggesting this. 
Please provide your feedback on this patch. I will soon port it to other 
architectures and post it.

Thanks
Prasanna

In situations where a kprobes handler calls a routine which has a probe on it,
then kprobes_handler() disarms the new probe forever. This patch just 
temporarily disarms the new probe and allows the new probe to single step 
without calling the user registered handlers. It saves the original kprobes 
variables before allowing the new probe to single step and later restores them
back after the new kprobe single steps.

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



---

 linux-2.6.12-rc3-prasanna/arch/i386/kernel/kprobes.c |   59 ++++++++++++++++---
 1 files changed, 51 insertions(+), 8 deletions(-)

diff -puN arch/i386/kernel/kprobes.c~kprobes-temporarily-disarm arch/i386/kernel/kprobes.c
--- linux-2.6.12-rc3/arch/i386/kernel/kprobes.c~kprobes-temporarily-disarm	2005-05-05 18:33:55.000000000 +0530
+++ linux-2.6.12-rc3-prasanna/arch/i386/kernel/kprobes.c	2005-05-05 18:33:55.000000000 +0530
@@ -36,9 +36,13 @@
 /* kprobe_status settings */
 #define KPROBE_HIT_ACTIVE	0x00000001
 #define KPROBE_HIT_SS		0x00000002
+#define KPROBE_HIT_SS_REENTER	0x00000004
+#define KPROBE_HIT_SS_DONE	0x00000008
 
 static struct kprobe *current_kprobe;
 static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
+static struct kprobe *prevcurrent_kprobe;
+static unsigned long prevkprobe_status, prevkprobe_old_eflags, prevkprobe_saved_eflags;
 static struct pt_regs jprobe_saved_regs;
 static long *jprobe_saved_esp;
 /* copy of the kernel stack at the probe fire time */
@@ -80,6 +84,31 @@ static inline void disarm_kprobe(struct 
 	regs->eip = (unsigned long)p->addr;
 }
 
+static inline void save_orig_kprobevar(void)
+{
+	prevcurrent_kprobe = current_kprobe;
+	prevkprobe_status = kprobe_status;
+	prevkprobe_old_eflags = kprobe_old_eflags;
+	prevkprobe_saved_eflags = kprobe_saved_eflags;
+}
+
+static inline void restore_orig_kprobevar(void)
+{
+	current_kprobe = prevcurrent_kprobe;
+	kprobe_status = prevkprobe_status;
+	kprobe_old_eflags = prevkprobe_old_eflags;
+	kprobe_saved_eflags = prevkprobe_saved_eflags;
+}
+
+static inline void save_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;
@@ -127,8 +156,17 @@ static int kprobe_handler(struct pt_regs
 				unlock_kprobes();
 				goto no_kprobe;
 			}
-			disarm_kprobe(p, regs);
-			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 new routine without calling
+			 * any user handlers.
+			 */
+			save_orig_kprobevar();
+			save_current_kprobe(p,regs);
+			prepare_singlestep(p, regs);
+			kprobe_status = KPROBE_HIT_SS_REENTER;
+			return 1;
 		} else {
 			p = current_kprobe;
 			if (p->break_handler && p->break_handler(p, regs)) {
@@ -163,11 +201,7 @@ static int kprobe_handler(struct pt_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;
+	save_current_kprobe(p, regs);
 
 	if (p->pre_handler && p->pre_handler(p, regs))
 		/* handler has already set things up, so skip ss setup */
@@ -256,13 +290,22 @@ static inline int post_kprobe_handler(st
 	if (!kprobe_running())
 		return 0;
 
-	if (current_kprobe->post_handler)
+
+	if ((kprobe_status != KPROBE_HIT_SS_REENTER) && current_kprobe->post_handler) {
+		kprobe_status = KPROBE_HIT_SS_DONE;
 		current_kprobe->post_handler(current_kprobe, regs, 0);
+	}
 
 	resume_execution(current_kprobe, regs);
 	regs->eflags |= kprobe_saved_eflags;
 
+	/*Restore back the original saved kprobes variables and continue. */
+	if (kprobe_status == KPROBE_HIT_SS_REENTER) {
+		restore_orig_kprobevar();
+		goto out;
+	}
 	unlock_kprobes();
+out:
 	preempt_enable_no_resched();
 
 	/*

_
-- 

Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<prasanna@in.ibm.com>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]