summaryrefslogtreecommitdiff
path: root/uprobe
diff options
context:
space:
mode:
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>2013-03-29 11:40:14 +0400
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>2013-03-29 11:40:14 +0400
commitc3b9737a10723d16da59c8aa718582be59dfb44e (patch)
tree846b4f88a147df24c4f094e041e5b7678e099ac4 /uprobe
parent637af38ee86b16db5a753059b617fe35a966957d (diff)
downloadswap-modules-c3b9737a10723d16da59c8aa718582be59dfb44e.tar.gz
swap-modules-c3b9737a10723d16da59c8aa718582be59dfb44e.tar.bz2
swap-modules-c3b9737a10723d16da59c8aa718582be59dfb44e.zip
[REFACTOR] move trampoline_uprobe_handler()
from src/modules/uprobe/arch/asm-arm/swap_uprobes.c to src/modules/uprobe/swap_uprobes.c
Diffstat (limited to 'uprobe')
-rw-r--r--uprobe/arch/asm-arm/swap_uprobes.c71
-rw-r--r--uprobe/arch/asm-arm/swap_uprobes.h3
-rw-r--r--uprobe/swap_uprobes.c58
-rw-r--r--uprobe/swap_uprobes.h6
4 files changed, 71 insertions, 67 deletions
diff --git a/uprobe/arch/asm-arm/swap_uprobes.c b/uprobe/arch/asm-arm/swap_uprobes.c
index d4fa8685..954f91e4 100644
--- a/uprobe/arch/asm-arm/swap_uprobes.c
+++ b/uprobe/arch/asm-arm/swap_uprobes.c
@@ -630,76 +630,23 @@ int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}
-int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs)
+unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
{
- struct uretprobe_instance *ri = NULL;
- struct hlist_head *head;
- struct hlist_node *node, *tmp;
- unsigned long flags, orig_ret_address = 0;
- unsigned long trampoline_address = 0;
-
- if (thumb_mode(regs)) {
- trampoline_address = (unsigned long)(p->ainsn.insn) + 0x1b;
- } else {
- trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
- }
-
- spin_lock_irqsave(&uretprobe_lock, flags);
-
- head = uretprobe_inst_table_head(current->mm);
-
- /*
- * It is possible to have multiple instances associated with a given
- * task either because an multiple functions in the call path
- * have a return probe installed on them, and/or more then one
- * return probe was registered for a target function.
- *
- * We can handle this because:
- * - instances are always inserted at the head of the list
- * - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
- * real return address, and all the rest will point to
- * uretprobe_trampoline
- */
- hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current) {
- /* another task is sharing our hash bucket */
- continue;
- }
-
- if (ri->rp && ri->rp->handler) {
- ri->rp->handler(ri, regs, ri->rp->priv_arg);
- }
-
- orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_urp_inst(ri);
+ return thumb_mode(regs) ?
+ (unsigned long)(p->ainsn.insn) + 0x1b :
+ (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
+}
- if (orig_ret_address != trampoline_address) {
- /*
- * This is the real return address. Any other
- * instances associated with this task are for
- * other calls deeper on the call stack
- */
- break;
- }
- }
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs)
+{
+ regs->ARM_lr = orig_ret_addr;
+ regs->ARM_pc = orig_ret_addr;
- regs->ARM_pc = orig_ret_address;
if (thumb_mode(regs) && !(regs->ARM_lr & 0x01)) {
regs->ARM_cpsr &= 0xFFFFFFDF;
} else if (user_mode(regs) && (regs->ARM_lr & 0x01)) {
regs->ARM_cpsr |= 0x20;
}
-
- spin_unlock_irqrestore(&uretprobe_lock, flags);
-
- /*
- * By returning a non-zero value, we are telling
- * kprobe_handler() that we don't want the post_handler
- * to run (and have re-enabled preemption)
- */
-
- return 1;
}
static int check_validity_insn(struct kprobe *p, struct pt_regs *regs, struct task_struct *task)
diff --git a/uprobe/arch/asm-arm/swap_uprobes.h b/uprobe/arch/asm-arm/swap_uprobes.h
index e76cb9c7..5ce45cc4 100644
--- a/uprobe/arch/asm-arm/swap_uprobes.h
+++ b/uprobe/arch/asm-arm/swap_uprobes.h
@@ -20,6 +20,9 @@ static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
void arch_prepare_uretprobe_hl(struct uretprobe_instance *ri, struct pt_regs *regs);
+unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
+void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
+
int swap_arch_init_uprobes(void);
void swap_arch_exit_uprobes(void);
diff --git a/uprobe/swap_uprobes.c b/uprobe/swap_uprobes.c
index f289b8eb..55a82313 100644
--- a/uprobe/swap_uprobes.c
+++ b/uprobe/swap_uprobes.c
@@ -389,7 +389,7 @@ static void remove_uprobe(struct kprobe *p, struct task_struct *task)
#endif /* CONFIG_ARM */
}
-struct hlist_head *uretprobe_inst_table_head(void *hash_key)
+static struct hlist_head *uretprobe_inst_table_head(void *hash_key)
{
return &uretprobe_inst_table[hash_ptr (hash_key, UPROBE_HASH_BITS)];
}
@@ -413,7 +413,7 @@ static void add_urp_inst(struct uretprobe_instance *ri)
}
/* Called with uretprobe_lock held */
-void recycle_urp_inst(struct uretprobe_instance *ri)
+static void recycle_urp_inst(struct uretprobe_instance *ri)
{
if (ri->rp) {
hlist_del(&ri->hlist);
@@ -673,6 +673,60 @@ void dbi_unregister_ujprobe(struct task_struct *task, struct jprobe *jp, int ato
#endif /* CONFIG_ARM */
}
+int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct uretprobe_instance *ri = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node, *tmp;
+ unsigned long flags, tramp_addr, orig_ret_addr = 0;
+
+ tramp_addr = arch_get_trampoline_addr(p, regs);
+ spin_lock_irqsave(&uretprobe_lock, flags);
+
+ head = uretprobe_inst_table_head(current->mm);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * uretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current) {
+ /* another task is sharing our hash bucket */
+ continue;
+ }
+
+ if (ri->rp && ri->rp->handler) {
+ ri->rp->handler(ri, regs, ri->rp->priv_arg);
+ }
+
+ orig_ret_addr = (unsigned long)ri->ret_addr;
+ recycle_urp_inst(ri);
+
+ if (orig_ret_addr != tramp_addr) {
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&uretprobe_lock, flags);
+ arch_set_orig_ret_addr(orig_ret_addr, regs);
+
+ return 1;
+}
+
static int pre_handler_uretprobe(struct kprobe *p, struct pt_regs *regs)
{
struct uretprobe *rp = container_of(p, struct uretprobe, kp);
diff --git a/uprobe/swap_uprobes.h b/uprobe/swap_uprobes.h
index a5c7113f..f8b2aa67 100644
--- a/uprobe/swap_uprobes.h
+++ b/uprobe/swap_uprobes.h
@@ -29,6 +29,8 @@
#include "dbi_kprobes.h"
+struct uretprobe_instance;
+
typedef int (*uretprobe_handler_t)(struct uretprobe_instance *, struct pt_regs *, void *);
/*
@@ -78,8 +80,6 @@ struct kprobe *get_uprobe(kprobe_opcode_t *addr, pid_t tgid);
void disarm_uprobe(struct kprobe *p, struct task_struct *task);
-extern spinlock_t uretprobe_lock;
-struct hlist_head *uretprobe_inst_table_head(void *hash_key);
-void recycle_urp_inst(struct uretprobe_instance *ri);
+int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs);
#endif /* _DBI_UPROBES_H */