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]

[PATCH] (updated) Allow a jprobe to coexist with kprobes


Hi,

I found a few issues with the patch I sent earlier. Here is the updated
patch.

Rusty,
With this patch, the "moving kprobe [dis]arm into arch specific" patch
may need a few minor tweaks.

Anil,
Please use this patch for testing on x86_64.

Thanks,
Ananth
This patch allows a jprobe to coexist with other kprobes at a given address.
Two jprobes can't (yet) coexist.

Signed-off-by: Ananth N Mavinakayanahalli <amavin@redhat.com>

 arch/i386/kernel/kprobes.c    |   14 ++++++++++--
 arch/ppc64/kernel/kprobes.c   |   14 ++++++++++--
 arch/sparc64/kernel/kprobes.c |   15 +++++++++++--
 arch/x86_64/kernel/kprobes.c  |   14 ++++++++++--
 include/linux/kprobes.h       |    1 
 kernel/kprobes.c              |   48 ++++++++++++++++++++++++++++++++++--------
 6 files changed, 89 insertions(+), 17 deletions(-)

Index: linux-2.6.12-rc4/arch/i386/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc4.orig/arch/i386/kernel/kprobes.c	2005-05-16 07:55:43.000000000 -0400
+++ linux-2.6.12-rc4/arch/i386/kernel/kprobes.c	2005-05-16 08:16:02.000000000 -0400
@@ -148,6 +148,7 @@ void arch_kprobe_flush_task(struct task_
 static int kprobe_handler(struct pt_regs *regs)
 {
 	struct kprobe *p;
+	struct kprobe *kp = NULL;
 	int ret = 0;
 	kprobe_opcode_t *addr = NULL;
 	unsigned long *lp;
@@ -181,8 +182,17 @@ static int kprobe_handler(struct pt_regs
 			ret = 1;
 		} else {
 			p = current_kprobe;
-			if (p->break_handler && p->break_handler(p, regs)) {
-				goto ss_probe;
+			if (p->pre_handler == aggr_pre_handler) {
+				/* jprobe-kprobe coexistance */
+				list_for_each_entry(kp, &p->list, list) {
+					if (kp->break_handler &&
+						kp->break_handler(kp, regs))
+						goto ss_probe;
+				}
+			} else {
+				if (p->break_handler &&
+						p->break_handler(p, regs))
+					goto ss_probe;
 			}
 		}
 		/* If it's not ours, can't be delete race, (we hold lock). */
Index: linux-2.6.12-rc4/arch/ppc64/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc4.orig/arch/ppc64/kernel/kprobes.c	2005-05-07 01:20:31.000000000 -0400
+++ linux-2.6.12-rc4/arch/ppc64/kernel/kprobes.c	2005-05-16 08:16:02.000000000 -0400
@@ -81,6 +81,7 @@ static inline void prepare_singlestep(st
 static inline int kprobe_handler(struct pt_regs *regs)
 {
 	struct kprobe *p;
+	struct kprobe *kp = NULL;
 	int ret = 0;
 	unsigned int *addr = (unsigned int *)regs->nip;
 
@@ -100,8 +101,17 @@ static inline int kprobe_handler(struct 
 			ret = 1;
 		} else {
 			p = current_kprobe;
-			if (p->break_handler && p->break_handler(p, regs)) {
-				goto ss_probe;
+			if (p->pre_handler == aggr_pre_handler) {
+				/* jprobe-kprobe coexistance */
+				list_for_each_entry(kp, &p->list, list) {
+					if (kp->break_handler &&
+						kp->break_handler(kp, regs))
+						goto ss_probe;
+				}
+			} else {
+				if (p->break_handler &&
+						p->break_handler(p, regs))
+					goto ss_probe;
 			}
 		}
 		/* If it's not ours, can't be delete race, (we hold lock). */
Index: linux-2.6.12-rc4/arch/sparc64/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc4.orig/arch/sparc64/kernel/kprobes.c	2005-05-07 01:20:31.000000000 -0400
+++ linux-2.6.12-rc4/arch/sparc64/kernel/kprobes.c	2005-05-16 08:16:02.000000000 -0400
@@ -92,6 +92,7 @@ static inline void disarm_kprobe(struct 
 static int kprobe_handler(struct pt_regs *regs)
 {
 	struct kprobe *p;
+	struct kprobe *kp = NULL;
 	void *addr = (void *) regs->tpc;
 	int ret = 0;
 
@@ -113,8 +114,18 @@ static int kprobe_handler(struct pt_regs
 			ret = 1;
 		} else {
 			p = current_kprobe;
-			if (p->break_handler && p->break_handler(p, regs))
-				goto ss_probe;
+			if (p->pre_handler == aggr_pre_handler) {
+				/* jprobe-kprobe coexistance */
+				list_for_each_entry(kp, &p->list, list) {
+					if (kp->break_handler &&
+						kp->break_handler(kp, regs))
+						goto ss_probe;
+				}
+			} else {
+				if (p->break_handler &&
+						p->break_handler(p, regs))
+					goto ss_probe;
+			}
 		}
 		/* If it's not ours, can't be delete race, (we hold lock). */
 		goto no_kprobe;
Index: linux-2.6.12-rc4/arch/x86_64/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc4.orig/arch/x86_64/kernel/kprobes.c	2005-05-07 01:20:31.000000000 -0400
+++ linux-2.6.12-rc4/arch/x86_64/kernel/kprobes.c	2005-05-16 08:16:02.000000000 -0400
@@ -247,6 +247,7 @@ static void prepare_singlestep(struct kp
 int kprobe_handler(struct pt_regs *regs)
 {
 	struct kprobe *p;
+	struct kprobe *kp = NULL;
 	int ret = 0;
 	kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->rip - sizeof(kprobe_opcode_t));
 
@@ -269,8 +270,17 @@ int kprobe_handler(struct pt_regs *regs)
 			ret = 1;
 		} else {
 			p = current_kprobe;
-			if (p->break_handler && p->break_handler(p, regs)) {
-				goto ss_probe;
+			if (p->pre_handler == aggr_pre_handler) {
+				/* jprobe-kprobe co-existance */
+				list_for_each_entry(kp, &p->list, list) {
+					if (kp->break_handler &&
+						kp->break_handler(kp, regs))
+						goto ss_probe;
+				}
+			} else {
+				if (p->break_handler &&
+						p->break_handler(p, regs)) {
+					goto ss_probe;
 			}
 		}
 		/* If it's not ours, can't be delete race, (we hold lock). */
Index: linux-2.6.12-rc4/include/linux/kprobes.h
===================================================================
--- linux-2.6.12-rc4.orig/include/linux/kprobes.h	2005-05-16 07:56:07.000000000 -0400
+++ linux-2.6.12-rc4/include/linux/kprobes.h	2005-05-16 08:16:02.000000000 -0400
@@ -168,6 +168,7 @@ extern int arch_prepare_kprobe(struct kp
 extern void arch_copy_kprobe(struct kprobe *p);
 extern void arch_remove_kprobe(struct kprobe *p);
 extern void show_registers(struct pt_regs *regs);
+extern int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs);
 
 /* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
 struct kprobe *get_kprobe(void *addr);
Index: linux-2.6.12-rc4/kernel/kprobes.c
===================================================================
--- linux-2.6.12-rc4.orig/kernel/kprobes.c	2005-05-16 07:56:07.000000000 -0400
+++ linux-2.6.12-rc4/kernel/kprobes.c	2005-05-16 08:43:08.000000000 -0400
@@ -89,7 +89,10 @@ int aggr_pre_handler(struct kprobe *p, s
 	list_for_each_entry(kp, &p->list, list) {
 		if (kp->pre_handler) {
 			curr_kprobe = kp;
-			kp->pre_handler(kp, regs);
+			if (kp->pre_handler(kp, regs)) {
+				curr_kprobe = NULL;
+				return 1;
+			}
 			curr_kprobe = NULL;
 		}
 	}
@@ -254,15 +257,42 @@ inline void free_rp_inst(struct kretprob
 }
 
 /*
+ * Add the new probe to old_p->list. Fail if this is the
+ * second jprobe at the address - two jprobes can't coexist
+ */
+static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
+{
+	struct kprobe *kp;
+
+	if (p->break_handler) {
+		list_for_each_entry(kp, &old_p->list, list) {
+			if (kp->break_handler)
+				return -EEXIST;
+		}
+		list_add_tail(&p->list, &old_p->list);
+	} else
+		list_add(&p->list, &old_p->list);
+	return 0;
+}
+
+/*
+ * Fill out these fields so we have a valid opcode and
+ * insn if the kprobe is passed to disram_kprobe()
+ */
+static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
+{
+	memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
+	memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
+}
+
+/*
  * Fill in the required fields of the "manager kprobe". Replace the
  * earlier kprobe in the hlist with the manager kprobe
  */
 static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
 {
+	copy_kprobe(p, ap);
 	ap->addr = p->addr;
-	ap->opcode = p->opcode;
-	memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn));
-
 	ap->pre_handler = aggr_pre_handler;
 	ap->post_handler = aggr_post_handler;
 	ap->fault_handler = aggr_fault_handler;
@@ -286,16 +316,16 @@ static int register_aggr_kprobe(struct k
 	int ret = 0;
 	struct kprobe *ap;
 
-	if (old_p->break_handler || p->break_handler) {
-		ret = -EEXIST;	/* kprobe and jprobe can't (yet) coexist */
-	} else if (old_p->pre_handler == aggr_pre_handler) {
-		list_add(&p->list, &old_p->list);
+	if (old_p->pre_handler == aggr_pre_handler) {
+		copy_kprobe(old_p, p);
+		ret = add_new_kprobe(old_p, p);
 	} else {
 		ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC);
 		if (!ap)
 			return -ENOMEM;
 		add_aggr_kprobe(ap, old_p);
-		list_add(&p->list, &ap->list);
+		copy_kprobe(ap, p);
+		ret = add_new_kprobe(ap, p);
 	}
 	return ret;
 }

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