Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1412726 > unrolled thread
| Started by | David Long <dave.long@linaro.org> |
|---|---|
| First post | 2016-06-03 05:30 +0200 |
| Last post | 2016-06-03 05:40 +0200 |
| Articles | 3 on this page of 23 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v13 00/10] arm64: Add kernel probes (kprobes) support David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
[PATCH v13 04/10] arm64: Blacklist non-kprobe-able symbol David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 04/10] arm64: Blacklist non-kprobe-able symbol Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-04 05:50 +0200
Re: [PATCH v13 04/10] arm64: Blacklist non-kprobe-able symbol David Long <dave.long@linaro.org> - 2016-06-07 06:00 +0200
Re: [PATCH v13 04/10] arm64: Blacklist non-kprobe-able symbol David Long <dave.long@linaro.org> - 2016-06-10 21:20 +0200
[PATCH v13 06/10] arm64: Treat all entry code as non-kprobe-able David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 06/10] arm64: Treat all entry code as non-kprobe-able Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-07 02:40 +0200
[PATCH v13 10/10] kprobes: Add arm64 case in kprobe example module David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 10/10] kprobes: Add arm64 case in kprobe example module Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-07 12:20 +0200
[PATCH v13 03/10] arm64: add conditional instruction simulation support David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 03/10] arm64: add conditional instruction simulation support Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-04 06:00 +0200
[PATCH v13 05/10] arm64: Kprobes with single stepping support David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 05/10] arm64: Kprobes with single stepping support Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-08 03:10 +0200
[PATCH v13 01/10] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 01/10] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-03 13:40 +0200
[PATCH v13 02/10] arm64: Add more test functions to insn.c David Long <dave.long@linaro.org> - 2016-06-03 05:30 +0200
Re: [PATCH v13 02/10] arm64: Add more test functions to insn.c Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-08 03:20 +0200
Re: [PATCH v13 02/10] arm64: Add more test functions to insn.c David Long <dave.long@linaro.org> - 2016-06-10 17:00 +0200
[PATCH v13 09/10] arm64: Add kernel return probes support (kretprobes) David Long <dave.long@linaro.org> - 2016-06-03 05:40 +0200
Re: [PATCH v13 09/10] arm64: Add kernel return probes support (kretprobes) Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-07 12:30 +0200
[PATCH v13 08/10] arm64: Add trampoline code for kretprobes David Long <dave.long@linaro.org> - 2016-06-03 05:40 +0200
Re: [PATCH v13 08/10] arm64: Add trampoline code for kretprobes Masami Hiramatsu <mhiramat@kernel.org> - 2016-06-07 12:40 +0200
[PATCH v13 07/10] arm64: kprobes instruction simulation support David Long <dave.long@linaro.org> - 2016-06-03 05:40 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | David Long <dave.long@linaro.org> |
|---|---|
| Date | 2016-06-03 05:40 +0200 |
| Subject | [PATCH v13 08/10] arm64: Add trampoline code for kretprobes |
| Message-ID | <rFO7M-6nc-33@gated-at.bofh.it> |
| In reply to | #1412726 |
From: William Cohen <wcohen@redhat.com>
The trampoline code is used by kretprobes to capture a return from a probed
function. This is done by saving the registers, calling the handler, and
restoring the registers. The code then returns to the original saved caller
return address. It is necessary to do this directly instead of using a
software breakpoint because the code used in processing that breakpoint
could itself be kprobe'd and cause a problematic reentry into the debug
exception handler.
Signed-off-by: William Cohen <wcohen@redhat.com>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
arch/arm64/include/asm/kprobes.h | 2 +
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/asm-offsets.c | 11 +++++
arch/arm64/kernel/kprobes.c | 5 ++
arch/arm64/kernel/kprobes_trampoline.S | 85 ++++++++++++++++++++++++++++++++++
5 files changed, 104 insertions(+)
create mode 100644 arch/arm64/kernel/kprobes_trampoline.S
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
index 79c9511..61b4915 100644
--- a/arch/arm64/include/asm/kprobes.h
+++ b/arch/arm64/include/asm/kprobes.h
@@ -56,5 +56,7 @@ int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
int kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr);
int kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr);
+void kretprobe_trampoline(void);
+void __kprobes *trampoline_probe_handler(struct pt_regs *regs);
#endif /* _ARM_KPROBES_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 46724a1..75751b7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -38,6 +38,7 @@ arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_KPROBES) += kprobes.o kprobes-arm64.o \
+ kprobes_trampoline.o \
probes-simulate-insn.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
arm64-obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index f8e5d47..03dfa27 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -51,6 +51,17 @@ int main(void)
DEFINE(S_X5, offsetof(struct pt_regs, regs[5]));
DEFINE(S_X6, offsetof(struct pt_regs, regs[6]));
DEFINE(S_X7, offsetof(struct pt_regs, regs[7]));
+ DEFINE(S_X8, offsetof(struct pt_regs, regs[8]));
+ DEFINE(S_X10, offsetof(struct pt_regs, regs[10]));
+ DEFINE(S_X12, offsetof(struct pt_regs, regs[12]));
+ DEFINE(S_X14, offsetof(struct pt_regs, regs[14]));
+ DEFINE(S_X16, offsetof(struct pt_regs, regs[16]));
+ DEFINE(S_X18, offsetof(struct pt_regs, regs[18]));
+ DEFINE(S_X20, offsetof(struct pt_regs, regs[20]));
+ DEFINE(S_X22, offsetof(struct pt_regs, regs[22]));
+ DEFINE(S_X24, offsetof(struct pt_regs, regs[24]));
+ DEFINE(S_X26, offsetof(struct pt_regs, regs[26]));
+ DEFINE(S_X28, offsetof(struct pt_regs, regs[28]));
DEFINE(S_LR, offsetof(struct pt_regs, regs[30]));
DEFINE(S_SP, offsetof(struct pt_regs, sp));
#ifdef CONFIG_COMPAT
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 9d0ad47..b35f76f 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -575,6 +575,11 @@ bool arch_within_kprobe_blacklist(unsigned long addr)
return false;
}
+void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
+{
+ return NULL;
+}
+
int __init arch_init_kprobes(void)
{
return 0;
diff --git a/arch/arm64/kernel/kprobes_trampoline.S b/arch/arm64/kernel/kprobes_trampoline.S
new file mode 100644
index 0000000..ba37d85
--- /dev/null
+++ b/arch/arm64/kernel/kprobes_trampoline.S
@@ -0,0 +1,85 @@
+/*
+ * trampoline entry and return code for kretprobes.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+
+ .text
+
+.macro save_all_base_regs
+ stp x0, x1, [sp, #S_X0]
+ stp x2, x3, [sp, #S_X2]
+ stp x4, x5, [sp, #S_X4]
+ stp x6, x7, [sp, #S_X6]
+ stp x8, x9, [sp, #S_X8]
+ stp x10, x11, [sp, #S_X10]
+ stp x12, x13, [sp, #S_X12]
+ stp x14, x15, [sp, #S_X14]
+ stp x16, x17, [sp, #S_X16]
+ stp x18, x19, [sp, #S_X18]
+ stp x20, x21, [sp, #S_X20]
+ stp x22, x23, [sp, #S_X22]
+ stp x24, x25, [sp, #S_X24]
+ stp x26, x27, [sp, #S_X26]
+ stp x28, x29, [sp, #S_X28]
+ add x0, sp, #S_FRAME_SIZE
+ stp lr, x0, [sp, #S_LR]
+/*
+ * Construct a useful saved PSTATE
+ */
+ mrs x0, nzcv
+ and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
+ mrs x1, daif
+ and x1, x1, #(PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
+ orr x0, x0, x1
+ mrs x1, CurrentEL
+ and x1, x1, #(3 << 2)
+ orr x0, x1, x0
+ mrs x1, SPSel
+ and x1, x1, #1
+ orr x0, x1, x0
+ str x0, [sp, #S_PSTATE]
+.endm
+
+.macro restore_all_base_regs
+ ldr x0, [sp, #S_PSTATE]
+ and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
+ msr nzcv, x0
+ ldp x0, x1, [sp, #S_X0]
+ ldp x2, x3, [sp, #S_X2]
+ ldp x4, x5, [sp, #S_X4]
+ ldp x6, x7, [sp, #S_X6]
+ ldp x8, x9, [sp, #S_X8]
+ ldp x10, x11, [sp, #S_X10]
+ ldp x12, x13, [sp, #S_X12]
+ ldp x14, x15, [sp, #S_X14]
+ ldp x16, x17, [sp, #S_X16]
+ ldp x18, x19, [sp, #S_X18]
+ ldp x20, x21, [sp, #S_X20]
+ ldp x22, x23, [sp, #S_X22]
+ ldp x24, x25, [sp, #S_X24]
+ ldp x26, x27, [sp, #S_X26]
+ ldp x28, x29, [sp, #S_X28]
+.endm
+
+ENTRY(kretprobe_trampoline)
+
+ sub sp, sp, #S_FRAME_SIZE
+
+ save_all_base_regs
+
+ mov x0, sp
+ bl trampoline_probe_handler
+ /* Replace trampoline address in lr with actual
+ orig_ret_addr return address. */
+ mov lr, x0
+
+ restore_all_base_regs
+
+ add sp, sp, #S_FRAME_SIZE
+
+ ret
+
+ENDPROC(kretprobe_trampoline)
--
2.5.0
[toc] | [prev] | [next] | [standalone]
| From | Masami Hiramatsu <mhiramat@kernel.org> |
|---|---|
| Date | 2016-06-07 12:40 +0200 |
| Subject | Re: [PATCH v13 08/10] arm64: Add trampoline code for kretprobes |
| Message-ID | <rHmAp-1vx-11@gated-at.bofh.it> |
| In reply to | #1412755 |
On Thu, 2 Jun 2016 23:26:22 -0400
David Long <dave.long@linaro.org> wrote:
> From: William Cohen <wcohen@redhat.com>
>
> The trampoline code is used by kretprobes to capture a return from a probed
> function. This is done by saving the registers, calling the handler, and
> restoring the registers. The code then returns to the original saved caller
> return address. It is necessary to do this directly instead of using a
> software breakpoint because the code used in processing that breakpoint
> could itself be kprobe'd and cause a problematic reentry into the debug
> exception handler.
OK, I think we had discussed why this was not included to the next patch.
(Not like to merge patches from different person?)
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Thanks,
> Signed-off-by: William Cohen <wcohen@redhat.com>
> Signed-off-by: David A. Long <dave.long@linaro.org>
> ---
> arch/arm64/include/asm/kprobes.h | 2 +
> arch/arm64/kernel/Makefile | 1 +
> arch/arm64/kernel/asm-offsets.c | 11 +++++
> arch/arm64/kernel/kprobes.c | 5 ++
> arch/arm64/kernel/kprobes_trampoline.S | 85 ++++++++++++++++++++++++++++++++++
> 5 files changed, 104 insertions(+)
> create mode 100644 arch/arm64/kernel/kprobes_trampoline.S
>
> diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
> index 79c9511..61b4915 100644
> --- a/arch/arm64/include/asm/kprobes.h
> +++ b/arch/arm64/include/asm/kprobes.h
> @@ -56,5 +56,7 @@ int kprobe_exceptions_notify(struct notifier_block *self,
> unsigned long val, void *data);
> int kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr);
> int kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr);
> +void kretprobe_trampoline(void);
> +void __kprobes *trampoline_probe_handler(struct pt_regs *regs);
>
> #endif /* _ARM_KPROBES_H */
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 46724a1..75751b7 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -38,6 +38,7 @@ arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
> arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
> arm64-obj-$(CONFIG_KGDB) += kgdb.o
> arm64-obj-$(CONFIG_KPROBES) += kprobes.o kprobes-arm64.o \
> + kprobes_trampoline.o \
> probes-simulate-insn.o
> arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
> arm64-obj-$(CONFIG_PCI) += pci.o
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index f8e5d47..03dfa27 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -51,6 +51,17 @@ int main(void)
> DEFINE(S_X5, offsetof(struct pt_regs, regs[5]));
> DEFINE(S_X6, offsetof(struct pt_regs, regs[6]));
> DEFINE(S_X7, offsetof(struct pt_regs, regs[7]));
> + DEFINE(S_X8, offsetof(struct pt_regs, regs[8]));
> + DEFINE(S_X10, offsetof(struct pt_regs, regs[10]));
> + DEFINE(S_X12, offsetof(struct pt_regs, regs[12]));
> + DEFINE(S_X14, offsetof(struct pt_regs, regs[14]));
> + DEFINE(S_X16, offsetof(struct pt_regs, regs[16]));
> + DEFINE(S_X18, offsetof(struct pt_regs, regs[18]));
> + DEFINE(S_X20, offsetof(struct pt_regs, regs[20]));
> + DEFINE(S_X22, offsetof(struct pt_regs, regs[22]));
> + DEFINE(S_X24, offsetof(struct pt_regs, regs[24]));
> + DEFINE(S_X26, offsetof(struct pt_regs, regs[26]));
> + DEFINE(S_X28, offsetof(struct pt_regs, regs[28]));
> DEFINE(S_LR, offsetof(struct pt_regs, regs[30]));
> DEFINE(S_SP, offsetof(struct pt_regs, sp));
> #ifdef CONFIG_COMPAT
> diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
> index 9d0ad47..b35f76f 100644
> --- a/arch/arm64/kernel/kprobes.c
> +++ b/arch/arm64/kernel/kprobes.c
> @@ -575,6 +575,11 @@ bool arch_within_kprobe_blacklist(unsigned long addr)
> return false;
> }
>
> +void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
> +{
> + return NULL;
> +}
> +
> int __init arch_init_kprobes(void)
> {
> return 0;
> diff --git a/arch/arm64/kernel/kprobes_trampoline.S b/arch/arm64/kernel/kprobes_trampoline.S
> new file mode 100644
> index 0000000..ba37d85
> --- /dev/null
> +++ b/arch/arm64/kernel/kprobes_trampoline.S
> @@ -0,0 +1,85 @@
> +/*
> + * trampoline entry and return code for kretprobes.
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/assembler.h>
> +
> + .text
> +
> +.macro save_all_base_regs
> + stp x0, x1, [sp, #S_X0]
> + stp x2, x3, [sp, #S_X2]
> + stp x4, x5, [sp, #S_X4]
> + stp x6, x7, [sp, #S_X6]
> + stp x8, x9, [sp, #S_X8]
> + stp x10, x11, [sp, #S_X10]
> + stp x12, x13, [sp, #S_X12]
> + stp x14, x15, [sp, #S_X14]
> + stp x16, x17, [sp, #S_X16]
> + stp x18, x19, [sp, #S_X18]
> + stp x20, x21, [sp, #S_X20]
> + stp x22, x23, [sp, #S_X22]
> + stp x24, x25, [sp, #S_X24]
> + stp x26, x27, [sp, #S_X26]
> + stp x28, x29, [sp, #S_X28]
> + add x0, sp, #S_FRAME_SIZE
> + stp lr, x0, [sp, #S_LR]
> +/*
> + * Construct a useful saved PSTATE
> + */
> + mrs x0, nzcv
> + and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
> + mrs x1, daif
> + and x1, x1, #(PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
> + orr x0, x0, x1
> + mrs x1, CurrentEL
> + and x1, x1, #(3 << 2)
> + orr x0, x1, x0
> + mrs x1, SPSel
> + and x1, x1, #1
> + orr x0, x1, x0
> + str x0, [sp, #S_PSTATE]
> +.endm
> +
> +.macro restore_all_base_regs
> + ldr x0, [sp, #S_PSTATE]
> + and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
> + msr nzcv, x0
> + ldp x0, x1, [sp, #S_X0]
> + ldp x2, x3, [sp, #S_X2]
> + ldp x4, x5, [sp, #S_X4]
> + ldp x6, x7, [sp, #S_X6]
> + ldp x8, x9, [sp, #S_X8]
> + ldp x10, x11, [sp, #S_X10]
> + ldp x12, x13, [sp, #S_X12]
> + ldp x14, x15, [sp, #S_X14]
> + ldp x16, x17, [sp, #S_X16]
> + ldp x18, x19, [sp, #S_X18]
> + ldp x20, x21, [sp, #S_X20]
> + ldp x22, x23, [sp, #S_X22]
> + ldp x24, x25, [sp, #S_X24]
> + ldp x26, x27, [sp, #S_X26]
> + ldp x28, x29, [sp, #S_X28]
> +.endm
> +
> +ENTRY(kretprobe_trampoline)
> +
> + sub sp, sp, #S_FRAME_SIZE
> +
> + save_all_base_regs
> +
> + mov x0, sp
> + bl trampoline_probe_handler
> + /* Replace trampoline address in lr with actual
> + orig_ret_addr return address. */
> + mov lr, x0
> +
> + restore_all_base_regs
> +
> + add sp, sp, #S_FRAME_SIZE
> +
> + ret
> +
> +ENDPROC(kretprobe_trampoline)
> --
> 2.5.0
>
--
Masami Hiramatsu <mhiramat@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | David Long <dave.long@linaro.org> |
|---|---|
| Date | 2016-06-03 05:40 +0200 |
| Subject | [PATCH v13 07/10] arm64: kprobes instruction simulation support |
| Message-ID | <rFO7M-6nc-39@gated-at.bofh.it> |
| In reply to | #1412726 |
From: Sandeepa Prabhu <sandeepa.s.prabhu@gmail.com>
Kprobes needs simulation of instructions that cannot be stepped
from a different memory location, e.g.: those instructions
that uses PC-relative addressing. In simulation, the behaviour
of the instruction is implemented using a copy of pt_regs.
The following instruction categories are simulated:
- All branching instructions(conditional, register, and immediate)
- Literal access instructions(load-literal, adr/adrp)
Conditional execution is limited to branching instructions in
ARM v8. If conditions at PSTATE do not match the condition fields
of opcode, the instruction is effectively NOP.
Thanks to Will Cohen for assorted suggested changes.
Signed-off-by: Sandeepa Prabhu <sandeepa.s.prabhu@gmail.com>
Signed-off-by: William Cohen <wcohen@redhat.com>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
arch/arm64/include/asm/insn.h | 1 +
arch/arm64/include/asm/probes.h | 5 +-
arch/arm64/kernel/Makefile | 3 +-
arch/arm64/kernel/insn.c | 1 +
arch/arm64/kernel/kprobes-arm64.c | 32 ++++-
arch/arm64/kernel/kprobes.c | 53 ++++++--
arch/arm64/kernel/probes-simulate-insn.c | 218 +++++++++++++++++++++++++++++++
arch/arm64/kernel/probes-simulate-insn.h | 28 ++++
8 files changed, 325 insertions(+), 16 deletions(-)
create mode 100644 arch/arm64/kernel/probes-simulate-insn.c
create mode 100644 arch/arm64/kernel/probes-simulate-insn.h
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index be2d2b9..1339f24 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -411,6 +411,7 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn);
typedef bool (pstate_check_t)(unsigned long);
extern pstate_check_t * const opcode_condition_checks[16];
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_INSN_H */
diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h
index c5fcbe6..d524f7d 100644
--- a/arch/arm64/include/asm/probes.h
+++ b/arch/arm64/include/asm/probes.h
@@ -15,11 +15,12 @@
#ifndef _ARM_PROBES_H
#define _ARM_PROBES_H
+#include <asm/opcodes.h>
+
struct kprobe;
struct arch_specific_insn;
typedef u32 kprobe_opcode_t;
-typedef unsigned long (kprobes_pstate_check_t)(unsigned long);
typedef void (kprobes_handler_t) (u32 opcode, long addr, struct pt_regs *);
enum pc_restore_type {
@@ -35,7 +36,7 @@ struct kprobe_pc_restore {
/* architecture specific copy of original instruction */
struct arch_specific_insn {
kprobe_opcode_t *insn;
- kprobes_pstate_check_t *pstate_cc;
+ pstate_check_t *pstate_cc;
kprobes_handler_t *handler;
/* restore address after step xol */
struct kprobe_pc_restore restore;
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index d78ed62..46724a1 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -37,7 +37,8 @@ arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
-arm64-obj-$(CONFIG_KPROBES) += kprobes.o kprobes-arm64.o
+arm64-obj-$(CONFIG_KPROBES) += kprobes.o kprobes-arm64.o \
+ probes-simulate-insn.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
arm64-obj-$(CONFIG_PCI) += pci.o
arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 4585b72..f949e4f 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -30,6 +30,7 @@
#include <asm/cacheflush.h>
#include <asm/debug-monitors.h>
#include <asm/fixmap.h>
+#include <asm/opcodes.h>
#include <asm/insn.h>
#define AARCH64_INSN_SF_BIT BIT(31)
diff --git a/arch/arm64/kernel/kprobes-arm64.c b/arch/arm64/kernel/kprobes-arm64.c
index 0af5d94..28b9c5b 100644
--- a/arch/arm64/kernel/kprobes-arm64.c
+++ b/arch/arm64/kernel/kprobes-arm64.c
@@ -21,6 +21,7 @@
#include <asm/sections.h>
#include "kprobes-arm64.h"
+#include "probes-simulate-insn.h"
static bool __kprobes aarch64_insn_is_steppable(u32 insn)
{
@@ -85,8 +86,37 @@ arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
*/
if (aarch64_insn_is_steppable(insn))
return INSN_GOOD;
- else
+
+ if (aarch64_insn_is_bcond(insn)) {
+ asi->handler = simulate_b_cond;
+ } else if (aarch64_insn_is_cbz(insn) ||
+ aarch64_insn_is_cbnz(insn)) {
+ asi->handler = simulate_cbz_cbnz;
+ } else if (aarch64_insn_is_tbz(insn) ||
+ aarch64_insn_is_tbnz(insn)) {
+ asi->handler = simulate_tbz_tbnz;
+ } else if (aarch64_insn_is_adr_adrp(insn)) {
+ asi->handler = simulate_adr_adrp;
+ } else if (aarch64_insn_is_b(insn) ||
+ aarch64_insn_is_bl(insn)) {
+ asi->handler = simulate_b_bl;
+ } else if (aarch64_insn_is_br(insn) ||
+ aarch64_insn_is_blr(insn) ||
+ aarch64_insn_is_ret(insn)) {
+ asi->handler = simulate_br_blr_ret;
+ } else if (aarch64_insn_is_ldr_lit(insn)) {
+ asi->handler = simulate_ldr_literal;
+ } else if (aarch64_insn_is_ldrsw_lit(insn)) {
+ asi->handler = simulate_ldrsw_literal;
+ } else {
+ /*
+ * Instruction cannot be stepped out-of-line and we don't
+ * (yet) simulate it.
+ */
return INSN_REJECTED;
+ }
+
+ return INSN_GOOD_NO_SLOT;
}
static bool __kprobes
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index ba43623..9d0ad47 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -45,6 +45,9 @@ void jprobe_return_break(void);
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+static void __kprobes
+post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
+
static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
{
/* prepare insn slot */
@@ -62,6 +65,24 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
p->ainsn.restore.type = RESTORE_PC;
}
+static void __kprobes arch_prepare_simulate(struct kprobe *p)
+{
+ /* This instructions is not executed xol. No need to adjust the PC */
+ p->ainsn.restore.addr = 0;
+ p->ainsn.restore.type = NO_RESTORE;
+}
+
+static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (p->ainsn.handler)
+ p->ainsn.handler((u32)p->opcode, (long)p->addr, regs);
+
+ /* single step simulated, now go for post processing */
+ post_kprobe_handler(kcb, regs);
+}
+
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
unsigned long probe_addr = (unsigned long)p->addr;
@@ -86,7 +107,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
return -EINVAL;
case INSN_GOOD_NO_SLOT: /* insn need simulation */
- return -EINVAL;
+ p->ainsn.insn = NULL;
+ break;
case INSN_GOOD: /* instruction uses slot */
p->ainsn.insn = get_insn_slot();
@@ -96,7 +118,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
};
/* prepare the instruction */
- arch_prepare_ss_slot(p);
+ if (p->ainsn.insn)
+ arch_prepare_ss_slot(p);
+ else
+ arch_prepare_simulate(p);
return 0;
}
@@ -222,20 +247,24 @@ static void __kprobes setup_singlestep(struct kprobe *p,
kcb->kprobe_status = KPROBE_HIT_SS;
}
- BUG_ON(!p->ainsn.insn);
- /* prepare for single stepping */
- slot = (unsigned long)p->ainsn.insn;
+ if (p->ainsn.insn) {
+ /* prepare for single stepping */
+ slot = (unsigned long)p->ainsn.insn;
- set_ss_context(kcb, slot); /* mark pending ss */
+ set_ss_context(kcb, slot); /* mark pending ss */
- if (kcb->kprobe_status == KPROBE_REENTER)
- spsr_set_debug_flag(regs, 0);
+ if (kcb->kprobe_status == KPROBE_REENTER)
+ spsr_set_debug_flag(regs, 0);
- /* IRQs and single stepping do not mix well. */
- kprobes_save_local_irqflag(kcb, regs);
- kernel_enable_single_step(regs);
- instruction_pointer(regs) = slot;
+ /* IRQs and single stepping do not mix well. */
+ kprobes_save_local_irqflag(kcb, regs);
+ kernel_enable_single_step(regs);
+ instruction_pointer(regs) = slot;
+ } else {
+ /* insn simulation */
+ arch_simulate_insn(p, regs);
+ }
}
static int __kprobes reenter_kprobe(struct kprobe *p,
diff --git a/arch/arm64/kernel/probes-simulate-insn.c b/arch/arm64/kernel/probes-simulate-insn.c
new file mode 100644
index 0000000..726caaa
--- /dev/null
+++ b/arch/arm64/kernel/probes-simulate-insn.c
@@ -0,0 +1,218 @@
+/*
+ * arch/arm64/kernel/probes-simulate-insn.c
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+
+#include "probes-simulate-insn.h"
+
+#define sign_extend(x, signbit) \
+ ((x) | (0 - ((x) & (1 << (signbit)))))
+
+#define bbl_displacement(insn) \
+ sign_extend(((insn) & 0x3ffffff) << 2, 27)
+
+#define bcond_displacement(insn) \
+ sign_extend(((insn >> 5) & 0x7ffff) << 2, 20)
+
+#define cbz_displacement(insn) \
+ sign_extend(((insn >> 5) & 0x7ffff) << 2, 20)
+
+#define tbz_displacement(insn) \
+ sign_extend(((insn >> 5) & 0x3fff) << 2, 15)
+
+#define ldr_displacement(insn) \
+ sign_extend(((insn >> 5) & 0x7ffff) << 2, 20)
+
+static inline void set_x_reg(struct pt_regs *regs, int reg, u64 val)
+{
+ if (reg < 31)
+ regs->regs[reg] = val;
+}
+
+static inline void set_w_reg(struct pt_regs *regs, int reg, u64 val)
+{
+ if (reg < 31)
+ regs->regs[reg] = lower_32_bits(val);
+}
+
+static inline u64 get_x_reg(struct pt_regs *regs, int reg)
+{
+ if (reg < 31)
+ return regs->regs[reg];
+ else
+ return 0;
+}
+
+static inline u32 get_w_reg(struct pt_regs *regs, int reg)
+{
+ if (reg < 31)
+ return lower_32_bits(regs->regs[reg]);
+ else
+ return 0;
+}
+
+static bool __kprobes check_cbz(u32 opcode, struct pt_regs *regs)
+{
+ int xn = opcode & 0x1f;
+
+ return (opcode & (1 << 31)) ?
+ (get_x_reg(regs, xn) == 0) : (get_w_reg(regs, xn) == 0);
+}
+
+static bool __kprobes check_cbnz(u32 opcode, struct pt_regs *regs)
+{
+ int xn = opcode & 0x1f;
+
+ return (opcode & (1 << 31)) ?
+ (get_x_reg(regs, xn) != 0) : (get_w_reg(regs, xn) != 0);
+}
+
+static bool __kprobes check_tbz(u32 opcode, struct pt_regs *regs)
+{
+ int xn = opcode & 0x1f;
+ int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+ return ((get_x_reg(regs, xn) >> bit_pos) & 0x1) == 0;
+}
+
+static bool __kprobes check_tbnz(u32 opcode, struct pt_regs *regs)
+{
+ int xn = opcode & 0x1f;
+ int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+ return ((get_x_reg(regs, xn) >> bit_pos) & 0x1) != 0;
+}
+
+/*
+ * instruction simulation functions
+ */
+void __kprobes
+simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs)
+{
+ long imm, xn, val;
+
+ xn = opcode & 0x1f;
+ imm = ((opcode >> 3) & 0x1ffffc) | ((opcode >> 29) & 0x3);
+ imm = sign_extend(imm, 20);
+ if (opcode & 0x80000000)
+ val = (imm<<12) + (addr & 0xfffffffffffff000);
+ else
+ val = imm + addr;
+
+ set_x_reg(regs, xn, val);
+
+ instruction_pointer(regs) += 4;
+}
+
+void __kprobes
+simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs)
+{
+ int disp = bbl_displacement(opcode);
+
+ /* Link register is x30 */
+ if (opcode & (1 << 31))
+ set_x_reg(regs, 30, addr + 4);
+
+ instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
+{
+ int disp = 4;
+
+ if (opcode_condition_checks[opcode & 0xf](regs->pstate & 0xffffffff))
+ disp = bcond_displacement(opcode);
+
+ instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs)
+{
+ int xn = (opcode >> 5) & 0x1f;
+
+ /* update pc first in case we're doing a "blr lr" */
+ instruction_pointer(regs) = get_x_reg(regs, xn);
+
+ /* Link register is x30 */
+ if (((opcode >> 21) & 0x3) == 1)
+ set_x_reg(regs, 30, addr + 4);
+}
+
+void __kprobes
+simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+ int disp = 4;
+
+ if (opcode & (1 << 24)) {
+ if (check_cbnz(opcode, regs))
+ disp = cbz_displacement(opcode);
+ } else {
+ if (check_cbz(opcode, regs))
+ disp = cbz_displacement(opcode);
+ }
+ instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+ int disp = 4;
+
+ if (opcode & (1 << 24)) {
+ if (check_tbnz(opcode, regs))
+ disp = tbz_displacement(opcode);
+ } else {
+ if (check_tbz(opcode, regs))
+ disp = tbz_displacement(opcode);
+ }
+ instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs)
+{
+ u64 *load_addr;
+ int xn = opcode & 0x1f;
+ int disp;
+
+ disp = ldr_displacement(opcode);
+ load_addr = (u64 *) (addr + disp);
+
+ if (opcode & (1 << 30)) /* x0-x30 */
+ set_x_reg(regs, xn, *load_addr);
+ else /* w0-w30 */
+ set_w_reg(regs, xn, *load_addr);
+
+ instruction_pointer(regs) += 4;
+}
+
+void __kprobes
+simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs)
+{
+ s32 *load_addr;
+ int xn = opcode & 0x1f;
+ int disp;
+
+ disp = ldr_displacement(opcode);
+ load_addr = (s32 *) (addr + disp);
+
+ set_x_reg(regs, xn, *load_addr);
+
+ instruction_pointer(regs) += 4;
+}
diff --git a/arch/arm64/kernel/probes-simulate-insn.h b/arch/arm64/kernel/probes-simulate-insn.h
new file mode 100644
index 0000000..d6bb9a5
--- /dev/null
+++ b/arch/arm64/kernel/probes-simulate-insn.h
@@ -0,0 +1,28 @@
+/*
+ * arch/arm64/kernel/probes-simulate-insn.h
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ARM_KERNEL_PROBES_SIMULATE_INSN_H
+#define _ARM_KERNEL_PROBES_SIMULATE_INSN_H
+
+void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs);
+
+#endif /* _ARM_KERNEL_PROBES_SIMULATE_INSN_H */
--
2.5.0
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web