From: Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp>
To: systemtap@sources.redhat.com
Cc: Satoshi Oshima <soshima@redhat.com>,
Hideo Aoki <haoki@redhat.com>,
sugita@sdl.hitachi.co.jp
Subject: [Patch 5/5][Djprobe]Djprobe Coexist with Kprobes
Date: Thu, 29 Sep 2005 13:01:00 -0000 [thread overview]
Message-ID: <433BE55E.1090800@sdl.hitachi.co.jp> (raw)
Hi,
This patch enables djprobe and kprobes to coexist
in the same address.
When a kprobe is inserted in the address in where
a djprobe was already inserted, the djprobe removes
a jump code and inserts a breakpoint (and it is driven
by kprobes).
When a djprobe is inserted in the address in where
a kprobe was already inserted, the djprobe behaves
like a kprobe.
After all kprobes are removed from the address, the
djprobe inserts a jump code again.
--
Masami HIRAMATSU
2nd Research Dept.
Hitachi, Ltd., Systems Development Laboratory
E-mail: hiramatu@sdl.hitachi.co.jp
arch/i386/kernel/kprobes.c | 7 ++
include/linux/kprobes.h | 2
kernel/kprobes.c | 110 ++++++++++++++++++++++++++++++++++-----------
3 files changed, 94 insertions(+), 25 deletions(-)
diff -Narup linux-2.6.13-mm1.djp.4/arch/i386/kernel/kprobes.c linux-2.6.13-mm1.djp.5/arch/i386/kernel/kprobes.c
--- linux-2.6.13-mm1.djp.4/arch/i386/kernel/kprobes.c 2005-09-28 20:14:16.000000000 +0900
+++ linux-2.6.13-mm1.djp.5/arch/i386/kernel/kprobes.c 2005-09-28 20:16:07.000000000 +0900
@@ -650,6 +650,13 @@ int __kprobes arch_prepare_djprobe_insta
return 0;
}
+ /*recover stub*/
+int __kprobes arch_recover_djprobe_instance(struct djprobe_instance *djpi)
+{
+ arch_prepare_djprobe_instance(djpi, DJPI_ARCH_SIZE(djpi));
+ djpi->stub.insn[ARCH_STUB_INST_IDX] = djpi->kp.ainsn.insn[0];
+ return 0;
+}
/* Insert "jmp" instruction into the probing point. */
void __kprobes arch_install_djprobe_instance(struct djprobe_instance *djpi)
diff -Narup linux-2.6.13-mm1.djp.4/include/linux/kprobes.h linux-2.6.13-mm1.djp.5/include/linux/kprobes.h
--- linux-2.6.13-mm1.djp.4/include/linux/kprobes.h 2005-09-28 20:14:16.000000000 +0900
+++ linux-2.6.13-mm1.djp.5/include/linux/kprobes.h 2005-09-28 20:16:07.000000000 +0900
@@ -155,6 +155,7 @@ struct djprobe_instance {
};
#define DJPI_EMPTY(djpi) (list_empty(&djpi->plist))
#define DJPI_CHECKED(djpi) (cpus_equal(djpi->checked_cpus, cpu_online_map))
+#define DJPI_FORCE_CHECK(djpi) (djpi->checked_cpus = cpu_online_map)
struct djprobe;
typedef void (*djprobe_handler_t)(struct djprobe *, struct pt_regs *);
@@ -229,6 +230,7 @@ extern int arch_prepare_djprobe_instance
extern int djprobe_bypass_handler(struct kprobe * kp, struct pt_regs * regs);
extern void arch_install_djprobe_instance(struct djprobe_instance *djpi);
extern void arch_uninstall_djprobe_instance(struct djprobe_instance *djpi);
+extern int arch_recover_djprobe_instance(struct djprobe_instance *djpi);
#endif /* ARCH_SUPPORTS_DJPROBES */
int register_djprobe(struct djprobe *p);
diff -Narup linux-2.6.13-mm1.djp.4/kernel/kprobes.c linux-2.6.13-mm1.djp.5/kernel/kprobes.c
--- linux-2.6.13-mm1.djp.4/kernel/kprobes.c 2005-09-28 20:14:16.000000000 +0900
+++ linux-2.6.13-mm1.djp.5/kernel/kprobes.c 2005-09-28 20:16:07.000000000 +0900
@@ -77,8 +77,10 @@ struct kprobe_insn_page_list {
static struct kprobe_insn_page_list kprobe_insn_pages = {
HLIST_HEAD_INIT, MAX_INSN_SIZE};
-static struct djprobe_instance *
- __kprobes get_djprobe_instance(void *addr, int size);
+static void __kprobes djprobe_avoid_confliction(void *addr);
+static void __kprobes djprobe_recover_confliction(void *addr);
+static int __kprobes djprobe_through_handler(struct kprobe *kp,
+ struct pt_regs * regs);
/**
* __get_insn_slot() - Find a slot on an executable page for an instruction.
@@ -481,8 +483,8 @@ int __kprobes register_kprobe(struct kpr
return ret;
#ifdef ARCH_SUPPORTS_DJPROBES
if (p->pre_handler != djprobe_bypass_handler &&
- get_djprobe_instance(p->addr, 1) != NULL )
- return -EEXIST;
+ p->pre_handler != djprobe_through_handler)
+ djprobe_avoid_confliction(p->addr);
#endif
if ((ret = arch_prepare_kprobe(p)) != 0)
goto rm_kprobe;
@@ -522,6 +524,11 @@ void __kprobes unregister_kprobe(struct
cleanup_aggr_kprobe(old_p, p, flags);
else
cleanup_kprobe(p, flags);
+#ifdef ARCH_SUPPORTS_DJPROBES
+ if (p->pre_handler != djprobe_bypass_handler &&
+ p->pre_handler != djprobe_through_handler)
+ djprobe_recover_confliction(p->addr);
+#endif
} else
spin_unlock_irqrestore(&kprobe_lock, flags);
}
@@ -639,14 +646,45 @@ static inline struct djprobe_instance *
return NULL;
}
-static struct djprobe_instance *
- __kprobes get_djprobe_instance(void *addr, int size)
+static inline struct kprobe * __get_kprobe_range(void * addr, int size)
+{
+ struct kprobe *kp = NULL;
+ for (; 0 < size; size--) {
+ kp = get_kprobe((void*)((long)addr + size - 1));
+ if (kp != NULL) break;
+ }
+ return kp;
+}
+
+/* kprobe emulated djprobe */
+static int __kprobes djprobe_through_handler(struct kprobe *kp,
+ struct pt_regs * regs)
+{
+ struct djprobe_instance *djpi =
+ container_of(kp,struct djprobe_instance, kp);
+ struct djprobe * djp;
+
+ list_for_each_entry_rcu(djp, &djpi->plist, plist) {
+ if (djp->handler)
+ djp->handler(djp, regs);
+ }
+ return 0;
+}
+
+/* avoid confliction with kprobe */
+static void __kprobes djprobe_avoid_confliction(void *addr)
{
struct djprobe_instance *djpi;
spin_lock(&djprobe_lock);
- djpi = __get_djprobe_instance(addr, size);
+ djpi = __get_djprobe_instance(addr, 1);
+ if (djpi && djpi->kp.pre_handler != djprobe_through_handler) {
+ if (!DJPI_EMPTY(djpi))
+ DJPI_FORCE_CHECK(djpi); /* stop check worker */
+ /* conflict: switch a djprobe to a kprobe */
+ djpi->kp.pre_handler = djprobe_through_handler;
+ arch_uninstall_djprobe_instance(djpi);
+ }
spin_unlock(&djprobe_lock);
- return djpi;
}
#ifdef CONFIG_SMP
@@ -687,7 +725,8 @@ static void __kprobes work_check_djprobe
spin_unlock(&djprobe_lock);
}
-static inline void schedule_check_djprobe_instances(void)
+static void __kprobes
+ schedule_check_djprobe_instance(struct djprobe_instance *djpi)
{
int cpu;
struct work_struct *wk;
@@ -722,7 +761,7 @@ static int __kprobes install_djprobe_ins
{
int ret;
ret = register_kprobe(&(djpi->kp));
- if (ret == 0) {
+ if (ret == 0 && djpi->kp.pre_handler != djprobe_through_handler) {
__install_djprobe_instance(djpi);
}
return ret;
@@ -731,15 +770,38 @@ static int __kprobes install_djprobe_ins
/* Use kprobe to check safety and release */
static void __kprobes uninstall_djprobe_instance(struct djprobe_instance *djpi)
{
- arch_uninstall_djprobe_instance(djpi);
- __uninstall_djprobe_instance(djpi);
+ if (djpi->kp.pre_handler != djprobe_through_handler) {
+ arch_uninstall_djprobe_instance(djpi);
+ __uninstall_djprobe_instance(djpi);
+ } else
+ __free_djprobe_instance(djpi);
}
-int __kprobes register_djprobe(struct djprobe * djp)
+/* recover confliction with kprobe */
+static void __kprobes djprobe_recover_confliction(void *addr)
{
struct djprobe_instance *djpi;
struct kprobe *kp;
- int ret = 0, i;
+ spin_lock(&djprobe_lock);
+ djpi = __get_djprobe_instance(addr, 1);
+ if (djpi) {
+ kp = __get_kprobe_range(djpi->kp.addr, DJPI_ARCH_SIZE(djpi));
+ if (kp->addr == djpi->kp.addr) {
+ unsigned long flags;
+ spin_lock_irqsave(&kprobe_lock, flags);
+ arch_recover_djprobe_instance(djpi); /*recover stub*/
+ djpi->kp.pre_handler = djprobe_bypass_handler;
+ __install_djprobe_instance(djpi);
+ spin_unlock_irqrestore(&kprobe_lock, flags);
+ }
+ }
+ spin_unlock(&djprobe_lock);
+}
+
+int __kprobes register_djprobe(struct djprobe * djp)
+{
+ struct djprobe_instance *djpi;
+ int ret = 0;
if (djp == NULL || djp->addr == NULL ||
djp->size > ARCH_STUB_INSN_MAX ||
@@ -764,14 +826,6 @@ int __kprobes register_djprobe(struct dj
goto out;
}
}
- /* check confliction with kprobes */
- for ( i=0; i < djp->size; i++) {
- kp = get_kprobe((void*)((long)djp->addr+i));
- if (kp != NULL) {
- ret = -EEXIST; /* a kprobes were inserted */
- goto out;
- }
- }
/* make a new instance */
djpi = kmalloc(sizeof(struct djprobe_instance),GFP_KERNEL);
if (djpi == NULL) {
@@ -794,9 +848,15 @@ int __kprobes register_djprobe(struct dj
ret = -ENOMEM; /* memory allocation error */
goto out;
}
- djpi->kp.pre_handler = djprobe_bypass_handler;
- arch_prepare_djprobe_instance(djpi, djp->size); /*TODO : remove size*/
-
+ if (__get_kprobe_range(djp->addr, djp->size) != NULL) {
+ /* conflict with kprobes */
+ djpi->kp.pre_handler = djprobe_through_handler;
+ DJPI_ARCH_SIZE(djpi) = djp->size;
+ DJPI_FORCE_CHECK(djpi); /* assume to be checked */
+ } else {
+ djpi->kp.pre_handler = djprobe_bypass_handler;
+ arch_prepare_djprobe_instance(djpi, djp->size); /*TODO : remove size*/
+ }
ret = install_djprobe_instance(djpi);
if (ret < 0) { /* failed to install */
djp->inst = NULL;
reply other threads:[~2005-09-29 13:01 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=433BE55E.1090800@sdl.hitachi.co.jp \
--to=hiramatu@sdl.hitachi.co.jp \
--cc=haoki@redhat.com \
--cc=soshima@redhat.com \
--cc=sugita@sdl.hitachi.co.jp \
--cc=systemtap@sources.redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).