aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@kernel.org>2024-04-23 22:52:34 +0200
committerJiri Olsa <jolsa@kernel.org>2024-04-25 12:23:40 +0200
commit554d1563d6bebe03a19f9500907d0b71df555713 (patch)
treea529c4210164aceecc68cfc25b6239fa2c52edb9
parent701e9a93fa0d2cd527e5ff28ab359e5f3c45cce8 (diff)
downloadperf-bpf/optimized_usdt_2.tar.gz
uprobe: Install optimized uprobebpf/optimized_usdt_2
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
-rw-r--r--arch/x86/kernel/uprobes.c28
-rw-r--r--include/linux/uprobes.h2
-rw-r--r--kernel/events/uprobes.c7
3 files changed, 36 insertions, 1 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 1380b1fa6cadff..10fc934d5b968e 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -1266,3 +1266,31 @@ void *arch_uprobe_nop_trampoline(unsigned long *tramp_size)
*tramp_size = optuprobe_template_end - optuprobe_template_entry;
return optuprobe_template_entry;
}
+
+static void
+__relative_insn(void *dest, void *from, void *to, u8 op)
+{
+ struct __arch_relative_insn {
+ u8 op;
+ s32 raddr;
+ } __packed *insn;
+
+ insn = (struct __arch_relative_insn *)dest;
+ insn->raddr = (s32)((long)(to) - ((long)(from) + 5));
+ insn->op = op;
+}
+
+/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
+static void relcall(void *dest, void *from, void *to)
+{
+ __relative_insn(dest, from, to, CALL_INSN_OPCODE);
+}
+
+int arch_optimize_uprobe(struct mm_struct *mm, unsigned long vaddr,
+ unsigned long tramp_vaddr)
+{
+ char call[5];
+
+ relcall(call, (void *) vaddr, (void *) tramp_vaddr);
+ return uprobe_write_page(mm, vaddr, call, 5, true);
+}
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 3dca657754c154..0963786d34f712 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -147,6 +147,8 @@ extern bool arch_uprobe_can_optimize(struct arch_uprobe *auprobe, unsigned long
extern void * arch_uprobe_nop_trampoline(unsigned long *psize);
extern unsigned long uprobe_get_trampoline_vaddr(void);
void handle_syscall_uprobe(struct pt_regs *regs, unsigned long bp_vaddr);
+extern int arch_optimize_uprobe(struct mm_struct *mm, unsigned long vaddr,
+ unsigned long tramp_vaddr);
#else /* !CONFIG_UPROBES */
struct uprobes_state {
};
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index a2860e05735068..0aa4d50d677335 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1099,6 +1099,11 @@ static struct trampoline_area *get_trampoline_area(unsigned long vaddr)
return area;
}
+int __weak arch_optimize_uprobe(struct mm_struct *mm, unsigned long vaddr,
+ unsigned long tramp_vaddr)
+{
+ return -EINVAL;
+}
static int
optimize_uprobe(struct uprobe *uprobe, struct mm_struct *mm,
@@ -1113,7 +1118,7 @@ optimize_uprobe(struct uprobe *uprobe, struct mm_struct *mm,
if (!area)
return -EINVAL;
- return -EINVAL;
+ return arch_optimize_uprobe(mm, vaddr, area->vaddr);
}
static int