#include "swap_kprobes.h"
#include <kprobe/swap_kprobes.h>
-
+#include <kprobe/swap_td_raw.h>
#include <kprobe/swap_kdebug.h>
#include <kprobe/swap_slots.h>
#include <kprobe/swap_kprobes_deps.h>
return 1;
}
+
+static struct td_raw kp_tdraw;
+
+static struct pt_regs *current_regs(void)
+{
+ return (struct pt_regs *)swap_td_raw(&kp_tdraw, current);
+}
+
+
+void restore_int3(void);
+__asm(
+ "restore_int3:\n"
+ "int3\n"
+);
+
static int __kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p = 0;
- int ret = 0, reenter = 0;
+ int ret = 0;
kprobe_opcode_t *addr = NULL;
struct kprobe_ctlblk *kcb;
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_REENTER;
- return 1;
+ goto out_get_kp_if_TF;
} else {
if (*addr != BREAKPOINT_INSTRUCTION) {
/* The breakpoint instruction was removed by
}
set_current_kprobe(p, regs, kcb);
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
- if (!reenter)
- kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+ /* save regs to stack */
+ *current_regs() = *regs;
- if (p->pre_handler) {
- ret = p->pre_handler(p, regs);
- if (ret)
- return ret;
- }
+ regs->ip = (unsigned long)restore_int3;
+ get_kp(p);
+
+ return 1;
ss_probe:
setup_singlestep(p, regs, kcb);
+out_get_kp_if_TF:
+ if ((regs->flags & TF_MASK))
+ get_kp(p);
+
return 1;
no_kprobe:
return ret;
}
+static int restore_handler(struct pt_regs *regs)
+{
+ struct kprobe *p = swap_kprobe_running();
+ struct kprobe_ctlblk *kcb = swap_get_kprobe_ctlblk();
+
+ /* restore regs from stack */
+ *regs = *current_regs();
+
+ if (p->pre_handler) {
+ int ret;
+
+ ret = p->pre_handler(p, regs);
+ if (ret) {
+ put_kp(p);
+ return ret;
+ }
+ }
+
+ setup_singlestep(p, regs, kcb);
+ if (!(regs->flags & TF_MASK))
+ put_kp(p);
+
+ return 1;
+}
+
static int kprobe_handler(struct pt_regs *regs)
{
int ret;
- ret = __kprobe_handler(regs);
+ if (regs->ip == (unsigned long)restore_int3 + 1)
+ ret = restore_handler(regs);
+ else
+ ret = __kprobe_handler(regs);
return ret;
}
if (!cur)
return 0;
+
+ put_kp(cur);
+
if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
kcb->kprobe_status = KPROBE_HIT_SSDONE;
cur->post_handler(cur, regs, 0);
{
int ret;
- ret = register_die_notifier(&kprobe_exceptions_nb);
+ ret = swap_td_raw_reg(&kp_tdraw, sizeof(struct pt_regs));
if (ret)
return ret;
+ ret = register_die_notifier(&kprobe_exceptions_nb);
+ if (ret)
+ goto unreg_tdraw;
+
ret = kjump_init();
if (ret)
- unregister_die_notifier(&kprobe_exceptions_nb);
+ goto unreg_die;
+ return 0;
+
+unreg_die:
+ unregister_die_notifier(&kprobe_exceptions_nb);
+unreg_tdraw:
+ swap_td_raw_unreg(&kp_tdraw);
return ret;
}
{
kjump_exit();
unregister_die_notifier(&kprobe_exceptions_nb);
+ swap_td_raw_unreg(&kp_tdraw);
}
#endif
if (!ap)
return -ENOMEM;
+
+ atomic_set(&ap->usage, 0);
add_aggr_kprobe(ap, old_p);
copy_kprobe(ap, p);
DBPRINTF("ap = %p p = %p old_p = %p\n", ap, p, old_p);
swap_slot_free(&sm, p->ainsn.insn);
}
+static void wait_kp(struct kprobe *p)
+{
+ while (atomic_read(&p->usage))
+ schedule();
+}
+
/**
* @brief Registers kprobe.
*
p->nmissed = 0;
INIT_LIST_HEAD(&p->list);
+ atomic_set(&p->usage, 0);
old_p = swap_get_kprobe(p->addr);
if (old_p) {
{
struct kprobe *list_p;
+ BUG_ON(in_atomic());
+
if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) &&
(p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
/* Only probe on the hash list */
swap_arch_disarm_kprobe(p);
- /* FIXME: move sync out from atomic context */
- if (!in_atomic())
- synchronize_sched();
+ synchronize_sched();
+ wait_kp(old_p);
hlist_del_rcu(&old_p->hlist);
remove_kprobe(old_p);
if (p->post_handler) {
list_for_each_entry_rcu(list_p, &old_p->list, list)
if (list_p->post_handler)
- return;
+ goto out;
old_p->post_handler = NULL;
}
}
+
+out:
/* Set NULL addr for reusability if symbol_name is used */
if (p->symbol_name)
p->addr = NULL;