This is the mail archive of the
systemtap@sources.redhat.com
mailing list for the systemtap project.
[PATCH] (updated) 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: Mon, 16 May 2005 09:05:48 -0400
- Subject: [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;
}