diff options
author | Vyacheslav Cherkashin <v.cherkashin@samsung.com> | 2013-03-29 11:40:14 +0400 |
---|---|---|
committer | Vyacheslav Cherkashin <v.cherkashin@samsung.com> | 2013-03-29 11:40:14 +0400 |
commit | c3b9737a10723d16da59c8aa718582be59dfb44e (patch) | |
tree | 846b4f88a147df24c4f094e041e5b7678e099ac4 /uprobe | |
parent | 637af38ee86b16db5a753059b617fe35a966957d (diff) | |
download | swap-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.c | 71 | ||||
-rw-r--r-- | uprobe/arch/asm-arm/swap_uprobes.h | 3 | ||||
-rw-r--r-- | uprobe/swap_uprobes.c | 58 | ||||
-rw-r--r-- | uprobe/swap_uprobes.h | 6 |
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 */ |