summaryrefslogtreecommitdiffstats
path: root/kernel/events/uprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/events/uprobes.c')
-rw-r--r--kernel/events/uprobes.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index c92651d619c..29c73d7b1c2 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -99,6 +99,7 @@ struct uprobe {
};
/*
+static struct xol_area *get_xol_area(struct mm_struct *mm);
* valid_vma: Verify if the specified vma is an executable vma
* Relax restrictions while unregistering: vm_flags might have
* changed after breakpoint was inserted.
@@ -1238,6 +1239,47 @@ static void xol_free_insn_slot(struct task_struct *tsk)
}
}
+/* xol_get_trampoline_slot - A trampoline slot is obtained the first
+ * time a uprobe corresponding to a uretprobe is hit for a process. We
+ * use one trampoline slot for all probes pertaining to a process, i.e
+ * one per uprobes_xol_area.
+ */
+static unsigned long xol_get_trampoline_slot(void)
+{
+ struct mm_struct *mm = current->mm;
+ struct xol_area *area;
+ unsigned long xol_trampoline_addr = 0;
+ unsigned long offset;
+ void *vaddr;
+ uprobe_opcode_t bp_insn = UPROBE_SWBP_INSN;
+
+ area = get_xol_area(mm);
+ if (!area) {
+ area = xol_alloc_area();
+ if (!area)
+ return 0;
+ }
+
+ xol_trampoline_addr = area->uretprobe_trampoline_addr;
+ if (!xol_trampoline_addr) {
+ xol_trampoline_addr = xol_take_insn_slot(area);
+ area->uretprobe_trampoline_addr = xol_trampoline_addr;
+ }
+
+ /* Initialize the slot if trampoline_addr points to valid
+ * instruction slot.
+ */
+ if (unlikely(!xol_trampoline_addr))
+ return 0;
+
+ offset = xol_trampoline_addr & ~PAGE_MASK;
+ vaddr = kmap_atomic(area->page);
+ memcpy(vaddr + offset, &bp_insn, UPROBE_SWBP_INSN_SIZE);
+ kunmap_atomic(vaddr);
+
+ return area->uretprobe_trampoline_addr;
+}
+
/**
* uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
* @regs: Reflects the saved state of the task after it has hit a breakpoint