summaryrefslogtreecommitdiff
path: root/uprobe
diff options
context:
space:
mode:
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>2015-07-12 16:54:24 +0300
committerVasiliy Ulyanov <v.ulyanov@samsung.com>2015-07-18 20:15:24 +0300
commit5b60bbe9edf7616e300e5d2324c05ad3fdc88934 (patch)
treeea74d61df14ac2c84f7a4d56a3a57daaceb78749 /uprobe
parent91843044de4ea0aee1281fba9b9a8f17387d0190 (diff)
downloadswap-modules-5b60bbe9edf7616e300e5d2324c05ad3fdc88934.tar.gz
swap-modules-5b60bbe9edf7616e300e5d2324c05ad3fdc88934.tar.bz2
swap-modules-5b60bbe9edf7616e300e5d2324c05ad3fdc88934.zip
[FIX] Save current uprobe state in stack (x86)
We cannot use per cpu vars here because when we make a singlestep in userspace there is a chance our task is preempted and resumed on another cpu. In that case we will not be able to restore its normal execution. Change-Id: I591ef52b52db8db0e741d81461903806ed00ef8e Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com> Signed-off-by: Vasiliy Ulyanov <v.ulyanov@samsung.com>
Diffstat (limited to 'uprobe')
-rw-r--r--uprobe/arch/x86/swap-asm/swap_uprobes.c72
1 files changed, 46 insertions, 26 deletions
diff --git a/uprobe/arch/x86/swap-asm/swap_uprobes.c b/uprobe/arch/x86/swap-asm/swap_uprobes.c
index 1b0fbe8e..f4f2272a 100644
--- a/uprobe/arch/x86/swap-asm/swap_uprobes.c
+++ b/uprobe/arch/x86/swap-asm/swap_uprobes.c
@@ -54,32 +54,31 @@ static unsigned long trampoline_addr(struct uprobe *up)
UPROBES_TRAMP_RET_BREAK_IDX);
}
-static DEFINE_PER_CPU(struct uprobe_ctlblk, ucb) = { 0, NULL };
-
-static struct kprobe *get_current_probe(void)
+static struct uprobe_ctlblk *current_ucb(void)
{
- return __get_cpu_var(ucb).p;
+ /* FIXME hardcoded offset */
+ return (struct uprobe_ctlblk *)(end_of_stack(current) + 20);
}
-static void set_current_probe(struct kprobe *p)
+static struct kprobe *get_current_probe(void)
{
- __get_cpu_var(ucb).p = p;
+ return current_ucb()->p;
}
-static void reset_current_probe(void)
+static void set_current_probe(struct kprobe *p)
{
- set_current_probe(NULL);
+ current_ucb()->p = p;
}
static void save_current_flags(struct pt_regs *regs)
{
- __get_cpu_var(ucb).flags = regs->EREG(flags);
+ current_ucb()->flags = regs->flags;
}
-static void restore_current_flags(struct pt_regs *regs)
+static void restore_current_flags(struct pt_regs *regs, unsigned long flags)
{
- regs->EREG(flags) &= ~IF_MASK;
- regs->EREG(flags) |= __get_cpu_var(ucb).flags & IF_MASK;
+ regs->flags &= ~IF_MASK;
+ regs->flags |= flags & IF_MASK;
}
/**
@@ -420,6 +419,27 @@ no_change:
return;
}
+static bool prepare_ss_addr(struct kprobe *p, struct pt_regs *regs)
+{
+ unsigned long *ss_addr = (long *)&p->ss_addr[smp_processor_id()];
+
+ if (*ss_addr) {
+ regs->ip = *ss_addr;
+ *ss_addr = 0;
+ return true;
+ } else {
+ regs->ip = (unsigned long)p->ainsn.insn;
+ return false;
+ }
+}
+
+static void prepare_ss(struct pt_regs *regs)
+{
+ /* set single step mode */
+ regs->flags |= TF_MASK;
+ regs->flags &= ~IF_MASK;
+}
+
static int uprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
@@ -445,38 +465,38 @@ static int uprobe_handler(struct pt_regs *regs)
return 1;
} else {
if (!p->pre_handler || !p->pre_handler(p, regs)) {
-
if (p->ainsn.boostable == 1 && !p->post_handler) {
- if (p->ss_addr[smp_processor_id()]) {
- regs->EREG(ip) = (unsigned long)p->ss_addr[smp_processor_id()];
- p->ss_addr[smp_processor_id()] = NULL;
- } else {
- regs->EREG(ip) = (unsigned long)p->ainsn.insn;
- }
+ prepare_ss_addr(p, regs);
return 1;
}
- prepare_singlestep(p, regs);
+ if (prepare_ss_addr(p, regs) == false) {
+ set_current_probe(p);
+ prepare_ss(regs);
+ }
}
}
- set_current_probe(p);
-
return 1;
}
static int post_uprobe_handler(struct pt_regs *regs)
{
struct kprobe *p = get_current_probe();
- unsigned long flags = __get_cpu_var(ucb).flags;
+ unsigned long flags = current_ucb()->flags;
- if (p == NULL)
+ if (p == NULL) {
+ printk("task[%u %u %s] current uprobe is not found\n",
+ current->tgid, current->pid, current->comm);
return 0;
+ }
resume_execution(p, regs, flags);
- restore_current_flags(regs);
+ restore_current_flags(regs, flags);
- reset_current_probe();
+ /* clean stack */
+ current_ucb()->p = 0;
+ current_ucb()->flags = 0;
return 1;
}