This is the mail archive of the
systemtap@sources.redhat.com
mailing list for the systemtap project.
[PATCH] Allow a jprobe to coexist with kprobes
- From: Ananth N Mavinakayanahalli <amavin at redhat dot com>
- To: SystemTAP <systemtap at sources dot redhat dot com>
- Date: Fri, 13 May 2005 15:12:41 -0400
- Subject: [PATCH] Allow a jprobe to coexist with kprobes
Hi,
Here is a patch (against 2.6.12-rc4-mm1) that allows for a jprobe to
coexist with kprobes at a given address. Two jprobes cannot be
registered at the same address however.
Tested and works on x86, I will be testing it on ppc64. Appreciate if
someone can give it a spin on x86_64.
I plan to post it to lkml early next week if all goes well.
Thanks,
Ananth
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 | 34 +++++++++++++++++++++++++++-------
6 files changed, 77 insertions(+), 15 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-13 14:13:35.000000000 -0400
+++ linux-2.6.12-rc4/arch/i386/kernel/kprobes.c 2005-05-13 14:49:09.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(p, 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-13 14:50:42.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, &kp->list, list) {
+ if (kp->break_handler &&
+ kp->break_handler(p, 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-13 14:50:19.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(p, 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-13 14:49:51.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(p, 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-13 14:14:00.000000000 -0400
+++ linux-2.6.12-rc4/include/linux/kprobes.h 2005-05-13 14:15:24.000000000 -0400
@@ -167,6 +167,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-13 14:14:00.000000000 -0400
+++ linux-2.6.12-rc4/kernel/kprobes.c 2005-05-13 14:55:49.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,6 +257,25 @@ 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_probe(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
*/
@@ -286,16 +308,14 @@ 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);
- } else {
+ if (old_p->pre_handler == aggr_pre_handler)
+ ret = add_new_probe(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);
+ ret = add_new_probe(ap, p);
}
return ret;
}