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]

[RFC] Jprobe-kprobe can coexist now- take 2


Hi,

Last week I spoke to Ananth about another approach for jprobe-kprobe
coexistance, which is similar to Ananth's approach, yet efficient and compact.
This patch avoids walking the lists during runtime and avoids changes to 
architecture specific code. As per Ananth's request, I am posting this patch 
on the lists.

This patch works fine on i386 and x86_64 architecture, however I could not test
this patch on ppc64, since multiple probes support on ppc64 seems to be broken
with the latest kernel 2.6.12-rc4.

Your comments are welcome!

Thanks
Prasanna

Presently either multiple kprobes or only one jprobe could be inserted. This
patch removes the above limitation and allows one jprobe and multiple kprobes to
coexist at the same address. However multiple jprobes cannot coexist with 
multiple kprobes. Currently I am working on the prototype to allow multiple 
jprobes coexist with multiple kprobes.

Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: Ananth N Mavinakayanhalli <amavin@redhat.com>

---



---

 linux-2.6.12-rc4-mm2-prasanna/kernel/kprobes.c |   61 ++++++++++++++++++++-----
 1 files changed, 51 insertions(+), 10 deletions(-)

diff -puN kernel/kprobes.c~jprobe-kprobe-can-coexist kernel/kprobes.c
--- linux-2.6.12-rc4-mm2/kernel/kprobes.c~jprobe-kprobe-can-coexist	2005-05-25 12:26:33.000000000 +0530
+++ linux-2.6.12-rc4-mm2-prasanna/kernel/kprobes.c	2005-05-25 12:26:33.000000000 +0530
@@ -89,9 +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);
-			curr_kprobe = NULL;
+			if (kp->pre_handler(kp, regs))
+				return 1;
 		}
+		curr_kprobe = NULL;
 	}
 	return 0;
 }
@@ -124,6 +125,19 @@ int aggr_fault_handler(struct kprobe *p,
 	return 0;
 }
 
+int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kprobe *kp = curr_kprobe;
+	if (curr_kprobe && kp->break_handler) {
+		if (kp->break_handler(kp, regs)) {
+			curr_kprobe = NULL;
+			return 1;
+		}
+	}
+	curr_kprobe = NULL;
+	return 0;
+}
+
 struct kprobe trampoline_p = {
 		.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 		.pre_handler = trampoline_probe_handler,
@@ -257,18 +271,45 @@ inline void free_rp_inst(struct kretprob
 }
 
 /*
+ * Keep all fields in the kprobe consistent
+ */
+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));
+}
+
+/*
+* 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 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;
-	memcpy(&ap->opcode, &p->opcode, sizeof(kprobe_opcode_t));
-	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;
+	ap->break_handler = aggr_break_handler;
 
 	INIT_LIST_HEAD(&ap->list);
 	list_add(&p->list, &ap->list);
@@ -289,16 +330,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;
 }

_
-- 

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]