All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-20 20:19 ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: "David A. Long" <dave.long@linaro.org>

This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
first seen in October 2013. This version attempts to address concerns raised by
reviewers and also fixes problems discovered during testing.

This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
and return probes(kretprobes) support for ARM64.

The kprobes mechanism makes use of software breakpoint and single stepping
support available in the ARM v8 kernel.

Changes since v2 include:

1) Removal of NOP padding in kprobe XOL slots. Slots are now exactly one
instruction long.
2) Disabling of interrupts during execution in single-step mode.
3) Fixing of numerous problems in instruction simulation code (mostly
thanks to Will Cohen).
4) Support for the HAVE_REGS_AND_STACK_ACCESS_API feature is added, to allow
access to kprobes through debugfs.
5) kprobes is *not* enabled in defconfig.
6) Numerous complaints from checkpatch have been cleaned up, although a couple
remain as removing the function pointer typedefs results in ugly code.

Changes since v3 include:

1) Remove table-driven instruction parsing and replace with an if statement
calling out to old and new instruction test functions in insn.c.
2) I removed the addition of orig_x0 to ptrace.h.
3) Reorder the patches.
4) Replace the previous interrupt disabling (from Will Cohen) with
an improved solution (from Steve Capper).

Changes since v4 include:

1) Added insn.c functions to detect exception instructions and DAIF
   read/write instructions, and use them to reject probing same.
2) Changed adr detect function to also recognize adrp. Reject both.
3) Added missing __kprobes for some new functions.
4) Added call to kprobes_fault_handler from mm do_page_fault.
5) Reject all non-simulated branch/ret instructions, not just those
   that use an immediate offset.
6) Moved software breakpoint definitions into debug-monitors.h.
7) Removed "!XIP_KERNEL" from Kconfig.
8) changed kprobes_condition_check_t and kprobes_prepare_t to probes_*,
   for future sharing with uprobes.
9) Removed bogus call to kprobes_restore_local_irqflag() from 
   trampoline_probe_handler().

Changes since v5 include:

1) Replaced installation of breakpoint hook with direct call from the
handlers in debug-monitors.c, as requested.
2) Reject probing of instructions that read the interrupt mask, in
addition to instructions that set it.
3) Cleaned up comments describing usage of Debug Mask.
4) Added KPROBE_REENTER case in reenter_kprobe.
5) Corrected the ifdef'd definitions for notify_page_fault() to be
consistent when KPROBES is not configed.
6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
7) Added back in missing new files in previous patch.
8) Changed two instances of pr_warning() to pr_warn().

Note that there seems to be at least a potential issue with kprobes
on multiple (possibly all) platforms having to do with use of kfree
inside of the kretprobes trampoline handler.  This has manifested
occasionally in systemtap testing on arm64.  There does not appear to
be an simple solution to the problem.

David A. Long (2):
  arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  arm64: Add more test functions to insn.c

Sandeepa Prabhu (4):
  arm64: Kprobes with single stepping support
  arm64: kprobes instruction simulation support
  arm64: Add kernel return probes support (kretprobes)
  kprobes: Add arm64 case in kprobe example module

 arch/arm64/Kconfig                       |   3 +
 arch/arm64/include/asm/debug-monitors.h  |   5 +
 arch/arm64/include/asm/insn.h            |  18 +
 arch/arm64/include/asm/kprobes.h         |  63 +++
 arch/arm64/include/asm/probes.h          |  50 +++
 arch/arm64/include/asm/ptrace.h          |  32 +-
 arch/arm64/include/uapi/asm/ptrace.h     |  36 ++
 arch/arm64/kernel/Makefile               |   3 +
 arch/arm64/kernel/debug-monitors.c       |  35 +-
 arch/arm64/kernel/insn.c                 |  28 ++
 arch/arm64/kernel/kprobes-arm64.c        | 166 ++++++++
 arch/arm64/kernel/kprobes-arm64.h        |  30 ++
 arch/arm64/kernel/kprobes.c              | 676 +++++++++++++++++++++++++++++++
 arch/arm64/kernel/kprobes.h              |  24 ++
 arch/arm64/kernel/probes-condn-check.c   | 122 ++++++
 arch/arm64/kernel/probes-simulate-insn.c | 174 ++++++++
 arch/arm64/kernel/probes-simulate-insn.h |  33 ++
 arch/arm64/kernel/ptrace.c               | 116 ++++++
 arch/arm64/kernel/vmlinux.lds.S          |   1 +
 arch/arm64/mm/fault.c                    |  25 ++
 samples/kprobes/kprobe_example.c         |   8 +
 21 files changed, 1637 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm64/include/asm/kprobes.h
 create mode 100644 arch/arm64/include/asm/probes.h
 create mode 100644 arch/arm64/kernel/kprobes-arm64.c
 create mode 100644 arch/arm64/kernel/kprobes-arm64.h
 create mode 100644 arch/arm64/kernel/kprobes.c
 create mode 100644 arch/arm64/kernel/kprobes.h
 create mode 100644 arch/arm64/kernel/probes-condn-check.c
 create mode 100644 arch/arm64/kernel/probes-simulate-insn.c
 create mode 100644 arch/arm64/kernel/probes-simulate-insn.h

-- 
1.8.1.2


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-20 20:19 ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: "David A. Long" <dave.long@linaro.org>

This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
first seen in October 2013. This version attempts to address concerns raised by
reviewers and also fixes problems discovered during testing.

This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
and return probes(kretprobes) support for ARM64.

The kprobes mechanism makes use of software breakpoint and single stepping
support available in the ARM v8 kernel.

Changes since v2 include:

1) Removal of NOP padding in kprobe XOL slots. Slots are now exactly one
instruction long.
2) Disabling of interrupts during execution in single-step mode.
3) Fixing of numerous problems in instruction simulation code (mostly
thanks to Will Cohen).
4) Support for the HAVE_REGS_AND_STACK_ACCESS_API feature is added, to allow
access to kprobes through debugfs.
5) kprobes is *not* enabled in defconfig.
6) Numerous complaints from checkpatch have been cleaned up, although a couple
remain as removing the function pointer typedefs results in ugly code.

Changes since v3 include:

1) Remove table-driven instruction parsing and replace with an if statement
calling out to old and new instruction test functions in insn.c.
2) I removed the addition of orig_x0 to ptrace.h.
3) Reorder the patches.
4) Replace the previous interrupt disabling (from Will Cohen) with
an improved solution (from Steve Capper).

Changes since v4 include:

1) Added insn.c functions to detect exception instructions and DAIF
   read/write instructions, and use them to reject probing same.
2) Changed adr detect function to also recognize adrp. Reject both.
3) Added missing __kprobes for some new functions.
4) Added call to kprobes_fault_handler from mm do_page_fault.
5) Reject all non-simulated branch/ret instructions, not just those
   that use an immediate offset.
6) Moved software breakpoint definitions into debug-monitors.h.
7) Removed "!XIP_KERNEL" from Kconfig.
8) changed kprobes_condition_check_t and kprobes_prepare_t to probes_*,
   for future sharing with uprobes.
9) Removed bogus call to kprobes_restore_local_irqflag() from 
   trampoline_probe_handler().

Changes since v5 include:

1) Replaced installation of breakpoint hook with direct call from the
handlers in debug-monitors.c, as requested.
2) Reject probing of instructions that read the interrupt mask, in
addition to instructions that set it.
3) Cleaned up comments describing usage of Debug Mask.
4) Added KPROBE_REENTER case in reenter_kprobe.
5) Corrected the ifdef'd definitions for notify_page_fault() to be
consistent when KPROBES is not configed.
6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
7) Added back in missing new files in previous patch.
8) Changed two instances of pr_warning() to pr_warn().

Note that there seems to be at least a potential issue with kprobes
on multiple (possibly all) platforms having to do with use of kfree
inside of the kretprobes trampoline handler.  This has manifested
occasionally in systemtap testing on arm64.  There does not appear to
be an simple solution to the problem.

David A. Long (2):
  arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  arm64: Add more test functions to insn.c

Sandeepa Prabhu (4):
  arm64: Kprobes with single stepping support
  arm64: kprobes instruction simulation support
  arm64: Add kernel return probes support (kretprobes)
  kprobes: Add arm64 case in kprobe example module

 arch/arm64/Kconfig                       |   3 +
 arch/arm64/include/asm/debug-monitors.h  |   5 +
 arch/arm64/include/asm/insn.h            |  18 +
 arch/arm64/include/asm/kprobes.h         |  63 +++
 arch/arm64/include/asm/probes.h          |  50 +++
 arch/arm64/include/asm/ptrace.h          |  32 +-
 arch/arm64/include/uapi/asm/ptrace.h     |  36 ++
 arch/arm64/kernel/Makefile               |   3 +
 arch/arm64/kernel/debug-monitors.c       |  35 +-
 arch/arm64/kernel/insn.c                 |  28 ++
 arch/arm64/kernel/kprobes-arm64.c        | 166 ++++++++
 arch/arm64/kernel/kprobes-arm64.h        |  30 ++
 arch/arm64/kernel/kprobes.c              | 676 +++++++++++++++++++++++++++++++
 arch/arm64/kernel/kprobes.h              |  24 ++
 arch/arm64/kernel/probes-condn-check.c   | 122 ++++++
 arch/arm64/kernel/probes-simulate-insn.c | 174 ++++++++
 arch/arm64/kernel/probes-simulate-insn.h |  33 ++
 arch/arm64/kernel/ptrace.c               | 116 ++++++
 arch/arm64/kernel/vmlinux.lds.S          |   1 +
 arch/arm64/mm/fault.c                    |  25 ++
 samples/kprobes/kprobe_example.c         |   8 +
 21 files changed, 1637 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm64/include/asm/kprobes.h
 create mode 100644 arch/arm64/include/asm/probes.h
 create mode 100644 arch/arm64/kernel/kprobes-arm64.c
 create mode 100644 arch/arm64/kernel/kprobes-arm64.h
 create mode 100644 arch/arm64/kernel/kprobes.c
 create mode 100644 arch/arm64/kernel/kprobes.h
 create mode 100644 arch/arm64/kernel/probes-condn-check.c
 create mode 100644 arch/arm64/kernel/probes-simulate-insn.c
 create mode 100644 arch/arm64/kernel/probes-simulate-insn.h

-- 
1.8.1.2

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  2015-04-20 20:19 ` David Long
@ 2015-04-20 20:19   ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: "David A. Long" <dave.long@linaro.org>

Add HAVE_REGS_AND_STACK_ACCESS_API feature for arm64.

Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/Kconfig                   |   1 +
 arch/arm64/include/asm/ptrace.h      |  29 +++++++++
 arch/arm64/include/uapi/asm/ptrace.h |  36 +++++++++++
 arch/arm64/kernel/ptrace.c           | 116 +++++++++++++++++++++++++++++++++++
 4 files changed, 182 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1b8e973..987a681 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -65,6 +65,7 @@ config ARM64
 	select HAVE_PERF_EVENTS
 	select HAVE_PERF_REGS
 	select HAVE_PERF_USER_STACK_DUMP
+	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_DOMAIN
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index d6dd9fd..655620e 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -118,6 +118,8 @@ struct pt_regs {
 	u64 syscallno;
 };
 
+#define MAX_REG_OFFSET (sizeof(struct user_pt_regs) - sizeof(u64))
+
 #define arch_has_single_step()	(1)
 
 #ifdef CONFIG_COMPAT
@@ -146,11 +148,38 @@ struct pt_regs {
 #define user_stack_pointer(regs) \
 	(!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
 
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:	   pt_regs from which register value is gotten
+ * @offset:    offset number of the register.
+ *
+ * regs_get_register returns the value of a register whose offset from @regs.
+ * The @offset is the offset of the register in struct pt_regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline u64 regs_get_register(struct pt_regs *regs,
+					      unsigned int offset)
+{
+	if (unlikely(offset > MAX_REG_OFFSET))
+		return 0;
+	return *(u64 *)((u64)regs + offset);
+}
+
+/* Valid only for Kernel mode traps. */
+static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+{
+	return regs->ARM_sp;
+}
+
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
 	return regs->regs[0];
 }
 
+extern int regs_query_register_offset(const char *name);
+extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+					       unsigned int n);
+
 /*
  * Are the current registers suitable for user mode? (used to maintain
  * security in signal handlers)
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 6913643..58c0223 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -61,6 +61,42 @@
 
 #ifndef __ASSEMBLY__
 
+#define ARM_pstate	pstate
+#define ARM_pc		pc
+#define ARM_sp		sp
+#define ARM_lr		regs[30]
+#define ARM_fp		regs[29]
+#define ARM_x28		regs[28]
+#define ARM_x27		regs[27]
+#define ARM_x26		regs[26]
+#define ARM_x25		regs[25]
+#define ARM_x24		regs[24]
+#define ARM_x23		regs[23]
+#define ARM_x22		regs[22]
+#define ARM_x21		regs[21]
+#define ARM_x20		regs[20]
+#define ARM_x19		regs[19]
+#define ARM_x18		regs[18]
+#define ARM_ip1		regs[17]
+#define ARM_ip0		regs[16]
+#define ARM_x15		regs[15]
+#define ARM_x14		regs[14]
+#define ARM_x13		regs[13]
+#define ARM_x12		regs[12]
+#define ARM_x11		regs[11]
+#define ARM_x10		regs[10]
+#define ARM_x9		regs[9]
+#define ARM_x8		regs[8]
+#define ARM_x7		regs[7]
+#define ARM_x6		regs[6]
+#define ARM_x5		regs[5]
+#define ARM_x4		regs[4]
+#define ARM_x3		regs[3]
+#define ARM_x2		regs[2]
+#define ARM_x1		regs[1]
+#define ARM_x0		regs[0]
+#define ARM_ORIG_x0	orig_x0
+
 /*
  * User structures for general purpose, floating point and debug registers.
  */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index d882b83..a889f79 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -48,6 +48,122 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
 
+struct pt_regs_offset {
+	const char *name;
+	int offset;
+};
+
+#define REG_OFFSET_NAME(r) \
+	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+	REG_OFFSET_NAME(x0),
+	REG_OFFSET_NAME(x1),
+	REG_OFFSET_NAME(x2),
+	REG_OFFSET_NAME(x3),
+	REG_OFFSET_NAME(x4),
+	REG_OFFSET_NAME(x5),
+	REG_OFFSET_NAME(x6),
+	REG_OFFSET_NAME(x7),
+	REG_OFFSET_NAME(x8),
+	REG_OFFSET_NAME(x9),
+	REG_OFFSET_NAME(x10),
+	REG_OFFSET_NAME(x11),
+	REG_OFFSET_NAME(x12),
+	REG_OFFSET_NAME(x13),
+	REG_OFFSET_NAME(x14),
+	REG_OFFSET_NAME(x15),
+	REG_OFFSET_NAME(ip0),
+	REG_OFFSET_NAME(ip1),
+	REG_OFFSET_NAME(x18),
+	REG_OFFSET_NAME(x19),
+	REG_OFFSET_NAME(x20),
+	REG_OFFSET_NAME(x21),
+	REG_OFFSET_NAME(x22),
+	REG_OFFSET_NAME(x23),
+	REG_OFFSET_NAME(x24),
+	REG_OFFSET_NAME(x25),
+	REG_OFFSET_NAME(x26),
+	REG_OFFSET_NAME(x27),
+	REG_OFFSET_NAME(x28),
+	REG_OFFSET_NAME(fp),
+	REG_OFFSET_NAME(lr),
+	REG_OFFSET_NAME(sp),
+	REG_OFFSET_NAME(pc),
+	REG_OFFSET_NAME(pstate),
+	REG_OFFSET_NAME(ORIG_x0),
+	REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:	the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+	const struct pt_regs_offset *roff;
+
+	for (roff = regoffset_table; roff->name != NULL; roff++)
+		if (!strcmp(roff->name, name))
+			return roff->offset;
+	return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:	the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+	const struct pt_regs_offset *roff;
+
+	for (roff = regoffset_table; roff->name != NULL; roff++)
+		if (roff->offset == offset)
+			return roff->name;
+	return NULL;
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @addr:      address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
+{
+	return ((addr & ~(THREAD_SIZE - 1))  ==
+		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:	pt_regs which contains kernel stack pointer.
+ * @n:		stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
+{
+	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+
+	addr += n;
+	if (regs_within_kernel_stack(regs, (unsigned long)addr))
+		return *addr;
+	else
+		return 0;
+}
+
 /*
  * TODO: does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
@ 2015-04-20 20:19   ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: "David A. Long" <dave.long@linaro.org>

Add HAVE_REGS_AND_STACK_ACCESS_API feature for arm64.

Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/Kconfig                   |   1 +
 arch/arm64/include/asm/ptrace.h      |  29 +++++++++
 arch/arm64/include/uapi/asm/ptrace.h |  36 +++++++++++
 arch/arm64/kernel/ptrace.c           | 116 +++++++++++++++++++++++++++++++++++
 4 files changed, 182 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1b8e973..987a681 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -65,6 +65,7 @@ config ARM64
 	select HAVE_PERF_EVENTS
 	select HAVE_PERF_REGS
 	select HAVE_PERF_USER_STACK_DUMP
+	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_DOMAIN
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index d6dd9fd..655620e 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -118,6 +118,8 @@ struct pt_regs {
 	u64 syscallno;
 };
 
+#define MAX_REG_OFFSET (sizeof(struct user_pt_regs) - sizeof(u64))
+
 #define arch_has_single_step()	(1)
 
 #ifdef CONFIG_COMPAT
@@ -146,11 +148,38 @@ struct pt_regs {
 #define user_stack_pointer(regs) \
 	(!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
 
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:	   pt_regs from which register value is gotten
+ * @offset:    offset number of the register.
+ *
+ * regs_get_register returns the value of a register whose offset from @regs.
+ * The @offset is the offset of the register in struct pt_regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline u64 regs_get_register(struct pt_regs *regs,
+					      unsigned int offset)
+{
+	if (unlikely(offset > MAX_REG_OFFSET))
+		return 0;
+	return *(u64 *)((u64)regs + offset);
+}
+
+/* Valid only for Kernel mode traps. */
+static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+{
+	return regs->ARM_sp;
+}
+
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
 	return regs->regs[0];
 }
 
+extern int regs_query_register_offset(const char *name);
+extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+					       unsigned int n);
+
 /*
  * Are the current registers suitable for user mode? (used to maintain
  * security in signal handlers)
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index 6913643..58c0223 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -61,6 +61,42 @@
 
 #ifndef __ASSEMBLY__
 
+#define ARM_pstate	pstate
+#define ARM_pc		pc
+#define ARM_sp		sp
+#define ARM_lr		regs[30]
+#define ARM_fp		regs[29]
+#define ARM_x28		regs[28]
+#define ARM_x27		regs[27]
+#define ARM_x26		regs[26]
+#define ARM_x25		regs[25]
+#define ARM_x24		regs[24]
+#define ARM_x23		regs[23]
+#define ARM_x22		regs[22]
+#define ARM_x21		regs[21]
+#define ARM_x20		regs[20]
+#define ARM_x19		regs[19]
+#define ARM_x18		regs[18]
+#define ARM_ip1		regs[17]
+#define ARM_ip0		regs[16]
+#define ARM_x15		regs[15]
+#define ARM_x14		regs[14]
+#define ARM_x13		regs[13]
+#define ARM_x12		regs[12]
+#define ARM_x11		regs[11]
+#define ARM_x10		regs[10]
+#define ARM_x9		regs[9]
+#define ARM_x8		regs[8]
+#define ARM_x7		regs[7]
+#define ARM_x6		regs[6]
+#define ARM_x5		regs[5]
+#define ARM_x4		regs[4]
+#define ARM_x3		regs[3]
+#define ARM_x2		regs[2]
+#define ARM_x1		regs[1]
+#define ARM_x0		regs[0]
+#define ARM_ORIG_x0	orig_x0
+
 /*
  * User structures for general purpose, floating point and debug registers.
  */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index d882b83..a889f79 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -48,6 +48,122 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
 
+struct pt_regs_offset {
+	const char *name;
+	int offset;
+};
+
+#define REG_OFFSET_NAME(r) \
+	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+	REG_OFFSET_NAME(x0),
+	REG_OFFSET_NAME(x1),
+	REG_OFFSET_NAME(x2),
+	REG_OFFSET_NAME(x3),
+	REG_OFFSET_NAME(x4),
+	REG_OFFSET_NAME(x5),
+	REG_OFFSET_NAME(x6),
+	REG_OFFSET_NAME(x7),
+	REG_OFFSET_NAME(x8),
+	REG_OFFSET_NAME(x9),
+	REG_OFFSET_NAME(x10),
+	REG_OFFSET_NAME(x11),
+	REG_OFFSET_NAME(x12),
+	REG_OFFSET_NAME(x13),
+	REG_OFFSET_NAME(x14),
+	REG_OFFSET_NAME(x15),
+	REG_OFFSET_NAME(ip0),
+	REG_OFFSET_NAME(ip1),
+	REG_OFFSET_NAME(x18),
+	REG_OFFSET_NAME(x19),
+	REG_OFFSET_NAME(x20),
+	REG_OFFSET_NAME(x21),
+	REG_OFFSET_NAME(x22),
+	REG_OFFSET_NAME(x23),
+	REG_OFFSET_NAME(x24),
+	REG_OFFSET_NAME(x25),
+	REG_OFFSET_NAME(x26),
+	REG_OFFSET_NAME(x27),
+	REG_OFFSET_NAME(x28),
+	REG_OFFSET_NAME(fp),
+	REG_OFFSET_NAME(lr),
+	REG_OFFSET_NAME(sp),
+	REG_OFFSET_NAME(pc),
+	REG_OFFSET_NAME(pstate),
+	REG_OFFSET_NAME(ORIG_x0),
+	REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:	the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+	const struct pt_regs_offset *roff;
+
+	for (roff = regoffset_table; roff->name != NULL; roff++)
+		if (!strcmp(roff->name, name))
+			return roff->offset;
+	return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:	the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+	const struct pt_regs_offset *roff;
+
+	for (roff = regoffset_table; roff->name != NULL; roff++)
+		if (roff->offset == offset)
+			return roff->name;
+	return NULL;
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @addr:      address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
+{
+	return ((addr & ~(THREAD_SIZE - 1))  ==
+		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:	pt_regs which contains kernel stack pointer.
+ * @n:		stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
+{
+	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+
+	addr += n;
+	if (regs_within_kernel_stack(regs, (unsigned long)addr))
+		return *addr;
+	else
+		return 0;
+}
+
 /*
  * TODO: does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 2/6] arm64: Add more test functions to insn.c
  2015-04-20 20:19 ` David Long
@ 2015-04-20 20:19   ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: "David A. Long" <dave.long@linaro.org>

Certain instructions are hard to execute correctly out-of-line (as in
kprobes).  Test functions are added to insn.[hc] to identify these.  The
instructions include any that use PC-relative addressing, change the PC,
or change interrupt masking. For efficiency and simplicity test
functions are also added for small collections of related instructions.

Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/include/asm/insn.h | 18 ++++++++++++++++++
 arch/arm64/kernel/insn.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index d2f4942..0626404 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -223,8 +223,13 @@ static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
 static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
 { return (val); }
 
+__AARCH64_INSN_FUNCS(adr_adrp,	0x1F000000, 0x10000000)
+__AARCH64_INSN_FUNCS(prfm_lit,	0xFF000000, 0xD8000000)
 __AARCH64_INSN_FUNCS(str_reg,	0x3FE0EC00, 0x38206800)
 __AARCH64_INSN_FUNCS(ldr_reg,	0x3FE0EC00, 0x38606800)
+__AARCH64_INSN_FUNCS(ldr_lit,	0xBF000000, 0x18000000)
+__AARCH64_INSN_FUNCS(ldrsw_lit,	0xFF000000, 0x98000000)
+__AARCH64_INSN_FUNCS(exclusive,	0x3F000000, 0x08000000)
 __AARCH64_INSN_FUNCS(stp_post,	0x7FC00000, 0x28800000)
 __AARCH64_INSN_FUNCS(ldp_post,	0x7FC00000, 0x28C00000)
 __AARCH64_INSN_FUNCS(stp_pre,	0x7FC00000, 0x29800000)
@@ -264,19 +269,29 @@ __AARCH64_INSN_FUNCS(ands,	0x7F200000, 0x6A000000)
 __AARCH64_INSN_FUNCS(bics,	0x7F200000, 0x6A200000)
 __AARCH64_INSN_FUNCS(b,		0xFC000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bl,	0xFC000000, 0x94000000)
+__AARCH64_INSN_FUNCS(b_bl,	0x7C000000, 0x14000000)
+__AARCH64_INSN_FUNCS(cb,	0x7E000000, 0x34000000)
 __AARCH64_INSN_FUNCS(cbz,	0x7F000000, 0x34000000)
 __AARCH64_INSN_FUNCS(cbnz,	0x7F000000, 0x35000000)
+__AARCH64_INSN_FUNCS(tb,	0x7E000000, 0x36000000)
 __AARCH64_INSN_FUNCS(tbz,	0x7F000000, 0x36000000)
 __AARCH64_INSN_FUNCS(tbnz,	0x7F000000, 0x37000000)
+__AARCH64_INSN_FUNCS(b_bl_cb_tb, 0x5C000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bcond,	0xFF000010, 0x54000000)
 __AARCH64_INSN_FUNCS(svc,	0xFFE0001F, 0xD4000001)
 __AARCH64_INSN_FUNCS(hvc,	0xFFE0001F, 0xD4000002)
 __AARCH64_INSN_FUNCS(smc,	0xFFE0001F, 0xD4000003)
 __AARCH64_INSN_FUNCS(brk,	0xFFE0001F, 0xD4200000)
+__AARCH64_INSN_FUNCS(exception,	0xFF000000, 0xD4000000)
 __AARCH64_INSN_FUNCS(hint,	0xFFFFF01F, 0xD503201F)
 __AARCH64_INSN_FUNCS(br,	0xFFFFFC1F, 0xD61F0000)
 __AARCH64_INSN_FUNCS(blr,	0xFFFFFC1F, 0xD63F0000)
+__AARCH64_INSN_FUNCS(br_blr,	0xFFDFFC1F, 0xD61F0000)
 __AARCH64_INSN_FUNCS(ret,	0xFFFFFC1F, 0xD65F0000)
+__AARCH64_INSN_FUNCS(msr_imm,	0xFFF8F000, 0xD5004000)
+__AARCH64_INSN_FUNCS(msr_reg,	0xFFF00000, 0xD5100000)
+__AARCH64_INSN_FUNCS(set_clr_daif, 0xFFFFF0DF, 0xD50340DF)
+__AARCH64_INSN_FUNCS(rd_wr_daif, 0xFFDFFFE0, 0xD51B4220)
 
 #undef	__AARCH64_INSN_FUNCS
 
@@ -285,6 +300,9 @@ bool aarch64_insn_is_nop(u32 insn);
 int aarch64_insn_read(void *addr, u32 *insnp);
 int aarch64_insn_write(void *addr, u32 insn);
 enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
+bool aarch64_insn_uses_literal(u32 insn);
+bool aarch64_insn_is_branch(u32 insn);
+bool aarch64_insn_is_daif_access(u32 insn);
 u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
 				  u32 insn, u64 imm);
 u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index c8eca88..cda1b3b 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -155,6 +155,34 @@ static bool __kprobes __aarch64_insn_hotpatch_safe(u32 insn)
 		aarch64_insn_is_nop(insn);
 }
 
+bool __kprobes aarch64_insn_uses_literal(u32 insn)
+{
+	/* ldr/ldrsw (literal), prfm */
+
+	return aarch64_insn_is_ldr_lit(insn) ||
+		aarch64_insn_is_ldrsw_lit(insn) ||
+		aarch64_insn_is_adr_adrp(insn) ||
+		aarch64_insn_is_prfm_lit(insn);
+}
+
+bool __kprobes aarch64_insn_is_branch(u32 insn)
+{
+	/* b, bl, cb*, tb*, b.cond, br, blr */
+
+	return aarch64_insn_is_b_bl_cb_tb(insn) ||
+		aarch64_insn_is_br_blr(insn) ||
+		aarch64_insn_is_ret(insn) ||
+		aarch64_insn_is_bcond(insn);
+}
+
+bool __kprobes aarch64_insn_is_daif_access(u32 insn)
+{
+	/* msr daif, mrs daif, msr daifset, msr daifclr */
+
+	return aarch64_insn_is_rd_wr_daif(insn) ||
+		aarch64_insn_is_set_clr_daif(insn);
+}
+
 /*
  * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a
  * Section B2.6.5 "Concurrent modification and execution of instructions":
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 2/6] arm64: Add more test functions to insn.c
@ 2015-04-20 20:19   ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: "David A. Long" <dave.long@linaro.org>

Certain instructions are hard to execute correctly out-of-line (as in
kprobes).  Test functions are added to insn.[hc] to identify these.  The
instructions include any that use PC-relative addressing, change the PC,
or change interrupt masking. For efficiency and simplicity test
functions are also added for small collections of related instructions.

Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/include/asm/insn.h | 18 ++++++++++++++++++
 arch/arm64/kernel/insn.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index d2f4942..0626404 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -223,8 +223,13 @@ static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
 static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
 { return (val); }
 
+__AARCH64_INSN_FUNCS(adr_adrp,	0x1F000000, 0x10000000)
+__AARCH64_INSN_FUNCS(prfm_lit,	0xFF000000, 0xD8000000)
 __AARCH64_INSN_FUNCS(str_reg,	0x3FE0EC00, 0x38206800)
 __AARCH64_INSN_FUNCS(ldr_reg,	0x3FE0EC00, 0x38606800)
+__AARCH64_INSN_FUNCS(ldr_lit,	0xBF000000, 0x18000000)
+__AARCH64_INSN_FUNCS(ldrsw_lit,	0xFF000000, 0x98000000)
+__AARCH64_INSN_FUNCS(exclusive,	0x3F000000, 0x08000000)
 __AARCH64_INSN_FUNCS(stp_post,	0x7FC00000, 0x28800000)
 __AARCH64_INSN_FUNCS(ldp_post,	0x7FC00000, 0x28C00000)
 __AARCH64_INSN_FUNCS(stp_pre,	0x7FC00000, 0x29800000)
@@ -264,19 +269,29 @@ __AARCH64_INSN_FUNCS(ands,	0x7F200000, 0x6A000000)
 __AARCH64_INSN_FUNCS(bics,	0x7F200000, 0x6A200000)
 __AARCH64_INSN_FUNCS(b,		0xFC000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bl,	0xFC000000, 0x94000000)
+__AARCH64_INSN_FUNCS(b_bl,	0x7C000000, 0x14000000)
+__AARCH64_INSN_FUNCS(cb,	0x7E000000, 0x34000000)
 __AARCH64_INSN_FUNCS(cbz,	0x7F000000, 0x34000000)
 __AARCH64_INSN_FUNCS(cbnz,	0x7F000000, 0x35000000)
+__AARCH64_INSN_FUNCS(tb,	0x7E000000, 0x36000000)
 __AARCH64_INSN_FUNCS(tbz,	0x7F000000, 0x36000000)
 __AARCH64_INSN_FUNCS(tbnz,	0x7F000000, 0x37000000)
+__AARCH64_INSN_FUNCS(b_bl_cb_tb, 0x5C000000, 0x14000000)
 __AARCH64_INSN_FUNCS(bcond,	0xFF000010, 0x54000000)
 __AARCH64_INSN_FUNCS(svc,	0xFFE0001F, 0xD4000001)
 __AARCH64_INSN_FUNCS(hvc,	0xFFE0001F, 0xD4000002)
 __AARCH64_INSN_FUNCS(smc,	0xFFE0001F, 0xD4000003)
 __AARCH64_INSN_FUNCS(brk,	0xFFE0001F, 0xD4200000)
+__AARCH64_INSN_FUNCS(exception,	0xFF000000, 0xD4000000)
 __AARCH64_INSN_FUNCS(hint,	0xFFFFF01F, 0xD503201F)
 __AARCH64_INSN_FUNCS(br,	0xFFFFFC1F, 0xD61F0000)
 __AARCH64_INSN_FUNCS(blr,	0xFFFFFC1F, 0xD63F0000)
+__AARCH64_INSN_FUNCS(br_blr,	0xFFDFFC1F, 0xD61F0000)
 __AARCH64_INSN_FUNCS(ret,	0xFFFFFC1F, 0xD65F0000)
+__AARCH64_INSN_FUNCS(msr_imm,	0xFFF8F000, 0xD5004000)
+__AARCH64_INSN_FUNCS(msr_reg,	0xFFF00000, 0xD5100000)
+__AARCH64_INSN_FUNCS(set_clr_daif, 0xFFFFF0DF, 0xD50340DF)
+__AARCH64_INSN_FUNCS(rd_wr_daif, 0xFFDFFFE0, 0xD51B4220)
 
 #undef	__AARCH64_INSN_FUNCS
 
@@ -285,6 +300,9 @@ bool aarch64_insn_is_nop(u32 insn);
 int aarch64_insn_read(void *addr, u32 *insnp);
 int aarch64_insn_write(void *addr, u32 insn);
 enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
+bool aarch64_insn_uses_literal(u32 insn);
+bool aarch64_insn_is_branch(u32 insn);
+bool aarch64_insn_is_daif_access(u32 insn);
 u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
 				  u32 insn, u64 imm);
 u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index c8eca88..cda1b3b 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -155,6 +155,34 @@ static bool __kprobes __aarch64_insn_hotpatch_safe(u32 insn)
 		aarch64_insn_is_nop(insn);
 }
 
+bool __kprobes aarch64_insn_uses_literal(u32 insn)
+{
+	/* ldr/ldrsw (literal), prfm */
+
+	return aarch64_insn_is_ldr_lit(insn) ||
+		aarch64_insn_is_ldrsw_lit(insn) ||
+		aarch64_insn_is_adr_adrp(insn) ||
+		aarch64_insn_is_prfm_lit(insn);
+}
+
+bool __kprobes aarch64_insn_is_branch(u32 insn)
+{
+	/* b, bl, cb*, tb*, b.cond, br, blr */
+
+	return aarch64_insn_is_b_bl_cb_tb(insn) ||
+		aarch64_insn_is_br_blr(insn) ||
+		aarch64_insn_is_ret(insn) ||
+		aarch64_insn_is_bcond(insn);
+}
+
+bool __kprobes aarch64_insn_is_daif_access(u32 insn)
+{
+	/* msr daif, mrs daif, msr daifset, msr daifclr */
+
+	return aarch64_insn_is_rd_wr_daif(insn) ||
+		aarch64_insn_is_set_clr_daif(insn);
+}
+
 /*
  * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a
  * Section B2.6.5 "Concurrent modification and execution of instructions":
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-04-20 20:19 ` David Long
@ 2015-04-20 20:19   ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

Add support for basic kernel probes(kprobes) and jump probes
(jprobes) for ARM64.

Kprobes utilizes software breakpoint and single step debug
exceptions supported on ARM v8.

A software breakpoint is placed at the probe address to trap the
kernel execution into the kprobe handler.

ARM v8 supports enabling single stepping before the break exception
return (ERET), with next PC in exception return address (ELR_EL1). The
kprobe handler prepares an executable memory slot for out-of-line
execution with a copy of the original instruction being probed, and
enables single stepping. The PC is set to the out-of-line slot address
before the ERET. With this scheme, the instruction is executed with the
exact same register context except for the PC (and DAIF) registers.

Debug mask (PSTATE.D) is enabled only when single stepping a recursive
kprobe, e.g.: during kprobes reenter so that probed instruction can be
single stepped within the kprobe handler -exception- context.
The recursion depth of kprobe is always 2, i.e. upon probe re-entry,
any further re-entry is prevented by not calling handlers and the case
counted as a missed kprobe).

Single stepping from the x-o-l slot has a drawback for PC-relative accesses
like branching and symbolic literals access as the offset from the new PC
(slot address) may not be ensured to fit in the immediate value of
the opcode. Such instructions need simulation, so reject
probing them.

Instructions generating exceptions or cpu mode change are rejected
for probing.

Instructions using Exclusive Monitor are rejected too.

System instructions are mostly enabled for stepping, except MSR/MRS
accesses to "DAIF" flags in PSTATE, which are not safe for
probing.

Thanks to Steve Capper and Pratyush Anand for several suggested
Changes.

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
Signed-off-by: Steve Capper <steve.capper@linaro.org>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/Kconfig                      |   1 +
 arch/arm64/include/asm/debug-monitors.h |   5 +
 arch/arm64/include/asm/kprobes.h        |  62 ++++
 arch/arm64/include/asm/probes.h         |  50 +++
 arch/arm64/include/asm/ptrace.h         |   3 +-
 arch/arm64/kernel/Makefile              |   1 +
 arch/arm64/kernel/debug-monitors.c      |  35 ++-
 arch/arm64/kernel/kprobes-arm64.c       |  68 ++++
 arch/arm64/kernel/kprobes-arm64.h       |  28 ++
 arch/arm64/kernel/kprobes.c             | 537 ++++++++++++++++++++++++++++++++
 arch/arm64/kernel/kprobes.h             |  24 ++
 arch/arm64/kernel/vmlinux.lds.S         |   1 +
 arch/arm64/mm/fault.c                   |  25 ++
 13 files changed, 829 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm64/include/asm/kprobes.h
 create mode 100644 arch/arm64/include/asm/probes.h
 create mode 100644 arch/arm64/kernel/kprobes-arm64.c
 create mode 100644 arch/arm64/kernel/kprobes-arm64.h
 create mode 100644 arch/arm64/kernel/kprobes.c
 create mode 100644 arch/arm64/kernel/kprobes.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 987a681..8e06a03 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -68,6 +68,7 @@ config ARM64
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_SYSCALL_TRACEPOINTS
+	select HAVE_KPROBES
 	select IRQ_DOMAIN
 	select MODULES_USE_ELF_RELA
 	select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 40ec68a..92d7cea 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -90,6 +90,11 @@
 
 #define CACHE_FLUSH_IS_SAFE		1
 
+/* kprobes BRK opcodes with ESR encoding  */
+#define BRK64_ESR_MASK		0xFFFF
+#define BRK64_ESR_KPROBES	0x0004
+#define BRK64_OPCODE_KPROBES	(AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5))
+
 /* AArch32 */
 #define DBG_ESR_EVT_BKPT	0x4
 #define DBG_ESR_EVT_VECC	0x5
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
new file mode 100644
index 0000000..af31c4d
--- /dev/null
+++ b/arch/arm64/include/asm/kprobes.h
@@ -0,0 +1,62 @@
+/*
+ * arch/arm64/include/asm/kprobes.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_KPROBES_H
+#define _ARM_KPROBES_H
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/percpu.h>
+
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+#define MAX_INSN_SIZE			1
+#define MAX_STACK_SIZE			128
+
+#define flush_insn_slot(p)		do { } while (0)
+#define kretprobe_blacklist_size	0
+
+#include <asm/probes.h>
+
+struct prev_kprobe {
+	struct kprobe *kp;
+	unsigned int status;
+};
+
+/* Single step context for kprobe */
+struct kprobe_step_ctx {
+#define KPROBES_STEP_NONE	0x0
+#define KPROBES_STEP_PENDING	0x1
+	unsigned long ss_status;
+	unsigned long match_addr;
+};
+
+/* per-cpu kprobe control block */
+struct kprobe_ctlblk {
+	unsigned int kprobe_status;
+	unsigned long saved_irqflag;
+	struct prev_kprobe prev_kprobe;
+	struct kprobe_step_ctx ss_ctx;
+	struct pt_regs jprobe_saved_regs;
+	char jprobes_stack[MAX_STACK_SIZE];
+};
+
+void arch_remove_kprobe(struct kprobe *);
+int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
+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);
+
+#endif /* _ARM_KPROBES_H */
diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h
new file mode 100644
index 0000000..7f5a27f
--- /dev/null
+++ b/arch/arm64/include/asm/probes.h
@@ -0,0 +1,50 @@
+/*
+ * arch/arm64/include/asm/probes.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_PROBES_H
+#define _ARM_PROBES_H
+
+struct kprobe;
+struct arch_specific_insn;
+
+typedef u32 kprobe_opcode_t;
+typedef unsigned long (kprobes_pstate_check_t)(unsigned long);
+typedef unsigned long
+(probes_condition_check_t)(struct kprobe *p, struct pt_regs *);
+typedef void
+(probes_prepare_t)(struct kprobe *, struct arch_specific_insn *);
+typedef void (kprobes_handler_t) (u32 opcode, long addr, struct pt_regs *);
+
+enum pc_restore_type {
+	NO_RESTORE,
+	RESTORE_PC,
+};
+
+struct kprobe_pc_restore {
+	enum pc_restore_type type;
+	unsigned long addr;
+};
+
+/* architecture specific copy of original instruction */
+struct arch_specific_insn {
+	kprobe_opcode_t *insn;
+	kprobes_pstate_check_t *pstate_cc;
+	probes_condition_check_t *check_condn;
+	probes_prepare_t *prepare;
+	kprobes_handler_t *handler;
+	/* restore address after step xol */
+	struct kprobe_pc_restore restore;
+};
+
+#endif
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 655620e..68a4795f 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -210,7 +210,8 @@ static inline int valid_user_regs(struct user_pt_regs *regs)
 	return 0;
 }
 
-#define instruction_pointer(regs)	((unsigned long)(regs)->pc)
+#define instruction_pointer(regs)	((regs)->pc)
+#define stack_pointer(regs)		((regs)->sp)
 
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5ee07ee..056b1a4 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -32,6 +32,7 @@ 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_EFI)			+= efi.o efi-stub.o efi-entry.o
 arm64-obj-$(CONFIG_PCI)			+= pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index b056369..486ee94 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -23,6 +23,7 @@
 #include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/ptrace.h>
+#include <linux/kprobes.h>
 #include <linux/stat.h>
 #include <linux/uaccess.h>
 
@@ -228,6 +229,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 			       struct pt_regs *regs)
 {
 	siginfo_t info;
+	bool handler_found = false;
 
 	/*
 	 * If we are stepping a pending breakpoint, call the hw_breakpoint
@@ -251,15 +253,21 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 		 */
 		user_rewind_single_step(current);
 	} else {
+#ifdef	CONFIG_KPROBES
+		if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
+			handler_found = true;
+#endif
 		if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
-			return 0;
-
-		pr_warning("Unexpected kernel single-step exception at EL1\n");
-		/*
-		 * Re-enable stepping since we know that we will be
-		 * returning to regs.
-		 */
-		set_regs_spsr_ss(regs);
+			handler_found = true;
+
+		if (!handler_found) {
+			pr_warn("Unexpected kernel single-step exception at EL1\n");
+			/*
+			 * Re-enable stepping since we know that we will be
+			 * returning to regs.
+			 */
+			set_regs_spsr_ss(regs);
+		}
 	}
 
 	return 0;
@@ -315,8 +323,15 @@ static int brk_handler(unsigned long addr, unsigned int esr,
 		};
 
 		force_sig_info(SIGTRAP, &info, current);
-	} else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
-		pr_warning("Unexpected kernel BRK exception at EL1\n");
+	}
+#ifdef	CONFIG_KPROBES
+	else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) {
+		if (kprobe_breakpoint_handler(regs, esr) != DBG_HOOK_HANDLED)
+			return -EFAULT;
+	}
+#endif
+	else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
+		pr_warn("Unexpected kernel BRK exception at EL1\n");
 		return -EFAULT;
 	}
 
diff --git a/arch/arm64/kernel/kprobes-arm64.c b/arch/arm64/kernel/kprobes-arm64.c
new file mode 100644
index 0000000..f958c52
--- /dev/null
+++ b/arch/arm64/kernel/kprobes-arm64.c
@@ -0,0 +1,68 @@
+/*
+ * arch/arm64/kernel/kprobes-arm64.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 <asm/kprobes.h>
+#include <asm/insn.h>
+
+#include "kprobes-arm64.h"
+
+static bool __kprobes aarch64_insn_is_steppable(u32 insn)
+{
+	if (aarch64_get_insn_class(insn) == AARCH64_INSN_CLS_BR_SYS) {
+		if (aarch64_insn_is_branch(insn))
+			return false;
+
+		/* modification of daif creates issues */
+		if (aarch64_insn_is_daif_access(insn))
+			return false;
+
+		if (aarch64_insn_is_exception(insn))
+			return false;
+
+		if (aarch64_insn_is_hint(insn))
+			return aarch64_insn_is_nop(insn);
+
+		return true;
+	}
+
+	if (aarch64_insn_uses_literal(insn))
+		return false;
+
+	if (aarch64_insn_is_exclusive(insn))
+		return false;
+
+	return true;
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ */
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/*
+	 * Instructions reading or modifying the PC won't work from the XOL
+	 * slot.
+	 */
+	if (aarch64_insn_is_steppable(insn))
+		return INSN_GOOD;
+	else
+		return INSN_REJECTED;
+}
diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
new file mode 100644
index 0000000..87e7891
--- /dev/null
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -0,0 +1,28 @@
+/*
+ * arch/arm64/kernel/kprobes-arm64.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_KPROBES_ARM64_H
+#define _ARM_KERNEL_KPROBES_ARM64_H
+
+enum kprobe_insn {
+	INSN_REJECTED,
+	INSN_GOOD_NO_SLOT,
+	INSN_GOOD,
+};
+
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
+
+#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
new file mode 100644
index 0000000..601d2c6
--- /dev/null
+++ b/arch/arm64/kernel/kprobes.c
@@ -0,0 +1,537 @@
+/*
+ * arch/arm64/kernel/kprobes.c
+ *
+ * Kprobes support for ARM64
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ * Author: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
+ *
+ * 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 <linux/slab.h>
+#include <linux/stop_machine.h>
+#include <linux/stringify.h>
+#include <asm/traps.h>
+#include <asm/ptrace.h>
+#include <asm/cacheflush.h>
+#include <asm/debug-monitors.h>
+#include <asm/system_misc.h>
+#include <asm/insn.h>
+
+#include "kprobes.h"
+#include "kprobes-arm64.h"
+
+#define MIN_STACK_SIZE(addr)	min((unsigned long)MAX_STACK_SIZE,	\
+	(unsigned long)current_thread_info() + THREAD_START_SP - (addr))
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
+{
+	/* prepare insn slot */
+	p->ainsn.insn[0] = p->opcode;
+
+	flush_icache_range((uintptr_t) (p->ainsn.insn),
+			   (uintptr_t) (p->ainsn.insn) + MAX_INSN_SIZE);
+
+	/*
+	 * Needs restoring of return address after stepping xol.
+	 */
+	p->ainsn.restore.addr = (unsigned long) p->addr +
+	  sizeof(kprobe_opcode_t);
+	p->ainsn.restore.type = RESTORE_PC;
+}
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+	kprobe_opcode_t insn;
+	unsigned long probe_addr = (unsigned long)p->addr;
+
+	/* copy instruction */
+	insn = *p->addr;
+	p->opcode = insn;
+
+	if (in_exception_text(probe_addr))
+		return -EINVAL;
+
+	/* decode instruction */
+	switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
+	case INSN_REJECTED:	/* insn not supported */
+		return -EINVAL;
+
+	case INSN_GOOD_NO_SLOT:	/* insn need simulation */
+		return -EINVAL;
+
+	case INSN_GOOD:	/* instruction uses slot */
+		p->ainsn.insn = get_insn_slot();
+		if (!p->ainsn.insn)
+			return -ENOMEM;
+		break;
+	};
+
+	/* prepare the instruction */
+	arch_prepare_ss_slot(p);
+
+	return 0;
+}
+
+static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
+{
+	void *addrs[1];
+	u32 insns[1];
+
+	addrs[0] = (void *)addr;
+	insns[0] = (u32)opcode;
+
+	return aarch64_insn_patch_text_sync(addrs, insns, 1);
+}
+
+/* arm kprobe: install breakpoint in text */
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+	patch_text(p->addr, BRK64_OPCODE_KPROBES);
+}
+
+/* disarm kprobe: remove breakpoint from text */
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+	patch_text(p->addr, p->opcode);
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+	if (p->ainsn.insn) {
+		free_insn_slot(p->ainsn.insn, 0);
+		p->ainsn.insn = NULL;
+	}
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	kcb->prev_kprobe.kp = kprobe_running();
+	kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
+	kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p)
+{
+	__this_cpu_write(current_kprobe, p);
+}
+
+/*
+ * The D-flag (Debug mask) is set (masked) upon exception entry.
+ * Kprobes needs to clear (unmask) D-flag -ONLY- in case of recursive
+ * probe i.e. when probe hit from kprobe handler context upon
+ * executing the pre/post handlers. In this case we return with
+ * D-flag clear so that single-stepping can be carried-out.
+ *
+ * Leave D-flag set in all other cases.
+ */
+static void __kprobes
+spsr_set_debug_flag(struct pt_regs *regs, int mask)
+{
+	unsigned long spsr = regs->pstate;
+
+	if (mask)
+		spsr |= PSR_D_BIT;
+	else
+		spsr &= ~PSR_D_BIT;
+
+	regs->pstate = spsr;
+}
+
+/*
+ * Interrupts need to be disabled before single-step mode is set, and not
+ * reenabled until after single-step mode ends.
+ * Without disabling interrupt on local CPU, there is a chance of
+ * interrupt occurrence in the period of exception return and  start of
+ * out-of-line single-step, that result in wrongly single stepping
+ * the interrupt handler.
+ */
+static void __kprobes kprobes_save_local_irqflag(struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	kcb->saved_irqflag = regs->pstate;
+	regs->pstate |= PSR_I_BIT;
+}
+
+static void __kprobes kprobes_restore_local_irqflag(struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	if (kcb->saved_irqflag & PSR_I_BIT)
+		regs->pstate |= PSR_I_BIT;
+	else
+		regs->pstate &= ~PSR_I_BIT;
+}
+
+static void __kprobes
+set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr)
+{
+	kcb->ss_ctx.ss_status = KPROBES_STEP_PENDING;
+	kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
+}
+
+static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb)
+{
+	kcb->ss_ctx.ss_status = KPROBES_STEP_NONE;
+	kcb->ss_ctx.match_addr = 0;
+}
+
+static void __kprobes
+skip_singlestep_missed(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
+{
+	/* set return addr to next pc to continue */
+	instruction_pointer(regs) += sizeof(kprobe_opcode_t);
+}
+
+static void __kprobes setup_singlestep(struct kprobe *p,
+				       struct pt_regs *regs,
+				       struct kprobe_ctlblk *kcb, int reenter)
+{
+	unsigned long slot;
+
+	if (reenter) {
+		save_previous_kprobe(kcb);
+		set_current_kprobe(p);
+		kcb->kprobe_status = KPROBE_REENTER;
+	} else {
+		kcb->kprobe_status = KPROBE_HIT_SS;
+	}
+
+	if (p->ainsn.insn) {
+		/* prepare for single stepping */
+		slot = (unsigned long)p->ainsn.insn;
+
+		set_ss_context(kcb, slot);	/* mark pending ss */
+
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			spsr_set_debug_flag(regs, 0);
+
+		/* IRQs and single stepping do not mix well. */
+		kprobes_save_local_irqflag(regs);
+		kernel_enable_single_step(regs);
+		instruction_pointer(regs) = slot;
+	} else	{
+		BUG();
+	}
+}
+
+static int __kprobes reenter_kprobe(struct kprobe *p,
+				    struct pt_regs *regs,
+				    struct kprobe_ctlblk *kcb)
+{
+	switch (kcb->kprobe_status) {
+	case KPROBE_HIT_SSDONE:
+	case KPROBE_HIT_ACTIVE:
+		if (!p->ainsn.check_condn || p->ainsn.check_condn(p, regs)) {
+			kprobes_inc_nmissed_count(p);
+			setup_singlestep(p, regs, kcb, 1);
+		} else	{
+			/* condition check failed, skip stepping */
+			skip_singlestep_missed(kcb, regs);
+		}
+		break;
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr);
+		dump_kprobe(p);
+		BUG();
+		break;
+	default:
+		WARN_ON(1);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void __kprobes
+post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
+{
+	struct kprobe *cur = kprobe_running();
+
+	if (!cur)
+		return;
+
+	/* return addr restore if non-branching insn */
+	if (cur->ainsn.restore.type == RESTORE_PC) {
+		instruction_pointer(regs) = cur->ainsn.restore.addr;
+		if (!instruction_pointer(regs))
+			BUG();
+	}
+
+	/* restore back original saved kprobe variables and continue */
+	if (kcb->kprobe_status == KPROBE_REENTER) {
+		restore_previous_kprobe(kcb);
+		return;
+	}
+	/* call post handler */
+	kcb->kprobe_status = KPROBE_HIT_SSDONE;
+	if (cur->post_handler)	{
+		/* post_handler can hit breakpoint and single step
+		 * again, so we enable D-flag for recursive exception.
+		 */
+		cur->post_handler(cur, regs, 0);
+	}
+
+	reset_current_kprobe();
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
+{
+	struct kprobe *cur = kprobe_running();
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	switch (kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the ip points back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		instruction_pointer(regs) = (unsigned long)cur->addr;
+		if (!instruction_pointer(regs))
+			BUG();
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
+
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accounting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned
+		 * zero, try to fix up.
+		 */
+		if (fixup_exception(regs))
+			return 1;
+
+		break;
+	}
+	return 0;
+}
+
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+				       unsigned long val, void *data)
+{
+	return NOTIFY_DONE;
+}
+
+void __kprobes kprobe_handler(struct pt_regs *regs)
+{
+	struct kprobe *p, *cur;
+	struct kprobe_ctlblk *kcb;
+	unsigned long addr = instruction_pointer(regs);
+
+	kcb = get_kprobe_ctlblk();
+	cur = kprobe_running();
+
+	p = get_kprobe((kprobe_opcode_t *) addr);
+
+	if (p) {
+		if (cur) {
+			if (reenter_kprobe(p, regs, kcb))
+				return;
+		} else if (!p->ainsn.check_condn ||
+			   p->ainsn.check_condn(p, regs)) {
+			/* Probe hit and conditional execution check ok. */
+			set_current_kprobe(p);
+			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+			/*
+			 * If we have no pre-handler or it returned 0, we
+			 * continue with normal processing.  If we have a
+			 * pre-handler and it returned non-zero, it prepped
+			 * for calling the break_handler below on re-entry,
+			 * so get out doing nothing more here.
+			 *
+			 * pre_handler can hit a breakpoint and can step thru
+			 * before return, keep PSTATE D-flag enabled until
+			 * pre_handler return back.
+			 */
+			if (!p->pre_handler || !p->pre_handler(p, regs)) {
+				kcb->kprobe_status = KPROBE_HIT_SS;
+				setup_singlestep(p, regs, kcb, 0);
+				return;
+			}
+		} else {
+			/*
+			 * Breakpoint hit but conditional check failed,
+			 * so just skip the instruction (NOP behaviour)
+			 */
+			skip_singlestep_missed(kcb, regs);
+			return;
+		}
+	} else if (*(kprobe_opcode_t *) addr != BRK64_OPCODE_KPROBES) {
+		/*
+		 * The breakpoint instruction was removed right
+		 * after we hit it.  Another cpu has removed
+		 * either a probepoint or a debugger breakpoint
+		 * at this address.  In either case, no further
+		 * handling of this interrupt is appropriate.
+		 * Return back to original instruction, and continue.
+		 */
+		return;
+	} else if (cur) {
+		/* We probably hit a jprobe.  Call its break handler. */
+		if (cur->break_handler && cur->break_handler(cur, regs)) {
+			kcb->kprobe_status = KPROBE_HIT_SS;
+			setup_singlestep(cur, regs, kcb, 0);
+			return;
+		}
+	} else {
+		/* breakpoint is removed, now in a race
+		 * Return back to original instruction & continue.
+		 */
+	}
+}
+
+static int __kprobes
+kprobe_ss_hit(struct kprobe_ctlblk *kcb, unsigned long addr)
+{
+	if ((kcb->ss_ctx.ss_status == KPROBES_STEP_PENDING)
+	    && (kcb->ss_ctx.match_addr == addr)) {
+		clear_ss_context(kcb);	/* clear pending ss */
+		return DBG_HOOK_HANDLED;
+	}
+	/* not ours, kprobes should ignore it */
+	return DBG_HOOK_ERROR;
+}
+
+int __kprobes
+kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	int retval;
+
+	/* return error if this is not our step */
+	retval = kprobe_ss_hit(kcb, instruction_pointer(regs));
+
+	if (retval == DBG_HOOK_HANDLED) {
+		kprobes_restore_local_irqflag(regs);
+		kernel_disable_single_step();
+
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			spsr_set_debug_flag(regs, 1);
+
+		post_kprobe_handler(kcb, regs);
+	}
+
+	return retval;
+}
+
+int __kprobes
+kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr)
+{
+	kprobe_handler(regs);
+	return DBG_HOOK_HANDLED;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	long stack_ptr = stack_pointer(regs);
+
+	kcb->jprobe_saved_regs = *regs;
+	memcpy(kcb->jprobes_stack, (void *)stack_ptr,
+	       MIN_STACK_SIZE(stack_ptr));
+
+	instruction_pointer(regs) = (long)jp->entry;
+	preempt_disable();
+	return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	/*
+	 * Jprobe handler return by entering break exception,
+	 * encoded same as kprobe, but with following conditions
+	 * -a magic number in x0 to identify from rest of other kprobes.
+	 * -restore stack addr to original saved pt_regs
+	 */
+	asm volatile ("ldr x0, [%0]\n\t"
+		      "mov sp, x0\n\t"
+		      "ldr x0, =" __stringify(JPROBES_MAGIC_NUM) "\n\t"
+		      "BRK %1\n\t"
+		      "NOP\n\t"
+		      :
+		      : "r"(&kcb->jprobe_saved_regs.sp),
+		      "I"(BRK64_ESR_KPROBES)
+		      : "memory");
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	long stack_addr = kcb->jprobe_saved_regs.sp;
+	long orig_sp = stack_pointer(regs);
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+	if (regs->regs[0] == JPROBES_MAGIC_NUM) {
+		if (orig_sp != stack_addr) {
+			struct pt_regs *saved_regs =
+			    (struct pt_regs *)kcb->jprobe_saved_regs.sp;
+			pr_err("current sp %lx does not match saved sp %lx\n",
+			       orig_sp, stack_addr);
+			pr_err("Saved registers for jprobe %p\n", jp);
+			show_regs(saved_regs);
+			pr_err("Current registers\n");
+			show_regs(regs);
+			BUG();
+		}
+		*regs = kcb->jprobe_saved_regs;
+		memcpy((void *)stack_addr, kcb->jprobes_stack,
+		       MIN_STACK_SIZE(stack_addr));
+		preempt_enable_no_resched();
+		return 1;
+	}
+	return 0;
+}
+
+int __init arch_init_kprobes(void)
+{
+	return 0;
+}
diff --git a/arch/arm64/kernel/kprobes.h b/arch/arm64/kernel/kprobes.h
new file mode 100644
index 0000000..e98ad60
--- /dev/null
+++ b/arch/arm64/kernel/kprobes.h
@@ -0,0 +1,24 @@
+/*
+ * arch/arm64/kernel/kprobes.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_KPROBES_H
+#define _ARM_KERNEL_KPROBES_H
+
+#define JPROBES_MAGIC_NUM	0xa5a5a5a5a5a5a5a5
+
+/* Move this out to appropriate header file */
+int fixup_exception(struct pt_regs *regs);
+
+#endif /* _ARM_KERNEL_KPROBES_H */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 5d9d2dc..2e51510 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -90,6 +90,7 @@ SECTIONS
 			TEXT_TEXT
 			SCHED_TEXT
 			LOCK_TEXT
+			KPROBES_TEXT
 			HYPERVISOR_TEXT
 			*(.fixup)
 			*(.gnu.warning)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 96da131..4c13dfb 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -39,6 +39,28 @@
 
 static const char *fault_name(unsigned int esr);
 
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+{
+	int ret = 0;
+
+	/* kprobe_running() needs smp_processor_id() */
+	if (!user_mode(regs)) {
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, esr))
+			ret = 1;
+		preempt_enable();
+	}
+
+	return ret;
+}
+#else
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+{
+	return 0;
+}
+#endif
+
 /*
  * Dump out the page tables associated with 'addr' in mm 'mm'.
  */
@@ -200,6 +222,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
 	unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
 	unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
+	if (notify_page_fault(regs, esr))
+		return 0;
+
 	tsk = current;
 	mm  = tsk->mm;
 
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-04-20 20:19   ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

Add support for basic kernel probes(kprobes) and jump probes
(jprobes) for ARM64.

Kprobes utilizes software breakpoint and single step debug
exceptions supported on ARM v8.

A software breakpoint is placed at the probe address to trap the
kernel execution into the kprobe handler.

ARM v8 supports enabling single stepping before the break exception
return (ERET), with next PC in exception return address (ELR_EL1). The
kprobe handler prepares an executable memory slot for out-of-line
execution with a copy of the original instruction being probed, and
enables single stepping. The PC is set to the out-of-line slot address
before the ERET. With this scheme, the instruction is executed with the
exact same register context except for the PC (and DAIF) registers.

Debug mask (PSTATE.D) is enabled only when single stepping a recursive
kprobe, e.g.: during kprobes reenter so that probed instruction can be
single stepped within the kprobe handler -exception- context.
The recursion depth of kprobe is always 2, i.e. upon probe re-entry,
any further re-entry is prevented by not calling handlers and the case
counted as a missed kprobe).

Single stepping from the x-o-l slot has a drawback for PC-relative accesses
like branching and symbolic literals access as the offset from the new PC
(slot address) may not be ensured to fit in the immediate value of
the opcode. Such instructions need simulation, so reject
probing them.

Instructions generating exceptions or cpu mode change are rejected
for probing.

Instructions using Exclusive Monitor are rejected too.

System instructions are mostly enabled for stepping, except MSR/MRS
accesses to "DAIF" flags in PSTATE, which are not safe for
probing.

Thanks to Steve Capper and Pratyush Anand for several suggested
Changes.

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
Signed-off-by: Steve Capper <steve.capper@linaro.org>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/Kconfig                      |   1 +
 arch/arm64/include/asm/debug-monitors.h |   5 +
 arch/arm64/include/asm/kprobes.h        |  62 ++++
 arch/arm64/include/asm/probes.h         |  50 +++
 arch/arm64/include/asm/ptrace.h         |   3 +-
 arch/arm64/kernel/Makefile              |   1 +
 arch/arm64/kernel/debug-monitors.c      |  35 ++-
 arch/arm64/kernel/kprobes-arm64.c       |  68 ++++
 arch/arm64/kernel/kprobes-arm64.h       |  28 ++
 arch/arm64/kernel/kprobes.c             | 537 ++++++++++++++++++++++++++++++++
 arch/arm64/kernel/kprobes.h             |  24 ++
 arch/arm64/kernel/vmlinux.lds.S         |   1 +
 arch/arm64/mm/fault.c                   |  25 ++
 13 files changed, 829 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm64/include/asm/kprobes.h
 create mode 100644 arch/arm64/include/asm/probes.h
 create mode 100644 arch/arm64/kernel/kprobes-arm64.c
 create mode 100644 arch/arm64/kernel/kprobes-arm64.h
 create mode 100644 arch/arm64/kernel/kprobes.c
 create mode 100644 arch/arm64/kernel/kprobes.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 987a681..8e06a03 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -68,6 +68,7 @@ config ARM64
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_SYSCALL_TRACEPOINTS
+	select HAVE_KPROBES
 	select IRQ_DOMAIN
 	select MODULES_USE_ELF_RELA
 	select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 40ec68a..92d7cea 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -90,6 +90,11 @@
 
 #define CACHE_FLUSH_IS_SAFE		1
 
+/* kprobes BRK opcodes with ESR encoding  */
+#define BRK64_ESR_MASK		0xFFFF
+#define BRK64_ESR_KPROBES	0x0004
+#define BRK64_OPCODE_KPROBES	(AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5))
+
 /* AArch32 */
 #define DBG_ESR_EVT_BKPT	0x4
 #define DBG_ESR_EVT_VECC	0x5
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
new file mode 100644
index 0000000..af31c4d
--- /dev/null
+++ b/arch/arm64/include/asm/kprobes.h
@@ -0,0 +1,62 @@
+/*
+ * arch/arm64/include/asm/kprobes.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_KPROBES_H
+#define _ARM_KPROBES_H
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/percpu.h>
+
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+#define MAX_INSN_SIZE			1
+#define MAX_STACK_SIZE			128
+
+#define flush_insn_slot(p)		do { } while (0)
+#define kretprobe_blacklist_size	0
+
+#include <asm/probes.h>
+
+struct prev_kprobe {
+	struct kprobe *kp;
+	unsigned int status;
+};
+
+/* Single step context for kprobe */
+struct kprobe_step_ctx {
+#define KPROBES_STEP_NONE	0x0
+#define KPROBES_STEP_PENDING	0x1
+	unsigned long ss_status;
+	unsigned long match_addr;
+};
+
+/* per-cpu kprobe control block */
+struct kprobe_ctlblk {
+	unsigned int kprobe_status;
+	unsigned long saved_irqflag;
+	struct prev_kprobe prev_kprobe;
+	struct kprobe_step_ctx ss_ctx;
+	struct pt_regs jprobe_saved_regs;
+	char jprobes_stack[MAX_STACK_SIZE];
+};
+
+void arch_remove_kprobe(struct kprobe *);
+int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
+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);
+
+#endif /* _ARM_KPROBES_H */
diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h
new file mode 100644
index 0000000..7f5a27f
--- /dev/null
+++ b/arch/arm64/include/asm/probes.h
@@ -0,0 +1,50 @@
+/*
+ * arch/arm64/include/asm/probes.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_PROBES_H
+#define _ARM_PROBES_H
+
+struct kprobe;
+struct arch_specific_insn;
+
+typedef u32 kprobe_opcode_t;
+typedef unsigned long (kprobes_pstate_check_t)(unsigned long);
+typedef unsigned long
+(probes_condition_check_t)(struct kprobe *p, struct pt_regs *);
+typedef void
+(probes_prepare_t)(struct kprobe *, struct arch_specific_insn *);
+typedef void (kprobes_handler_t) (u32 opcode, long addr, struct pt_regs *);
+
+enum pc_restore_type {
+	NO_RESTORE,
+	RESTORE_PC,
+};
+
+struct kprobe_pc_restore {
+	enum pc_restore_type type;
+	unsigned long addr;
+};
+
+/* architecture specific copy of original instruction */
+struct arch_specific_insn {
+	kprobe_opcode_t *insn;
+	kprobes_pstate_check_t *pstate_cc;
+	probes_condition_check_t *check_condn;
+	probes_prepare_t *prepare;
+	kprobes_handler_t *handler;
+	/* restore address after step xol */
+	struct kprobe_pc_restore restore;
+};
+
+#endif
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 655620e..68a4795f 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -210,7 +210,8 @@ static inline int valid_user_regs(struct user_pt_regs *regs)
 	return 0;
 }
 
-#define instruction_pointer(regs)	((unsigned long)(regs)->pc)
+#define instruction_pointer(regs)	((regs)->pc)
+#define stack_pointer(regs)		((regs)->sp)
 
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5ee07ee..056b1a4 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -32,6 +32,7 @@ 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_EFI)			+= efi.o efi-stub.o efi-entry.o
 arm64-obj-$(CONFIG_PCI)			+= pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index b056369..486ee94 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -23,6 +23,7 @@
 #include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/ptrace.h>
+#include <linux/kprobes.h>
 #include <linux/stat.h>
 #include <linux/uaccess.h>
 
@@ -228,6 +229,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 			       struct pt_regs *regs)
 {
 	siginfo_t info;
+	bool handler_found = false;
 
 	/*
 	 * If we are stepping a pending breakpoint, call the hw_breakpoint
@@ -251,15 +253,21 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 		 */
 		user_rewind_single_step(current);
 	} else {
+#ifdef	CONFIG_KPROBES
+		if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
+			handler_found = true;
+#endif
 		if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
-			return 0;
-
-		pr_warning("Unexpected kernel single-step exception at EL1\n");
-		/*
-		 * Re-enable stepping since we know that we will be
-		 * returning to regs.
-		 */
-		set_regs_spsr_ss(regs);
+			handler_found = true;
+
+		if (!handler_found) {
+			pr_warn("Unexpected kernel single-step exception at EL1\n");
+			/*
+			 * Re-enable stepping since we know that we will be
+			 * returning to regs.
+			 */
+			set_regs_spsr_ss(regs);
+		}
 	}
 
 	return 0;
@@ -315,8 +323,15 @@ static int brk_handler(unsigned long addr, unsigned int esr,
 		};
 
 		force_sig_info(SIGTRAP, &info, current);
-	} else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
-		pr_warning("Unexpected kernel BRK exception at EL1\n");
+	}
+#ifdef	CONFIG_KPROBES
+	else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) {
+		if (kprobe_breakpoint_handler(regs, esr) != DBG_HOOK_HANDLED)
+			return -EFAULT;
+	}
+#endif
+	else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
+		pr_warn("Unexpected kernel BRK exception at EL1\n");
 		return -EFAULT;
 	}
 
diff --git a/arch/arm64/kernel/kprobes-arm64.c b/arch/arm64/kernel/kprobes-arm64.c
new file mode 100644
index 0000000..f958c52
--- /dev/null
+++ b/arch/arm64/kernel/kprobes-arm64.c
@@ -0,0 +1,68 @@
+/*
+ * arch/arm64/kernel/kprobes-arm64.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 <asm/kprobes.h>
+#include <asm/insn.h>
+
+#include "kprobes-arm64.h"
+
+static bool __kprobes aarch64_insn_is_steppable(u32 insn)
+{
+	if (aarch64_get_insn_class(insn) == AARCH64_INSN_CLS_BR_SYS) {
+		if (aarch64_insn_is_branch(insn))
+			return false;
+
+		/* modification of daif creates issues */
+		if (aarch64_insn_is_daif_access(insn))
+			return false;
+
+		if (aarch64_insn_is_exception(insn))
+			return false;
+
+		if (aarch64_insn_is_hint(insn))
+			return aarch64_insn_is_nop(insn);
+
+		return true;
+	}
+
+	if (aarch64_insn_uses_literal(insn))
+		return false;
+
+	if (aarch64_insn_is_exclusive(insn))
+		return false;
+
+	return true;
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ */
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/*
+	 * Instructions reading or modifying the PC won't work from the XOL
+	 * slot.
+	 */
+	if (aarch64_insn_is_steppable(insn))
+		return INSN_GOOD;
+	else
+		return INSN_REJECTED;
+}
diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
new file mode 100644
index 0000000..87e7891
--- /dev/null
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -0,0 +1,28 @@
+/*
+ * arch/arm64/kernel/kprobes-arm64.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_KPROBES_ARM64_H
+#define _ARM_KERNEL_KPROBES_ARM64_H
+
+enum kprobe_insn {
+	INSN_REJECTED,
+	INSN_GOOD_NO_SLOT,
+	INSN_GOOD,
+};
+
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
+
+#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
new file mode 100644
index 0000000..601d2c6
--- /dev/null
+++ b/arch/arm64/kernel/kprobes.c
@@ -0,0 +1,537 @@
+/*
+ * arch/arm64/kernel/kprobes.c
+ *
+ * Kprobes support for ARM64
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ * Author: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
+ *
+ * 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 <linux/slab.h>
+#include <linux/stop_machine.h>
+#include <linux/stringify.h>
+#include <asm/traps.h>
+#include <asm/ptrace.h>
+#include <asm/cacheflush.h>
+#include <asm/debug-monitors.h>
+#include <asm/system_misc.h>
+#include <asm/insn.h>
+
+#include "kprobes.h"
+#include "kprobes-arm64.h"
+
+#define MIN_STACK_SIZE(addr)	min((unsigned long)MAX_STACK_SIZE,	\
+	(unsigned long)current_thread_info() + THREAD_START_SP - (addr))
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
+{
+	/* prepare insn slot */
+	p->ainsn.insn[0] = p->opcode;
+
+	flush_icache_range((uintptr_t) (p->ainsn.insn),
+			   (uintptr_t) (p->ainsn.insn) + MAX_INSN_SIZE);
+
+	/*
+	 * Needs restoring of return address after stepping xol.
+	 */
+	p->ainsn.restore.addr = (unsigned long) p->addr +
+	  sizeof(kprobe_opcode_t);
+	p->ainsn.restore.type = RESTORE_PC;
+}
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+	kprobe_opcode_t insn;
+	unsigned long probe_addr = (unsigned long)p->addr;
+
+	/* copy instruction */
+	insn = *p->addr;
+	p->opcode = insn;
+
+	if (in_exception_text(probe_addr))
+		return -EINVAL;
+
+	/* decode instruction */
+	switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
+	case INSN_REJECTED:	/* insn not supported */
+		return -EINVAL;
+
+	case INSN_GOOD_NO_SLOT:	/* insn need simulation */
+		return -EINVAL;
+
+	case INSN_GOOD:	/* instruction uses slot */
+		p->ainsn.insn = get_insn_slot();
+		if (!p->ainsn.insn)
+			return -ENOMEM;
+		break;
+	};
+
+	/* prepare the instruction */
+	arch_prepare_ss_slot(p);
+
+	return 0;
+}
+
+static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
+{
+	void *addrs[1];
+	u32 insns[1];
+
+	addrs[0] = (void *)addr;
+	insns[0] = (u32)opcode;
+
+	return aarch64_insn_patch_text_sync(addrs, insns, 1);
+}
+
+/* arm kprobe: install breakpoint in text */
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+	patch_text(p->addr, BRK64_OPCODE_KPROBES);
+}
+
+/* disarm kprobe: remove breakpoint from text */
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+	patch_text(p->addr, p->opcode);
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+	if (p->ainsn.insn) {
+		free_insn_slot(p->ainsn.insn, 0);
+		p->ainsn.insn = NULL;
+	}
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	kcb->prev_kprobe.kp = kprobe_running();
+	kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
+	kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p)
+{
+	__this_cpu_write(current_kprobe, p);
+}
+
+/*
+ * The D-flag (Debug mask) is set (masked) upon exception entry.
+ * Kprobes needs to clear (unmask) D-flag -ONLY- in case of recursive
+ * probe i.e. when probe hit from kprobe handler context upon
+ * executing the pre/post handlers. In this case we return with
+ * D-flag clear so that single-stepping can be carried-out.
+ *
+ * Leave D-flag set in all other cases.
+ */
+static void __kprobes
+spsr_set_debug_flag(struct pt_regs *regs, int mask)
+{
+	unsigned long spsr = regs->pstate;
+
+	if (mask)
+		spsr |= PSR_D_BIT;
+	else
+		spsr &= ~PSR_D_BIT;
+
+	regs->pstate = spsr;
+}
+
+/*
+ * Interrupts need to be disabled before single-step mode is set, and not
+ * reenabled until after single-step mode ends.
+ * Without disabling interrupt on local CPU, there is a chance of
+ * interrupt occurrence in the period of exception return and  start of
+ * out-of-line single-step, that result in wrongly single stepping
+ * the interrupt handler.
+ */
+static void __kprobes kprobes_save_local_irqflag(struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	kcb->saved_irqflag = regs->pstate;
+	regs->pstate |= PSR_I_BIT;
+}
+
+static void __kprobes kprobes_restore_local_irqflag(struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	if (kcb->saved_irqflag & PSR_I_BIT)
+		regs->pstate |= PSR_I_BIT;
+	else
+		regs->pstate &= ~PSR_I_BIT;
+}
+
+static void __kprobes
+set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr)
+{
+	kcb->ss_ctx.ss_status = KPROBES_STEP_PENDING;
+	kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
+}
+
+static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb)
+{
+	kcb->ss_ctx.ss_status = KPROBES_STEP_NONE;
+	kcb->ss_ctx.match_addr = 0;
+}
+
+static void __kprobes
+skip_singlestep_missed(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
+{
+	/* set return addr to next pc to continue */
+	instruction_pointer(regs) += sizeof(kprobe_opcode_t);
+}
+
+static void __kprobes setup_singlestep(struct kprobe *p,
+				       struct pt_regs *regs,
+				       struct kprobe_ctlblk *kcb, int reenter)
+{
+	unsigned long slot;
+
+	if (reenter) {
+		save_previous_kprobe(kcb);
+		set_current_kprobe(p);
+		kcb->kprobe_status = KPROBE_REENTER;
+	} else {
+		kcb->kprobe_status = KPROBE_HIT_SS;
+	}
+
+	if (p->ainsn.insn) {
+		/* prepare for single stepping */
+		slot = (unsigned long)p->ainsn.insn;
+
+		set_ss_context(kcb, slot);	/* mark pending ss */
+
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			spsr_set_debug_flag(regs, 0);
+
+		/* IRQs and single stepping do not mix well. */
+		kprobes_save_local_irqflag(regs);
+		kernel_enable_single_step(regs);
+		instruction_pointer(regs) = slot;
+	} else	{
+		BUG();
+	}
+}
+
+static int __kprobes reenter_kprobe(struct kprobe *p,
+				    struct pt_regs *regs,
+				    struct kprobe_ctlblk *kcb)
+{
+	switch (kcb->kprobe_status) {
+	case KPROBE_HIT_SSDONE:
+	case KPROBE_HIT_ACTIVE:
+		if (!p->ainsn.check_condn || p->ainsn.check_condn(p, regs)) {
+			kprobes_inc_nmissed_count(p);
+			setup_singlestep(p, regs, kcb, 1);
+		} else	{
+			/* condition check failed, skip stepping */
+			skip_singlestep_missed(kcb, regs);
+		}
+		break;
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr);
+		dump_kprobe(p);
+		BUG();
+		break;
+	default:
+		WARN_ON(1);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void __kprobes
+post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
+{
+	struct kprobe *cur = kprobe_running();
+
+	if (!cur)
+		return;
+
+	/* return addr restore if non-branching insn */
+	if (cur->ainsn.restore.type == RESTORE_PC) {
+		instruction_pointer(regs) = cur->ainsn.restore.addr;
+		if (!instruction_pointer(regs))
+			BUG();
+	}
+
+	/* restore back original saved kprobe variables and continue */
+	if (kcb->kprobe_status == KPROBE_REENTER) {
+		restore_previous_kprobe(kcb);
+		return;
+	}
+	/* call post handler */
+	kcb->kprobe_status = KPROBE_HIT_SSDONE;
+	if (cur->post_handler)	{
+		/* post_handler can hit breakpoint and single step
+		 * again, so we enable D-flag for recursive exception.
+		 */
+		cur->post_handler(cur, regs, 0);
+	}
+
+	reset_current_kprobe();
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
+{
+	struct kprobe *cur = kprobe_running();
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	switch (kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the ip points back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		instruction_pointer(regs) = (unsigned long)cur->addr;
+		if (!instruction_pointer(regs))
+			BUG();
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			restore_previous_kprobe(kcb);
+		else
+			reset_current_kprobe();
+
+		break;
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accounting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it first.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
+			return 1;
+
+		/*
+		 * In case the user-specified fault handler returned
+		 * zero, try to fix up.
+		 */
+		if (fixup_exception(regs))
+			return 1;
+
+		break;
+	}
+	return 0;
+}
+
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+				       unsigned long val, void *data)
+{
+	return NOTIFY_DONE;
+}
+
+void __kprobes kprobe_handler(struct pt_regs *regs)
+{
+	struct kprobe *p, *cur;
+	struct kprobe_ctlblk *kcb;
+	unsigned long addr = instruction_pointer(regs);
+
+	kcb = get_kprobe_ctlblk();
+	cur = kprobe_running();
+
+	p = get_kprobe((kprobe_opcode_t *) addr);
+
+	if (p) {
+		if (cur) {
+			if (reenter_kprobe(p, regs, kcb))
+				return;
+		} else if (!p->ainsn.check_condn ||
+			   p->ainsn.check_condn(p, regs)) {
+			/* Probe hit and conditional execution check ok. */
+			set_current_kprobe(p);
+			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+			/*
+			 * If we have no pre-handler or it returned 0, we
+			 * continue with normal processing.  If we have a
+			 * pre-handler and it returned non-zero, it prepped
+			 * for calling the break_handler below on re-entry,
+			 * so get out doing nothing more here.
+			 *
+			 * pre_handler can hit a breakpoint and can step thru
+			 * before return, keep PSTATE D-flag enabled until
+			 * pre_handler return back.
+			 */
+			if (!p->pre_handler || !p->pre_handler(p, regs)) {
+				kcb->kprobe_status = KPROBE_HIT_SS;
+				setup_singlestep(p, regs, kcb, 0);
+				return;
+			}
+		} else {
+			/*
+			 * Breakpoint hit but conditional check failed,
+			 * so just skip the instruction (NOP behaviour)
+			 */
+			skip_singlestep_missed(kcb, regs);
+			return;
+		}
+	} else if (*(kprobe_opcode_t *) addr != BRK64_OPCODE_KPROBES) {
+		/*
+		 * The breakpoint instruction was removed right
+		 * after we hit it.  Another cpu has removed
+		 * either a probepoint or a debugger breakpoint
+		 * at this address.  In either case, no further
+		 * handling of this interrupt is appropriate.
+		 * Return back to original instruction, and continue.
+		 */
+		return;
+	} else if (cur) {
+		/* We probably hit a jprobe.  Call its break handler. */
+		if (cur->break_handler && cur->break_handler(cur, regs)) {
+			kcb->kprobe_status = KPROBE_HIT_SS;
+			setup_singlestep(cur, regs, kcb, 0);
+			return;
+		}
+	} else {
+		/* breakpoint is removed, now in a race
+		 * Return back to original instruction & continue.
+		 */
+	}
+}
+
+static int __kprobes
+kprobe_ss_hit(struct kprobe_ctlblk *kcb, unsigned long addr)
+{
+	if ((kcb->ss_ctx.ss_status == KPROBES_STEP_PENDING)
+	    && (kcb->ss_ctx.match_addr == addr)) {
+		clear_ss_context(kcb);	/* clear pending ss */
+		return DBG_HOOK_HANDLED;
+	}
+	/* not ours, kprobes should ignore it */
+	return DBG_HOOK_ERROR;
+}
+
+int __kprobes
+kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	int retval;
+
+	/* return error if this is not our step */
+	retval = kprobe_ss_hit(kcb, instruction_pointer(regs));
+
+	if (retval == DBG_HOOK_HANDLED) {
+		kprobes_restore_local_irqflag(regs);
+		kernel_disable_single_step();
+
+		if (kcb->kprobe_status == KPROBE_REENTER)
+			spsr_set_debug_flag(regs, 1);
+
+		post_kprobe_handler(kcb, regs);
+	}
+
+	return retval;
+}
+
+int __kprobes
+kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr)
+{
+	kprobe_handler(regs);
+	return DBG_HOOK_HANDLED;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	long stack_ptr = stack_pointer(regs);
+
+	kcb->jprobe_saved_regs = *regs;
+	memcpy(kcb->jprobes_stack, (void *)stack_ptr,
+	       MIN_STACK_SIZE(stack_ptr));
+
+	instruction_pointer(regs) = (long)jp->entry;
+	preempt_disable();
+	return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	/*
+	 * Jprobe handler return by entering break exception,
+	 * encoded same as kprobe, but with following conditions
+	 * -a magic number in x0 to identify from rest of other kprobes.
+	 * -restore stack addr to original saved pt_regs
+	 */
+	asm volatile ("ldr x0, [%0]\n\t"
+		      "mov sp, x0\n\t"
+		      "ldr x0, =" __stringify(JPROBES_MAGIC_NUM) "\n\t"
+		      "BRK %1\n\t"
+		      "NOP\n\t"
+		      :
+		      : "r"(&kcb->jprobe_saved_regs.sp),
+		      "I"(BRK64_ESR_KPROBES)
+		      : "memory");
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	long stack_addr = kcb->jprobe_saved_regs.sp;
+	long orig_sp = stack_pointer(regs);
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+	if (regs->regs[0] == JPROBES_MAGIC_NUM) {
+		if (orig_sp != stack_addr) {
+			struct pt_regs *saved_regs =
+			    (struct pt_regs *)kcb->jprobe_saved_regs.sp;
+			pr_err("current sp %lx does not match saved sp %lx\n",
+			       orig_sp, stack_addr);
+			pr_err("Saved registers for jprobe %p\n", jp);
+			show_regs(saved_regs);
+			pr_err("Current registers\n");
+			show_regs(regs);
+			BUG();
+		}
+		*regs = kcb->jprobe_saved_regs;
+		memcpy((void *)stack_addr, kcb->jprobes_stack,
+		       MIN_STACK_SIZE(stack_addr));
+		preempt_enable_no_resched();
+		return 1;
+	}
+	return 0;
+}
+
+int __init arch_init_kprobes(void)
+{
+	return 0;
+}
diff --git a/arch/arm64/kernel/kprobes.h b/arch/arm64/kernel/kprobes.h
new file mode 100644
index 0000000..e98ad60
--- /dev/null
+++ b/arch/arm64/kernel/kprobes.h
@@ -0,0 +1,24 @@
+/*
+ * arch/arm64/kernel/kprobes.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_KPROBES_H
+#define _ARM_KERNEL_KPROBES_H
+
+#define JPROBES_MAGIC_NUM	0xa5a5a5a5a5a5a5a5
+
+/* Move this out to appropriate header file */
+int fixup_exception(struct pt_regs *regs);
+
+#endif /* _ARM_KERNEL_KPROBES_H */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 5d9d2dc..2e51510 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -90,6 +90,7 @@ SECTIONS
 			TEXT_TEXT
 			SCHED_TEXT
 			LOCK_TEXT
+			KPROBES_TEXT
 			HYPERVISOR_TEXT
 			*(.fixup)
 			*(.gnu.warning)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 96da131..4c13dfb 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -39,6 +39,28 @@
 
 static const char *fault_name(unsigned int esr);
 
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+{
+	int ret = 0;
+
+	/* kprobe_running() needs smp_processor_id() */
+	if (!user_mode(regs)) {
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, esr))
+			ret = 1;
+		preempt_enable();
+	}
+
+	return ret;
+}
+#else
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+{
+	return 0;
+}
+#endif
+
 /*
  * Dump out the page tables associated with 'addr' in mm 'mm'.
  */
@@ -200,6 +222,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
 	unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
 	unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
+	if (notify_page_fault(regs, esr))
+		return 0;
+
 	tsk = current;
 	mm  = tsk->mm;
 
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 4/6] arm64: kprobes instruction simulation support
  2015-04-20 20:19 ` David Long
@ 2015-04-20 20:19   ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

Kprobes needs simulation of instructions that cannot be stepped
from 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.

Following instruction catagories 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. Kprobes considers
this case as 'miss'.

Thanks to Will Cohen for assorted suggested changes.

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
Signed-off-by: William Cohen <wcohen@redhat.com>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/kernel/Makefile               |   4 +-
 arch/arm64/kernel/kprobes-arm64.c        |  98 +++++++++++++++++
 arch/arm64/kernel/kprobes-arm64.h        |   2 +
 arch/arm64/kernel/kprobes.c              |  35 ++++++-
 arch/arm64/kernel/probes-condn-check.c   | 122 ++++++++++++++++++++++
 arch/arm64/kernel/probes-simulate-insn.c | 174 +++++++++++++++++++++++++++++++
 arch/arm64/kernel/probes-simulate-insn.h |  33 ++++++
 7 files changed, 464 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/kernel/probes-condn-check.c
 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/kernel/Makefile b/arch/arm64/kernel/Makefile
index 056b1a4..0444e15 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -32,7 +32,9 @@ 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		\
+					   probes-condn-check.o
 arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
 arm64-obj-$(CONFIG_PCI)			+= pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
diff --git a/arch/arm64/kernel/kprobes-arm64.c b/arch/arm64/kernel/kprobes-arm64.c
index f958c52..8a7e6b0 100644
--- a/arch/arm64/kernel/kprobes-arm64.c
+++ b/arch/arm64/kernel/kprobes-arm64.c
@@ -20,6 +20,76 @@
 #include <asm/insn.h>
 
 #include "kprobes-arm64.h"
+#include "probes-simulate-insn.h"
+
+/*
+ * condition check functions for kprobes simulation
+ */
+static unsigned long __kprobes
+__check_pstate(struct kprobe *p, struct pt_regs *regs)
+{
+	struct arch_specific_insn *asi = &p->ainsn;
+	unsigned long pstate = regs->pstate & 0xffffffff;
+
+	return asi->pstate_cc(pstate);
+}
+
+static unsigned long __kprobes
+__check_cbz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_cbz((u32)p->opcode, regs);
+}
+
+static unsigned long __kprobes
+__check_cbnz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_cbnz((u32)p->opcode, regs);
+}
+
+static unsigned long __kprobes
+__check_tbz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_tbz((u32)p->opcode, regs);
+}
+
+static unsigned long __kprobes
+__check_tbnz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_tbnz((u32)p->opcode, regs);
+}
+
+/*
+ * prepare functions for instruction simulation
+ */
+static void __kprobes
+prepare_none(struct kprobe *p, struct arch_specific_insn *asi)
+{
+}
+
+static void __kprobes
+prepare_bcond(struct kprobe *p, struct arch_specific_insn *asi)
+{
+	kprobe_opcode_t insn = p->opcode;
+
+	asi->check_condn = __check_pstate;
+	asi->pstate_cc = kprobe_condition_checks[insn & 0xf];
+}
+
+static void __kprobes
+prepare_cbz_cbnz(struct kprobe *p, struct arch_specific_insn *asi)
+{
+	kprobe_opcode_t insn = p->opcode;
+
+	asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz;
+}
+
+static void __kprobes
+prepare_tbz_tbnz(struct kprobe *p, struct arch_specific_insn *asi)
+{
+	kprobe_opcode_t insn = p->opcode;
+
+	asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz;
+}
 
 static bool __kprobes aarch64_insn_is_steppable(u32 insn)
 {
@@ -63,6 +133,34 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 	 */
 	if (aarch64_insn_is_steppable(insn))
 		return INSN_GOOD;
+
+	asi->prepare = prepare_none;
+
+	if (aarch64_insn_is_bcond(insn)) {
+		asi->prepare = prepare_bcond;
+		asi->handler = simulate_b_cond;
+	} else if (aarch64_insn_is_cb(insn)) {
+		asi->prepare = prepare_cbz_cbnz;
+		asi->handler = simulate_cbz_cbnz;
+	} else if (aarch64_insn_is_tb(insn)) {
+		asi->prepare = prepare_tbz_tbnz;
+		asi->handler = simulate_tbz_tbnz;
+	} else if (aarch64_insn_is_adr_adrp(insn))
+		asi->handler = simulate_adr_adrp;
+	else if (aarch64_insn_is_b_bl(insn))
+		asi->handler = simulate_b_bl;
+	else if (aarch64_insn_is_br_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;
 }
diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
index 87e7891..ff8a55f 100644
--- a/arch/arm64/kernel/kprobes-arm64.h
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -22,6 +22,8 @@ enum kprobe_insn {
 	INSN_GOOD,
 };
 
+extern kprobes_pstate_check_t * const kprobe_condition_checks[16];
+
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
 
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 601d2c6..6255814 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -38,6 +38,9 @@
 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 */
@@ -54,6 +57,27 @@ 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)
+{
+	if (p->ainsn.prepare)
+		p->ainsn.prepare(p, &p->ainsn);
+
+	/* 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)
 {
 	kprobe_opcode_t insn;
@@ -72,7 +96,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();
@@ -82,7 +107,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;
 }
@@ -231,7 +259,8 @@ static void __kprobes setup_singlestep(struct kprobe *p,
 		kernel_enable_single_step(regs);
 		instruction_pointer(regs) = slot;
 	} else	{
-		BUG();
+		/* insn simulation */
+		arch_simulate_insn(p, regs);
 	}
 }
 
diff --git a/arch/arm64/kernel/probes-condn-check.c b/arch/arm64/kernel/probes-condn-check.c
new file mode 100644
index 0000000..e68aa0c
--- /dev/null
+++ b/arch/arm64/kernel/probes-condn-check.c
@@ -0,0 +1,122 @@
+/*
+ * arch/arm64/kernel/probes-condn-check.c
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * Copied from: arch/arm/kernel/kprobes-common.c
+ *
+ * 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.
+ *
+ * Description:
+ *
+ *  AArch64 and AArch32 shares same conditional(CNZV) flags encoding.
+ *  This file implements conditional check helpers compatible with
+ *  both AArch64 and AArch32 modes. Uprobes on v8 can handle both 32-bit
+ *  & 64-bit user-space instructions, so we abstract the common functions
+ *  in this file. While AArch64 and AArch32 specific instruction handling
+ *  are implemented in separate files, this file contains common bits.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/probes.h>
+
+static unsigned long __kprobes __check_eq(unsigned long pstate)
+{
+	return pstate & PSR_Z_BIT;
+}
+
+static unsigned long __kprobes __check_ne(unsigned long pstate)
+{
+	return (~pstate) & PSR_Z_BIT;
+}
+
+static unsigned long __kprobes __check_cs(unsigned long pstate)
+{
+	return pstate & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_cc(unsigned long pstate)
+{
+	return (~pstate) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_mi(unsigned long pstate)
+{
+	return pstate & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_pl(unsigned long pstate)
+{
+	return (~pstate) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_vs(unsigned long pstate)
+{
+	return pstate & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_vc(unsigned long pstate)
+{
+	return (~pstate) & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_hi(unsigned long pstate)
+{
+	pstate &= ~(pstate >> 1);	/* PSR_C_BIT &= ~PSR_Z_BIT */
+	return pstate & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ls(unsigned long pstate)
+{
+	pstate &= ~(pstate >> 1);	/* PSR_C_BIT &= ~PSR_Z_BIT */
+	return (~pstate) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ge(unsigned long pstate)
+{
+	pstate ^= (pstate << 3);	/* PSR_N_BIT ^= PSR_V_BIT */
+	return (~pstate) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_lt(unsigned long pstate)
+{
+	pstate ^= (pstate << 3);	/* PSR_N_BIT ^= PSR_V_BIT */
+	return pstate & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_gt(unsigned long pstate)
+{
+	/*PSR_N_BIT ^= PSR_V_BIT */
+	unsigned long temp = pstate ^ (pstate << 3);
+
+	temp |= (pstate << 1);	/*PSR_N_BIT |= PSR_Z_BIT */
+	return (~temp) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_le(unsigned long pstate)
+{
+	/*PSR_N_BIT ^= PSR_V_BIT */
+	unsigned long temp = pstate ^ (pstate << 3);
+
+	temp |= (pstate << 1);	/*PSR_N_BIT |= PSR_Z_BIT */
+	return temp & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_al(unsigned long pstate)
+{
+	return true;
+}
+
+kprobes_pstate_check_t * const kprobe_condition_checks[16] = {
+	&__check_eq, &__check_ne, &__check_cs, &__check_cc,
+	&__check_mi, &__check_pl, &__check_vs, &__check_vc,
+	&__check_hi, &__check_ls, &__check_ge, &__check_lt,
+	&__check_gt, &__check_le, &__check_al, &__check_al
+};
diff --git a/arch/arm64/kernel/probes-simulate-insn.c b/arch/arm64/kernel/probes-simulate-insn.c
new file mode 100644
index 0000000..a224c91
--- /dev/null
+++ b/arch/arm64/kernel/probes-simulate-insn.c
@@ -0,0 +1,174 @@
+/*
+ * 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, 21)
+
+#define cbz_displacement(insn)	\
+	sign_extend(((insn >> 5) & 0x7ffff) << 2, 21)
+
+#define tbz_displacement(insn)	\
+	sign_extend(((insn >> 5) & 0x3fff) << 2, 15)
+
+#define ldr_displacement(insn)	\
+	sign_extend(((insn >> 5) & 0x7ffff) << 2, 21)
+
+
+unsigned long __kprobes check_cbz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+
+	return (opcode & (1 << 31)) ?
+	    !(regs->regs[xn]) : !(regs->regs[xn] & 0xffffffff);
+}
+
+unsigned long __kprobes check_cbnz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+
+	return (opcode & (1 << 31)) ?
+	    (regs->regs[xn]) : (regs->regs[xn] & 0xffffffff);
+}
+
+unsigned long __kprobes check_tbz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+	int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+	return ~((regs->regs[xn] >> bit_pos) & 0x1);
+}
+
+unsigned long __kprobes check_tbnz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+	int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+	return (regs->regs[xn] >> bit_pos) & 0x1;
+}
+
+/*
+ * instruction simulate functions
+ */
+void __kprobes simulate_none(u32 opcode, long addr, struct pt_regs *regs)
+{
+}
+
+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;
+
+	regs->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))
+		regs->regs[30] = addr + 4;
+
+	instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
+{
+	int 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;
+
+	/* Link register is x30 */
+	if (((opcode >> 21) & 0x3) == 1)
+		regs->regs[30] = addr + 4;
+
+	instruction_pointer(regs) = regs->regs[xn];
+}
+
+void __kprobes
+simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+	int disp = cbz_displacement(opcode);
+
+	instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+	int 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 = ldr_displacement(opcode);
+
+	load_addr = (u64 *) (addr + disp);
+
+	if (opcode & (1 << 30))	/* x0-x31 */
+		regs->regs[xn] = *load_addr;
+	else			/* w0-w31 */
+		*(u32 *) (&regs->regs[xn]) = (*(u32 *) (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 = ldr_displacement(opcode);
+
+	load_addr = (s32 *) (addr + disp);
+	regs->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..406f5c2
--- /dev/null
+++ b/arch/arm64/kernel/probes-simulate-insn.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+unsigned long check_cbz(u32 opcode, struct pt_regs *regs);
+unsigned long check_cbnz(u32 opcode, struct pt_regs *regs);
+unsigned long check_tbz(u32 opcode, struct pt_regs *regs);
+unsigned long check_tbnz(u32 opcode, struct pt_regs *regs);
+void simulate_none(u32 opcode, long addr, struct pt_regs *regs);
+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 */
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 4/6] arm64: kprobes instruction simulation support
@ 2015-04-20 20:19   ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

Kprobes needs simulation of instructions that cannot be stepped
from 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.

Following instruction catagories 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. Kprobes considers
this case as 'miss'.

Thanks to Will Cohen for assorted suggested changes.

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
Signed-off-by: William Cohen <wcohen@redhat.com>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/kernel/Makefile               |   4 +-
 arch/arm64/kernel/kprobes-arm64.c        |  98 +++++++++++++++++
 arch/arm64/kernel/kprobes-arm64.h        |   2 +
 arch/arm64/kernel/kprobes.c              |  35 ++++++-
 arch/arm64/kernel/probes-condn-check.c   | 122 ++++++++++++++++++++++
 arch/arm64/kernel/probes-simulate-insn.c | 174 +++++++++++++++++++++++++++++++
 arch/arm64/kernel/probes-simulate-insn.h |  33 ++++++
 7 files changed, 464 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/kernel/probes-condn-check.c
 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/kernel/Makefile b/arch/arm64/kernel/Makefile
index 056b1a4..0444e15 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -32,7 +32,9 @@ 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		\
+					   probes-condn-check.o
 arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
 arm64-obj-$(CONFIG_PCI)			+= pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)	+= armv8_deprecated.o
diff --git a/arch/arm64/kernel/kprobes-arm64.c b/arch/arm64/kernel/kprobes-arm64.c
index f958c52..8a7e6b0 100644
--- a/arch/arm64/kernel/kprobes-arm64.c
+++ b/arch/arm64/kernel/kprobes-arm64.c
@@ -20,6 +20,76 @@
 #include <asm/insn.h>
 
 #include "kprobes-arm64.h"
+#include "probes-simulate-insn.h"
+
+/*
+ * condition check functions for kprobes simulation
+ */
+static unsigned long __kprobes
+__check_pstate(struct kprobe *p, struct pt_regs *regs)
+{
+	struct arch_specific_insn *asi = &p->ainsn;
+	unsigned long pstate = regs->pstate & 0xffffffff;
+
+	return asi->pstate_cc(pstate);
+}
+
+static unsigned long __kprobes
+__check_cbz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_cbz((u32)p->opcode, regs);
+}
+
+static unsigned long __kprobes
+__check_cbnz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_cbnz((u32)p->opcode, regs);
+}
+
+static unsigned long __kprobes
+__check_tbz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_tbz((u32)p->opcode, regs);
+}
+
+static unsigned long __kprobes
+__check_tbnz(struct kprobe *p, struct pt_regs *regs)
+{
+	return check_tbnz((u32)p->opcode, regs);
+}
+
+/*
+ * prepare functions for instruction simulation
+ */
+static void __kprobes
+prepare_none(struct kprobe *p, struct arch_specific_insn *asi)
+{
+}
+
+static void __kprobes
+prepare_bcond(struct kprobe *p, struct arch_specific_insn *asi)
+{
+	kprobe_opcode_t insn = p->opcode;
+
+	asi->check_condn = __check_pstate;
+	asi->pstate_cc = kprobe_condition_checks[insn & 0xf];
+}
+
+static void __kprobes
+prepare_cbz_cbnz(struct kprobe *p, struct arch_specific_insn *asi)
+{
+	kprobe_opcode_t insn = p->opcode;
+
+	asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz;
+}
+
+static void __kprobes
+prepare_tbz_tbnz(struct kprobe *p, struct arch_specific_insn *asi)
+{
+	kprobe_opcode_t insn = p->opcode;
+
+	asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz;
+}
 
 static bool __kprobes aarch64_insn_is_steppable(u32 insn)
 {
@@ -63,6 +133,34 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 	 */
 	if (aarch64_insn_is_steppable(insn))
 		return INSN_GOOD;
+
+	asi->prepare = prepare_none;
+
+	if (aarch64_insn_is_bcond(insn)) {
+		asi->prepare = prepare_bcond;
+		asi->handler = simulate_b_cond;
+	} else if (aarch64_insn_is_cb(insn)) {
+		asi->prepare = prepare_cbz_cbnz;
+		asi->handler = simulate_cbz_cbnz;
+	} else if (aarch64_insn_is_tb(insn)) {
+		asi->prepare = prepare_tbz_tbnz;
+		asi->handler = simulate_tbz_tbnz;
+	} else if (aarch64_insn_is_adr_adrp(insn))
+		asi->handler = simulate_adr_adrp;
+	else if (aarch64_insn_is_b_bl(insn))
+		asi->handler = simulate_b_bl;
+	else if (aarch64_insn_is_br_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;
 }
diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
index 87e7891..ff8a55f 100644
--- a/arch/arm64/kernel/kprobes-arm64.h
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -22,6 +22,8 @@ enum kprobe_insn {
 	INSN_GOOD,
 };
 
+extern kprobes_pstate_check_t * const kprobe_condition_checks[16];
+
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
 
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 601d2c6..6255814 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -38,6 +38,9 @@
 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 */
@@ -54,6 +57,27 @@ 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)
+{
+	if (p->ainsn.prepare)
+		p->ainsn.prepare(p, &p->ainsn);
+
+	/* 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)
 {
 	kprobe_opcode_t insn;
@@ -72,7 +96,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();
@@ -82,7 +107,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;
 }
@@ -231,7 +259,8 @@ static void __kprobes setup_singlestep(struct kprobe *p,
 		kernel_enable_single_step(regs);
 		instruction_pointer(regs) = slot;
 	} else	{
-		BUG();
+		/* insn simulation */
+		arch_simulate_insn(p, regs);
 	}
 }
 
diff --git a/arch/arm64/kernel/probes-condn-check.c b/arch/arm64/kernel/probes-condn-check.c
new file mode 100644
index 0000000..e68aa0c
--- /dev/null
+++ b/arch/arm64/kernel/probes-condn-check.c
@@ -0,0 +1,122 @@
+/*
+ * arch/arm64/kernel/probes-condn-check.c
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * Copied from: arch/arm/kernel/kprobes-common.c
+ *
+ * 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.
+ *
+ * Description:
+ *
+ *  AArch64 and AArch32 shares same conditional(CNZV) flags encoding.
+ *  This file implements conditional check helpers compatible with
+ *  both AArch64 and AArch32 modes. Uprobes on v8 can handle both 32-bit
+ *  & 64-bit user-space instructions, so we abstract the common functions
+ *  in this file. While AArch64 and AArch32 specific instruction handling
+ *  are implemented in separate files, this file contains common bits.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/probes.h>
+
+static unsigned long __kprobes __check_eq(unsigned long pstate)
+{
+	return pstate & PSR_Z_BIT;
+}
+
+static unsigned long __kprobes __check_ne(unsigned long pstate)
+{
+	return (~pstate) & PSR_Z_BIT;
+}
+
+static unsigned long __kprobes __check_cs(unsigned long pstate)
+{
+	return pstate & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_cc(unsigned long pstate)
+{
+	return (~pstate) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_mi(unsigned long pstate)
+{
+	return pstate & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_pl(unsigned long pstate)
+{
+	return (~pstate) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_vs(unsigned long pstate)
+{
+	return pstate & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_vc(unsigned long pstate)
+{
+	return (~pstate) & PSR_V_BIT;
+}
+
+static unsigned long __kprobes __check_hi(unsigned long pstate)
+{
+	pstate &= ~(pstate >> 1);	/* PSR_C_BIT &= ~PSR_Z_BIT */
+	return pstate & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ls(unsigned long pstate)
+{
+	pstate &= ~(pstate >> 1);	/* PSR_C_BIT &= ~PSR_Z_BIT */
+	return (~pstate) & PSR_C_BIT;
+}
+
+static unsigned long __kprobes __check_ge(unsigned long pstate)
+{
+	pstate ^= (pstate << 3);	/* PSR_N_BIT ^= PSR_V_BIT */
+	return (~pstate) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_lt(unsigned long pstate)
+{
+	pstate ^= (pstate << 3);	/* PSR_N_BIT ^= PSR_V_BIT */
+	return pstate & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_gt(unsigned long pstate)
+{
+	/*PSR_N_BIT ^= PSR_V_BIT */
+	unsigned long temp = pstate ^ (pstate << 3);
+
+	temp |= (pstate << 1);	/*PSR_N_BIT |= PSR_Z_BIT */
+	return (~temp) & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_le(unsigned long pstate)
+{
+	/*PSR_N_BIT ^= PSR_V_BIT */
+	unsigned long temp = pstate ^ (pstate << 3);
+
+	temp |= (pstate << 1);	/*PSR_N_BIT |= PSR_Z_BIT */
+	return temp & PSR_N_BIT;
+}
+
+static unsigned long __kprobes __check_al(unsigned long pstate)
+{
+	return true;
+}
+
+kprobes_pstate_check_t * const kprobe_condition_checks[16] = {
+	&__check_eq, &__check_ne, &__check_cs, &__check_cc,
+	&__check_mi, &__check_pl, &__check_vs, &__check_vc,
+	&__check_hi, &__check_ls, &__check_ge, &__check_lt,
+	&__check_gt, &__check_le, &__check_al, &__check_al
+};
diff --git a/arch/arm64/kernel/probes-simulate-insn.c b/arch/arm64/kernel/probes-simulate-insn.c
new file mode 100644
index 0000000..a224c91
--- /dev/null
+++ b/arch/arm64/kernel/probes-simulate-insn.c
@@ -0,0 +1,174 @@
+/*
+ * 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, 21)
+
+#define cbz_displacement(insn)	\
+	sign_extend(((insn >> 5) & 0x7ffff) << 2, 21)
+
+#define tbz_displacement(insn)	\
+	sign_extend(((insn >> 5) & 0x3fff) << 2, 15)
+
+#define ldr_displacement(insn)	\
+	sign_extend(((insn >> 5) & 0x7ffff) << 2, 21)
+
+
+unsigned long __kprobes check_cbz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+
+	return (opcode & (1 << 31)) ?
+	    !(regs->regs[xn]) : !(regs->regs[xn] & 0xffffffff);
+}
+
+unsigned long __kprobes check_cbnz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+
+	return (opcode & (1 << 31)) ?
+	    (regs->regs[xn]) : (regs->regs[xn] & 0xffffffff);
+}
+
+unsigned long __kprobes check_tbz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+	int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+	return ~((regs->regs[xn] >> bit_pos) & 0x1);
+}
+
+unsigned long __kprobes check_tbnz(u32 opcode, struct pt_regs *regs)
+{
+	int xn = opcode & 0x1f;
+	int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+	return (regs->regs[xn] >> bit_pos) & 0x1;
+}
+
+/*
+ * instruction simulate functions
+ */
+void __kprobes simulate_none(u32 opcode, long addr, struct pt_regs *regs)
+{
+}
+
+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;
+
+	regs->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))
+		regs->regs[30] = addr + 4;
+
+	instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
+{
+	int 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;
+
+	/* Link register is x30 */
+	if (((opcode >> 21) & 0x3) == 1)
+		regs->regs[30] = addr + 4;
+
+	instruction_pointer(regs) = regs->regs[xn];
+}
+
+void __kprobes
+simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+	int disp = cbz_displacement(opcode);
+
+	instruction_pointer(regs) = addr + disp;
+}
+
+void __kprobes
+simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+	int 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 = ldr_displacement(opcode);
+
+	load_addr = (u64 *) (addr + disp);
+
+	if (opcode & (1 << 30))	/* x0-x31 */
+		regs->regs[xn] = *load_addr;
+	else			/* w0-w31 */
+		*(u32 *) (&regs->regs[xn]) = (*(u32 *) (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 = ldr_displacement(opcode);
+
+	load_addr = (s32 *) (addr + disp);
+	regs->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..406f5c2
--- /dev/null
+++ b/arch/arm64/kernel/probes-simulate-insn.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+unsigned long check_cbz(u32 opcode, struct pt_regs *regs);
+unsigned long check_cbnz(u32 opcode, struct pt_regs *regs);
+unsigned long check_tbz(u32 opcode, struct pt_regs *regs);
+unsigned long check_tbnz(u32 opcode, struct pt_regs *regs);
+void simulate_none(u32 opcode, long addr, struct pt_regs *regs);
+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 */
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 5/6] arm64: Add kernel return probes support (kretprobes)
  2015-04-20 20:19 ` David Long
@ 2015-04-20 20:19   ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

AArch64 ISA does not have instructions to pop the PC register
value from the stack(like ARM v7 has ldmia {...,pc}) without using
one of the general purpose registers. This means return probes
cannot return to the actual return address directly without
modifying register context, and without trapping into debug exception.

So, like many other architectures, we prepare a global routine
with NOPs which serve as a trampoline to hack away the
function return address by placing an extra kprobe on the
trampoline entry.

The pre-handler of this special 'trampoline' kprobe executes the return
probe handler functions and restores original return address in ELR_EL1.
This way the saved pt_regs still hold the original register context to be
carried back to the probed kernel function.

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/Kconfig               |   1 +
 arch/arm64/include/asm/kprobes.h |   1 +
 arch/arm64/kernel/kprobes.c      | 112 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8e06a03..84f3c9e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -69,6 +69,7 @@ config ARM64
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_KPROBES
+	select HAVE_KRETPROBES if HAVE_KPROBES
 	select IRQ_DOMAIN
 	select MODULES_USE_ELF_RELA
 	select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
index af31c4d..d081f49 100644
--- a/arch/arm64/include/asm/kprobes.h
+++ b/arch/arm64/include/asm/kprobes.h
@@ -58,5 +58,6 @@ 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);
 
 #endif /* _ARM_KPROBES_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 6255814..2b3ef17 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -560,7 +560,117 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 	return 0;
 }
 
+/*
+ * Kretprobes: kernel return probes handling
+ *
+ * AArch64 mode does not support popping the PC value from the
+ * stack like on ARM 32-bit (ldmia {..,pc}), so atleast one
+ * register need to be used to achieve branching/return.
+ * It means return probes cannot return back to the original
+ * return address directly without modifying the register context.
+ *
+ * So like other architectures, we prepare a global routine
+ * with NOPs, which serve as trampoline address that hack away the
+ * function return, with the exact register context.
+ * Placing a kprobe on trampoline routine entry will trap again to
+ * execute return probe handlers and restore original return address
+ * in ELR_EL1, this way saved pt_regs still hold the original
+ * register values to be carried back to the caller.
+ */
+static void __used kretprobe_trampoline_holder(void)
+{
+	asm volatile (".global kretprobe_trampoline\n"
+			"kretprobe_trampoline:\n"
+			"NOP\n\t"
+			"NOP\n\t");
+}
+
+static int __kprobes
+trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kretprobe_instance *ri = NULL;
+	struct hlist_head *head, empty_rp;
+	struct hlist_node *tmp;
+	unsigned long flags, orig_ret_addr = 0;
+	unsigned long trampoline_address =
+		(unsigned long)&kretprobe_trampoline;
+
+	INIT_HLIST_HEAD(&empty_rp);
+	kretprobe_hash_lock(current, &head, &flags);
+
+	/*
+	 * It is possible to have multiple instances associated with a given
+	 * task either because multiple functions in the call path have
+	 * a return probe installed on them, and/or more than 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
+	 *       kretprobe_trampoline
+	 */
+	hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
+
+		if (ri->rp && ri->rp->handler) {
+			__this_cpu_write(current_kprobe, &ri->rp->kp);
+			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+			ri->rp->handler(ri, regs);
+			__this_cpu_write(current_kprobe, NULL);
+		}
+
+		orig_ret_addr = (unsigned long)ri->ret_addr;
+		recycle_rp_inst(ri, &empty_rp);
+
+		if (orig_ret_addr != 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;
+	}
+
+	kretprobe_assert(ri, orig_ret_addr, trampoline_address);
+	/* restore the original return address */
+	instruction_pointer(regs) = orig_ret_addr;
+	reset_current_kprobe();
+	kretprobe_hash_unlock(current, &flags);
+
+	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
+		hlist_del(&ri->hlist);
+		kfree(ri);
+	}
+
+	/* return 1 so that post handlers not called */
+	return 1;
+}
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+				      struct pt_regs *regs)
+{
+	ri->ret_addr = (kprobe_opcode_t *)regs->regs[30];
+
+	/* replace return addr (x30) with trampoline */
+	regs->regs[30] = (long)&kretprobe_trampoline;
+}
+
+static struct kprobe trampoline = {
+	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+	.pre_handler = trampoline_probe_handler
+};
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline;
+}
+
 int __init arch_init_kprobes(void)
 {
-	return 0;
+	/* register trampoline for kret probe */
+	return register_kprobe(&trampoline);
 }
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 5/6] arm64: Add kernel return probes support (kretprobes)
@ 2015-04-20 20:19   ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

AArch64 ISA does not have instructions to pop the PC register
value from the stack(like ARM v7 has ldmia {...,pc}) without using
one of the general purpose registers. This means return probes
cannot return to the actual return address directly without
modifying register context, and without trapping into debug exception.

So, like many other architectures, we prepare a global routine
with NOPs which serve as a trampoline to hack away the
function return address by placing an extra kprobe on the
trampoline entry.

The pre-handler of this special 'trampoline' kprobe executes the return
probe handler functions and restores original return address in ELR_EL1.
This way the saved pt_regs still hold the original register context to be
carried back to the probed kernel function.

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
Signed-off-by: David A. Long <dave.long@linaro.org>
---
 arch/arm64/Kconfig               |   1 +
 arch/arm64/include/asm/kprobes.h |   1 +
 arch/arm64/kernel/kprobes.c      | 112 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8e06a03..84f3c9e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -69,6 +69,7 @@ config ARM64
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_KPROBES
+	select HAVE_KRETPROBES if HAVE_KPROBES
 	select IRQ_DOMAIN
 	select MODULES_USE_ELF_RELA
 	select NO_BOOTMEM
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
index af31c4d..d081f49 100644
--- a/arch/arm64/include/asm/kprobes.h
+++ b/arch/arm64/include/asm/kprobes.h
@@ -58,5 +58,6 @@ 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);
 
 #endif /* _ARM_KPROBES_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 6255814..2b3ef17 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -560,7 +560,117 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 	return 0;
 }
 
+/*
+ * Kretprobes: kernel return probes handling
+ *
+ * AArch64 mode does not support popping the PC value from the
+ * stack like on ARM 32-bit (ldmia {..,pc}), so atleast one
+ * register need to be used to achieve branching/return.
+ * It means return probes cannot return back to the original
+ * return address directly without modifying the register context.
+ *
+ * So like other architectures, we prepare a global routine
+ * with NOPs, which serve as trampoline address that hack away the
+ * function return, with the exact register context.
+ * Placing a kprobe on trampoline routine entry will trap again to
+ * execute return probe handlers and restore original return address
+ * in ELR_EL1, this way saved pt_regs still hold the original
+ * register values to be carried back to the caller.
+ */
+static void __used kretprobe_trampoline_holder(void)
+{
+	asm volatile (".global kretprobe_trampoline\n"
+			"kretprobe_trampoline:\n"
+			"NOP\n\t"
+			"NOP\n\t");
+}
+
+static int __kprobes
+trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kretprobe_instance *ri = NULL;
+	struct hlist_head *head, empty_rp;
+	struct hlist_node *tmp;
+	unsigned long flags, orig_ret_addr = 0;
+	unsigned long trampoline_address =
+		(unsigned long)&kretprobe_trampoline;
+
+	INIT_HLIST_HEAD(&empty_rp);
+	kretprobe_hash_lock(current, &head, &flags);
+
+	/*
+	 * It is possible to have multiple instances associated with a given
+	 * task either because multiple functions in the call path have
+	 * a return probe installed on them, and/or more than 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
+	 *       kretprobe_trampoline
+	 */
+	hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
+
+		if (ri->rp && ri->rp->handler) {
+			__this_cpu_write(current_kprobe, &ri->rp->kp);
+			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+			ri->rp->handler(ri, regs);
+			__this_cpu_write(current_kprobe, NULL);
+		}
+
+		orig_ret_addr = (unsigned long)ri->ret_addr;
+		recycle_rp_inst(ri, &empty_rp);
+
+		if (orig_ret_addr != 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;
+	}
+
+	kretprobe_assert(ri, orig_ret_addr, trampoline_address);
+	/* restore the original return address */
+	instruction_pointer(regs) = orig_ret_addr;
+	reset_current_kprobe();
+	kretprobe_hash_unlock(current, &flags);
+
+	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
+		hlist_del(&ri->hlist);
+		kfree(ri);
+	}
+
+	/* return 1 so that post handlers not called */
+	return 1;
+}
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+				      struct pt_regs *regs)
+{
+	ri->ret_addr = (kprobe_opcode_t *)regs->regs[30];
+
+	/* replace return addr (x30) with trampoline */
+	regs->regs[30] = (long)&kretprobe_trampoline;
+}
+
+static struct kprobe trampoline = {
+	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+	.pre_handler = trampoline_probe_handler
+};
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline;
+}
+
 int __init arch_init_kprobes(void)
 {
-	return 0;
+	/* register trampoline for kret probe */
+	return register_kprobe(&trampoline);
 }
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 6/6] kprobes: Add arm64 case in kprobe example module
  2015-04-20 20:19 ` David Long
@ 2015-04-20 20:19   ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel, Russell King
  Cc: sandeepa.s.prabhu, William Cohen, Steve Capper, Catalin Marinas,
	Will Deacon, Jon Medhurst (Tixy),
	Masami Hiramatsu, Ananth N Mavinakayanahalli,
	Anil S Keshavamurthy, davem, linux-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

Add info prints in sample kprobe handlers for ARM64

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
---
 samples/kprobes/kprobe_example.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c
index 366db1a..51d459c 100644
--- a/samples/kprobes/kprobe_example.c
+++ b/samples/kprobes/kprobe_example.c
@@ -42,6 +42,10 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
 			" ex1 = 0x%lx\n",
 		p->addr, regs->pc, regs->ex1);
 #endif
+#ifdef CONFIG_ARM64
+	pr_info("pre_handler: p->addr = 0x%p, pc = 0x%lx\n",
+		p->addr, (long)regs->pc);
+#endif
 
 	/* A dump_stack() here will give a stack backtrace */
 	return 0;
@@ -67,6 +71,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
 	printk(KERN_INFO "post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
 		p->addr, regs->ex1);
 #endif
+#ifdef CONFIG_ARM64
+	pr_info("post_handler: p->addr = 0x%p, pc = 0x%lx\n",
+		p->addr, (long)regs->pc);
+#endif
 }
 
 /*
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 6/6] kprobes: Add arm64 case in kprobe example module
@ 2015-04-20 20:19   ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-20 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>

Add info prints in sample kprobe handlers for ARM64

Signed-off-by: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
---
 samples/kprobes/kprobe_example.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c
index 366db1a..51d459c 100644
--- a/samples/kprobes/kprobe_example.c
+++ b/samples/kprobes/kprobe_example.c
@@ -42,6 +42,10 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
 			" ex1 = 0x%lx\n",
 		p->addr, regs->pc, regs->ex1);
 #endif
+#ifdef CONFIG_ARM64
+	pr_info("pre_handler: p->addr = 0x%p, pc = 0x%lx\n",
+		p->addr, (long)regs->pc);
+#endif
 
 	/* A dump_stack() here will give a stack backtrace */
 	return 0;
@@ -67,6 +71,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
 	printk(KERN_INFO "post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
 		p->addr, regs->ex1);
 #endif
+#ifdef CONFIG_ARM64
+	pr_info("post_handler: p->addr = 0x%p, pc = 0x%lx\n",
+		p->addr, (long)regs->pc);
+#endif
 }
 
 /*
-- 
1.8.1.2

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-20 20:19 ` David Long
@ 2015-04-21 11:42   ` Masami Hiramatsu
  -1 siblings, 0 replies; 74+ messages in thread
From: Masami Hiramatsu @ 2015-04-21 11:42 UTC (permalink / raw)
  To: David Long
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, William Cohen,
	Steve Capper, Catalin Marinas, Will Deacon, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

(2015/04/21 5:19), David Long wrote:
> From: "David A. Long" <dave.long@linaro.org>
> 
> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
> first seen in October 2013. This version attempts to address concerns raised by
> reviewers and also fixes problems discovered during testing.
> 
> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
> and return probes(kretprobes) support for ARM64.
> 
> The kprobes mechanism makes use of software breakpoint and single stepping
> support available in the ARM v8 kernel.
> 
[...]
> Changes since v5 include:
> 
> 1) Replaced installation of breakpoint hook with direct call from the
> handlers in debug-monitors.c, as requested.
> 2) Reject probing of instructions that read the interrupt mask, in
> addition to instructions that set it.
> 3) Cleaned up comments describing usage of Debug Mask.
> 4) Added KPROBE_REENTER case in reenter_kprobe.
> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
> consistent when KPROBES is not configed.
> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
> 7) Added back in missing new files in previous patch.
> 8) Changed two instances of pr_warning() to pr_warn().

Looks OK to me:)
BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.

> Note that there seems to be at least a potential issue with kprobes
> on multiple (possibly all) platforms having to do with use of kfree
> inside of the kretprobes trampoline handler.  This has manifested
> occasionally in systemtap testing on arm64.  There does not appear to
> be an simple solution to the problem.

No, trampoline handler must call recycle_rp_inst() instead of kfree
to return kretprobe instance to the pool. Hmm, I should look into it.

Thank you,

-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt@hitachi.com



^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-21 11:42   ` Masami Hiramatsu
  0 siblings, 0 replies; 74+ messages in thread
From: Masami Hiramatsu @ 2015-04-21 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

(2015/04/21 5:19), David Long wrote:
> From: "David A. Long" <dave.long@linaro.org>
> 
> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
> first seen in October 2013. This version attempts to address concerns raised by
> reviewers and also fixes problems discovered during testing.
> 
> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
> and return probes(kretprobes) support for ARM64.
> 
> The kprobes mechanism makes use of software breakpoint and single stepping
> support available in the ARM v8 kernel.
> 
[...]
> Changes since v5 include:
> 
> 1) Replaced installation of breakpoint hook with direct call from the
> handlers in debug-monitors.c, as requested.
> 2) Reject probing of instructions that read the interrupt mask, in
> addition to instructions that set it.
> 3) Cleaned up comments describing usage of Debug Mask.
> 4) Added KPROBE_REENTER case in reenter_kprobe.
> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
> consistent when KPROBES is not configed.
> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
> 7) Added back in missing new files in previous patch.
> 8) Changed two instances of pr_warning() to pr_warn().

Looks OK to me:)
BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.

> Note that there seems to be at least a potential issue with kprobes
> on multiple (possibly all) platforms having to do with use of kfree
> inside of the kretprobes trampoline handler.  This has manifested
> occasionally in systemtap testing on arm64.  There does not appear to
> be an simple solution to the problem.

No, trampoline handler must call recycle_rp_inst() instead of kfree
to return kretprobe instance to the pool. Hmm, I should look into it.

Thank you,

-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt at hitachi.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-21 11:42   ` Masami Hiramatsu
@ 2015-04-21 14:07     ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-04-21 14:07 UTC (permalink / raw)
  To: Masami Hiramatsu, David Long
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Will Deacon, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3037 bytes --]

On 04/21/2015 07:42 AM, Masami Hiramatsu wrote:
> (2015/04/21 5:19), David Long wrote:
>> From: "David A. Long" <dave.long@linaro.org>
>>
>> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
>> first seen in October 2013. This version attempts to address concerns raised by
>> reviewers and also fixes problems discovered during testing.
>>
>> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
>> and return probes(kretprobes) support for ARM64.
>>
>> The kprobes mechanism makes use of software breakpoint and single stepping
>> support available in the ARM v8 kernel.
>>
> [...]
>> Changes since v5 include:
>>
>> 1) Replaced installation of breakpoint hook with direct call from the
>> handlers in debug-monitors.c, as requested.
>> 2) Reject probing of instructions that read the interrupt mask, in
>> addition to instructions that set it.
>> 3) Cleaned up comments describing usage of Debug Mask.
>> 4) Added KPROBE_REENTER case in reenter_kprobe.
>> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
>> consistent when KPROBES is not configed.
>> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
>> 7) Added back in missing new files in previous patch.
>> 8) Changed two instances of pr_warning() to pr_warn().
> 
> Looks OK to me:)
> BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
> If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.
> 
>> Note that there seems to be at least a potential issue with kprobes
>> on multiple (possibly all) platforms having to do with use of kfree
>> inside of the kretprobes trampoline handler.  This has manifested
>> occasionally in systemtap testing on arm64.  There does not appear to
>> be an simple solution to the problem.
> 
> No, trampoline handler must call recycle_rp_inst() instead of kfree
> to return kretprobe instance to the pool. Hmm, I should look into it.
> 
> Thank you,
> 

Hi,

I have noticed when running the systemtap testsuite even with this newest revision of the arm64 kprobe patches the system will start spewing the following message:

Unexpected kernel single-step exception at EL1

That is triggered by the functioncallcount.stp test in the systemtap examples.  The test is instrumenting many function calls and returns in the memory management code.  It appears that the problem is triggered during the kfree call/return towards the end of trampoline_probe_handler.  The single_step_handler function in debug-monitors.c calls kprobe_single_step_handler which indicates that the breakpoint is not a kprobe breakpoint.  Thus, single_step_handler starts flagging the breakpoint with the above message.

It would be good if the warning message included and address to be a bit more informative.  I put in some addition code (the attached patch) to print out register information to diagnose what was going on.

Other architecture do use kfree in the kretprobe trampoline handlers but do not seem to encounter this problem. 

-Will

[-- Attachment #2: debug_diag.patch --]
[-- Type: text/x-patch, Size: 915 bytes --]

diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index dae7bb4..ec5a1b2 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -262,6 +262,19 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 
 		if (!handler_found) {
 			pr_warning("Unexpected kernel single-step exception at EL1\n");
+			{
+		  	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+			pr_warning("kcb->ss_ctx.ss_status = %ld\n",
+				   kcb->ss_ctx.ss_status);
+			printk("kcb->ss_ctx.match_addr = %lx ",
+				     kcb->ss_ctx.match_addr);
+			print_symbol("%s\n", kcb->ss_ctx.match_addr);
+			printk("instruction_pointer(regs) = %lx ",
+				   instruction_pointer(regs));
+			print_symbol("%s\n", instruction_pointer(regs));
+			show_regs(regs);
+			BUG();
+			}
 			/*
 			 * Re-enable stepping since we know that we will be
 			 * returning to regs.

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-21 14:07     ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-04-21 14:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/21/2015 07:42 AM, Masami Hiramatsu wrote:
> (2015/04/21 5:19), David Long wrote:
>> From: "David A. Long" <dave.long@linaro.org>
>>
>> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
>> first seen in October 2013. This version attempts to address concerns raised by
>> reviewers and also fixes problems discovered during testing.
>>
>> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
>> and return probes(kretprobes) support for ARM64.
>>
>> The kprobes mechanism makes use of software breakpoint and single stepping
>> support available in the ARM v8 kernel.
>>
> [...]
>> Changes since v5 include:
>>
>> 1) Replaced installation of breakpoint hook with direct call from the
>> handlers in debug-monitors.c, as requested.
>> 2) Reject probing of instructions that read the interrupt mask, in
>> addition to instructions that set it.
>> 3) Cleaned up comments describing usage of Debug Mask.
>> 4) Added KPROBE_REENTER case in reenter_kprobe.
>> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
>> consistent when KPROBES is not configed.
>> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
>> 7) Added back in missing new files in previous patch.
>> 8) Changed two instances of pr_warning() to pr_warn().
> 
> Looks OK to me:)
> BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
> If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.
> 
>> Note that there seems to be at least a potential issue with kprobes
>> on multiple (possibly all) platforms having to do with use of kfree
>> inside of the kretprobes trampoline handler.  This has manifested
>> occasionally in systemtap testing on arm64.  There does not appear to
>> be an simple solution to the problem.
> 
> No, trampoline handler must call recycle_rp_inst() instead of kfree
> to return kretprobe instance to the pool. Hmm, I should look into it.
> 
> Thank you,
> 

Hi,

I have noticed when running the systemtap testsuite even with this newest revision of the arm64 kprobe patches the system will start spewing the following message:

Unexpected kernel single-step exception at EL1

That is triggered by the functioncallcount.stp test in the systemtap examples.  The test is instrumenting many function calls and returns in the memory management code.  It appears that the problem is triggered during the kfree call/return towards the end of trampoline_probe_handler.  The single_step_handler function in debug-monitors.c calls kprobe_single_step_handler which indicates that the breakpoint is not a kprobe breakpoint.  Thus, single_step_handler starts flagging the breakpoint with the above message.

It would be good if the warning message included and address to be a bit more informative.  I put in some addition code (the attached patch) to print out register information to diagnose what was going on.

Other architecture do use kfree in the kretprobe trampoline handlers but do not seem to encounter this problem. 

-Will
-------------- next part --------------
A non-text attachment was scrubbed...
Name: debug_diag.patch
Type: text/x-patch
Size: 915 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150421/dca21984/attachment.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-21 11:42   ` Masami Hiramatsu
@ 2015-04-24 21:14     ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-04-24 21:14 UTC (permalink / raw)
  To: Masami Hiramatsu, David Long
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Will Deacon, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 04/21/2015 07:42 AM, Masami Hiramatsu wrote:
> (2015/04/21 5:19), David Long wrote:
>> From: "David A. Long" <dave.long@linaro.org>
>>
>> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
>> first seen in October 2013. This version attempts to address concerns raised by
>> reviewers and also fixes problems discovered during testing.
>>
>> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
>> and return probes(kretprobes) support for ARM64.
>>
>> The kprobes mechanism makes use of software breakpoint and single stepping
>> support available in the ARM v8 kernel.
>>
> [...]
>> Changes since v5 include:
>>
>> 1) Replaced installation of breakpoint hook with direct call from the
>> handlers in debug-monitors.c, as requested.
>> 2) Reject probing of instructions that read the interrupt mask, in
>> addition to instructions that set it.
>> 3) Cleaned up comments describing usage of Debug Mask.
>> 4) Added KPROBE_REENTER case in reenter_kprobe.
>> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
>> consistent when KPROBES is not configed.
>> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
>> 7) Added back in missing new files in previous patch.
>> 8) Changed two instances of pr_warning() to pr_warn().
> 
> Looks OK to me:)
> BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
> If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.
> 
>> Note that there seems to be at least a potential issue with kprobes
>> on multiple (possibly all) platforms having to do with use of kfree
>> inside of the kretprobes trampoline handler.  This has manifested
>> occasionally in systemtap testing on arm64.  There does not appear to
>> be an simple solution to the problem.
> 
> No, trampoline handler must call recycle_rp_inst() instead of kfree
> to return kretprobe instance to the pool. Hmm, I should look into it.
> 
> Thank you,
> 

Hi All,

At time the kernel with arm64 kprobe patches gets stuck printing out:

Unexpected kernel single-step exception at EL1

I put some instrumentation in debug-monitor.c to print out the kcb and register state when this happens.  Below is an example output:

[14613.263536] Unexpected kernel single-step exception at EL1
[14613.269001] kcb->ss_ctx.ss_status = 1
[14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
[14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
[14613.286003] 
[14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
[14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
[14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
[14613.310430] PC is at el1_da+0x8/0x70
[14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
[14613.319363] pc : [<fffffe0000093358>] lr : [<fffffe0000687590>] pstate: 600001c5
[14613.326724] sp : fffffe01d68af640
[14613.330021] x29: fffffe01d68afbf0 x28: fffffe01d68ac000 
[14613.335328] x27: fffffe00000939cc x26: fffffe0000bb09d0 
[14613.340634] x25: fffffe01d68afdb0 x24: 0000000000000025 
[14613.345939] x23: 00000000800003c5 x22: fffffdfffc001284 
[14613.351245] x21: fffffe01d68af760 x20: fffffe01d7c79a00 
[14613.356552] x19: 0000000000000000 x18: 000003ffa4b8e600 
[14613.361858] x17: 000003ffa5480698 x16: fffffe00001f2afc 
[14613.367164] x15: 0000000000000007 x14: 000003ffeffa8690 
[14613.372471] x13: 0000000000000001 x12: 000003ffa4baf200 
[14613.377778] x11: fffffe00006bb328 x10: fffffe00006bb32c 
[14613.383084] x9 : fffffe01d68afd10 x8 : fffffe01d6806d10 
[14613.388390] x7 : fffffe01ffd01298 x6 : fffffe000009192c 
[14613.393696] x5 : fffffe0000c1b398 x4 : 0000000000000000 
[14613.399001] x3 : 0000000000200200 x2 : 0000000000100100 
[14613.404306] x1 : 0000000096000006 x0 : 0000000000000015 
[14613.409610] 
[14613.411094] BUG: failure at arch/arm64/kernel/debug-monitors.c:276/single_step_handler()!

One thing to note is the pstate value 0x600001c5; it has the SS bit set.  I think that sometime during handling the kprobe the SS is being set incorrectly or not cleared in the saved state.  When the register state gets reload a single step is attempted and the debug-monitors code flags it because it doesn't match up to the currently running kprobe.

Is single_step_handler functions setting the flag again with set_regs_spsr_ss(regs) the correct way to handle this if it wasn't previously handled?  If the single step isn't handled the first time, why are the following instructions going to be handled? It is going to spew many warning messages.

-Will Cohen

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-24 21:14     ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-04-24 21:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/21/2015 07:42 AM, Masami Hiramatsu wrote:
> (2015/04/21 5:19), David Long wrote:
>> From: "David A. Long" <dave.long@linaro.org>
>>
>> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
>> first seen in October 2013. This version attempts to address concerns raised by
>> reviewers and also fixes problems discovered during testing.
>>
>> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
>> and return probes(kretprobes) support for ARM64.
>>
>> The kprobes mechanism makes use of software breakpoint and single stepping
>> support available in the ARM v8 kernel.
>>
> [...]
>> Changes since v5 include:
>>
>> 1) Replaced installation of breakpoint hook with direct call from the
>> handlers in debug-monitors.c, as requested.
>> 2) Reject probing of instructions that read the interrupt mask, in
>> addition to instructions that set it.
>> 3) Cleaned up comments describing usage of Debug Mask.
>> 4) Added KPROBE_REENTER case in reenter_kprobe.
>> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
>> consistent when KPROBES is not configed.
>> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
>> 7) Added back in missing new files in previous patch.
>> 8) Changed two instances of pr_warning() to pr_warn().
> 
> Looks OK to me:)
> BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
> If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.
> 
>> Note that there seems to be at least a potential issue with kprobes
>> on multiple (possibly all) platforms having to do with use of kfree
>> inside of the kretprobes trampoline handler.  This has manifested
>> occasionally in systemtap testing on arm64.  There does not appear to
>> be an simple solution to the problem.
> 
> No, trampoline handler must call recycle_rp_inst() instead of kfree
> to return kretprobe instance to the pool. Hmm, I should look into it.
> 
> Thank you,
> 

Hi All,

At time the kernel with arm64 kprobe patches gets stuck printing out:

Unexpected kernel single-step exception at EL1

I put some instrumentation in debug-monitor.c to print out the kcb and register state when this happens.  Below is an example output:

[14613.263536] Unexpected kernel single-step exception at EL1
[14613.269001] kcb->ss_ctx.ss_status = 1
[14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
[14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
[14613.286003] 
[14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
[14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
[14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
[14613.310430] PC is at el1_da+0x8/0x70
[14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
[14613.319363] pc : [<fffffe0000093358>] lr : [<fffffe0000687590>] pstate: 600001c5
[14613.326724] sp : fffffe01d68af640
[14613.330021] x29: fffffe01d68afbf0 x28: fffffe01d68ac000 
[14613.335328] x27: fffffe00000939cc x26: fffffe0000bb09d0 
[14613.340634] x25: fffffe01d68afdb0 x24: 0000000000000025 
[14613.345939] x23: 00000000800003c5 x22: fffffdfffc001284 
[14613.351245] x21: fffffe01d68af760 x20: fffffe01d7c79a00 
[14613.356552] x19: 0000000000000000 x18: 000003ffa4b8e600 
[14613.361858] x17: 000003ffa5480698 x16: fffffe00001f2afc 
[14613.367164] x15: 0000000000000007 x14: 000003ffeffa8690 
[14613.372471] x13: 0000000000000001 x12: 000003ffa4baf200 
[14613.377778] x11: fffffe00006bb328 x10: fffffe00006bb32c 
[14613.383084] x9 : fffffe01d68afd10 x8 : fffffe01d6806d10 
[14613.388390] x7 : fffffe01ffd01298 x6 : fffffe000009192c 
[14613.393696] x5 : fffffe0000c1b398 x4 : 0000000000000000 
[14613.399001] x3 : 0000000000200200 x2 : 0000000000100100 
[14613.404306] x1 : 0000000096000006 x0 : 0000000000000015 
[14613.409610] 
[14613.411094] BUG: failure at arch/arm64/kernel/debug-monitors.c:276/single_step_handler()!

One thing to note is the pstate value 0x600001c5; it has the SS bit set.  I think that sometime during handling the kprobe the SS is being set incorrectly or not cleared in the saved state.  When the register state gets reload a single step is attempted and the debug-monitors code flags it because it doesn't match up to the currently running kprobe.

Is single_step_handler functions setting the flag again with set_regs_spsr_ss(regs) the correct way to handle this if it wasn't previously handled?  If the single step isn't handled the first time, why are the following instructions going to be handled? It is going to spew many warning messages.

-Will Cohen

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-24 21:14     ` William Cohen
@ 2015-04-28  2:58       ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-04-28  2:58 UTC (permalink / raw)
  To: Masami Hiramatsu, David Long, Will Deacon
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3481 bytes --]


Hi All,

I have been experimenting with the patches for arm64 kprobes support.
On occasion the kernel gets stuck in a loop printing output:

 Unexpected kernel single-step exception at EL1

This message by itself is not that enlighten.  I added the attached
patch to get some additional information about register state when the
warning is printed out.  Below is an example output:


[14613.263536] Unexpected kernel single-step exception at EL1
[14613.269001] kcb->ss_ctx.ss_status = 1
[14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
[14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
[14613.286003] 
[14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
[14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
[14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
[14613.310430] PC is at el1_da+0x8/0x70
[14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
[14613.319363] pc : [<fffffe0000093358>] lr : [<fffffe0000687590>] pstate: 600001c5
[14613.326724] sp : fffffe01d68af640
[14613.330021] x29: fffffe01d68afbf0 x28: fffffe01d68ac000 
[14613.335328] x27: fffffe00000939cc x26: fffffe0000bb09d0 
[14613.340634] x25: fffffe01d68afdb0 x24: 0000000000000025 
[14613.345939] x23: 00000000800003c5 x22: fffffdfffc001284 
[14613.351245] x21: fffffe01d68af760 x20: fffffe01d7c79a00 
[14613.356552] x19: 0000000000000000 x18: 000003ffa4b8e600 
[14613.361858] x17: 000003ffa5480698 x16: fffffe00001f2afc 
[14613.367164] x15: 0000000000000007 x14: 000003ffeffa8690 
[14613.372471] x13: 0000000000000001 x12: 000003ffa4baf200 
[14613.377778] x11: fffffe00006bb328 x10: fffffe00006bb32c 
[14613.383084] x9 : fffffe01d68afd10 x8 : fffffe01d6806d10 
[14613.388390] x7 : fffffe01ffd01298 x6 : fffffe000009192c 
[14613.393696] x5 : fffffe0000c1b398 x4 : 0000000000000000 
[14613.399001] x3 : 0000000000200200 x2 : 0000000000100100 
[14613.404306] x1 : 0000000096000006 x0 : 0000000000000015 
[14613.409610] 
[14613.411094] BUG: failure at arch/arm64/kernel/debug-monitors.c:276/single_step_handler()!


The really odd thing is the address of the PC it is in el1_da the code
to handle data aborts.  it looks like it is getting the unexpected
single_step exception right after the enable_debug in el1_da.  I think
what might be happening is:

-an instruction is instrumented with kprobe
-the instruction is copied to a buffer
-a breakpoint replaces the instruction
-the kprobe fires when the breakpoint is encountered
-the instruction in the buffer is set to single step
-a single step of the instruction is attempted
-a data abort exception is raised
-el1_da is called
-el1_da does an enable_dbg to unmask the debug exceptions
-single_step_handler is called
-single_step_handler doesn't find anything to handle that pc
-single_step_handler prints the warning about unexpected el1 single step
-single_step_handler re-enable ss step
-the single step of the instruction is attempted endlessly

It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
was trying to address a similar problem for the el1_dbg
function.  Should el1_da and other el1_* functions have the enable_dbg
removed?

If single_step_handler doesn't find a handler, is re-enabling the
single step with set_regs_spsr_ss in single_step_handler the right thing to do?

-Will


[-- Attachment #2: debug_diag.patch --]
[-- Type: text/x-patch, Size: 915 bytes --]

diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index dae7bb4..ec5a1b2 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -262,6 +262,19 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 
 		if (!handler_found) {
 			pr_warning("Unexpected kernel single-step exception at EL1\n");
+			{
+		  	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+			pr_warning("kcb->ss_ctx.ss_status = %ld\n",
+				   kcb->ss_ctx.ss_status);
+			printk("kcb->ss_ctx.match_addr = %lx ",
+				     kcb->ss_ctx.match_addr);
+			print_symbol("%s\n", kcb->ss_ctx.match_addr);
+			printk("instruction_pointer(regs) = %lx ",
+				   instruction_pointer(regs));
+			print_symbol("%s\n", instruction_pointer(regs));
+			show_regs(regs);
+			BUG();
+			}
 			/*
 			 * Re-enable stepping since we know that we will be
 			 * returning to regs.

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-28  2:58       ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-04-28  2:58 UTC (permalink / raw)
  To: linux-arm-kernel


Hi All,

I have been experimenting with the patches for arm64 kprobes support.
On occasion the kernel gets stuck in a loop printing output:

 Unexpected kernel single-step exception at EL1

This message by itself is not that enlighten.  I added the attached
patch to get some additional information about register state when the
warning is printed out.  Below is an example output:


[14613.263536] Unexpected kernel single-step exception at EL1
[14613.269001] kcb->ss_ctx.ss_status = 1
[14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
[14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
[14613.286003] 
[14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
[14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
[14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
[14613.310430] PC is at el1_da+0x8/0x70
[14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
[14613.319363] pc : [<fffffe0000093358>] lr : [<fffffe0000687590>] pstate: 600001c5
[14613.326724] sp : fffffe01d68af640
[14613.330021] x29: fffffe01d68afbf0 x28: fffffe01d68ac000 
[14613.335328] x27: fffffe00000939cc x26: fffffe0000bb09d0 
[14613.340634] x25: fffffe01d68afdb0 x24: 0000000000000025 
[14613.345939] x23: 00000000800003c5 x22: fffffdfffc001284 
[14613.351245] x21: fffffe01d68af760 x20: fffffe01d7c79a00 
[14613.356552] x19: 0000000000000000 x18: 000003ffa4b8e600 
[14613.361858] x17: 000003ffa5480698 x16: fffffe00001f2afc 
[14613.367164] x15: 0000000000000007 x14: 000003ffeffa8690 
[14613.372471] x13: 0000000000000001 x12: 000003ffa4baf200 
[14613.377778] x11: fffffe00006bb328 x10: fffffe00006bb32c 
[14613.383084] x9 : fffffe01d68afd10 x8 : fffffe01d6806d10 
[14613.388390] x7 : fffffe01ffd01298 x6 : fffffe000009192c 
[14613.393696] x5 : fffffe0000c1b398 x4 : 0000000000000000 
[14613.399001] x3 : 0000000000200200 x2 : 0000000000100100 
[14613.404306] x1 : 0000000096000006 x0 : 0000000000000015 
[14613.409610] 
[14613.411094] BUG: failure at arch/arm64/kernel/debug-monitors.c:276/single_step_handler()!


The really odd thing is the address of the PC it is in el1_da the code
to handle data aborts.  it looks like it is getting the unexpected
single_step exception right after the enable_debug in el1_da.  I think
what might be happening is:

-an instruction is instrumented with kprobe
-the instruction is copied to a buffer
-a breakpoint replaces the instruction
-the kprobe fires when the breakpoint is encountered
-the instruction in the buffer is set to single step
-a single step of the instruction is attempted
-a data abort exception is raised
-el1_da is called
-el1_da does an enable_dbg to unmask the debug exceptions
-single_step_handler is called
-single_step_handler doesn't find anything to handle that pc
-single_step_handler prints the warning about unexpected el1 single step
-single_step_handler re-enable ss step
-the single step of the instruction is attempted endlessly

It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
was trying to address a similar problem for the el1_dbg
function.  Should el1_da and other el1_* functions have the enable_dbg
removed?

If single_step_handler doesn't find a handler, is re-enabling the
single step with set_regs_spsr_ss in single_step_handler the right thing to do?

-Will

-------------- next part --------------
A non-text attachment was scrubbed...
Name: debug_diag.patch
Type: text/x-patch
Size: 915 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150427/2a3d266f/attachment.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-21 11:42   ` Masami Hiramatsu
@ 2015-04-29  4:33     ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-29  4:33 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, William Cohen,
	Steve Capper, Catalin Marinas, Will Deacon, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 04/21/15 07:42, Masami Hiramatsu wrote:
> (2015/04/21 5:19), David Long wrote:
>> From: "David A. Long" <dave.long@linaro.org>
>>
>> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
>> first seen in October 2013. This version attempts to address concerns raised by
>> reviewers and also fixes problems discovered during testing.
>>
>> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
>> and return probes(kretprobes) support for ARM64.
>>
>> The kprobes mechanism makes use of software breakpoint and single stepping
>> support available in the ARM v8 kernel.
>>
> [...]
>> Changes since v5 include:
>>
>> 1) Replaced installation of breakpoint hook with direct call from the
>> handlers in debug-monitors.c, as requested.
>> 2) Reject probing of instructions that read the interrupt mask, in
>> addition to instructions that set it.
>> 3) Cleaned up comments describing usage of Debug Mask.
>> 4) Added KPROBE_REENTER case in reenter_kprobe.
>> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
>> consistent when KPROBES is not configed.
>> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
>> 7) Added back in missing new files in previous patch.
>> 8) Changed two instances of pr_warning() to pr_warn().
> 
> Looks OK to me:)
> BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
> If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.
> 

Yes, it builds with CONFIG_KPROBE_EVENT.  Thanks for the suggestion
regarding ftracetest, I was not actually aware of that test.  I ran it
with no failures, 11 "PASS", and 4 "UNSUPPORTED" tests.

>> Note that there seems to be at least a potential issue with kprobes
>> on multiple (possibly all) platforms having to do with use of kfree
>> inside of the kretprobes trampoline handler.  This has manifested
>> occasionally in systemtap testing on arm64.  There does not appear to
>> be an simple solution to the problem.
> 
> No, trampoline handler must call recycle_rp_inst() instead of kfree
> to return kretprobe instance to the pool. Hmm, I should look into it.
> 

I think all architectures call both from the kretprobe trampoline.  In
the arm64 case at least the kfree call apparently is very infrequent,
and very problematic for now if anything it subsequently calls has a
kretprobe set.

Thanks,
-dl



^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-29  4:33     ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-04-29  4:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/21/15 07:42, Masami Hiramatsu wrote:
> (2015/04/21 5:19), David Long wrote:
>> From: "David A. Long" <dave.long@linaro.org>
>>
>> This patchset is heavily based on Sandeepa Prabhu's ARM v8 kprobes patches,
>> first seen in October 2013. This version attempts to address concerns raised by
>> reviewers and also fixes problems discovered during testing.
>>
>> This patchset adds support for kernel probes(kprobes), jump probes(jprobes)
>> and return probes(kretprobes) support for ARM64.
>>
>> The kprobes mechanism makes use of software breakpoint and single stepping
>> support available in the ARM v8 kernel.
>>
> [...]
>> Changes since v5 include:
>>
>> 1) Replaced installation of breakpoint hook with direct call from the
>> handlers in debug-monitors.c, as requested.
>> 2) Reject probing of instructions that read the interrupt mask, in
>> addition to instructions that set it.
>> 3) Cleaned up comments describing usage of Debug Mask.
>> 4) Added KPROBE_REENTER case in reenter_kprobe.
>> 5) Corrected the ifdef'd definitions for notify_page_fault() to be
>> consistent when KPROBES is not configed.
>> 6) Changed "cpsr" to "pstate" for HAVE_REGS_AND_STACK_ACCESS_API feature.
>> 7) Added back in missing new files in previous patch.
>> 8) Changed two instances of pr_warning() to pr_warn().
> 
> Looks OK to me:)
> BTW, have you tried to build and test this with CONFIG_KPROBE_EVENT?
> If so, you can also test it by tools/testing/selftests/ftrace/ftracetest.
> 

Yes, it builds with CONFIG_KPROBE_EVENT.  Thanks for the suggestion
regarding ftracetest, I was not actually aware of that test.  I ran it
with no failures, 11 "PASS", and 4 "UNSUPPORTED" tests.

>> Note that there seems to be at least a potential issue with kprobes
>> on multiple (possibly all) platforms having to do with use of kfree
>> inside of the kretprobes trampoline handler.  This has manifested
>> occasionally in systemtap testing on arm64.  There does not appear to
>> be an simple solution to the problem.
> 
> No, trampoline handler must call recycle_rp_inst() instead of kfree
> to return kretprobe instance to the pool. Hmm, I should look into it.
> 

I think all architectures call both from the kretprobe trampoline.  In
the arm64 case at least the kfree call apparently is very infrequent,
and very problematic for now if anything it subsequently calls has a
kretprobe set.

Thanks,
-dl

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-28  2:58       ` William Cohen
@ 2015-04-29 10:23         ` Will Deacon
  -1 siblings, 0 replies; 74+ messages in thread
From: Will Deacon @ 2015-04-29 10:23 UTC (permalink / raw)
  To: William Cohen
  Cc: Masami Hiramatsu, David Long, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On Tue, Apr 28, 2015 at 03:58:21AM +0100, William Cohen wrote:
> Hi All,

Hi Will,

> I have been experimenting with the patches for arm64 kprobes support.
> On occasion the kernel gets stuck in a loop printing output:
> 
>  Unexpected kernel single-step exception at EL1
> 
> This message by itself is not that enlighten.  I added the attached
> patch to get some additional information about register state when the
> warning is printed out.  Below is an example output:

Given that we've got the pt_regs in our hands at that point, I'm happy to
print something more useful if you like (e.g. the PC?).

> [14613.263536] Unexpected kernel single-step exception at EL1
> [14613.269001] kcb->ss_ctx.ss_status = 1
> [14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
> [14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
> [14613.286003] 
> [14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
> [14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
> [14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
> [14613.310430] PC is at el1_da+0x8/0x70
> [14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec

> The really odd thing is the address of the PC it is in el1_da the code
> to handle data aborts.  it looks like it is getting the unexpected
> single_step exception right after the enable_debug in el1_da.  I think
> what might be happening is:
> 
> -an instruction is instrumented with kprobe
> -the instruction is copied to a buffer
> -a breakpoint replaces the instruction
> -the kprobe fires when the breakpoint is encountered
> -the instruction in the buffer is set to single step
> -a single step of the instruction is attempted
> -a data abort exception is raised
> -el1_da is called

So that's the bit that I find weird. Can you take a look at what we're doing
in trampoline_probe_handler, please? It could be that we're doing something
like get_user and aborting on a faulting userspace address, but I think
kprobes should handle that rather than us trying to get the generic
single-step code to deal with it.

> It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
> Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
> was trying to address a similar problem for the el1_dbg
> function.  Should el1_da and other el1_* functions have the enable_dbg
> removed?

I don't think so. The current behaviour of the low-level debug handler is to
step into traps, which is more flexible than trying to step over them (which
could lead to us stepping over interrupts, or preemption points). It should
be up to the higher-level debugger (e.g. kprobes, kgdb) to distinguish
between the traps it does and does not care about.

An equivalent userspace example would be GDB stepping into single handlers,
I suppose.

Will

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-04-29 10:23         ` Will Deacon
  0 siblings, 0 replies; 74+ messages in thread
From: Will Deacon @ 2015-04-29 10:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 28, 2015 at 03:58:21AM +0100, William Cohen wrote:
> Hi All,

Hi Will,

> I have been experimenting with the patches for arm64 kprobes support.
> On occasion the kernel gets stuck in a loop printing output:
> 
>  Unexpected kernel single-step exception at EL1
> 
> This message by itself is not that enlighten.  I added the attached
> patch to get some additional information about register state when the
> warning is printed out.  Below is an example output:

Given that we've got the pt_regs in our hands at that point, I'm happy to
print something more useful if you like (e.g. the PC?).

> [14613.263536] Unexpected kernel single-step exception at EL1
> [14613.269001] kcb->ss_ctx.ss_status = 1
> [14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
> [14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
> [14613.286003] 
> [14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
> [14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
> [14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
> [14613.310430] PC is at el1_da+0x8/0x70
> [14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec

> The really odd thing is the address of the PC it is in el1_da the code
> to handle data aborts.  it looks like it is getting the unexpected
> single_step exception right after the enable_debug in el1_da.  I think
> what might be happening is:
> 
> -an instruction is instrumented with kprobe
> -the instruction is copied to a buffer
> -a breakpoint replaces the instruction
> -the kprobe fires when the breakpoint is encountered
> -the instruction in the buffer is set to single step
> -a single step of the instruction is attempted
> -a data abort exception is raised
> -el1_da is called

So that's the bit that I find weird. Can you take a look at what we're doing
in trampoline_probe_handler, please? It could be that we're doing something
like get_user and aborting on a faulting userspace address, but I think
kprobes should handle that rather than us trying to get the generic
single-step code to deal with it.

> It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
> Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
> was trying to address a similar problem for the el1_dbg
> function.  Should el1_da and other el1_* functions have the enable_dbg
> removed?

I don't think so. The current behaviour of the low-level debug handler is to
step into traps, which is more flexible than trying to step over them (which
could lead to us stepping over interrupts, or preemption points). It should
be up to the higher-level debugger (e.g. kprobes, kgdb) to distinguish
between the traps it does and does not care about.

An equivalent userspace example would be GDB stepping into single handlers,
I suppose.

Will

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-04-29 10:23         ` Will Deacon
@ 2015-05-02  1:44           ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-02  1:44 UTC (permalink / raw)
  To: Will Deacon
  Cc: Masami Hiramatsu, David Long, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 04/29/2015 06:23 AM, Will Deacon wrote:
> On Tue, Apr 28, 2015 at 03:58:21AM +0100, William Cohen wrote:
>> Hi All,
> 
> Hi Will,
> 
>> I have been experimenting with the patches for arm64 kprobes support.
>> On occasion the kernel gets stuck in a loop printing output:
>>
>>  Unexpected kernel single-step exception at EL1
>>
>> This message by itself is not that enlighten.  I added the attached
>> patch to get some additional information about register state when the
>> warning is printed out.  Below is an example output:
> 
> Given that we've got the pt_regs in our hands at that point, I'm happy to
> print something more useful if you like (e.g. the PC?).
> 
>> [14613.263536] Unexpected kernel single-step exception at EL1
>> [14613.269001] kcb->ss_ctx.ss_status = 1
>> [14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
>> [14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
>> [14613.286003] 
>> [14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
>> [14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
>> [14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
>> [14613.310430] PC is at el1_da+0x8/0x70
>> [14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
> 
>> The really odd thing is the address of the PC it is in el1_da the code
>> to handle data aborts.  it looks like it is getting the unexpected
>> single_step exception right after the enable_debug in el1_da.  I think
>> what might be happening is:
>>
>> -an instruction is instrumented with kprobe
>> -the instruction is copied to a buffer
>> -a breakpoint replaces the instruction
>> -the kprobe fires when the breakpoint is encountered
>> -the instruction in the buffer is set to single step
>> -a single step of the instruction is attempted
>> -a data abort exception is raised
>> -el1_da is called
> 
> So that's the bit that I find weird. Can you take a look at what we're doing
> in trampoline_probe_handler, please? It could be that we're doing something
> like get_user and aborting on a faulting userspace address, but I think
> kprobes should handle that rather than us trying to get the generic
> single-step code to deal with it.
> 
>> It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
>> Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
>> was trying to address a similar problem for the el1_dbg
>> function.  Should el1_da and other el1_* functions have the enable_dbg
>> removed?
> 
> I don't think so. The current behaviour of the low-level debug handler is to
> step into traps, which is more flexible than trying to step over them (which
> could lead to us stepping over interrupts, or preemption points). It should
> be up to the higher-level debugger (e.g. kprobes, kgdb) to distinguish
> between the traps it does and does not care about.
> 
> An equivalent userspace example would be GDB stepping into single handlers,
> I suppose.
> 
> Will
> 

Dave Long and I did some additional experimentation to better
understand what is condition causes the kernel to sometimes spew:

Unexpected kernel single-step exception at EL1

The functioncallcount.stp test instruments the entry and return of
every function in the mm files, including kfree.  In most cases the
arm64 trampoline_probe_handler just determines which return probe
instance matches the current conditions, runs the associated handler,
and recycles the return probe instance for another use by placing it
on a hlist.  However, it is possible that a return probe instance has
been set up on function entry and the return probe is unregistered
before the return probe instance fires.  In this case kfree is called
by the trampoline handler to remove the return probe instances related
to the unregistered kretprobe.  This case where the the kprobed kfree
is called within the arm64 trampoline_probe_handler function trigger
the problem.

The kprobe breakpoint for the kfree call from within the
trampoline_probe_handler is encountered and started, but things go
wrong when attempting the single step on the instruction.

It took a while to trigger this problem with the sytemtap testsuite.
Dave Long came up with steps that reproduce this more quickly with a
probed function that is always called within the trampoline handler.
Trying the same on x86_64 doesn't trigger the problem.  It appears
that the x86_64 code can handle a single step from within the
trampoline_handler.

-Will Cohen




^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-02  1:44           ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-02  1:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/29/2015 06:23 AM, Will Deacon wrote:
> On Tue, Apr 28, 2015 at 03:58:21AM +0100, William Cohen wrote:
>> Hi All,
> 
> Hi Will,
> 
>> I have been experimenting with the patches for arm64 kprobes support.
>> On occasion the kernel gets stuck in a loop printing output:
>>
>>  Unexpected kernel single-step exception at EL1
>>
>> This message by itself is not that enlighten.  I added the attached
>> patch to get some additional information about register state when the
>> warning is printed out.  Below is an example output:
> 
> Given that we've got the pt_regs in our hands at that point, I'm happy to
> print something more useful if you like (e.g. the PC?).
> 
>> [14613.263536] Unexpected kernel single-step exception at EL1
>> [14613.269001] kcb->ss_ctx.ss_status = 1
>> [14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
>> [14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
>> [14613.286003] 
>> [14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
>> [14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
>> [14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
>> [14613.310430] PC is at el1_da+0x8/0x70
>> [14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
> 
>> The really odd thing is the address of the PC it is in el1_da the code
>> to handle data aborts.  it looks like it is getting the unexpected
>> single_step exception right after the enable_debug in el1_da.  I think
>> what might be happening is:
>>
>> -an instruction is instrumented with kprobe
>> -the instruction is copied to a buffer
>> -a breakpoint replaces the instruction
>> -the kprobe fires when the breakpoint is encountered
>> -the instruction in the buffer is set to single step
>> -a single step of the instruction is attempted
>> -a data abort exception is raised
>> -el1_da is called
> 
> So that's the bit that I find weird. Can you take a look at what we're doing
> in trampoline_probe_handler, please? It could be that we're doing something
> like get_user and aborting on a faulting userspace address, but I think
> kprobes should handle that rather than us trying to get the generic
> single-step code to deal with it.
> 
>> It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
>> Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
>> was trying to address a similar problem for the el1_dbg
>> function.  Should el1_da and other el1_* functions have the enable_dbg
>> removed?
> 
> I don't think so. The current behaviour of the low-level debug handler is to
> step into traps, which is more flexible than trying to step over them (which
> could lead to us stepping over interrupts, or preemption points). It should
> be up to the higher-level debugger (e.g. kprobes, kgdb) to distinguish
> between the traps it does and does not care about.
> 
> An equivalent userspace example would be GDB stepping into single handlers,
> I suppose.
> 
> Will
> 

Dave Long and I did some additional experimentation to better
understand what is condition causes the kernel to sometimes spew:

Unexpected kernel single-step exception at EL1

The functioncallcount.stp test instruments the entry and return of
every function in the mm files, including kfree.  In most cases the
arm64 trampoline_probe_handler just determines which return probe
instance matches the current conditions, runs the associated handler,
and recycles the return probe instance for another use by placing it
on a hlist.  However, it is possible that a return probe instance has
been set up on function entry and the return probe is unregistered
before the return probe instance fires.  In this case kfree is called
by the trampoline handler to remove the return probe instances related
to the unregistered kretprobe.  This case where the the kprobed kfree
is called within the arm64 trampoline_probe_handler function trigger
the problem.

The kprobe breakpoint for the kfree call from within the
trampoline_probe_handler is encountered and started, but things go
wrong when attempting the single step on the instruction.

It took a while to trigger this problem with the sytemtap testsuite.
Dave Long came up with steps that reproduce this more quickly with a
probed function that is always called within the trampoline handler.
Trying the same on x86_64 doesn't trigger the problem.  It appears
that the x86_64 code can handle a single step from within the
trampoline_handler.

-Will Cohen

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-02  1:44           ` William Cohen
@ 2015-05-05  5:14             ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-05  5:14 UTC (permalink / raw)
  To: William Cohen, Will Deacon
  Cc: Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 05/01/15 21:44, William Cohen wrote:
> On 04/29/2015 06:23 AM, Will Deacon wrote:
>> On Tue, Apr 28, 2015 at 03:58:21AM +0100, William Cohen wrote:
>>> Hi All,
>>
>> Hi Will,
>>
>>> I have been experimenting with the patches for arm64 kprobes support.
>>> On occasion the kernel gets stuck in a loop printing output:
>>>
>>>   Unexpected kernel single-step exception at EL1
>>>
>>> This message by itself is not that enlighten.  I added the attached
>>> patch to get some additional information about register state when the
>>> warning is printed out.  Below is an example output:
>>
>> Given that we've got the pt_regs in our hands at that point, I'm happy to
>> print something more useful if you like (e.g. the PC?).
>>
>>> [14613.263536] Unexpected kernel single-step exception at EL1
>>> [14613.269001] kcb->ss_ctx.ss_status = 1
>>> [14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
>>> [14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
>>> [14613.286003]
>>> [14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
>>> [14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
>>> [14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
>>> [14613.310430] PC is at el1_da+0x8/0x70
>>> [14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
>>
>>> The really odd thing is the address of the PC it is in el1_da the code
>>> to handle data aborts.  it looks like it is getting the unexpected
>>> single_step exception right after the enable_debug in el1_da.  I think
>>> what might be happening is:
>>>
>>> -an instruction is instrumented with kprobe
>>> -the instruction is copied to a buffer
>>> -a breakpoint replaces the instruction
>>> -the kprobe fires when the breakpoint is encountered
>>> -the instruction in the buffer is set to single step
>>> -a single step of the instruction is attempted
>>> -a data abort exception is raised
>>> -el1_da is called
>>
>> So that's the bit that I find weird. Can you take a look at what we're doing
>> in trampoline_probe_handler, please? It could be that we're doing something
>> like get_user and aborting on a faulting userspace address, but I think
>> kprobes should handle that rather than us trying to get the generic
>> single-step code to deal with it.
>>
>>> It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
>>> Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
>>> was trying to address a similar problem for the el1_dbg
>>> function.  Should el1_da and other el1_* functions have the enable_dbg
>>> removed?
>>
>> I don't think so. The current behaviour of the low-level debug handler is to
>> step into traps, which is more flexible than trying to step over them (which
>> could lead to us stepping over interrupts, or preemption points). It should
>> be up to the higher-level debugger (e.g. kprobes, kgdb) to distinguish
>> between the traps it does and does not care about.
>>
>> An equivalent userspace example would be GDB stepping into single handlers,
>> I suppose.
>>
>> Will
>>
>
> Dave Long and I did some additional experimentation to better
> understand what is condition causes the kernel to sometimes spew:
>
> Unexpected kernel single-step exception at EL1
>
> The functioncallcount.stp test instruments the entry and return of
> every function in the mm files, including kfree.  In most cases the
> arm64 trampoline_probe_handler just determines which return probe
> instance matches the current conditions, runs the associated handler,
> and recycles the return probe instance for another use by placing it
> on a hlist.  However, it is possible that a return probe instance has
> been set up on function entry and the return probe is unregistered
> before the return probe instance fires.  In this case kfree is called
> by the trampoline handler to remove the return probe instances related
> to the unregistered kretprobe.  This case where the the kprobed kfree
> is called within the arm64 trampoline_probe_handler function trigger
> the problem.
>
> The kprobe breakpoint for the kfree call from within the
> trampoline_probe_handler is encountered and started, but things go
> wrong when attempting the single step on the instruction.
>
> It took a while to trigger this problem with the sytemtap testsuite.
> Dave Long came up with steps that reproduce this more quickly with a
> probed function that is always called within the trampoline handler.
> Trying the same on x86_64 doesn't trigger the problem.  It appears
> that the x86_64 code can handle a single step from within the
> trampoline_handler.
>
> -Will Cohen
>
>
>

I'm assuming there are no plans for supporting software breakpoint debug 
exceptions during processing of single-step exceptions, any time soon on 
arm64.  Given that the only solution that I can come with for this is 
instead of making this orphaned kretprobe instance list exist only 
temporarily (in the scope of the kretprobe trampoline handler), make it 
always exist and kfree any items found on it as part of a periodic 
cleanup running outside of the handler context.  I think these changes 
would still all be in archiecture-specific code.  This doesn't feel to 
me like a bad solution.  Does anyone think there is a simpler way out of 
this?

-Dave Long


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-05  5:14             ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-05  5:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/01/15 21:44, William Cohen wrote:
> On 04/29/2015 06:23 AM, Will Deacon wrote:
>> On Tue, Apr 28, 2015 at 03:58:21AM +0100, William Cohen wrote:
>>> Hi All,
>>
>> Hi Will,
>>
>>> I have been experimenting with the patches for arm64 kprobes support.
>>> On occasion the kernel gets stuck in a loop printing output:
>>>
>>>   Unexpected kernel single-step exception at EL1
>>>
>>> This message by itself is not that enlighten.  I added the attached
>>> patch to get some additional information about register state when the
>>> warning is printed out.  Below is an example output:
>>
>> Given that we've got the pt_regs in our hands at that point, I'm happy to
>> print something more useful if you like (e.g. the PC?).
>>
>>> [14613.263536] Unexpected kernel single-step exception at EL1
>>> [14613.269001] kcb->ss_ctx.ss_status = 1
>>> [14613.272643] kcb->ss_ctx.match_addr = fffffdfffc001250 0xfffffdfffc001250
>>> [14613.279324] instruction_pointer(regs) = fffffe0000093358 el1_da+0x8/0x70
>>> [14613.286003]
>>> [14613.287487] CPU: 3 PID: 621 Comm: irqbalance Tainted: G           OE   4.0.0u4+ #6
>>> [14613.295019] Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0-rh-0.15 Mar 13 2015
>>> [14613.302982] task: fffffe01d6806780 ti: fffffe01d68ac000 task.ti: fffffe01d68ac000
>>> [14613.310430] PC is at el1_da+0x8/0x70
>>> [14613.313990] LR is at trampoline_probe_handler+0x188/0x1ec
>>
>>> The really odd thing is the address of the PC it is in el1_da the code
>>> to handle data aborts.  it looks like it is getting the unexpected
>>> single_step exception right after the enable_debug in el1_da.  I think
>>> what might be happening is:
>>>
>>> -an instruction is instrumented with kprobe
>>> -the instruction is copied to a buffer
>>> -a breakpoint replaces the instruction
>>> -the kprobe fires when the breakpoint is encountered
>>> -the instruction in the buffer is set to single step
>>> -a single step of the instruction is attempted
>>> -a data abort exception is raised
>>> -el1_da is called
>>
>> So that's the bit that I find weird. Can you take a look at what we're doing
>> in trampoline_probe_handler, please? It could be that we're doing something
>> like get_user and aborting on a faulting userspace address, but I think
>> kprobes should handle that rather than us trying to get the generic
>> single-step code to deal with it.
>>
>>> It looks like commit 1059c6bf8534acda249e7e65c81e7696fb074dc1 from Mon
>>> Sep 22   "arm64: debug: don't re-enable debug exceptions on return from el1_dbg"
>>> was trying to address a similar problem for the el1_dbg
>>> function.  Should el1_da and other el1_* functions have the enable_dbg
>>> removed?
>>
>> I don't think so. The current behaviour of the low-level debug handler is to
>> step into traps, which is more flexible than trying to step over them (which
>> could lead to us stepping over interrupts, or preemption points). It should
>> be up to the higher-level debugger (e.g. kprobes, kgdb) to distinguish
>> between the traps it does and does not care about.
>>
>> An equivalent userspace example would be GDB stepping into single handlers,
>> I suppose.
>>
>> Will
>>
>
> Dave Long and I did some additional experimentation to better
> understand what is condition causes the kernel to sometimes spew:
>
> Unexpected kernel single-step exception at EL1
>
> The functioncallcount.stp test instruments the entry and return of
> every function in the mm files, including kfree.  In most cases the
> arm64 trampoline_probe_handler just determines which return probe
> instance matches the current conditions, runs the associated handler,
> and recycles the return probe instance for another use by placing it
> on a hlist.  However, it is possible that a return probe instance has
> been set up on function entry and the return probe is unregistered
> before the return probe instance fires.  In this case kfree is called
> by the trampoline handler to remove the return probe instances related
> to the unregistered kretprobe.  This case where the the kprobed kfree
> is called within the arm64 trampoline_probe_handler function trigger
> the problem.
>
> The kprobe breakpoint for the kfree call from within the
> trampoline_probe_handler is encountered and started, but things go
> wrong when attempting the single step on the instruction.
>
> It took a while to trigger this problem with the sytemtap testsuite.
> Dave Long came up with steps that reproduce this more quickly with a
> probed function that is always called within the trampoline handler.
> Trying the same on x86_64 doesn't trigger the problem.  It appears
> that the x86_64 code can handle a single step from within the
> trampoline_handler.
>
> -Will Cohen
>
>
>

I'm assuming there are no plans for supporting software breakpoint debug 
exceptions during processing of single-step exceptions, any time soon on 
arm64.  Given that the only solution that I can come with for this is 
instead of making this orphaned kretprobe instance list exist only 
temporarily (in the scope of the kretprobe trampoline handler), make it 
always exist and kfree any items found on it as part of a periodic 
cleanup running outside of the handler context.  I think these changes 
would still all be in archiecture-specific code.  This doesn't feel to 
me like a bad solution.  Does anyone think there is a simpler way out of 
this?

-Dave Long

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-05  5:14             ` David Long
@ 2015-05-05 15:48               ` Will Deacon
  -1 siblings, 0 replies; 74+ messages in thread
From: Will Deacon @ 2015-05-05 15:48 UTC (permalink / raw)
  To: David Long
  Cc: William Cohen, Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
> On 05/01/15 21:44, William Cohen wrote:
> > Dave Long and I did some additional experimentation to better
> > understand what is condition causes the kernel to sometimes spew:
> >
> > Unexpected kernel single-step exception at EL1
> >
> > The functioncallcount.stp test instruments the entry and return of
> > every function in the mm files, including kfree.  In most cases the
> > arm64 trampoline_probe_handler just determines which return probe
> > instance matches the current conditions, runs the associated handler,
> > and recycles the return probe instance for another use by placing it
> > on a hlist.  However, it is possible that a return probe instance has
> > been set up on function entry and the return probe is unregistered
> > before the return probe instance fires.  In this case kfree is called
> > by the trampoline handler to remove the return probe instances related
> > to the unregistered kretprobe.  This case where the the kprobed kfree
> > is called within the arm64 trampoline_probe_handler function trigger
> > the problem.
> >
> > The kprobe breakpoint for the kfree call from within the
> > trampoline_probe_handler is encountered and started, but things go
> > wrong when attempting the single step on the instruction.
> >
> > It took a while to trigger this problem with the sytemtap testsuite.
> > Dave Long came up with steps that reproduce this more quickly with a
> > probed function that is always called within the trampoline handler.
> > Trying the same on x86_64 doesn't trigger the problem.  It appears
> > that the x86_64 code can handle a single step from within the
> > trampoline_handler.
> >
> 
> I'm assuming there are no plans for supporting software breakpoint debug 
> exceptions during processing of single-step exceptions, any time soon on 
> arm64.  Given that the only solution that I can come with for this is 
> instead of making this orphaned kretprobe instance list exist only 
> temporarily (in the scope of the kretprobe trampoline handler), make it 
> always exist and kfree any items found on it as part of a periodic 
> cleanup running outside of the handler context.  I think these changes 
> would still all be in archiecture-specific code.  This doesn't feel to 
> me like a bad solution.  Does anyone think there is a simpler way out of 
> this?

Just to clarify, is the problem here the software breakpoint exception,
or trying to step the faulting instruction whilst we were already handling
a step?

I think I'd be inclined to keep the code run in debug context to a minimum.
We already can't block there, and the more code we add the more black spots
we end up with in the kernel itself. The alternative would be to make your
kprobes code re-entrant, but that sounds like a nightmare.

You say this works on x86. How do they handle it? Is the nested probe
on kfree ignored or handled?

Will

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-05 15:48               ` Will Deacon
  0 siblings, 0 replies; 74+ messages in thread
From: Will Deacon @ 2015-05-05 15:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
> On 05/01/15 21:44, William Cohen wrote:
> > Dave Long and I did some additional experimentation to better
> > understand what is condition causes the kernel to sometimes spew:
> >
> > Unexpected kernel single-step exception at EL1
> >
> > The functioncallcount.stp test instruments the entry and return of
> > every function in the mm files, including kfree.  In most cases the
> > arm64 trampoline_probe_handler just determines which return probe
> > instance matches the current conditions, runs the associated handler,
> > and recycles the return probe instance for another use by placing it
> > on a hlist.  However, it is possible that a return probe instance has
> > been set up on function entry and the return probe is unregistered
> > before the return probe instance fires.  In this case kfree is called
> > by the trampoline handler to remove the return probe instances related
> > to the unregistered kretprobe.  This case where the the kprobed kfree
> > is called within the arm64 trampoline_probe_handler function trigger
> > the problem.
> >
> > The kprobe breakpoint for the kfree call from within the
> > trampoline_probe_handler is encountered and started, but things go
> > wrong when attempting the single step on the instruction.
> >
> > It took a while to trigger this problem with the sytemtap testsuite.
> > Dave Long came up with steps that reproduce this more quickly with a
> > probed function that is always called within the trampoline handler.
> > Trying the same on x86_64 doesn't trigger the problem.  It appears
> > that the x86_64 code can handle a single step from within the
> > trampoline_handler.
> >
> 
> I'm assuming there are no plans for supporting software breakpoint debug 
> exceptions during processing of single-step exceptions, any time soon on 
> arm64.  Given that the only solution that I can come with for this is 
> instead of making this orphaned kretprobe instance list exist only 
> temporarily (in the scope of the kretprobe trampoline handler), make it 
> always exist and kfree any items found on it as part of a periodic 
> cleanup running outside of the handler context.  I think these changes 
> would still all be in archiecture-specific code.  This doesn't feel to 
> me like a bad solution.  Does anyone think there is a simpler way out of 
> this?

Just to clarify, is the problem here the software breakpoint exception,
or trying to step the faulting instruction whilst we were already handling
a step?

I think I'd be inclined to keep the code run in debug context to a minimum.
We already can't block there, and the more code we add the more black spots
we end up with in the kernel itself. The alternative would be to make your
kprobes code re-entrant, but that sounds like a nightmare.

You say this works on x86. How do they handle it? Is the nested probe
on kfree ignored or handled?

Will

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-05 15:48               ` Will Deacon
@ 2015-05-05 16:18                 ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-05 16:18 UTC (permalink / raw)
  To: Will Deacon, David Long
  Cc: Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 05/05/2015 11:48 AM, Will Deacon wrote:
> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>> On 05/01/15 21:44, William Cohen wrote:
>>> Dave Long and I did some additional experimentation to better
>>> understand what is condition causes the kernel to sometimes spew:
>>>
>>> Unexpected kernel single-step exception at EL1
>>>
>>> The functioncallcount.stp test instruments the entry and return of
>>> every function in the mm files, including kfree.  In most cases the
>>> arm64 trampoline_probe_handler just determines which return probe
>>> instance matches the current conditions, runs the associated handler,
>>> and recycles the return probe instance for another use by placing it
>>> on a hlist.  However, it is possible that a return probe instance has
>>> been set up on function entry and the return probe is unregistered
>>> before the return probe instance fires.  In this case kfree is called
>>> by the trampoline handler to remove the return probe instances related
>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>> is called within the arm64 trampoline_probe_handler function trigger
>>> the problem.
>>>
>>> The kprobe breakpoint for the kfree call from within the
>>> trampoline_probe_handler is encountered and started, but things go
>>> wrong when attempting the single step on the instruction.
>>>
>>> It took a while to trigger this problem with the sytemtap testsuite.
>>> Dave Long came up with steps that reproduce this more quickly with a
>>> probed function that is always called within the trampoline handler.
>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>> that the x86_64 code can handle a single step from within the
>>> trampoline_handler.
>>>
>>
>> I'm assuming there are no plans for supporting software breakpoint debug 
>> exceptions during processing of single-step exceptions, any time soon on 
>> arm64.  Given that the only solution that I can come with for this is 
>> instead of making this orphaned kretprobe instance list exist only 
>> temporarily (in the scope of the kretprobe trampoline handler), make it 
>> always exist and kfree any items found on it as part of a periodic 
>> cleanup running outside of the handler context.  I think these changes 
>> would still all be in archiecture-specific code.  This doesn't feel to 
>> me like a bad solution.  Does anyone think there is a simpler way out of 
>> this?
> 
> Just to clarify, is the problem here the software breakpoint exception,
> or trying to step the faulting instruction whilst we were already handling
> a step?
> 
> I think I'd be inclined to keep the code run in debug context to a minimum.
> We already can't block there, and the more code we add the more black spots
> we end up with in the kernel itself. The alternative would be to make your
> kprobes code re-entrant, but that sounds like a nightmare.
> 
> You say this works on x86. How do they handle it? Is the nested probe
> on kfree ignored or handled?
> 
> Will
> 

Hi Will,

I ran the experiment on the x86_64 machine and the x86_64 was definitely able to do the software breakpoint of the probed function and then do a single step from within the trampoline handler.  It looks like the x86_64 code avoids doing a breakpoint to implement the trampoline:

http://lxr.linux.no/#linux+v3.19.1/arch/x86/kernel/kprobes/core.c#L645

x86_64 saves the registers and then directly calls the trampoline_handler.  Maybe it would be possible implement something similar on aarch64 with some carefully crafted assembly code to save the register state and then directly call the trampoline code.  This would move the trampoline handler out of exception state and make it act more like a normal function.

-Will Cohen

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-05 16:18                 ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-05 16:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/05/2015 11:48 AM, Will Deacon wrote:
> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>> On 05/01/15 21:44, William Cohen wrote:
>>> Dave Long and I did some additional experimentation to better
>>> understand what is condition causes the kernel to sometimes spew:
>>>
>>> Unexpected kernel single-step exception at EL1
>>>
>>> The functioncallcount.stp test instruments the entry and return of
>>> every function in the mm files, including kfree.  In most cases the
>>> arm64 trampoline_probe_handler just determines which return probe
>>> instance matches the current conditions, runs the associated handler,
>>> and recycles the return probe instance for another use by placing it
>>> on a hlist.  However, it is possible that a return probe instance has
>>> been set up on function entry and the return probe is unregistered
>>> before the return probe instance fires.  In this case kfree is called
>>> by the trampoline handler to remove the return probe instances related
>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>> is called within the arm64 trampoline_probe_handler function trigger
>>> the problem.
>>>
>>> The kprobe breakpoint for the kfree call from within the
>>> trampoline_probe_handler is encountered and started, but things go
>>> wrong when attempting the single step on the instruction.
>>>
>>> It took a while to trigger this problem with the sytemtap testsuite.
>>> Dave Long came up with steps that reproduce this more quickly with a
>>> probed function that is always called within the trampoline handler.
>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>> that the x86_64 code can handle a single step from within the
>>> trampoline_handler.
>>>
>>
>> I'm assuming there are no plans for supporting software breakpoint debug 
>> exceptions during processing of single-step exceptions, any time soon on 
>> arm64.  Given that the only solution that I can come with for this is 
>> instead of making this orphaned kretprobe instance list exist only 
>> temporarily (in the scope of the kretprobe trampoline handler), make it 
>> always exist and kfree any items found on it as part of a periodic 
>> cleanup running outside of the handler context.  I think these changes 
>> would still all be in archiecture-specific code.  This doesn't feel to 
>> me like a bad solution.  Does anyone think there is a simpler way out of 
>> this?
> 
> Just to clarify, is the problem here the software breakpoint exception,
> or trying to step the faulting instruction whilst we were already handling
> a step?
> 
> I think I'd be inclined to keep the code run in debug context to a minimum.
> We already can't block there, and the more code we add the more black spots
> we end up with in the kernel itself. The alternative would be to make your
> kprobes code re-entrant, but that sounds like a nightmare.
> 
> You say this works on x86. How do they handle it? Is the nested probe
> on kfree ignored or handled?
> 
> Will
> 

Hi Will,

I ran the experiment on the x86_64 machine and the x86_64 was definitely able to do the software breakpoint of the probed function and then do a single step from within the trampoline handler.  It looks like the x86_64 code avoids doing a breakpoint to implement the trampoline:

http://lxr.linux.no/#linux+v3.19.1/arch/x86/kernel/kprobes/core.c#L645

x86_64 saves the registers and then directly calls the trampoline_handler.  Maybe it would be possible implement something similar on aarch64 with some carefully crafted assembly code to save the register state and then directly call the trampoline code.  This would move the trampoline handler out of exception state and make it act more like a normal function.

-Will Cohen

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-05 15:48               ` Will Deacon
@ 2015-05-05 21:02                 ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-05 21:02 UTC (permalink / raw)
  To: Will Deacon, David Long
  Cc: Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3577 bytes --]

On 05/05/2015 11:48 AM, Will Deacon wrote:
> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>> On 05/01/15 21:44, William Cohen wrote:
>>> Dave Long and I did some additional experimentation to better
>>> understand what is condition causes the kernel to sometimes spew:
>>>
>>> Unexpected kernel single-step exception at EL1
>>>
>>> The functioncallcount.stp test instruments the entry and return of
>>> every function in the mm files, including kfree.  In most cases the
>>> arm64 trampoline_probe_handler just determines which return probe
>>> instance matches the current conditions, runs the associated handler,
>>> and recycles the return probe instance for another use by placing it
>>> on a hlist.  However, it is possible that a return probe instance has
>>> been set up on function entry and the return probe is unregistered
>>> before the return probe instance fires.  In this case kfree is called
>>> by the trampoline handler to remove the return probe instances related
>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>> is called within the arm64 trampoline_probe_handler function trigger
>>> the problem.
>>>
>>> The kprobe breakpoint for the kfree call from within the
>>> trampoline_probe_handler is encountered and started, but things go
>>> wrong when attempting the single step on the instruction.
>>>
>>> It took a while to trigger this problem with the sytemtap testsuite.
>>> Dave Long came up with steps that reproduce this more quickly with a
>>> probed function that is always called within the trampoline handler.
>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>> that the x86_64 code can handle a single step from within the
>>> trampoline_handler.
>>>
>>
>> I'm assuming there are no plans for supporting software breakpoint debug 
>> exceptions during processing of single-step exceptions, any time soon on 
>> arm64.  Given that the only solution that I can come with for this is 
>> instead of making this orphaned kretprobe instance list exist only 
>> temporarily (in the scope of the kretprobe trampoline handler), make it 
>> always exist and kfree any items found on it as part of a periodic 
>> cleanup running outside of the handler context.  I think these changes 
>> would still all be in archiecture-specific code.  This doesn't feel to 
>> me like a bad solution.  Does anyone think there is a simpler way out of 
>> this?
> 
> Just to clarify, is the problem here the software breakpoint exception,
> or trying to step the faulting instruction whilst we were already handling
> a step?
> 
> I think I'd be inclined to keep the code run in debug context to a minimum.
> We already can't block there, and the more code we add the more black spots
> we end up with in the kernel itself. The alternative would be to make your
> kprobes code re-entrant, but that sounds like a nightmare.
> 
> You say this works on x86. How do they handle it? Is the nested probe
> on kfree ignored or handled?
> 
> Will
> 

Hi Dave and Will,

The attached patch attempts to eliminate the need for the breakpoint in the trampoline.  It is modeled after the x86_64 code and just saves the register state, calls the trampoline handler, and then fixes the return address.  The code compiles, but I have NOT verified that it works. It looks feasible to do things this way.  In addition to avoiding the possible issue with a kretprobe on kfree it would also make the kretprobes faster because it would avoid the breakpoint exception and the associated kprobe handling in the trampoline.

-Will

[-- Attachment #2: avoid_bkpt_trampoline.diff --]
[-- Type: text/x-patch, Size: 4465 bytes --]

diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
index ff8a55f..0b9987d 100644
--- a/arch/arm64/kernel/kprobes-arm64.h
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -27,4 +27,40 @@ extern kprobes_pstate_check_t * const kprobe_condition_checks[16];
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
 
+#define SAVE_REGS_STRING\
+	"	stp x0, x1, [sp, #16 * 0]\n"	\
+	"	stp x2, x3, [sp, #16 * 1]\n"	\
+	"	stp x4, x5, [sp, #16 * 2]\n"	\
+	"	stp x6, x7, [sp, #16 * 3]\n"	\
+	"	stp x8, x9, [sp, #16 * 4]\n"	\
+	"	stp x10, x11, [sp, #16 * 5]\n"	\
+	"	stp x12, x13, [sp, #16 * 6]\n"	\
+	"	stp x14, x15, [sp, #16 * 7]\n"	\
+	"	stp x16, x17, [sp, #16 * 8]\n"	\
+	"	stp x18, x19, [sp, #16 * 9]\n"	\
+	"	stp x20, x21, [sp, #16 * 10]\n"	\
+	"	stp x22, x23, [sp, #16 * 11]\n"	\
+	"	stp x24, x25, [sp, #16 * 12]\n"	\
+	"	stp x26, x27, [sp, #16 * 13]\n"	\
+	"	stp x28, x29, [sp, #16 * 14]\n"	\
+	"	str x30,   [sp, #16 * 15]\n"
+
+#define RESTORE_REGS_STRING\
+	"	ldp x2, x3, [sp, #16 * 1]\n"	\
+	"	ldp x4, x5, [sp, #16 * 2]\n"	\
+	"	ldp x6, x7, [sp, #16 * 3]\n"	\
+	"	ldp x8, x9, [sp, #16 * 4]\n"	\
+	"	ldp x10, x11, [sp, #16 * 5]\n"	\
+	"	ldp x12, x13, [sp, #16 * 6]\n"	\
+	"	ldp x14, x15, [sp, #16 * 7]\n"	\
+	"	ldp x16, x17, [sp, #16 * 8]\n"	\
+	"	ldp x18, x19, [sp, #16 * 9]\n"	\
+	"	ldp x20, x21, [sp, #16 * 10]\n"	\
+	"	ldp x22, x23, [sp, #16 * 11]\n"	\
+	"	ldp x24, x25, [sp, #16 * 12]\n"	\
+	"	ldp x26, x27, [sp, #16 * 13]\n"	\
+	"	ldp x28, x29, [sp, #16 * 14]\n"	\
+	"	ldr x30,   [sp, #16 * 15]\n"
+
+
 #endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 2b3ef17..f5dab2d 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -561,32 +561,27 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 }
 
 /*
- * Kretprobes: kernel return probes handling
- *
- * AArch64 mode does not support popping the PC value from the
- * stack like on ARM 32-bit (ldmia {..,pc}), so atleast one
- * register need to be used to achieve branching/return.
- * It means return probes cannot return back to the original
- * return address directly without modifying the register context.
- *
- * So like other architectures, we prepare a global routine
- * with NOPs, which serve as trampoline address that hack away the
- * function return, with the exact register context.
- * Placing a kprobe on trampoline routine entry will trap again to
- * execute return probe handlers and restore original return address
- * in ELR_EL1, this way saved pt_regs still hold the original
- * register values to be carried back to the caller.
+ * When a retprobed function returns, this code saves registers and
+ * calls trampoline_handler() runs, which calls the kretprobe's handler.
  */
-static void __used kretprobe_trampoline_holder(void)
+static void __kprobes __used kretprobe_trampoline_holder(void)
 {
-	asm volatile (".global kretprobe_trampoline\n"
-			"kretprobe_trampoline:\n"
-			"NOP\n\t"
-			"NOP\n\t");
+	asm volatile (
+		".global kretprobe_trampoline\n"
+		"kretprobe_trampoline: \n"
+		SAVE_REGS_STRING
+		"mov x0, sp\n"
+		"bl trampoline_handler\n"
+		/* Replace trampoline address in lr with actual
+		   orig_ret_addr return address. */
+		"str x0, [sp, #16 * 15]\n"
+		RESTORE_REGS_STRING
+		"ret\n"
+		: : : "memory");
 }
 
-static int __kprobes
-trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+
+static void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
 {
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
@@ -647,7 +642,7 @@ trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 	}
 
 	/* return 1 so that post handlers not called */
-	return 1;
+	return (void *) orig_ret_addr;
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
@@ -659,18 +654,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 	regs->regs[30] = (long)&kretprobe_trampoline;
 }
 
-static struct kprobe trampoline = {
-	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
-	.pre_handler = trampoline_probe_handler
-};
-
-int __kprobes arch_trampoline_kprobe(struct kprobe *p)
-{
-	return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline;
-}
-
 int __init arch_init_kprobes(void)
 {
-	/* register trampoline for kret probe */
-	return register_kprobe(&trampoline);
+	return 0;
 }

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-05 21:02                 ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-05 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/05/2015 11:48 AM, Will Deacon wrote:
> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>> On 05/01/15 21:44, William Cohen wrote:
>>> Dave Long and I did some additional experimentation to better
>>> understand what is condition causes the kernel to sometimes spew:
>>>
>>> Unexpected kernel single-step exception at EL1
>>>
>>> The functioncallcount.stp test instruments the entry and return of
>>> every function in the mm files, including kfree.  In most cases the
>>> arm64 trampoline_probe_handler just determines which return probe
>>> instance matches the current conditions, runs the associated handler,
>>> and recycles the return probe instance for another use by placing it
>>> on a hlist.  However, it is possible that a return probe instance has
>>> been set up on function entry and the return probe is unregistered
>>> before the return probe instance fires.  In this case kfree is called
>>> by the trampoline handler to remove the return probe instances related
>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>> is called within the arm64 trampoline_probe_handler function trigger
>>> the problem.
>>>
>>> The kprobe breakpoint for the kfree call from within the
>>> trampoline_probe_handler is encountered and started, but things go
>>> wrong when attempting the single step on the instruction.
>>>
>>> It took a while to trigger this problem with the sytemtap testsuite.
>>> Dave Long came up with steps that reproduce this more quickly with a
>>> probed function that is always called within the trampoline handler.
>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>> that the x86_64 code can handle a single step from within the
>>> trampoline_handler.
>>>
>>
>> I'm assuming there are no plans for supporting software breakpoint debug 
>> exceptions during processing of single-step exceptions, any time soon on 
>> arm64.  Given that the only solution that I can come with for this is 
>> instead of making this orphaned kretprobe instance list exist only 
>> temporarily (in the scope of the kretprobe trampoline handler), make it 
>> always exist and kfree any items found on it as part of a periodic 
>> cleanup running outside of the handler context.  I think these changes 
>> would still all be in archiecture-specific code.  This doesn't feel to 
>> me like a bad solution.  Does anyone think there is a simpler way out of 
>> this?
> 
> Just to clarify, is the problem here the software breakpoint exception,
> or trying to step the faulting instruction whilst we were already handling
> a step?
> 
> I think I'd be inclined to keep the code run in debug context to a minimum.
> We already can't block there, and the more code we add the more black spots
> we end up with in the kernel itself. The alternative would be to make your
> kprobes code re-entrant, but that sounds like a nightmare.
> 
> You say this works on x86. How do they handle it? Is the nested probe
> on kfree ignored or handled?
> 
> Will
> 

Hi Dave and Will,

The attached patch attempts to eliminate the need for the breakpoint in the trampoline.  It is modeled after the x86_64 code and just saves the register state, calls the trampoline handler, and then fixes the return address.  The code compiles, but I have NOT verified that it works. It looks feasible to do things this way.  In addition to avoiding the possible issue with a kretprobe on kfree it would also make the kretprobes faster because it would avoid the breakpoint exception and the associated kprobe handling in the trampoline.

-Will
-------------- next part --------------
A non-text attachment was scrubbed...
Name: avoid_bkpt_trampoline.diff
Type: text/x-patch
Size: 4465 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150505/1ebbc086/attachment-0001.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-05 21:02                 ` William Cohen
@ 2015-05-06  3:14                   ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-06  3:14 UTC (permalink / raw)
  To: Will Deacon, David Long
  Cc: Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3883 bytes --]

On 05/05/2015 05:02 PM, William Cohen wrote:
> On 05/05/2015 11:48 AM, Will Deacon wrote:
>> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>>> On 05/01/15 21:44, William Cohen wrote:
>>>> Dave Long and I did some additional experimentation to better
>>>> understand what is condition causes the kernel to sometimes spew:
>>>>
>>>> Unexpected kernel single-step exception at EL1
>>>>
>>>> The functioncallcount.stp test instruments the entry and return of
>>>> every function in the mm files, including kfree.  In most cases the
>>>> arm64 trampoline_probe_handler just determines which return probe
>>>> instance matches the current conditions, runs the associated handler,
>>>> and recycles the return probe instance for another use by placing it
>>>> on a hlist.  However, it is possible that a return probe instance has
>>>> been set up on function entry and the return probe is unregistered
>>>> before the return probe instance fires.  In this case kfree is called
>>>> by the trampoline handler to remove the return probe instances related
>>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>>> is called within the arm64 trampoline_probe_handler function trigger
>>>> the problem.
>>>>
>>>> The kprobe breakpoint for the kfree call from within the
>>>> trampoline_probe_handler is encountered and started, but things go
>>>> wrong when attempting the single step on the instruction.
>>>>
>>>> It took a while to trigger this problem with the sytemtap testsuite.
>>>> Dave Long came up with steps that reproduce this more quickly with a
>>>> probed function that is always called within the trampoline handler.
>>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>>> that the x86_64 code can handle a single step from within the
>>>> trampoline_handler.
>>>>
>>>
>>> I'm assuming there are no plans for supporting software breakpoint debug 
>>> exceptions during processing of single-step exceptions, any time soon on 
>>> arm64.  Given that the only solution that I can come with for this is 
>>> instead of making this orphaned kretprobe instance list exist only 
>>> temporarily (in the scope of the kretprobe trampoline handler), make it 
>>> always exist and kfree any items found on it as part of a periodic 
>>> cleanup running outside of the handler context.  I think these changes 
>>> would still all be in archiecture-specific code.  This doesn't feel to 
>>> me like a bad solution.  Does anyone think there is a simpler way out of 
>>> this?
>>
>> Just to clarify, is the problem here the software breakpoint exception,
>> or trying to step the faulting instruction whilst we were already handling
>> a step?
>>
>> I think I'd be inclined to keep the code run in debug context to a minimum.
>> We already can't block there, and the more code we add the more black spots
>> we end up with in the kernel itself. The alternative would be to make your
>> kprobes code re-entrant, but that sounds like a nightmare.
>>
>> You say this works on x86. How do they handle it? Is the nested probe
>> on kfree ignored or handled?
>>
>> Will
>>
> 
> Hi Dave and Will,
> 
> The attached patch attempts to eliminate the need for the breakpoint in the trampoline.  It is modeled after the x86_64 code and just saves the register state, calls the trampoline handler, and then fixes the return address.  The code compiles, but I have NOT verified that it works. It looks feasible to do things this way.  In addition to avoiding the possible issue with a kretprobe on kfree it would also make the kretprobes faster because it would avoid the breakpoint exception and the associated kprobe handling in the trampoline.
> 
> -Will
> 


Hi Dave and Will,

Attached is a revised version of the patch to avoid using a kprobe breakpoint in the trampoline.  It shows signs of working, but is still a work in progress.

-Will Cohen

[-- Attachment #2: avoid_bkpt_tramp.diff --]
[-- Type: text/x-patch, Size: 4583 bytes --]

diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
index ff8a55f..0b9987d 100644
--- a/arch/arm64/kernel/kprobes-arm64.h
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -27,4 +27,40 @@ extern kprobes_pstate_check_t * const kprobe_condition_checks[16];
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
 
+#define SAVE_REGS_STRING\
+	"	stp x0, x1, [sp, #16 * 0]\n"	\
+	"	stp x2, x3, [sp, #16 * 1]\n"	\
+	"	stp x4, x5, [sp, #16 * 2]\n"	\
+	"	stp x6, x7, [sp, #16 * 3]\n"	\
+	"	stp x8, x9, [sp, #16 * 4]\n"	\
+	"	stp x10, x11, [sp, #16 * 5]\n"	\
+	"	stp x12, x13, [sp, #16 * 6]\n"	\
+	"	stp x14, x15, [sp, #16 * 7]\n"	\
+	"	stp x16, x17, [sp, #16 * 8]\n"	\
+	"	stp x18, x19, [sp, #16 * 9]\n"	\
+	"	stp x20, x21, [sp, #16 * 10]\n"	\
+	"	stp x22, x23, [sp, #16 * 11]\n"	\
+	"	stp x24, x25, [sp, #16 * 12]\n"	\
+	"	stp x26, x27, [sp, #16 * 13]\n"	\
+	"	stp x28, x29, [sp, #16 * 14]\n"	\
+	"	str x30,   [sp, #16 * 15]\n"
+
+#define RESTORE_REGS_STRING\
+	"	ldp x2, x3, [sp, #16 * 1]\n"	\
+	"	ldp x4, x5, [sp, #16 * 2]\n"	\
+	"	ldp x6, x7, [sp, #16 * 3]\n"	\
+	"	ldp x8, x9, [sp, #16 * 4]\n"	\
+	"	ldp x10, x11, [sp, #16 * 5]\n"	\
+	"	ldp x12, x13, [sp, #16 * 6]\n"	\
+	"	ldp x14, x15, [sp, #16 * 7]\n"	\
+	"	ldp x16, x17, [sp, #16 * 8]\n"	\
+	"	ldp x18, x19, [sp, #16 * 9]\n"	\
+	"	ldp x20, x21, [sp, #16 * 10]\n"	\
+	"	ldp x22, x23, [sp, #16 * 11]\n"	\
+	"	ldp x24, x25, [sp, #16 * 12]\n"	\
+	"	ldp x26, x27, [sp, #16 * 13]\n"	\
+	"	ldp x28, x29, [sp, #16 * 14]\n"	\
+	"	ldr x30,   [sp, #16 * 15]\n"
+
+
 #endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index 2b3ef17..470b537 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -561,32 +561,27 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 }
 
 /*
- * Kretprobes: kernel return probes handling
- *
- * AArch64 mode does not support popping the PC value from the
- * stack like on ARM 32-bit (ldmia {..,pc}), so atleast one
- * register need to be used to achieve branching/return.
- * It means return probes cannot return back to the original
- * return address directly without modifying the register context.
- *
- * So like other architectures, we prepare a global routine
- * with NOPs, which serve as trampoline address that hack away the
- * function return, with the exact register context.
- * Placing a kprobe on trampoline routine entry will trap again to
- * execute return probe handlers and restore original return address
- * in ELR_EL1, this way saved pt_regs still hold the original
- * register values to be carried back to the caller.
+ * When a retprobed function returns, this code saves registers and
+ * calls trampoline_handler() runs, which calls the kretprobe's handler.
  */
-static void __used kretprobe_trampoline_holder(void)
+static void __used __kprobes kretprobe_trampoline_holder(void)
 {
 	asm volatile (".global kretprobe_trampoline\n"
 			"kretprobe_trampoline:\n"
-			"NOP\n\t"
-			"NOP\n\t");
+		        "sub sp, sp, %0\n"
+			SAVE_REGS_STRING
+			"mov x0, sp\n"
+			"bl trampoline_probe_handler\n"
+			/* Replace trampoline address in lr with actual
+			   orig_ret_addr return address. */
+			"str x0, [sp, #16 * 15]\n"
+			RESTORE_REGS_STRING
+		        "add sp, sp, %0\n"
+			"ret\n"
+		      : : "I"(sizeof(struct pt_regs)) : "memory");
 }
 
-static int __kprobes
-trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
 {
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
@@ -647,7 +642,7 @@ trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 	}
 
 	/* return 1 so that post handlers not called */
-	return 1;
+	return (void *) orig_ret_addr;
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
@@ -659,18 +654,12 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 	regs->regs[30] = (long)&kretprobe_trampoline;
 }
 
-static struct kprobe trampoline = {
-	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
-	.pre_handler = trampoline_probe_handler
-};
-
-int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+int __init arch_init_kprobes(void)
 {
-	return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline;
+	return 0;
 }
 
-int __init arch_init_kprobes(void)
+int arch_trampoline_kprobe(struct kprobe *p)
 {
-	/* register trampoline for kret probe */
-	return register_kprobe(&trampoline);
+	return 0;
 }

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-06  3:14                   ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-06  3:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/05/2015 05:02 PM, William Cohen wrote:
> On 05/05/2015 11:48 AM, Will Deacon wrote:
>> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>>> On 05/01/15 21:44, William Cohen wrote:
>>>> Dave Long and I did some additional experimentation to better
>>>> understand what is condition causes the kernel to sometimes spew:
>>>>
>>>> Unexpected kernel single-step exception at EL1
>>>>
>>>> The functioncallcount.stp test instruments the entry and return of
>>>> every function in the mm files, including kfree.  In most cases the
>>>> arm64 trampoline_probe_handler just determines which return probe
>>>> instance matches the current conditions, runs the associated handler,
>>>> and recycles the return probe instance for another use by placing it
>>>> on a hlist.  However, it is possible that a return probe instance has
>>>> been set up on function entry and the return probe is unregistered
>>>> before the return probe instance fires.  In this case kfree is called
>>>> by the trampoline handler to remove the return probe instances related
>>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>>> is called within the arm64 trampoline_probe_handler function trigger
>>>> the problem.
>>>>
>>>> The kprobe breakpoint for the kfree call from within the
>>>> trampoline_probe_handler is encountered and started, but things go
>>>> wrong when attempting the single step on the instruction.
>>>>
>>>> It took a while to trigger this problem with the sytemtap testsuite.
>>>> Dave Long came up with steps that reproduce this more quickly with a
>>>> probed function that is always called within the trampoline handler.
>>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>>> that the x86_64 code can handle a single step from within the
>>>> trampoline_handler.
>>>>
>>>
>>> I'm assuming there are no plans for supporting software breakpoint debug 
>>> exceptions during processing of single-step exceptions, any time soon on 
>>> arm64.  Given that the only solution that I can come with for this is 
>>> instead of making this orphaned kretprobe instance list exist only 
>>> temporarily (in the scope of the kretprobe trampoline handler), make it 
>>> always exist and kfree any items found on it as part of a periodic 
>>> cleanup running outside of the handler context.  I think these changes 
>>> would still all be in archiecture-specific code.  This doesn't feel to 
>>> me like a bad solution.  Does anyone think there is a simpler way out of 
>>> this?
>>
>> Just to clarify, is the problem here the software breakpoint exception,
>> or trying to step the faulting instruction whilst we were already handling
>> a step?
>>
>> I think I'd be inclined to keep the code run in debug context to a minimum.
>> We already can't block there, and the more code we add the more black spots
>> we end up with in the kernel itself. The alternative would be to make your
>> kprobes code re-entrant, but that sounds like a nightmare.
>>
>> You say this works on x86. How do they handle it? Is the nested probe
>> on kfree ignored or handled?
>>
>> Will
>>
> 
> Hi Dave and Will,
> 
> The attached patch attempts to eliminate the need for the breakpoint in the trampoline.  It is modeled after the x86_64 code and just saves the register state, calls the trampoline handler, and then fixes the return address.  The code compiles, but I have NOT verified that it works. It looks feasible to do things this way.  In addition to avoiding the possible issue with a kretprobe on kfree it would also make the kretprobes faster because it would avoid the breakpoint exception and the associated kprobe handling in the trampoline.
> 
> -Will
> 


Hi Dave and Will,

Attached is a revised version of the patch to avoid using a kprobe breakpoint in the trampoline.  It shows signs of working, but is still a work in progress.

-Will Cohen
-------------- next part --------------
A non-text attachment was scrubbed...
Name: avoid_bkpt_tramp.diff
Type: text/x-patch
Size: 4583 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150505/42530767/attachment.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-05 15:48               ` Will Deacon
@ 2015-05-12  5:54                 ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-12  5:54 UTC (permalink / raw)
  To: Will Deacon, William Cohen
  Cc: Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 05/05/15 11:48, Will Deacon wrote:
> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>> On 05/01/15 21:44, William Cohen wrote:
>>> Dave Long and I did some additional experimentation to better
>>> understand what is condition causes the kernel to sometimes spew:
>>>
>>> Unexpected kernel single-step exception at EL1
>>>
>>> The functioncallcount.stp test instruments the entry and return of
>>> every function in the mm files, including kfree.  In most cases the
>>> arm64 trampoline_probe_handler just determines which return probe
>>> instance matches the current conditions, runs the associated handler,
>>> and recycles the return probe instance for another use by placing it
>>> on a hlist.  However, it is possible that a return probe instance has
>>> been set up on function entry and the return probe is unregistered
>>> before the return probe instance fires.  In this case kfree is called
>>> by the trampoline handler to remove the return probe instances related
>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>> is called within the arm64 trampoline_probe_handler function trigger
>>> the problem.
>>>
>>> The kprobe breakpoint for the kfree call from within the
>>> trampoline_probe_handler is encountered and started, but things go
>>> wrong when attempting the single step on the instruction.
>>>
>>> It took a while to trigger this problem with the sytemtap testsuite.
>>> Dave Long came up with steps that reproduce this more quickly with a
>>> probed function that is always called within the trampoline handler.
>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>> that the x86_64 code can handle a single step from within the
>>> trampoline_handler.
>>>
>>
>> I'm assuming there are no plans for supporting software breakpoint debug
>> exceptions during processing of single-step exceptions, any time soon on
>> arm64.  Given that the only solution that I can come with for this is
>> instead of making this orphaned kretprobe instance list exist only
>> temporarily (in the scope of the kretprobe trampoline handler), make it
>> always exist and kfree any items found on it as part of a periodic
>> cleanup running outside of the handler context.  I think these changes
>> would still all be in archiecture-specific code.  This doesn't feel to
>> me like a bad solution.  Does anyone think there is a simpler way out of
>> this?
>
> Just to clarify, is the problem here the software breakpoint exception,
> or trying to step the faulting instruction whilst we were already handling
> a step?
>

Sorry for the delay, I got tripped up with some global optimizations 
that happened when I made more testing changes.  When the kprobes 
software breakpoint handler for kretprobes is reentered it sets up the 
single-step and that ends up hitting inside entry.S, apparently in 
el1_undef.

> I think I'd be inclined to keep the code run in debug context to a minimum.
> We already can't block there, and the more code we add the more black spots
> we end up with in the kernel itself. The alternative would be to make your
> kprobes code re-entrant, but that sounds like a nightmare.
>
> You say this works on x86. How do they handle it? Is the nested probe
> on kfree ignored or handled?
>

Will Cohen's email pointing out x86 does not use a breakpoint for the 
trampoline handler explains a lot.  I'm experimenting starting with his 
proposed new trampoline code.  I can't see a reason this can't be made 
to work and so given everything it doesn't seem interesting to try and 
understand the failure in reentering the kprobe break handler in any 
more detail.

-dave long



^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-12  5:54                 ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-12  5:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/05/15 11:48, Will Deacon wrote:
> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>> On 05/01/15 21:44, William Cohen wrote:
>>> Dave Long and I did some additional experimentation to better
>>> understand what is condition causes the kernel to sometimes spew:
>>>
>>> Unexpected kernel single-step exception at EL1
>>>
>>> The functioncallcount.stp test instruments the entry and return of
>>> every function in the mm files, including kfree.  In most cases the
>>> arm64 trampoline_probe_handler just determines which return probe
>>> instance matches the current conditions, runs the associated handler,
>>> and recycles the return probe instance for another use by placing it
>>> on a hlist.  However, it is possible that a return probe instance has
>>> been set up on function entry and the return probe is unregistered
>>> before the return probe instance fires.  In this case kfree is called
>>> by the trampoline handler to remove the return probe instances related
>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>> is called within the arm64 trampoline_probe_handler function trigger
>>> the problem.
>>>
>>> The kprobe breakpoint for the kfree call from within the
>>> trampoline_probe_handler is encountered and started, but things go
>>> wrong when attempting the single step on the instruction.
>>>
>>> It took a while to trigger this problem with the sytemtap testsuite.
>>> Dave Long came up with steps that reproduce this more quickly with a
>>> probed function that is always called within the trampoline handler.
>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>> that the x86_64 code can handle a single step from within the
>>> trampoline_handler.
>>>
>>
>> I'm assuming there are no plans for supporting software breakpoint debug
>> exceptions during processing of single-step exceptions, any time soon on
>> arm64.  Given that the only solution that I can come with for this is
>> instead of making this orphaned kretprobe instance list exist only
>> temporarily (in the scope of the kretprobe trampoline handler), make it
>> always exist and kfree any items found on it as part of a periodic
>> cleanup running outside of the handler context.  I think these changes
>> would still all be in archiecture-specific code.  This doesn't feel to
>> me like a bad solution.  Does anyone think there is a simpler way out of
>> this?
>
> Just to clarify, is the problem here the software breakpoint exception,
> or trying to step the faulting instruction whilst we were already handling
> a step?
>

Sorry for the delay, I got tripped up with some global optimizations 
that happened when I made more testing changes.  When the kprobes 
software breakpoint handler for kretprobes is reentered it sets up the 
single-step and that ends up hitting inside entry.S, apparently in 
el1_undef.

> I think I'd be inclined to keep the code run in debug context to a minimum.
> We already can't block there, and the more code we add the more black spots
> we end up with in the kernel itself. The alternative would be to make your
> kprobes code re-entrant, but that sounds like a nightmare.
>
> You say this works on x86. How do they handle it? Is the nested probe
> on kfree ignored or handled?
>

Will Cohen's email pointing out x86 does not use a breakpoint for the 
trampoline handler explains a lot.  I'm experimenting starting with his 
proposed new trampoline code.  I can't see a reason this can't be made 
to work and so given everything it doesn't seem interesting to try and 
understand the failure in reentering the kprobe break handler in any 
more detail.

-dave long

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-12  5:54                 ` David Long
@ 2015-05-12 12:48                   ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-12 12:48 UTC (permalink / raw)
  To: David Long, Will Deacon
  Cc: Masami Hiramatsu, linux-arm-kernel, Russell King,
	sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4550 bytes --]

On 05/12/2015 01:54 AM, David Long wrote:
> On 05/05/15 11:48, Will Deacon wrote:
>> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>>> On 05/01/15 21:44, William Cohen wrote:
>>>> Dave Long and I did some additional experimentation to better
>>>> understand what is condition causes the kernel to sometimes spew:
>>>>
>>>> Unexpected kernel single-step exception at EL1
>>>>
>>>> The functioncallcount.stp test instruments the entry and return of
>>>> every function in the mm files, including kfree.  In most cases the
>>>> arm64 trampoline_probe_handler just determines which return probe
>>>> instance matches the current conditions, runs the associated handler,
>>>> and recycles the return probe instance for another use by placing it
>>>> on a hlist.  However, it is possible that a return probe instance has
>>>> been set up on function entry and the return probe is unregistered
>>>> before the return probe instance fires.  In this case kfree is called
>>>> by the trampoline handler to remove the return probe instances related
>>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>>> is called within the arm64 trampoline_probe_handler function trigger
>>>> the problem.
>>>>
>>>> The kprobe breakpoint for the kfree call from within the
>>>> trampoline_probe_handler is encountered and started, but things go
>>>> wrong when attempting the single step on the instruction.
>>>>
>>>> It took a while to trigger this problem with the sytemtap testsuite.
>>>> Dave Long came up with steps that reproduce this more quickly with a
>>>> probed function that is always called within the trampoline handler.
>>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>>> that the x86_64 code can handle a single step from within the
>>>> trampoline_handler.
>>>>
>>>
>>> I'm assuming there are no plans for supporting software breakpoint debug
>>> exceptions during processing of single-step exceptions, any time soon on
>>> arm64.  Given that the only solution that I can come with for this is
>>> instead of making this orphaned kretprobe instance list exist only
>>> temporarily (in the scope of the kretprobe trampoline handler), make it
>>> always exist and kfree any items found on it as part of a periodic
>>> cleanup running outside of the handler context.  I think these changes
>>> would still all be in archiecture-specific code.  This doesn't feel to
>>> me like a bad solution.  Does anyone think there is a simpler way out of
>>> this?
>>
>> Just to clarify, is the problem here the software breakpoint exception,
>> or trying to step the faulting instruction whilst we were already handling
>> a step?
>>
> 
> Sorry for the delay, I got tripped up with some global optimizations that happened when I made more testing changes.  When the kprobes software breakpoint handler for kretprobes is reentered it sets up the single-step and that ends up hitting inside entry.S, apparently in el1_undef.
> 
>> I think I'd be inclined to keep the code run in debug context to a minimum.
>> We already can't block there, and the more code we add the more black spots
>> we end up with in the kernel itself. The alternative would be to make your
>> kprobes code re-entrant, but that sounds like a nightmare.
>>
>> You say this works on x86. How do they handle it? Is the nested probe
>> on kfree ignored or handled?
>>
> 
> Will Cohen's email pointing out x86 does not use a breakpoint for the trampoline handler explains a lot.  I'm experimenting starting with his proposed new trampoline code.  I can't see a reason this can't be made to work and so given everything it doesn't seem interesting to try and understand the failure in reentering the kprobe break handler in any more detail.
> 
> -dave long
> 
> 

Hi Dave,

In some of the previous diagnostic output it looked like things would go wrong in the entry.S when the D bit was cleared and the debug interrupts were unmasksed.  I wonder if some of the issue might be due to the starting the kprobe for the trampoline, but leaving things in an odd state when another set of krpobe/kretporbes are hit when the trampoline is running.  As Dave mentioned the proposed trampoline patch avoids using a kprobe in the trampoline and directly calls the trampoline handler.  Attached is the current version of the patch which was able to run the systemtap testsuite.  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would be good to have additional raw kprobe tests to check that kprobe reentry works as expected.

-Will Cohen

[-- Attachment #2: avoid_bkpt_tramp_v2.diff --]
[-- Type: text/x-patch, Size: 4738 bytes --]

diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
index ff8a55f..46dab24 100644
--- a/arch/arm64/kernel/kprobes-arm64.h
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -27,4 +27,47 @@ extern kprobes_pstate_check_t * const kprobe_condition_checks[16];
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
 
+#define SAVE_REGS_STRING\
+	"	stp x0, x1, [sp, #16 * 0]\n"	\
+	"	stp x2, x3, [sp, #16 * 1]\n"	\
+	"	stp x4, x5, [sp, #16 * 2]\n"	\
+	"	stp x6, x7, [sp, #16 * 3]\n"	\
+	"	stp x8, x9, [sp, #16 * 4]\n"	\
+	"	stp x10, x11, [sp, #16 * 5]\n"	\
+	"	stp x12, x13, [sp, #16 * 6]\n"	\
+	"	stp x14, x15, [sp, #16 * 7]\n"	\
+	"	stp x16, x17, [sp, #16 * 8]\n"	\
+	"	stp x18, x19, [sp, #16 * 9]\n"	\
+	"	stp x20, x21, [sp, #16 * 10]\n"	\
+	"	stp x22, x23, [sp, #16 * 11]\n"	\
+	"	stp x24, x25, [sp, #16 * 12]\n"	\
+	"	stp x26, x27, [sp, #16 * 13]\n"	\
+	"	stp x28, x29, [sp, #16 * 14]\n"	\
+	"	str x30,   [sp, #16 * 15]\n"    \
+	"	mrs x0, nzcv\n"			\
+	"	str x0, [sp, #8 * 33]\n"
+	
+
+#define RESTORE_REGS_STRING\
+	"	ldr x0, [sp, #8 * 33]\n"	\
+	"	msr nzcv, x0\n"			\
+	"	ldp x0, x1, [sp, #16 * 0]\n"	\
+	"	ldp x2, x3, [sp, #16 * 1]\n"	\
+	"	ldp x4, x5, [sp, #16 * 2]\n"	\
+	"	ldp x6, x7, [sp, #16 * 3]\n"	\
+	"	ldp x8, x9, [sp, #16 * 4]\n"	\
+	"	ldp x10, x11, [sp, #16 * 5]\n"	\
+	"	ldp x12, x13, [sp, #16 * 6]\n"	\
+	"	ldp x14, x15, [sp, #16 * 7]\n"	\
+	"	ldp x16, x17, [sp, #16 * 8]\n"	\
+	"	ldp x18, x19, [sp, #16 * 9]\n"	\
+	"	ldp x20, x21, [sp, #16 * 10]\n"	\
+	"	ldp x22, x23, [sp, #16 * 11]\n"	\
+	"	ldp x24, x25, [sp, #16 * 12]\n"	\
+	"	ldp x26, x27, [sp, #16 * 13]\n"	\
+	"	ldp x28, x29, [sp, #16 * 14]\n"	\
+	"	ldr x30,   [sp, #16 * 15]\n"	\
+
+
+
 #endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index d2aa4bc..af55e37 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -565,32 +565,27 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 }
 
 /*
- * Kretprobes: kernel return probes handling
- *
- * AArch64 mode does not support popping the PC value from the
- * stack like on ARM 32-bit (ldmia {..,pc}), so atleast one
- * register need to be used to achieve branching/return.
- * It means return probes cannot return back to the original
- * return address directly without modifying the register context.
- *
- * So like other architectures, we prepare a global routine
- * with NOPs, which serve as trampoline address that hack away the
- * function return, with the exact register context.
- * Placing a kprobe on trampoline routine entry will trap again to
- * execute return probe handlers and restore original return address
- * in ELR_EL1, this way saved pt_regs still hold the original
- * register values to be carried back to the caller.
+ * When a retprobed function returns, this code saves registers and
+ * calls trampoline_handler() runs, which calls the kretprobe's handler.
  */
-static void __used kretprobe_trampoline_holder(void)
+static void __used __kprobes kretprobe_trampoline_holder(void)
 {
 	asm volatile (".global kretprobe_trampoline\n"
 			"kretprobe_trampoline:\n"
-			"NOP\n\t"
-			"NOP\n\t");
+		        "sub sp, sp, %0\n"
+			SAVE_REGS_STRING
+			"mov x0, sp\n"
+			"bl trampoline_probe_handler\n"
+			/* Replace trampoline address in lr with actual
+			   orig_ret_addr return address. */
+			"str x0, [sp, #16 * 15]\n"
+			RESTORE_REGS_STRING
+		        "add sp, sp, %0\n"
+			"ret\n"
+		      : : "I"(sizeof(struct pt_regs)) : "memory");
 }
 
-static int __kprobes
-trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
 {
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
@@ -651,7 +646,7 @@ trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 	}
 
 	/* return 1 so that post handlers not called */
-	return 1;
+	return (void *) orig_ret_addr;
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
@@ -663,18 +658,12 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 	regs->regs[30] = (long)&kretprobe_trampoline;
 }
 
-static struct kprobe trampoline = {
-	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
-	.pre_handler = trampoline_probe_handler
-};
-
-int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+int __init arch_init_kprobes(void)
 {
-	return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline;
+	return 0;
 }
 
-int __init arch_init_kprobes(void)
+int arch_trampoline_kprobe(struct kprobe *p)
 {
-	/* register trampoline for kret probe */
-	return register_kprobe(&trampoline);
+	return 0;
 }

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-12 12:48                   ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-12 12:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/12/2015 01:54 AM, David Long wrote:
> On 05/05/15 11:48, Will Deacon wrote:
>> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>>> On 05/01/15 21:44, William Cohen wrote:
>>>> Dave Long and I did some additional experimentation to better
>>>> understand what is condition causes the kernel to sometimes spew:
>>>>
>>>> Unexpected kernel single-step exception at EL1
>>>>
>>>> The functioncallcount.stp test instruments the entry and return of
>>>> every function in the mm files, including kfree.  In most cases the
>>>> arm64 trampoline_probe_handler just determines which return probe
>>>> instance matches the current conditions, runs the associated handler,
>>>> and recycles the return probe instance for another use by placing it
>>>> on a hlist.  However, it is possible that a return probe instance has
>>>> been set up on function entry and the return probe is unregistered
>>>> before the return probe instance fires.  In this case kfree is called
>>>> by the trampoline handler to remove the return probe instances related
>>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>>> is called within the arm64 trampoline_probe_handler function trigger
>>>> the problem.
>>>>
>>>> The kprobe breakpoint for the kfree call from within the
>>>> trampoline_probe_handler is encountered and started, but things go
>>>> wrong when attempting the single step on the instruction.
>>>>
>>>> It took a while to trigger this problem with the sytemtap testsuite.
>>>> Dave Long came up with steps that reproduce this more quickly with a
>>>> probed function that is always called within the trampoline handler.
>>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>>> that the x86_64 code can handle a single step from within the
>>>> trampoline_handler.
>>>>
>>>
>>> I'm assuming there are no plans for supporting software breakpoint debug
>>> exceptions during processing of single-step exceptions, any time soon on
>>> arm64.  Given that the only solution that I can come with for this is
>>> instead of making this orphaned kretprobe instance list exist only
>>> temporarily (in the scope of the kretprobe trampoline handler), make it
>>> always exist and kfree any items found on it as part of a periodic
>>> cleanup running outside of the handler context.  I think these changes
>>> would still all be in archiecture-specific code.  This doesn't feel to
>>> me like a bad solution.  Does anyone think there is a simpler way out of
>>> this?
>>
>> Just to clarify, is the problem here the software breakpoint exception,
>> or trying to step the faulting instruction whilst we were already handling
>> a step?
>>
> 
> Sorry for the delay, I got tripped up with some global optimizations that happened when I made more testing changes.  When the kprobes software breakpoint handler for kretprobes is reentered it sets up the single-step and that ends up hitting inside entry.S, apparently in el1_undef.
> 
>> I think I'd be inclined to keep the code run in debug context to a minimum.
>> We already can't block there, and the more code we add the more black spots
>> we end up with in the kernel itself. The alternative would be to make your
>> kprobes code re-entrant, but that sounds like a nightmare.
>>
>> You say this works on x86. How do they handle it? Is the nested probe
>> on kfree ignored or handled?
>>
> 
> Will Cohen's email pointing out x86 does not use a breakpoint for the trampoline handler explains a lot.  I'm experimenting starting with his proposed new trampoline code.  I can't see a reason this can't be made to work and so given everything it doesn't seem interesting to try and understand the failure in reentering the kprobe break handler in any more detail.
> 
> -dave long
> 
> 

Hi Dave,

In some of the previous diagnostic output it looked like things would go wrong in the entry.S when the D bit was cleared and the debug interrupts were unmasksed.  I wonder if some of the issue might be due to the starting the kprobe for the trampoline, but leaving things in an odd state when another set of krpobe/kretporbes are hit when the trampoline is running.  As Dave mentioned the proposed trampoline patch avoids using a kprobe in the trampoline and directly calls the trampoline handler.  Attached is the current version of the patch which was able to run the systemtap testsuite.  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would be good to have additional raw kprobe tests to check that kprobe reentry works as expected.

-Will Cohen
-------------- next part --------------
A non-text attachment was scrubbed...
Name: avoid_bkpt_tramp_v2.diff
Type: text/x-patch
Size: 4738 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150512/098399ee/attachment.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-12 12:48                   ` William Cohen
@ 2015-05-13  9:22                     ` Masami Hiramatsu
  -1 siblings, 0 replies; 74+ messages in thread
From: Masami Hiramatsu @ 2015-05-13  9:22 UTC (permalink / raw)
  To: William Cohen, David Long, Will Deacon
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 2015/05/12 21:48, William Cohen wrote:
> On 05/12/2015 01:54 AM, David Long wrote:
>> On 05/05/15 11:48, Will Deacon wrote:
>>> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>>>> On 05/01/15 21:44, William Cohen wrote:
>>>>> Dave Long and I did some additional experimentation to better
>>>>> understand what is condition causes the kernel to sometimes spew:
>>>>>
>>>>> Unexpected kernel single-step exception at EL1
>>>>>
>>>>> The functioncallcount.stp test instruments the entry and return of
>>>>> every function in the mm files, including kfree.  In most cases the
>>>>> arm64 trampoline_probe_handler just determines which return probe
>>>>> instance matches the current conditions, runs the associated handler,
>>>>> and recycles the return probe instance for another use by placing it
>>>>> on a hlist.  However, it is possible that a return probe instance has
>>>>> been set up on function entry and the return probe is unregistered
>>>>> before the return probe instance fires.  In this case kfree is called
>>>>> by the trampoline handler to remove the return probe instances related
>>>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>>>> is called within the arm64 trampoline_probe_handler function trigger
>>>>> the problem.
>>>>>
>>>>> The kprobe breakpoint for the kfree call from within the
>>>>> trampoline_probe_handler is encountered and started, but things go
>>>>> wrong when attempting the single step on the instruction.
>>>>>
>>>>> It took a while to trigger this problem with the sytemtap testsuite.
>>>>> Dave Long came up with steps that reproduce this more quickly with a
>>>>> probed function that is always called within the trampoline handler.
>>>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>>>> that the x86_64 code can handle a single step from within the
>>>>> trampoline_handler.
>>>>>
>>>>
>>>> I'm assuming there are no plans for supporting software breakpoint debug
>>>> exceptions during processing of single-step exceptions, any time soon on
>>>> arm64.  Given that the only solution that I can come with for this is
>>>> instead of making this orphaned kretprobe instance list exist only
>>>> temporarily (in the scope of the kretprobe trampoline handler), make it
>>>> always exist and kfree any items found on it as part of a periodic
>>>> cleanup running outside of the handler context.  I think these changes
>>>> would still all be in archiecture-specific code.  This doesn't feel to
>>>> me like a bad solution.  Does anyone think there is a simpler way out of
>>>> this?
>>>
>>> Just to clarify, is the problem here the software breakpoint exception,
>>> or trying to step the faulting instruction whilst we were already handling
>>> a step?
>>>
>>
>> Sorry for the delay, I got tripped up with some global optimizations that happened when I made more testing changes.  When the kprobes software breakpoint handler for kretprobes is reentered it sets up the single-step and that ends up hitting inside entry.S, apparently in el1_undef.
>>
>>> I think I'd be inclined to keep the code run in debug context to a minimum.
>>> We already can't block there, and the more code we add the more black spots
>>> we end up with in the kernel itself. The alternative would be to make your
>>> kprobes code re-entrant, but that sounds like a nightmare.
>>>
>>> You say this works on x86. How do they handle it? Is the nested probe
>>> on kfree ignored or handled?
>>>
>>
>> Will Cohen's email pointing out x86 does not use a breakpoint for the trampoline handler explains a lot.  I'm experimenting starting with his proposed new trampoline code.  I can't see a reason this can't be made to work and so given everything it doesn't seem interesting to try and understand the failure in reentering the kprobe break handler in any more detail.
>>
>> -dave long
>>
>>
> 
> Hi Dave,
> 
> In some of the previous diagnostic output it looked like things would go wrong
> in the entry.S when the D bit was cleared and the debug interrupts were 
> unmasksed.  I wonder if some of the issue might be due to the starting the 
> kprobe for the trampoline, but leaving things in an odd state when another
> set of krpobe/kretporbes are hit when the trampoline is running.

Hmm, does this mean we have a trouble if a user kprobe handler calls the
function which is probed by other kprobe? Or, is this just a problem
only for kretprobes?

>  As Dave
> mentioned the proposed trampoline patch avoids using a kprobe in the
> trampoline and directly calls the trampoline handler.  Attached is the
> current version of the patch which was able to run the systemtap testsuite.
>  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
> be good to have additional raw kprobe tests to check that kprobe reentry
> works as expected.

Actually, Will's patch looks like the same thing what I did on x86,
as the kretprobe-booster. So I'm OK for that. But if the above problem
is not solved, we need to fix that, since kprobes can be used from
different sources.

Thank you,

-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt@hitachi.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-13  9:22                     ` Masami Hiramatsu
  0 siblings, 0 replies; 74+ messages in thread
From: Masami Hiramatsu @ 2015-05-13  9:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 2015/05/12 21:48, William Cohen wrote:
> On 05/12/2015 01:54 AM, David Long wrote:
>> On 05/05/15 11:48, Will Deacon wrote:
>>> On Tue, May 05, 2015 at 06:14:51AM +0100, David Long wrote:
>>>> On 05/01/15 21:44, William Cohen wrote:
>>>>> Dave Long and I did some additional experimentation to better
>>>>> understand what is condition causes the kernel to sometimes spew:
>>>>>
>>>>> Unexpected kernel single-step exception at EL1
>>>>>
>>>>> The functioncallcount.stp test instruments the entry and return of
>>>>> every function in the mm files, including kfree.  In most cases the
>>>>> arm64 trampoline_probe_handler just determines which return probe
>>>>> instance matches the current conditions, runs the associated handler,
>>>>> and recycles the return probe instance for another use by placing it
>>>>> on a hlist.  However, it is possible that a return probe instance has
>>>>> been set up on function entry and the return probe is unregistered
>>>>> before the return probe instance fires.  In this case kfree is called
>>>>> by the trampoline handler to remove the return probe instances related
>>>>> to the unregistered kretprobe.  This case where the the kprobed kfree
>>>>> is called within the arm64 trampoline_probe_handler function trigger
>>>>> the problem.
>>>>>
>>>>> The kprobe breakpoint for the kfree call from within the
>>>>> trampoline_probe_handler is encountered and started, but things go
>>>>> wrong when attempting the single step on the instruction.
>>>>>
>>>>> It took a while to trigger this problem with the sytemtap testsuite.
>>>>> Dave Long came up with steps that reproduce this more quickly with a
>>>>> probed function that is always called within the trampoline handler.
>>>>> Trying the same on x86_64 doesn't trigger the problem.  It appears
>>>>> that the x86_64 code can handle a single step from within the
>>>>> trampoline_handler.
>>>>>
>>>>
>>>> I'm assuming there are no plans for supporting software breakpoint debug
>>>> exceptions during processing of single-step exceptions, any time soon on
>>>> arm64.  Given that the only solution that I can come with for this is
>>>> instead of making this orphaned kretprobe instance list exist only
>>>> temporarily (in the scope of the kretprobe trampoline handler), make it
>>>> always exist and kfree any items found on it as part of a periodic
>>>> cleanup running outside of the handler context.  I think these changes
>>>> would still all be in archiecture-specific code.  This doesn't feel to
>>>> me like a bad solution.  Does anyone think there is a simpler way out of
>>>> this?
>>>
>>> Just to clarify, is the problem here the software breakpoint exception,
>>> or trying to step the faulting instruction whilst we were already handling
>>> a step?
>>>
>>
>> Sorry for the delay, I got tripped up with some global optimizations that happened when I made more testing changes.  When the kprobes software breakpoint handler for kretprobes is reentered it sets up the single-step and that ends up hitting inside entry.S, apparently in el1_undef.
>>
>>> I think I'd be inclined to keep the code run in debug context to a minimum.
>>> We already can't block there, and the more code we add the more black spots
>>> we end up with in the kernel itself. The alternative would be to make your
>>> kprobes code re-entrant, but that sounds like a nightmare.
>>>
>>> You say this works on x86. How do they handle it? Is the nested probe
>>> on kfree ignored or handled?
>>>
>>
>> Will Cohen's email pointing out x86 does not use a breakpoint for the trampoline handler explains a lot.  I'm experimenting starting with his proposed new trampoline code.  I can't see a reason this can't be made to work and so given everything it doesn't seem interesting to try and understand the failure in reentering the kprobe break handler in any more detail.
>>
>> -dave long
>>
>>
> 
> Hi Dave,
> 
> In some of the previous diagnostic output it looked like things would go wrong
> in the entry.S when the D bit was cleared and the debug interrupts were 
> unmasksed.  I wonder if some of the issue might be due to the starting the 
> kprobe for the trampoline, but leaving things in an odd state when another
> set of krpobe/kretporbes are hit when the trampoline is running.

Hmm, does this mean we have a trouble if a user kprobe handler calls the
function which is probed by other kprobe? Or, is this just a problem
only for kretprobes?

>  As Dave
> mentioned the proposed trampoline patch avoids using a kprobe in the
> trampoline and directly calls the trampoline handler.  Attached is the
> current version of the patch which was able to run the systemtap testsuite.
>  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
> be good to have additional raw kprobe tests to check that kprobe reentry
> works as expected.

Actually, Will's patch looks like the same thing what I did on x86,
as the kretprobe-booster. So I'm OK for that. But if the above problem
is not solved, we need to fix that, since kprobes can be used from
different sources.

Thank you,

-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt at hitachi.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-13  9:22                     ` Masami Hiramatsu
@ 2015-05-13 15:41                       ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-13 15:41 UTC (permalink / raw)
  To: Masami Hiramatsu, David Long, Will Deacon
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2494 bytes --]

On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
> On 2015/05/12 21:48, William Cohen wrote:

>> Hi Dave,
>>
>> In some of the previous diagnostic output it looked like things would go wrong
>> in the entry.S when the D bit was cleared and the debug interrupts were 
>> unmasksed.  I wonder if some of the issue might be due to the starting the 
>> kprobe for the trampoline, but leaving things in an odd state when another
>> set of krpobe/kretporbes are hit when the trampoline is running.
> 
> Hmm, does this mean we have a trouble if a user kprobe handler calls the
> function which is probed by other kprobe? Or, is this just a problem
> only for kretprobes?

Hi Masami,

I wrote an example based off of sample/kprobes/kprobes_sample.c to force the reentry issue for kprobes (the attached kprobe_rentry_example.c). That seemed to run fine.  I think the reason that the trampoline handler got into trouble is because of the reset_current_kprobe() before the possible call to kfree, but I haven't verified it. It seems like that should be at the end of trampoline handler just before the return.  Other architectures have similar trampoline handlers, so I am surprised that the other architectures haven't encountered this issue with kretprobes.  Maybe this is due to specific of arm64 exception handling.

# modprobe kprobe_reentry_example
[  909.617295] Planted kprobe at fffffe00000b7b34
[  909.623873] Planted kprobe at fffffe000032d34c
# rmmod kprobe_reentry_example
[ 1482.647504] kprobe at fffffe00000b7b34 unregistered
[ 1482.687506] kprobe at fffffe000032d34c unregistered
[ 1482.692361] y = 42
[ 1482.694361] z = 0
# grep \ int_sqrt$ /proc/kallsyms 
fffffe000032d34c T int_sqrt
# grep \ do_fork$ /proc/kallsyms 
fffffe00000b7b34 T do_fork

> 
>>  As Dave
>> mentioned the proposed trampoline patch avoids using a kprobe in the
>> trampoline and directly calls the trampoline handler.  Attached is the
>> current version of the patch which was able to run the systemtap testsuite.
>>  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>> be good to have additional raw kprobe tests to check that kprobe reentry
>> works as expected.
> 
> Actually, Will's patch looks like the same thing what I did on x86,
> as the kretprobe-booster. So I'm OK for that. But if the above problem
> is not solved, we need to fix that, since kprobes can be used from
> different sources.

The patch should look similar to the x86 code. The x86 code was used as a model.

-Will


[-- Attachment #2: kprobe_reentry_example.c --]
[-- Type: text/x-csrc, Size: 2827 bytes --]

/*
 * NOTE: This example is designed to check that the kprobe reentry work.
 *
 * For more information on theory of operation of kprobes, see
 * Documentation/kprobes.txt
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
	.symbol_name	= "do_fork",
};

static struct kprobe kp_re = {
	.symbol_name	= "int_sqrt",
};

static unsigned long y=0;
static unsigned long z=0;

/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
  /* call another function that is instrumented with a kprobe to
     ensure that reentry works */
  unsigned long x=1764;
  y = int_sqrt(x);
  return 0;
}

/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs,
				unsigned long flags)
{
  return;
}

/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre_re(struct kprobe *p, struct pt_regs *regs)
{
  /* if reentry is working as expected this code may not be executed */
  z = 0xdeadbeef;
  return 0;
}

/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post_re(struct kprobe *p, struct pt_regs *regs,
				unsigned long flags)
{
  return;
}

/*
 * fault_handler: this is called if an exception is generated for any
 * instruction within the pre- or post-handler, or when Kprobes
 * single-steps the probed instruction.
 */
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
	printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
		p->addr, trapnr);
	/* Return 0 because we don't handle the fault. */
	return 0;
}

static int __init kprobe_init(void)
{
	int ret;
	kp.pre_handler = handler_pre;
	kp.post_handler = handler_post;
	kp.fault_handler = handler_fault;

	ret = register_kprobe(&kp);
	if (ret < 0) {
		printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
		return ret;
	}
	printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);

	kp_re.pre_handler = handler_pre_re;
	kp_re.post_handler = handler_post_re;
	kp_re.fault_handler = handler_fault;

	ret = register_kprobe(&kp_re);
	if (ret < 0) {
		printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
		return ret;
	}
	printk(KERN_INFO "Planted kprobe at %p\n", kp_re.addr);
	return 0;
}

static void __exit kprobe_exit(void)
{
	unregister_kprobe(&kp);
	printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
	unregister_kprobe(&kp_re);
	printk(KERN_INFO "kprobe at %p unregistered\n", kp_re.addr);
	printk(KERN_INFO "y = %ld\n", y);
	printk(KERN_INFO "z = %lx\n", z);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-13 15:41                       ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-13 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
> On 2015/05/12 21:48, William Cohen wrote:

>> Hi Dave,
>>
>> In some of the previous diagnostic output it looked like things would go wrong
>> in the entry.S when the D bit was cleared and the debug interrupts were 
>> unmasksed.  I wonder if some of the issue might be due to the starting the 
>> kprobe for the trampoline, but leaving things in an odd state when another
>> set of krpobe/kretporbes are hit when the trampoline is running.
> 
> Hmm, does this mean we have a trouble if a user kprobe handler calls the
> function which is probed by other kprobe? Or, is this just a problem
> only for kretprobes?

Hi Masami,

I wrote an example based off of sample/kprobes/kprobes_sample.c to force the reentry issue for kprobes (the attached kprobe_rentry_example.c). That seemed to run fine.  I think the reason that the trampoline handler got into trouble is because of the reset_current_kprobe() before the possible call to kfree, but I haven't verified it. It seems like that should be at the end of trampoline handler just before the return.  Other architectures have similar trampoline handlers, so I am surprised that the other architectures haven't encountered this issue with kretprobes.  Maybe this is due to specific of arm64 exception handling.

# modprobe kprobe_reentry_example
[  909.617295] Planted kprobe at fffffe00000b7b34
[  909.623873] Planted kprobe at fffffe000032d34c
# rmmod kprobe_reentry_example
[ 1482.647504] kprobe at fffffe00000b7b34 unregistered
[ 1482.687506] kprobe at fffffe000032d34c unregistered
[ 1482.692361] y = 42
[ 1482.694361] z = 0
# grep \ int_sqrt$ /proc/kallsyms 
fffffe000032d34c T int_sqrt
# grep \ do_fork$ /proc/kallsyms 
fffffe00000b7b34 T do_fork

> 
>>  As Dave
>> mentioned the proposed trampoline patch avoids using a kprobe in the
>> trampoline and directly calls the trampoline handler.  Attached is the
>> current version of the patch which was able to run the systemtap testsuite.
>>  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>> be good to have additional raw kprobe tests to check that kprobe reentry
>> works as expected.
> 
> Actually, Will's patch looks like the same thing what I did on x86,
> as the kretprobe-booster. So I'm OK for that. But if the above problem
> is not solved, we need to fix that, since kprobes can be used from
> different sources.

The patch should look similar to the x86 code. The x86 code was used as a model.

-Will

-------------- next part --------------
A non-text attachment was scrubbed...
Name: kprobe_reentry_example.c
Type: text/x-csrc
Size: 2827 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150513/d4c30667/attachment.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-13 15:41                       ` William Cohen
@ 2015-05-13 19:58                         ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-13 19:58 UTC (permalink / raw)
  To: William Cohen, Masami Hiramatsu, Will Deacon
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 05/13/15 11:41, William Cohen wrote:
> On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
>> On 2015/05/12 21:48, William Cohen wrote:
>
>>> Hi Dave,
>>>
>>> In some of the previous diagnostic output it looked like things would go wrong
>>> in the entry.S when the D bit was cleared and the debug interrupts were
>>> unmasksed.  I wonder if some of the issue might be due to the starting the
>>> kprobe for the trampoline, but leaving things in an odd state when another
>>> set of krpobe/kretporbes are hit when the trampoline is running.
>>
>> Hmm, does this mean we have a trouble if a user kprobe handler calls the
>> function which is probed by other kprobe? Or, is this just a problem
>> only for kretprobes?
>
> Hi Masami,
>
> I wrote an example based off of sample/kprobes/kprobes_sample.c to force the reentry issue for kprobes (the attached kprobe_rentry_example.c). That seemed to run fine.  I think the reason that the trampoline handler got into trouble is because of the reset_current_kprobe() before the possible call to kfree, but I haven't verified it. It seems like that should be at the end of trampoline handler just before the return.  Other architectures have similar trampoline handlers, so I am surprised that the other architectures haven't encountered this issue with kretprobes.  Maybe this is due to specific of arm64 exception handling.
>
> # modprobe kprobe_reentry_example
> [  909.617295] Planted kprobe at fffffe00000b7b34
> [  909.623873] Planted kprobe at fffffe000032d34c
> # rmmod kprobe_reentry_example
> [ 1482.647504] kprobe at fffffe00000b7b34 unregistered
> [ 1482.687506] kprobe at fffffe000032d34c unregistered
> [ 1482.692361] y = 42
> [ 1482.694361] z = 0
> # grep \ int_sqrt$ /proc/kallsyms
> fffffe000032d34c T int_sqrt
> # grep \ do_fork$ /proc/kallsyms
> fffffe00000b7b34 T do_fork
>

I actually have been doing exactly the same thing.  I was not able to 
provoke a failure in either the pre or post handler when having them 
call to another kprobe'd (dummy) function.  However it does look to me 
like it's reentering the exception handler firstly at the second 
software breakpoint and then (shortly after returning from that) with a 
single-step.   That's what you would expect but I *thought* neither of 
those cases was allowed.  It does not call either the pre or post 
handler in the dummy function.  I would expect this to be an issue for a 
kretprobe pre handler too, although I've yet to test this.

>>
>>>   As Dave
>>> mentioned the proposed trampoline patch avoids using a kprobe in the
>>> trampoline and directly calls the trampoline handler.  Attached is the
>>> current version of the patch which was able to run the systemtap testsuite.
>>>   Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>>> be good to have additional raw kprobe tests to check that kprobe reentry
>>> works as expected.
>>
>> Actually, Will's patch looks like the same thing what I did on x86,
>> as the kretprobe-booster. So I'm OK for that. But if the above problem
>> is not solved, we need to fix that, since kprobes can be used from
>> different sources.
>
> The patch should look similar to the x86 code. The x86 code was used as a model.
>
> -Will
>


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-13 19:58                         ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-13 19:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/13/15 11:41, William Cohen wrote:
> On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
>> On 2015/05/12 21:48, William Cohen wrote:
>
>>> Hi Dave,
>>>
>>> In some of the previous diagnostic output it looked like things would go wrong
>>> in the entry.S when the D bit was cleared and the debug interrupts were
>>> unmasksed.  I wonder if some of the issue might be due to the starting the
>>> kprobe for the trampoline, but leaving things in an odd state when another
>>> set of krpobe/kretporbes are hit when the trampoline is running.
>>
>> Hmm, does this mean we have a trouble if a user kprobe handler calls the
>> function which is probed by other kprobe? Or, is this just a problem
>> only for kretprobes?
>
> Hi Masami,
>
> I wrote an example based off of sample/kprobes/kprobes_sample.c to force the reentry issue for kprobes (the attached kprobe_rentry_example.c). That seemed to run fine.  I think the reason that the trampoline handler got into trouble is because of the reset_current_kprobe() before the possible call to kfree, but I haven't verified it. It seems like that should be at the end of trampoline handler just before the return.  Other architectures have similar trampoline handlers, so I am surprised that the other architectures haven't encountered this issue with kretprobes.  Maybe this is due to specific of arm64 exception handling.
>
> # modprobe kprobe_reentry_example
> [  909.617295] Planted kprobe at fffffe00000b7b34
> [  909.623873] Planted kprobe at fffffe000032d34c
> # rmmod kprobe_reentry_example
> [ 1482.647504] kprobe at fffffe00000b7b34 unregistered
> [ 1482.687506] kprobe at fffffe000032d34c unregistered
> [ 1482.692361] y = 42
> [ 1482.694361] z = 0
> # grep \ int_sqrt$ /proc/kallsyms
> fffffe000032d34c T int_sqrt
> # grep \ do_fork$ /proc/kallsyms
> fffffe00000b7b34 T do_fork
>

I actually have been doing exactly the same thing.  I was not able to 
provoke a failure in either the pre or post handler when having them 
call to another kprobe'd (dummy) function.  However it does look to me 
like it's reentering the exception handler firstly at the second 
software breakpoint and then (shortly after returning from that) with a 
single-step.   That's what you would expect but I *thought* neither of 
those cases was allowed.  It does not call either the pre or post 
handler in the dummy function.  I would expect this to be an issue for a 
kretprobe pre handler too, although I've yet to test this.

>>
>>>   As Dave
>>> mentioned the proposed trampoline patch avoids using a kprobe in the
>>> trampoline and directly calls the trampoline handler.  Attached is the
>>> current version of the patch which was able to run the systemtap testsuite.
>>>   Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>>> be good to have additional raw kprobe tests to check that kprobe reentry
>>> works as expected.
>>
>> Actually, Will's patch looks like the same thing what I did on x86,
>> as the kretprobe-booster. So I'm OK for that. But if the above problem
>> is not solved, we need to fix that, since kprobes can be used from
>> different sources.
>
> The patch should look similar to the x86 code. The x86 code was used as a model.
>
> -Will
>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-13 19:58                         ` David Long
@ 2015-05-13 20:35                           ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-13 20:35 UTC (permalink / raw)
  To: David Long, Masami Hiramatsu, Will Deacon
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Jon Medhurst (Tixy),
	Ananth N Mavinakayanahalli, Anil S Keshavamurthy, davem,
	linux-kernel

On 05/13/2015 03:58 PM, David Long wrote:
> On 05/13/15 11:41, William Cohen wrote:
>> On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
>>> On 2015/05/12 21:48, William Cohen wrote:
>>
>>>> Hi Dave,
>>>>
>>>> In some of the previous diagnostic output it looked like things would go wrong
>>>> in the entry.S when the D bit was cleared and the debug interrupts were
>>>> unmasksed.  I wonder if some of the issue might be due to the starting the
>>>> kprobe for the trampoline, but leaving things in an odd state when another
>>>> set of krpobe/kretporbes are hit when the trampoline is running.
>>>
>>> Hmm, does this mean we have a trouble if a user kprobe handler calls the
>>> function which is probed by other kprobe? Or, is this just a problem
>>> only for kretprobes?
>>
>> Hi Masami,
>>
>> I wrote an example based off of sample/kprobes/kprobes_sample.c to force the reentry issue for kprobes (the attached kprobe_rentry_example.c). That seemed to run fine.  I think the reason that the trampoline handler got into trouble is because of the reset_current_kprobe() before the possible call to kfree, but I haven't verified it. It seems like that should be at the end of trampoline handler just before the return.  Other architectures have similar trampoline handlers, so I am surprised that the other architectures haven't encountered this issue with kretprobes.  Maybe this is due to specific of arm64 exception handling.
>>
>> # modprobe kprobe_reentry_example
>> [  909.617295] Planted kprobe at fffffe00000b7b34
>> [  909.623873] Planted kprobe at fffffe000032d34c
>> # rmmod kprobe_reentry_example
>> [ 1482.647504] kprobe at fffffe00000b7b34 unregistered
>> [ 1482.687506] kprobe at fffffe000032d34c unregistered
>> [ 1482.692361] y = 42
>> [ 1482.694361] z = 0
>> # grep \ int_sqrt$ /proc/kallsyms
>> fffffe000032d34c T int_sqrt
>> # grep \ do_fork$ /proc/kallsyms
>> fffffe00000b7b34 T do_fork
>>
> 
> I actually have been doing exactly the same thing.  I was not able to provoke a failure in either the pre or post handler when having them call to another kprobe'd (dummy) function.  However it does look to me like it's reentering the exception handler firstly at the second software breakpoint and then (shortly after returning from that) with a single-step.   That's what you would expect but I *thought* neither of those cases was allowed.  It does not call either the pre or post handler in the dummy function.  I would expect this to be an issue for a kretprobe pre handler too, although I've yet to test this.
> 

Hi Dave,

That is a good point. If the kprobe machinery disables the kretprobe handler because of reentry, that would be problem.  The kretprobe handler always has to fix up the return address, no exceptions.  The patch with the direct call to the trampoline handler would avoid these possible kprobe handler disables.  Could the skipping of the kretprobe trampoline handler be triggered by putting a kprobe on a "ret" instruction that is in a kretprobe'd function?  Is there any functions in the arm64 kernel memory that end up being a stub with just a return instruction in the memory management code?  Something similar to the following routines:

fffffe0000090e10 <calibration_delay_done>:
fffffe0000090e10:       d65f03c0        ret

or

fffffe0000094aac <exit_thread>:
fffffe0000094aac:       d65f03c0        ret



-Will


>>>
>>>>   As Dave
>>>> mentioned the proposed trampoline patch avoids using a kprobe in the
>>>> trampoline and directly calls the trampoline handler.  Attached is the
>>>> current version of the patch which was able to run the systemtap testsuite.
>>>>   Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>>>> be good to have additional raw kprobe tests to check that kprobe reentry
>>>> works as expected.
>>>
>>> Actually, Will's patch looks like the same thing what I did on x86,
>>> as the kretprobe-booster. So I'm OK for that. But if the above problem
>>> is not solved, we need to fix that, since kprobes can be used from
>>> different sources.
>>
>> The patch should look similar to the x86 code. The x86 code was used as a model.
>>
>> -Will
>>
> 


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-13 20:35                           ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-13 20:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/13/2015 03:58 PM, David Long wrote:
> On 05/13/15 11:41, William Cohen wrote:
>> On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
>>> On 2015/05/12 21:48, William Cohen wrote:
>>
>>>> Hi Dave,
>>>>
>>>> In some of the previous diagnostic output it looked like things would go wrong
>>>> in the entry.S when the D bit was cleared and the debug interrupts were
>>>> unmasksed.  I wonder if some of the issue might be due to the starting the
>>>> kprobe for the trampoline, but leaving things in an odd state when another
>>>> set of krpobe/kretporbes are hit when the trampoline is running.
>>>
>>> Hmm, does this mean we have a trouble if a user kprobe handler calls the
>>> function which is probed by other kprobe? Or, is this just a problem
>>> only for kretprobes?
>>
>> Hi Masami,
>>
>> I wrote an example based off of sample/kprobes/kprobes_sample.c to force the reentry issue for kprobes (the attached kprobe_rentry_example.c). That seemed to run fine.  I think the reason that the trampoline handler got into trouble is because of the reset_current_kprobe() before the possible call to kfree, but I haven't verified it. It seems like that should be at the end of trampoline handler just before the return.  Other architectures have similar trampoline handlers, so I am surprised that the other architectures haven't encountered this issue with kretprobes.  Maybe this is due to specific of arm64 exception handling.
>>
>> # modprobe kprobe_reentry_example
>> [  909.617295] Planted kprobe at fffffe00000b7b34
>> [  909.623873] Planted kprobe at fffffe000032d34c
>> # rmmod kprobe_reentry_example
>> [ 1482.647504] kprobe at fffffe00000b7b34 unregistered
>> [ 1482.687506] kprobe at fffffe000032d34c unregistered
>> [ 1482.692361] y = 42
>> [ 1482.694361] z = 0
>> # grep \ int_sqrt$ /proc/kallsyms
>> fffffe000032d34c T int_sqrt
>> # grep \ do_fork$ /proc/kallsyms
>> fffffe00000b7b34 T do_fork
>>
> 
> I actually have been doing exactly the same thing.  I was not able to provoke a failure in either the pre or post handler when having them call to another kprobe'd (dummy) function.  However it does look to me like it's reentering the exception handler firstly at the second software breakpoint and then (shortly after returning from that) with a single-step.   That's what you would expect but I *thought* neither of those cases was allowed.  It does not call either the pre or post handler in the dummy function.  I would expect this to be an issue for a kretprobe pre handler too, although I've yet to test this.
> 

Hi Dave,

That is a good point. If the kprobe machinery disables the kretprobe handler because of reentry, that would be problem.  The kretprobe handler always has to fix up the return address, no exceptions.  The patch with the direct call to the trampoline handler would avoid these possible kprobe handler disables.  Could the skipping of the kretprobe trampoline handler be triggered by putting a kprobe on a "ret" instruction that is in a kretprobe'd function?  Is there any functions in the arm64 kernel memory that end up being a stub with just a return instruction in the memory management code?  Something similar to the following routines:

fffffe0000090e10 <calibration_delay_done>:
fffffe0000090e10:       d65f03c0        ret

or

fffffe0000094aac <exit_thread>:
fffffe0000094aac:       d65f03c0        ret



-Will


>>>
>>>>   As Dave
>>>> mentioned the proposed trampoline patch avoids using a kprobe in the
>>>> trampoline and directly calls the trampoline handler.  Attached is the
>>>> current version of the patch which was able to run the systemtap testsuite.
>>>>   Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>>>> be good to have additional raw kprobe tests to check that kprobe reentry
>>>> works as expected.
>>>
>>> Actually, Will's patch looks like the same thing what I did on x86,
>>> as the kretprobe-booster. So I'm OK for that. But if the above problem
>>> is not solved, we need to fix that, since kprobes can be used from
>>> different sources.
>>
>> The patch should look similar to the x86 code. The x86 code was used as a model.
>>
>> -Will
>>
> 

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-13 15:41                       ` William Cohen
@ 2015-05-14  0:01                         ` Masami Hiramatsu
  -1 siblings, 0 replies; 74+ messages in thread
From: Masami Hiramatsu @ 2015-05-14  0:01 UTC (permalink / raw)
  To: William Cohen, David Long, Will Deacon, Ananth N Mavinakayanahalli
  Cc: linux-arm-kernel, Russell King, sandeepa.s.prabhu, Steve Capper,
	Catalin Marinas, Jon Medhurst (Tixy),
	Anil S Keshavamurthy, davem, linux-kernel

On 2015/05/14 0:41, William Cohen wrote:
> On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
>> On 2015/05/12 21:48, William Cohen wrote:
> 
>>> Hi Dave,
>>>
>>> In some of the previous diagnostic output it looked like things would go wrong
>>> in the entry.S when the D bit was cleared and the debug interrupts were 
>>> unmasksed.  I wonder if some of the issue might be due to the starting the 
>>> kprobe for the trampoline, but leaving things in an odd state when another
>>> set of krpobe/kretporbes are hit when the trampoline is running.
>>
>> Hmm, does this mean we have a trouble if a user kprobe handler calls the
>> function which is probed by other kprobe? Or, is this just a problem
>> only for kretprobes?
> 
> Hi Masami,
> 
> I wrote an example based off of sample/kprobes/kprobes_sample.c to force 
> the reentry issue for kprobes (the attached kprobe_rentry_example.c). That
> seemed to run fine.  I think the reason that the trampoline handler got 
> into trouble is because of the reset_current_kprobe() before the possible
> call to kfree, but I haven't verified it.

I still doubt about kfree() reentrant call, since kretprobe handler only
calls recycle_rp_inst() which doesn't free the instance but just push it back
to the unused instance list.

> It seems like that should be at the end of trampoline handler just before
> the return.  Other architectures have similar trampoline handlers,
> so I am surprised that the other architectures haven't encountered this
> issue with kretprobes.  Maybe this is due to specific of arm64 exception
> handling.

Ah, indeed the reset_current_kprobe() here seems not good since some
interruption or some other reason, another kprobes can be hit before
returning.

If kprobes can handle reentered probes correctly, I think your patch
(directly branch from trampoline) looks good to fix this problem.
Actually, arm32 and x86 already has same method.

It seems that powerpc will have similar issue, does someone checked
that? Ananth?

Thank you,

> 
> # modprobe kprobe_reentry_example
> [  909.617295] Planted kprobe at fffffe00000b7b34
> [  909.623873] Planted kprobe at fffffe000032d34c
> # rmmod kprobe_reentry_example
> [ 1482.647504] kprobe at fffffe00000b7b34 unregistered
> [ 1482.687506] kprobe at fffffe000032d34c unregistered
> [ 1482.692361] y = 42
> [ 1482.694361] z = 0
> # grep \ int_sqrt$ /proc/kallsyms 
> fffffe000032d34c T int_sqrt
> # grep \ do_fork$ /proc/kallsyms 
> fffffe00000b7b34 T do_fork
> 
>>
>>>  As Dave
>>> mentioned the proposed trampoline patch avoids using a kprobe in the
>>> trampoline and directly calls the trampoline handler.  Attached is the
>>> current version of the patch which was able to run the systemtap testsuite.
>>>  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>>> be good to have additional raw kprobe tests to check that kprobe reentry
>>> works as expected.
>>
>> Actually, Will's patch looks like the same thing what I did on x86,
>> as the kretprobe-booster. So I'm OK for that. But if the above problem
>> is not solved, we need to fix that, since kprobes can be used from
>> different sources.
> 
> The patch should look similar to the x86 code. The x86 code was used as a model.
> 
> -Will
> 


-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt@hitachi.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-14  0:01                         ` Masami Hiramatsu
  0 siblings, 0 replies; 74+ messages in thread
From: Masami Hiramatsu @ 2015-05-14  0:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 2015/05/14 0:41, William Cohen wrote:
> On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
>> On 2015/05/12 21:48, William Cohen wrote:
> 
>>> Hi Dave,
>>>
>>> In some of the previous diagnostic output it looked like things would go wrong
>>> in the entry.S when the D bit was cleared and the debug interrupts were 
>>> unmasksed.  I wonder if some of the issue might be due to the starting the 
>>> kprobe for the trampoline, but leaving things in an odd state when another
>>> set of krpobe/kretporbes are hit when the trampoline is running.
>>
>> Hmm, does this mean we have a trouble if a user kprobe handler calls the
>> function which is probed by other kprobe? Or, is this just a problem
>> only for kretprobes?
> 
> Hi Masami,
> 
> I wrote an example based off of sample/kprobes/kprobes_sample.c to force 
> the reentry issue for kprobes (the attached kprobe_rentry_example.c). That
> seemed to run fine.  I think the reason that the trampoline handler got 
> into trouble is because of the reset_current_kprobe() before the possible
> call to kfree, but I haven't verified it.

I still doubt about kfree() reentrant call, since kretprobe handler only
calls recycle_rp_inst() which doesn't free the instance but just push it back
to the unused instance list.

> It seems like that should be at the end of trampoline handler just before
> the return.  Other architectures have similar trampoline handlers,
> so I am surprised that the other architectures haven't encountered this
> issue with kretprobes.  Maybe this is due to specific of arm64 exception
> handling.

Ah, indeed the reset_current_kprobe() here seems not good since some
interruption or some other reason, another kprobes can be hit before
returning.

If kprobes can handle reentered probes correctly, I think your patch
(directly branch from trampoline) looks good to fix this problem.
Actually, arm32 and x86 already has same method.

It seems that powerpc will have similar issue, does someone checked
that? Ananth?

Thank you,

> 
> # modprobe kprobe_reentry_example
> [  909.617295] Planted kprobe at fffffe00000b7b34
> [  909.623873] Planted kprobe at fffffe000032d34c
> # rmmod kprobe_reentry_example
> [ 1482.647504] kprobe at fffffe00000b7b34 unregistered
> [ 1482.687506] kprobe at fffffe000032d34c unregistered
> [ 1482.692361] y = 42
> [ 1482.694361] z = 0
> # grep \ int_sqrt$ /proc/kallsyms 
> fffffe000032d34c T int_sqrt
> # grep \ do_fork$ /proc/kallsyms 
> fffffe00000b7b34 T do_fork
> 
>>
>>>  As Dave
>>> mentioned the proposed trampoline patch avoids using a kprobe in the
>>> trampoline and directly calls the trampoline handler.  Attached is the
>>> current version of the patch which was able to run the systemtap testsuite.
>>>  Systemtap does exercise the kprobe/kretprobe infrastructure, but it would
>>> be good to have additional raw kprobe tests to check that kprobe reentry
>>> works as expected.
>>
>> Actually, Will's patch looks like the same thing what I did on x86,
>> as the kretprobe-booster. So I'm OK for that. But if the above problem
>> is not solved, we need to fix that, since kprobes can be used from
>> different sources.
> 
> The patch should look similar to the x86 code. The x86 code was used as a model.
> 
> -Will
> 


-- 
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: masami.hiramatsu.pt at hitachi.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Re: [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
  2015-05-14  0:01                         ` Masami Hiramatsu
@ 2015-05-14  3:48                           ` Ananth N Mavinakayanahalli
  -1 siblings, 0 replies; 74+ messages in thread
From: Ananth N Mavinakayanahalli @ 2015-05-14  3:48 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: William Cohen, David Long, Will Deacon, linux-arm-kernel,
	Russell King, sandeepa.s.prabhu, Steve Capper, Catalin Marinas,
	Jon Medhurst (Tixy),
	Anil S Keshavamurthy, davem, linux-kernel

On Thu, May 14, 2015 at 09:01:03AM +0900, Masami Hiramatsu wrote:
> On 2015/05/14 0:41, William Cohen wrote:
> > On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
> >> On 2015/05/12 21:48, William Cohen wrote:
> > 
> >>> Hi Dave,
> >>>
> >>> In some of the previous diagnostic output it looked like things would go wrong
> >>> in the entry.S when the D bit was cleared and the debug interrupts were 
> >>> unmasksed.  I wonder if some of the issue might be due to the starting the 
> >>> kprobe for the trampoline, but leaving things in an odd state when another
> >>> set of krpobe/kretporbes are hit when the trampoline is running.
> >>
> >> Hmm, does this mean we have a trouble if a user kprobe handler calls the
> >> function which is probed by other kprobe? Or, is this just a problem
> >> only for kretprobes?
> > 
> > Hi Masami,
> > 
> > I wrote an example based off of sample/kprobes/kprobes_sample.c to force 
> > the reentry issue for kprobes (the attached kprobe_rentry_example.c). That
> > seemed to run fine.  I think the reason that the trampoline handler got 
> > into trouble is because of the reset_current_kprobe() before the possible
> > call to kfree, but I haven't verified it.
> 
> I still doubt about kfree() reentrant call, since kretprobe handler only
> calls recycle_rp_inst() which doesn't free the instance but just push it back
> to the unused instance list.
> 
> > It seems like that should be at the end of trampoline handler just before
> > the return.  Other architectures have similar trampoline handlers,
> > so I am surprised that the other architectures haven't encountered this
> > issue with kretprobes.  Maybe this is due to specific of arm64 exception
> > handling.
> 
> Ah, indeed the reset_current_kprobe() here seems not good since some
> interruption or some other reason, another kprobes can be hit before
> returning.
> 
> If kprobes can handle reentered probes correctly, I think your patch
> (directly branch from trampoline) looks good to fix this problem.
> Actually, arm32 and x86 already has same method.
> 
> It seems that powerpc will have similar issue, does someone checked
> that? Ananth?

Yes, there is a window where this can happen on powerpc. I haven't
however been able to trigger it thus far -- will try with a different
sample and test.

Thanks for the heads-up.

Ananth


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support
@ 2015-05-14  3:48                           ` Ananth N Mavinakayanahalli
  0 siblings, 0 replies; 74+ messages in thread
From: Ananth N Mavinakayanahalli @ 2015-05-14  3:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 14, 2015 at 09:01:03AM +0900, Masami Hiramatsu wrote:
> On 2015/05/14 0:41, William Cohen wrote:
> > On 05/13/2015 05:22 AM, Masami Hiramatsu wrote:
> >> On 2015/05/12 21:48, William Cohen wrote:
> > 
> >>> Hi Dave,
> >>>
> >>> In some of the previous diagnostic output it looked like things would go wrong
> >>> in the entry.S when the D bit was cleared and the debug interrupts were 
> >>> unmasksed.  I wonder if some of the issue might be due to the starting the 
> >>> kprobe for the trampoline, but leaving things in an odd state when another
> >>> set of krpobe/kretporbes are hit when the trampoline is running.
> >>
> >> Hmm, does this mean we have a trouble if a user kprobe handler calls the
> >> function which is probed by other kprobe? Or, is this just a problem
> >> only for kretprobes?
> > 
> > Hi Masami,
> > 
> > I wrote an example based off of sample/kprobes/kprobes_sample.c to force 
> > the reentry issue for kprobes (the attached kprobe_rentry_example.c). That
> > seemed to run fine.  I think the reason that the trampoline handler got 
> > into trouble is because of the reset_current_kprobe() before the possible
> > call to kfree, but I haven't verified it.
> 
> I still doubt about kfree() reentrant call, since kretprobe handler only
> calls recycle_rp_inst() which doesn't free the instance but just push it back
> to the unused instance list.
> 
> > It seems like that should be at the end of trampoline handler just before
> > the return.  Other architectures have similar trampoline handlers,
> > so I am surprised that the other architectures haven't encountered this
> > issue with kretprobes.  Maybe this is due to specific of arm64 exception
> > handling.
> 
> Ah, indeed the reset_current_kprobe() here seems not good since some
> interruption or some other reason, another kprobes can be hit before
> returning.
> 
> If kprobes can handle reentered probes correctly, I think your patch
> (directly branch from trampoline) looks good to fix this problem.
> Actually, arm32 and x86 already has same method.
> 
> It seems that powerpc will have similar issue, does someone checked
> that? Ananth?

Yes, there is a window where this can happen on powerpc. I haven't
however been able to trigger it thus far -- will try with a different
sample and test.

Thanks for the heads-up.

Ananth

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  2015-04-20 20:19   ` David Long
@ 2015-05-20 13:39     ` Catalin Marinas
  -1 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-20 13:39 UTC (permalink / raw)
  To: David Long
  Cc: linux-arm-kernel, Russell King, Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, Masami Hiramatsu,
	sandeepa.s.prabhu, William Cohen, davem

On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
> index 6913643..58c0223 100644
> --- a/arch/arm64/include/uapi/asm/ptrace.h
> +++ b/arch/arm64/include/uapi/asm/ptrace.h
> @@ -61,6 +61,42 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +#define ARM_pstate	pstate
> +#define ARM_pc		pc
> +#define ARM_sp		sp
> +#define ARM_lr		regs[30]
> +#define ARM_fp		regs[29]
> +#define ARM_x28		regs[28]
> +#define ARM_x27		regs[27]
> +#define ARM_x26		regs[26]
> +#define ARM_x25		regs[25]
> +#define ARM_x24		regs[24]
> +#define ARM_x23		regs[23]
> +#define ARM_x22		regs[22]
> +#define ARM_x21		regs[21]
> +#define ARM_x20		regs[20]
> +#define ARM_x19		regs[19]
> +#define ARM_x18		regs[18]
> +#define ARM_ip1		regs[17]
> +#define ARM_ip0		regs[16]
> +#define ARM_x15		regs[15]
> +#define ARM_x14		regs[14]
> +#define ARM_x13		regs[13]
> +#define ARM_x12		regs[12]
> +#define ARM_x11		regs[11]
> +#define ARM_x10		regs[10]
> +#define ARM_x9		regs[9]
> +#define ARM_x8		regs[8]
> +#define ARM_x7		regs[7]
> +#define ARM_x6		regs[6]
> +#define ARM_x5		regs[5]
> +#define ARM_x4		regs[4]
> +#define ARM_x3		regs[3]
> +#define ARM_x2		regs[2]
> +#define ARM_x1		regs[1]
> +#define ARM_x0		regs[0]
> +#define ARM_ORIG_x0	orig_x0

I replied some time ago on this part. I don't see the point these
macros.

> +
>  /*
>   * User structures for general purpose, floating point and debug registers.
>   */
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index d882b83..a889f79 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -48,6 +48,122 @@
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/syscalls.h>
>  
> +struct pt_regs_offset {
> +	const char *name;
> +	int offset;
> +};
> +
> +#define REG_OFFSET_NAME(r) \
> +	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}

Can you not just use "offsetof(struct pt_regs, r)" here? That would be
the same as x86, powerpc.

> +#define REG_OFFSET_END {.name = NULL, .offset = 0}
> +
> +static const struct pt_regs_offset regoffset_table[] = {
> +	REG_OFFSET_NAME(x0),
> +	REG_OFFSET_NAME(x1),
> +	REG_OFFSET_NAME(x2),
> +	REG_OFFSET_NAME(x3),
> +	REG_OFFSET_NAME(x4),
> +	REG_OFFSET_NAME(x5),
> +	REG_OFFSET_NAME(x6),
> +	REG_OFFSET_NAME(x7),
> +	REG_OFFSET_NAME(x8),
> +	REG_OFFSET_NAME(x9),
> +	REG_OFFSET_NAME(x10),
> +	REG_OFFSET_NAME(x11),
> +	REG_OFFSET_NAME(x12),
> +	REG_OFFSET_NAME(x13),
> +	REG_OFFSET_NAME(x14),
> +	REG_OFFSET_NAME(x15),
> +	REG_OFFSET_NAME(ip0),
> +	REG_OFFSET_NAME(ip1),
> +	REG_OFFSET_NAME(x18),
> +	REG_OFFSET_NAME(x19),
> +	REG_OFFSET_NAME(x20),
> +	REG_OFFSET_NAME(x21),
> +	REG_OFFSET_NAME(x22),
> +	REG_OFFSET_NAME(x23),
> +	REG_OFFSET_NAME(x24),
> +	REG_OFFSET_NAME(x25),
> +	REG_OFFSET_NAME(x26),
> +	REG_OFFSET_NAME(x27),
> +	REG_OFFSET_NAME(x28),
> +	REG_OFFSET_NAME(fp),
> +	REG_OFFSET_NAME(lr),
> +	REG_OFFSET_NAME(sp),
> +	REG_OFFSET_NAME(pc),

and stick to x16, x17, x29, x30 instead of the ip0 etc.

> +	REG_OFFSET_NAME(pstate),
> +	REG_OFFSET_NAME(ORIG_x0),
> +	REG_OFFSET_END,

Do we need orig_x0 of MAX_REG_OFFSET doesn't include it?

> +};
> +
> +/**
> + * regs_query_register_offset() - query register offset from its name
> + * @name:	the name of a register
> + *
> + * regs_query_register_offset() returns the offset of a register in struct
> + * pt_regs from its name. If the name is invalid, this returns -EINVAL;
> + */
> +int regs_query_register_offset(const char *name)
> +{
> +	const struct pt_regs_offset *roff;
> +
> +	for (roff = regoffset_table; roff->name != NULL; roff++)
> +		if (!strcmp(roff->name, name))
> +			return roff->offset;
> +	return -EINVAL;
> +}
> +
> +/**
> + * regs_query_register_name() - query register name from its offset
> + * @offset:	the offset of a register in struct pt_regs.
> + *
> + * regs_query_register_name() returns the name of a register from its
> + * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
> + */
> +const char *regs_query_register_name(unsigned int offset)
> +{
> +	const struct pt_regs_offset *roff;
> +
> +	for (roff = regoffset_table; roff->name != NULL; roff++)
> +		if (roff->offset == offset)
> +			return roff->name;
> +	return NULL;
> +}

BTW, these functions together with the pt_regs_offset structure look the
same on the other architectures. Can we move them to some common header
to avoid duplication (e.g. linux/ptrace.h)?

> +
> +/**
> + * regs_within_kernel_stack() - check the address in the stack
> + * @regs:      pt_regs which contains kernel stack pointer.
> + * @addr:      address which is checked.
> + *
> + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
> + * If @addr is within the kernel stack, it returns true. If not, returns false.
> + */
> +bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
> +{
> +	return ((addr & ~(THREAD_SIZE - 1))  ==
> +		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
> +}
> +
> +/**
> + * regs_get_kernel_stack_nth() - get Nth entry of the stack
> + * @regs:	pt_regs which contains kernel stack pointer.
> + * @n:		stack entry number.
> + *
> + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
> + * is specified by @regs. If the @n th entry is NOT in the kernel stack,
> + * this returns 0.
> + */
> +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
> +{
> +	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
> +
> +	addr += n;
> +	if (regs_within_kernel_stack(regs, (unsigned long)addr))
> +		return *addr;
> +	else
> +		return 0;
> +}

Same here.

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
@ 2015-05-20 13:39     ` Catalin Marinas
  0 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-20 13:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
> index 6913643..58c0223 100644
> --- a/arch/arm64/include/uapi/asm/ptrace.h
> +++ b/arch/arm64/include/uapi/asm/ptrace.h
> @@ -61,6 +61,42 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +#define ARM_pstate	pstate
> +#define ARM_pc		pc
> +#define ARM_sp		sp
> +#define ARM_lr		regs[30]
> +#define ARM_fp		regs[29]
> +#define ARM_x28		regs[28]
> +#define ARM_x27		regs[27]
> +#define ARM_x26		regs[26]
> +#define ARM_x25		regs[25]
> +#define ARM_x24		regs[24]
> +#define ARM_x23		regs[23]
> +#define ARM_x22		regs[22]
> +#define ARM_x21		regs[21]
> +#define ARM_x20		regs[20]
> +#define ARM_x19		regs[19]
> +#define ARM_x18		regs[18]
> +#define ARM_ip1		regs[17]
> +#define ARM_ip0		regs[16]
> +#define ARM_x15		regs[15]
> +#define ARM_x14		regs[14]
> +#define ARM_x13		regs[13]
> +#define ARM_x12		regs[12]
> +#define ARM_x11		regs[11]
> +#define ARM_x10		regs[10]
> +#define ARM_x9		regs[9]
> +#define ARM_x8		regs[8]
> +#define ARM_x7		regs[7]
> +#define ARM_x6		regs[6]
> +#define ARM_x5		regs[5]
> +#define ARM_x4		regs[4]
> +#define ARM_x3		regs[3]
> +#define ARM_x2		regs[2]
> +#define ARM_x1		regs[1]
> +#define ARM_x0		regs[0]
> +#define ARM_ORIG_x0	orig_x0

I replied some time ago on this part. I don't see the point these
macros.

> +
>  /*
>   * User structures for general purpose, floating point and debug registers.
>   */
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index d882b83..a889f79 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -48,6 +48,122 @@
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/syscalls.h>
>  
> +struct pt_regs_offset {
> +	const char *name;
> +	int offset;
> +};
> +
> +#define REG_OFFSET_NAME(r) \
> +	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}

Can you not just use "offsetof(struct pt_regs, r)" here? That would be
the same as x86, powerpc.

> +#define REG_OFFSET_END {.name = NULL, .offset = 0}
> +
> +static const struct pt_regs_offset regoffset_table[] = {
> +	REG_OFFSET_NAME(x0),
> +	REG_OFFSET_NAME(x1),
> +	REG_OFFSET_NAME(x2),
> +	REG_OFFSET_NAME(x3),
> +	REG_OFFSET_NAME(x4),
> +	REG_OFFSET_NAME(x5),
> +	REG_OFFSET_NAME(x6),
> +	REG_OFFSET_NAME(x7),
> +	REG_OFFSET_NAME(x8),
> +	REG_OFFSET_NAME(x9),
> +	REG_OFFSET_NAME(x10),
> +	REG_OFFSET_NAME(x11),
> +	REG_OFFSET_NAME(x12),
> +	REG_OFFSET_NAME(x13),
> +	REG_OFFSET_NAME(x14),
> +	REG_OFFSET_NAME(x15),
> +	REG_OFFSET_NAME(ip0),
> +	REG_OFFSET_NAME(ip1),
> +	REG_OFFSET_NAME(x18),
> +	REG_OFFSET_NAME(x19),
> +	REG_OFFSET_NAME(x20),
> +	REG_OFFSET_NAME(x21),
> +	REG_OFFSET_NAME(x22),
> +	REG_OFFSET_NAME(x23),
> +	REG_OFFSET_NAME(x24),
> +	REG_OFFSET_NAME(x25),
> +	REG_OFFSET_NAME(x26),
> +	REG_OFFSET_NAME(x27),
> +	REG_OFFSET_NAME(x28),
> +	REG_OFFSET_NAME(fp),
> +	REG_OFFSET_NAME(lr),
> +	REG_OFFSET_NAME(sp),
> +	REG_OFFSET_NAME(pc),

and stick to x16, x17, x29, x30 instead of the ip0 etc.

> +	REG_OFFSET_NAME(pstate),
> +	REG_OFFSET_NAME(ORIG_x0),
> +	REG_OFFSET_END,

Do we need orig_x0 of MAX_REG_OFFSET doesn't include it?

> +};
> +
> +/**
> + * regs_query_register_offset() - query register offset from its name
> + * @name:	the name of a register
> + *
> + * regs_query_register_offset() returns the offset of a register in struct
> + * pt_regs from its name. If the name is invalid, this returns -EINVAL;
> + */
> +int regs_query_register_offset(const char *name)
> +{
> +	const struct pt_regs_offset *roff;
> +
> +	for (roff = regoffset_table; roff->name != NULL; roff++)
> +		if (!strcmp(roff->name, name))
> +			return roff->offset;
> +	return -EINVAL;
> +}
> +
> +/**
> + * regs_query_register_name() - query register name from its offset
> + * @offset:	the offset of a register in struct pt_regs.
> + *
> + * regs_query_register_name() returns the name of a register from its
> + * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
> + */
> +const char *regs_query_register_name(unsigned int offset)
> +{
> +	const struct pt_regs_offset *roff;
> +
> +	for (roff = regoffset_table; roff->name != NULL; roff++)
> +		if (roff->offset == offset)
> +			return roff->name;
> +	return NULL;
> +}

BTW, these functions together with the pt_regs_offset structure look the
same on the other architectures. Can we move them to some common header
to avoid duplication (e.g. linux/ptrace.h)?

> +
> +/**
> + * regs_within_kernel_stack() - check the address in the stack
> + * @regs:      pt_regs which contains kernel stack pointer.
> + * @addr:      address which is checked.
> + *
> + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
> + * If @addr is within the kernel stack, it returns true. If not, returns false.
> + */
> +bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
> +{
> +	return ((addr & ~(THREAD_SIZE - 1))  ==
> +		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
> +}
> +
> +/**
> + * regs_get_kernel_stack_nth() - get Nth entry of the stack
> + * @regs:	pt_regs which contains kernel stack pointer.
> + * @n:		stack entry number.
> + *
> + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
> + * is specified by @regs. If the @n th entry is NOT in the kernel stack,
> + * this returns 0.
> + */
> +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
> +{
> +	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
> +
> +	addr += n;
> +	if (regs_within_kernel_stack(regs, (unsigned long)addr))
> +		return *addr;
> +	else
> +		return 0;
> +}

Same here.

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-04-20 20:19   ` David Long
@ 2015-05-20 16:39     ` Catalin Marinas
  -1 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-20 16:39 UTC (permalink / raw)
  To: David Long
  Cc: linux-arm-kernel, Russell King, Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, Masami Hiramatsu,
	sandeepa.s.prabhu, William Cohen, davem

On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
> Add support for basic kernel probes(kprobes) and jump probes
> (jprobes) for ARM64.
> 
> Kprobes utilizes software breakpoint and single step debug
> exceptions supported on ARM v8.
> 
> A software breakpoint is placed at the probe address to trap the
> kernel execution into the kprobe handler.
> 
> ARM v8 supports enabling single stepping before the break exception
> return (ERET), with next PC in exception return address (ELR_EL1). The
> kprobe handler prepares an executable memory slot for out-of-line
> execution with a copy of the original instruction being probed, and
> enables single stepping. The PC is set to the out-of-line slot address
> before the ERET. With this scheme, the instruction is executed with the
> exact same register context except for the PC (and DAIF) registers.

I wonder whether it would be simpler to use another software breakpoint
after the out of line instruction copy. You won't run the instructions
that change the PC anyway.

Since an unconditional branch instruction within the kernel address
space can reach any point in the kernel (and modules), could we go a
step further and avoid the software breakpoint altogether, just generate
a branch instruction to the original location (after the software
breakpoint)?

As for simulating/emulating instructions, could we actually avoid it for
most of them where we can generate a similar instruction with the
corrected offset? If the out of line slot is somewhere within the kernel
data section, I think many of them can be re-encoded (e.g. branches).

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-05-20 16:39     ` Catalin Marinas
  0 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-20 16:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
> Add support for basic kernel probes(kprobes) and jump probes
> (jprobes) for ARM64.
> 
> Kprobes utilizes software breakpoint and single step debug
> exceptions supported on ARM v8.
> 
> A software breakpoint is placed at the probe address to trap the
> kernel execution into the kprobe handler.
> 
> ARM v8 supports enabling single stepping before the break exception
> return (ERET), with next PC in exception return address (ELR_EL1). The
> kprobe handler prepares an executable memory slot for out-of-line
> execution with a copy of the original instruction being probed, and
> enables single stepping. The PC is set to the out-of-line slot address
> before the ERET. With this scheme, the instruction is executed with the
> exact same register context except for the PC (and DAIF) registers.

I wonder whether it would be simpler to use another software breakpoint
after the out of line instruction copy. You won't run the instructions
that change the PC anyway.

Since an unconditional branch instruction within the kernel address
space can reach any point in the kernel (and modules), could we go a
step further and avoid the software breakpoint altogether, just generate
a branch instruction to the original location (after the software
breakpoint)?

As for simulating/emulating instructions, could we actually avoid it for
most of them where we can generate a similar instruction with the
corrected offset? If the out of line slot is somewhere within the kernel
data section, I think many of them can be re-encoded (e.g. branches).

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  2015-05-20 13:39     ` Catalin Marinas
@ 2015-05-21  3:29       ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-21  3:29 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: linux-arm-kernel, Russell King, Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, Masami Hiramatsu,
	sandeepa.s.prabhu, William Cohen, davem

On 05/20/15 09:39, Catalin Marinas wrote:
> On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
>> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
>> index 6913643..58c0223 100644
>> --- a/arch/arm64/include/uapi/asm/ptrace.h
>> +++ b/arch/arm64/include/uapi/asm/ptrace.h
>> @@ -61,6 +61,42 @@
>>
>>   #ifndef __ASSEMBLY__
>>
>> +#define ARM_pstate	pstate
>> +#define ARM_pc		pc
>> +#define ARM_sp		sp
>> +#define ARM_lr		regs[30]
>> +#define ARM_fp		regs[29]
>> +#define ARM_x28		regs[28]
>> +#define ARM_x27		regs[27]
>> +#define ARM_x26		regs[26]
>> +#define ARM_x25		regs[25]
>> +#define ARM_x24		regs[24]
>> +#define ARM_x23		regs[23]
>> +#define ARM_x22		regs[22]
>> +#define ARM_x21		regs[21]
>> +#define ARM_x20		regs[20]
>> +#define ARM_x19		regs[19]
>> +#define ARM_x18		regs[18]
>> +#define ARM_ip1		regs[17]
>> +#define ARM_ip0		regs[16]
>> +#define ARM_x15		regs[15]
>> +#define ARM_x14		regs[14]
>> +#define ARM_x13		regs[13]
>> +#define ARM_x12		regs[12]
>> +#define ARM_x11		regs[11]
>> +#define ARM_x10		regs[10]
>> +#define ARM_x9		regs[9]
>> +#define ARM_x8		regs[8]
>> +#define ARM_x7		regs[7]
>> +#define ARM_x6		regs[6]
>> +#define ARM_x5		regs[5]
>> +#define ARM_x4		regs[4]
>> +#define ARM_x3		regs[3]
>> +#define ARM_x2		regs[2]
>> +#define ARM_x1		regs[1]
>> +#define ARM_x0		regs[0]
>> +#define ARM_ORIG_x0	orig_x0
>
> I replied some time ago on this part. I don't see the point these
> macros.
>

I replied belatedly on April 20 saying what I did matches (more or less) 
how it's done on various other platforms, including arm and powerpc.  It 
looks like this comes from the pt_regs structure defining the registers 
as an array instead of a list of structure fields. It looks to me like 
that design choice is pretty widely depended upon now and would be quite 
disruptive to change.  It also seems to me a relatively clean way to do 
it on systems with a uniform register set.

>> +
>>   /*
>>    * User structures for general purpose, floating point and debug registers.
>>    */
>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>> index d882b83..a889f79 100644
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -48,6 +48,122 @@
>>   #define CREATE_TRACE_POINTS
>>   #include <trace/events/syscalls.h>
>>
>> +struct pt_regs_offset {
>> +	const char *name;
>> +	int offset;
>> +};
>> +
>> +#define REG_OFFSET_NAME(r) \
>> +	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
>
> Can you not just use "offsetof(struct pt_regs, r)" here? That would be
> the same as x86, powerpc.
>

The registers (except for pc, pstate, and sp) are not separate structure 
fields, they are slots in a single array. To reference them the symbolic 
name has to be converted to an index (integer register number) somehow.

>> +#define REG_OFFSET_END {.name = NULL, .offset = 0}
>> +
>> +static const struct pt_regs_offset regoffset_table[] = {
>> +	REG_OFFSET_NAME(x0),
>> +	REG_OFFSET_NAME(x1),
>> +	REG_OFFSET_NAME(x2),
>> +	REG_OFFSET_NAME(x3),
>> +	REG_OFFSET_NAME(x4),
>> +	REG_OFFSET_NAME(x5),
>> +	REG_OFFSET_NAME(x6),
>> +	REG_OFFSET_NAME(x7),
>> +	REG_OFFSET_NAME(x8),
>> +	REG_OFFSET_NAME(x9),
>> +	REG_OFFSET_NAME(x10),
>> +	REG_OFFSET_NAME(x11),
>> +	REG_OFFSET_NAME(x12),
>> +	REG_OFFSET_NAME(x13),
>> +	REG_OFFSET_NAME(x14),
>> +	REG_OFFSET_NAME(x15),
>> +	REG_OFFSET_NAME(ip0),
>> +	REG_OFFSET_NAME(ip1),
>> +	REG_OFFSET_NAME(x18),
>> +	REG_OFFSET_NAME(x19),
>> +	REG_OFFSET_NAME(x20),
>> +	REG_OFFSET_NAME(x21),
>> +	REG_OFFSET_NAME(x22),
>> +	REG_OFFSET_NAME(x23),
>> +	REG_OFFSET_NAME(x24),
>> +	REG_OFFSET_NAME(x25),
>> +	REG_OFFSET_NAME(x26),
>> +	REG_OFFSET_NAME(x27),
>> +	REG_OFFSET_NAME(x28),
>> +	REG_OFFSET_NAME(fp),
>> +	REG_OFFSET_NAME(lr),
>> +	REG_OFFSET_NAME(sp),
>> +	REG_OFFSET_NAME(pc),
>
> and stick to x16, x17, x29, x30 instead of the ip0 etc.
>

OK.

>> +	REG_OFFSET_NAME(pstate),
>> +	REG_OFFSET_NAME(ORIG_x0),
>> +	REG_OFFSET_END,
>
> Do we need orig_x0 of MAX_REG_OFFSET doesn't include it?
>

I think this should indeed be removed.

>> +};
>> +
>> +/**
>> + * regs_query_register_offset() - query register offset from its name
>> + * @name:	the name of a register
>> + *
>> + * regs_query_register_offset() returns the offset of a register in struct
>> + * pt_regs from its name. If the name is invalid, this returns -EINVAL;
>> + */
>> +int regs_query_register_offset(const char *name)
>> +{
>> +	const struct pt_regs_offset *roff;
>> +
>> +	for (roff = regoffset_table; roff->name != NULL; roff++)
>> +		if (!strcmp(roff->name, name))
>> +			return roff->offset;
>> +	return -EINVAL;
>> +}
>> +
>> +/**
>> + * regs_query_register_name() - query register name from its offset
>> + * @offset:	the offset of a register in struct pt_regs.
>> + *
>> + * regs_query_register_name() returns the name of a register from its
>> + * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
>> + */
>> +const char *regs_query_register_name(unsigned int offset)
>> +{
>> +	const struct pt_regs_offset *roff;
>> +
>> +	for (roff = regoffset_table; roff->name != NULL; roff++)
>> +		if (roff->offset == offset)
>> +			return roff->name;
>> +	return NULL;
>> +}
>
> BTW, these functions together with the pt_regs_offset structure look the
> same on the other architectures. Can we move them to some common header
> to avoid duplication (e.g. linux/ptrace.h)?
>

Common header *and* .c files?  Yes, I see your point.

>> +
>> +/**
>> + * regs_within_kernel_stack() - check the address in the stack
>> + * @regs:      pt_regs which contains kernel stack pointer.
>> + * @addr:      address which is checked.
>> + *
>> + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
>> + * If @addr is within the kernel stack, it returns true. If not, returns false.
>> + */
>> +bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
>> +{
>> +	return ((addr & ~(THREAD_SIZE - 1))  ==
>> +		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
>> +}
>> +
>> +/**
>> + * regs_get_kernel_stack_nth() - get Nth entry of the stack
>> + * @regs:	pt_regs which contains kernel stack pointer.
>> + * @n:		stack entry number.
>> + *
>> + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
>> + * is specified by @regs. If the @n th entry is NOT in the kernel stack,
>> + * this returns 0.
>> + */
>> +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
>> +{
>> +	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
>> +
>> +	addr += n;
>> +	if (regs_within_kernel_stack(regs, (unsigned long)addr))
>> +		return *addr;
>> +	else
>> +		return 0;
>> +}
>
> Same here.
>

Also makes sense and looks doable.


-dl


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
@ 2015-05-21  3:29       ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-21  3:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/20/15 09:39, Catalin Marinas wrote:
> On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
>> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
>> index 6913643..58c0223 100644
>> --- a/arch/arm64/include/uapi/asm/ptrace.h
>> +++ b/arch/arm64/include/uapi/asm/ptrace.h
>> @@ -61,6 +61,42 @@
>>
>>   #ifndef __ASSEMBLY__
>>
>> +#define ARM_pstate	pstate
>> +#define ARM_pc		pc
>> +#define ARM_sp		sp
>> +#define ARM_lr		regs[30]
>> +#define ARM_fp		regs[29]
>> +#define ARM_x28		regs[28]
>> +#define ARM_x27		regs[27]
>> +#define ARM_x26		regs[26]
>> +#define ARM_x25		regs[25]
>> +#define ARM_x24		regs[24]
>> +#define ARM_x23		regs[23]
>> +#define ARM_x22		regs[22]
>> +#define ARM_x21		regs[21]
>> +#define ARM_x20		regs[20]
>> +#define ARM_x19		regs[19]
>> +#define ARM_x18		regs[18]
>> +#define ARM_ip1		regs[17]
>> +#define ARM_ip0		regs[16]
>> +#define ARM_x15		regs[15]
>> +#define ARM_x14		regs[14]
>> +#define ARM_x13		regs[13]
>> +#define ARM_x12		regs[12]
>> +#define ARM_x11		regs[11]
>> +#define ARM_x10		regs[10]
>> +#define ARM_x9		regs[9]
>> +#define ARM_x8		regs[8]
>> +#define ARM_x7		regs[7]
>> +#define ARM_x6		regs[6]
>> +#define ARM_x5		regs[5]
>> +#define ARM_x4		regs[4]
>> +#define ARM_x3		regs[3]
>> +#define ARM_x2		regs[2]
>> +#define ARM_x1		regs[1]
>> +#define ARM_x0		regs[0]
>> +#define ARM_ORIG_x0	orig_x0
>
> I replied some time ago on this part. I don't see the point these
> macros.
>

I replied belatedly on April 20 saying what I did matches (more or less) 
how it's done on various other platforms, including arm and powerpc.  It 
looks like this comes from the pt_regs structure defining the registers 
as an array instead of a list of structure fields. It looks to me like 
that design choice is pretty widely depended upon now and would be quite 
disruptive to change.  It also seems to me a relatively clean way to do 
it on systems with a uniform register set.

>> +
>>   /*
>>    * User structures for general purpose, floating point and debug registers.
>>    */
>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>> index d882b83..a889f79 100644
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -48,6 +48,122 @@
>>   #define CREATE_TRACE_POINTS
>>   #include <trace/events/syscalls.h>
>>
>> +struct pt_regs_offset {
>> +	const char *name;
>> +	int offset;
>> +};
>> +
>> +#define REG_OFFSET_NAME(r) \
>> +	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
>
> Can you not just use "offsetof(struct pt_regs, r)" here? That would be
> the same as x86, powerpc.
>

The registers (except for pc, pstate, and sp) are not separate structure 
fields, they are slots in a single array. To reference them the symbolic 
name has to be converted to an index (integer register number) somehow.

>> +#define REG_OFFSET_END {.name = NULL, .offset = 0}
>> +
>> +static const struct pt_regs_offset regoffset_table[] = {
>> +	REG_OFFSET_NAME(x0),
>> +	REG_OFFSET_NAME(x1),
>> +	REG_OFFSET_NAME(x2),
>> +	REG_OFFSET_NAME(x3),
>> +	REG_OFFSET_NAME(x4),
>> +	REG_OFFSET_NAME(x5),
>> +	REG_OFFSET_NAME(x6),
>> +	REG_OFFSET_NAME(x7),
>> +	REG_OFFSET_NAME(x8),
>> +	REG_OFFSET_NAME(x9),
>> +	REG_OFFSET_NAME(x10),
>> +	REG_OFFSET_NAME(x11),
>> +	REG_OFFSET_NAME(x12),
>> +	REG_OFFSET_NAME(x13),
>> +	REG_OFFSET_NAME(x14),
>> +	REG_OFFSET_NAME(x15),
>> +	REG_OFFSET_NAME(ip0),
>> +	REG_OFFSET_NAME(ip1),
>> +	REG_OFFSET_NAME(x18),
>> +	REG_OFFSET_NAME(x19),
>> +	REG_OFFSET_NAME(x20),
>> +	REG_OFFSET_NAME(x21),
>> +	REG_OFFSET_NAME(x22),
>> +	REG_OFFSET_NAME(x23),
>> +	REG_OFFSET_NAME(x24),
>> +	REG_OFFSET_NAME(x25),
>> +	REG_OFFSET_NAME(x26),
>> +	REG_OFFSET_NAME(x27),
>> +	REG_OFFSET_NAME(x28),
>> +	REG_OFFSET_NAME(fp),
>> +	REG_OFFSET_NAME(lr),
>> +	REG_OFFSET_NAME(sp),
>> +	REG_OFFSET_NAME(pc),
>
> and stick to x16, x17, x29, x30 instead of the ip0 etc.
>

OK.

>> +	REG_OFFSET_NAME(pstate),
>> +	REG_OFFSET_NAME(ORIG_x0),
>> +	REG_OFFSET_END,
>
> Do we need orig_x0 of MAX_REG_OFFSET doesn't include it?
>

I think this should indeed be removed.

>> +};
>> +
>> +/**
>> + * regs_query_register_offset() - query register offset from its name
>> + * @name:	the name of a register
>> + *
>> + * regs_query_register_offset() returns the offset of a register in struct
>> + * pt_regs from its name. If the name is invalid, this returns -EINVAL;
>> + */
>> +int regs_query_register_offset(const char *name)
>> +{
>> +	const struct pt_regs_offset *roff;
>> +
>> +	for (roff = regoffset_table; roff->name != NULL; roff++)
>> +		if (!strcmp(roff->name, name))
>> +			return roff->offset;
>> +	return -EINVAL;
>> +}
>> +
>> +/**
>> + * regs_query_register_name() - query register name from its offset
>> + * @offset:	the offset of a register in struct pt_regs.
>> + *
>> + * regs_query_register_name() returns the name of a register from its
>> + * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
>> + */
>> +const char *regs_query_register_name(unsigned int offset)
>> +{
>> +	const struct pt_regs_offset *roff;
>> +
>> +	for (roff = regoffset_table; roff->name != NULL; roff++)
>> +		if (roff->offset == offset)
>> +			return roff->name;
>> +	return NULL;
>> +}
>
> BTW, these functions together with the pt_regs_offset structure look the
> same on the other architectures. Can we move them to some common header
> to avoid duplication (e.g. linux/ptrace.h)?
>

Common header *and* .c files?  Yes, I see your point.

>> +
>> +/**
>> + * regs_within_kernel_stack() - check the address in the stack
>> + * @regs:      pt_regs which contains kernel stack pointer.
>> + * @addr:      address which is checked.
>> + *
>> + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
>> + * If @addr is within the kernel stack, it returns true. If not, returns false.
>> + */
>> +bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
>> +{
>> +	return ((addr & ~(THREAD_SIZE - 1))  ==
>> +		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
>> +}
>> +
>> +/**
>> + * regs_get_kernel_stack_nth() - get Nth entry of the stack
>> + * @regs:	pt_regs which contains kernel stack pointer.
>> + * @n:		stack entry number.
>> + *
>> + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
>> + * is specified by @regs. If the @n th entry is NOT in the kernel stack,
>> + * this returns 0.
>> + */
>> +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
>> +{
>> +	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
>> +
>> +	addr += n;
>> +	if (regs_within_kernel_stack(regs, (unsigned long)addr))
>> +		return *addr;
>> +	else
>> +		return 0;
>> +}
>
> Same here.
>

Also makes sense and looks doable.


-dl

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-05-20 16:39     ` Catalin Marinas
@ 2015-05-21  4:44       ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-21  4:44 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: linux-arm-kernel, Russell King, Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, Masami Hiramatsu,
	sandeepa.s.prabhu, William Cohen, davem

On 05/20/15 12:39, Catalin Marinas wrote:
> On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
>> Add support for basic kernel probes(kprobes) and jump probes
>> (jprobes) for ARM64.
>>
>> Kprobes utilizes software breakpoint and single step debug
>> exceptions supported on ARM v8.
>>
>> A software breakpoint is placed at the probe address to trap the
>> kernel execution into the kprobe handler.
>>
>> ARM v8 supports enabling single stepping before the break exception
>> return (ERET), with next PC in exception return address (ELR_EL1). The
>> kprobe handler prepares an executable memory slot for out-of-line
>> execution with a copy of the original instruction being probed, and
>> enables single stepping. The PC is set to the out-of-line slot address
>> before the ERET. With this scheme, the instruction is executed with the
>> exact same register context except for the PC (and DAIF) registers.
>
> I wonder whether it would be simpler to use another software breakpoint
> after the out of line instruction copy. You won't run the instructions
> that change the PC anyway.

We put quite a bit of work into making single-step work.  I don't see 
any obvious advantage to trying to switch to a software breakpoint. 
Both are debug exceptions but SS does leave open the possibility of 
maybe eventually running some instructions that do change the PC.

>
> Since an unconditional branch instruction within the kernel address
> space can reach any point in the kernel (and modules), could we go a
> step further and avoid the software breakpoint altogether, just generate
> a branch instruction to the original location (after the software
> breakpoint)?

Wouldn't a branch instruction have to make use of a register in order to 
span the whole address space?  How could you do that and have all the 
registers unmolested when you land back after the original probe point? 
  The thing that really kills this though is the fact we need to be able 
to run the pre and post functions before and *after* the XOL stepping.

>
> As for simulating/emulating instructions, could we actually avoid it for
> most of them where we can generate a similar instruction with the
> corrected offset? If the out of line slot is somewhere within the kernel
> data section, I think many of them can be re-encoded (e.g. branches).
>

Again, do we get enough displacement for this to always work?  A quick 
look at the ARMv8 ARM makes me think we get +/-128M offset for a branch 
and only +/-1M for a load literal.  For any given instruction type I 
don't think it works unless it works for all possible offsets.

-dl


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-05-21  4:44       ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-21  4:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/20/15 12:39, Catalin Marinas wrote:
> On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
>> Add support for basic kernel probes(kprobes) and jump probes
>> (jprobes) for ARM64.
>>
>> Kprobes utilizes software breakpoint and single step debug
>> exceptions supported on ARM v8.
>>
>> A software breakpoint is placed at the probe address to trap the
>> kernel execution into the kprobe handler.
>>
>> ARM v8 supports enabling single stepping before the break exception
>> return (ERET), with next PC in exception return address (ELR_EL1). The
>> kprobe handler prepares an executable memory slot for out-of-line
>> execution with a copy of the original instruction being probed, and
>> enables single stepping. The PC is set to the out-of-line slot address
>> before the ERET. With this scheme, the instruction is executed with the
>> exact same register context except for the PC (and DAIF) registers.
>
> I wonder whether it would be simpler to use another software breakpoint
> after the out of line instruction copy. You won't run the instructions
> that change the PC anyway.

We put quite a bit of work into making single-step work.  I don't see 
any obvious advantage to trying to switch to a software breakpoint. 
Both are debug exceptions but SS does leave open the possibility of 
maybe eventually running some instructions that do change the PC.

>
> Since an unconditional branch instruction within the kernel address
> space can reach any point in the kernel (and modules), could we go a
> step further and avoid the software breakpoint altogether, just generate
> a branch instruction to the original location (after the software
> breakpoint)?

Wouldn't a branch instruction have to make use of a register in order to 
span the whole address space?  How could you do that and have all the 
registers unmolested when you land back after the original probe point? 
  The thing that really kills this though is the fact we need to be able 
to run the pre and post functions before and *after* the XOL stepping.

>
> As for simulating/emulating instructions, could we actually avoid it for
> most of them where we can generate a similar instruction with the
> corrected offset? If the out of line slot is somewhere within the kernel
> data section, I think many of them can be re-encoded (e.g. branches).
>

Again, do we get enough displacement for this to always work?  A quick 
look at the ARMv8 ARM makes me think we get +/-128M offset for a branch 
and only +/-1M for a load literal.  For any given instruction type I 
don't think it works unless it works for all possible offsets.

-dl

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  2015-05-21  3:29       ` David Long
@ 2015-05-21 17:55         ` Catalin Marinas
  -1 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-21 17:55 UTC (permalink / raw)
  To: David Long
  Cc: Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, sandeepa.s.prabhu,
	Masami Hiramatsu, Russell King, William Cohen, davem,
	linux-arm-kernel

On Wed, May 20, 2015 at 11:29:24PM -0400, David Long wrote:
> On 05/20/15 09:39, Catalin Marinas wrote:
> >On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
> >>diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
> >>index 6913643..58c0223 100644
> >>--- a/arch/arm64/include/uapi/asm/ptrace.h
> >>+++ b/arch/arm64/include/uapi/asm/ptrace.h
> >>@@ -61,6 +61,42 @@
> >>
> >>  #ifndef __ASSEMBLY__
> >>
> >>+#define ARM_pstate	pstate
> >>+#define ARM_pc		pc
> >>+#define ARM_sp		sp
> >>+#define ARM_lr		regs[30]
> >>+#define ARM_fp		regs[29]
> >>+#define ARM_x28		regs[28]
> >>+#define ARM_x27		regs[27]
> >>+#define ARM_x26		regs[26]
> >>+#define ARM_x25		regs[25]
> >>+#define ARM_x24		regs[24]
> >>+#define ARM_x23		regs[23]
> >>+#define ARM_x22		regs[22]
> >>+#define ARM_x21		regs[21]
> >>+#define ARM_x20		regs[20]
> >>+#define ARM_x19		regs[19]
> >>+#define ARM_x18		regs[18]
> >>+#define ARM_ip1		regs[17]
> >>+#define ARM_ip0		regs[16]
> >>+#define ARM_x15		regs[15]
> >>+#define ARM_x14		regs[14]
> >>+#define ARM_x13		regs[13]
> >>+#define ARM_x12		regs[12]
> >>+#define ARM_x11		regs[11]
> >>+#define ARM_x10		regs[10]
> >>+#define ARM_x9		regs[9]
> >>+#define ARM_x8		regs[8]
> >>+#define ARM_x7		regs[7]
> >>+#define ARM_x6		regs[6]
> >>+#define ARM_x5		regs[5]
> >>+#define ARM_x4		regs[4]
> >>+#define ARM_x3		regs[3]
> >>+#define ARM_x2		regs[2]
> >>+#define ARM_x1		regs[1]
> >>+#define ARM_x0		regs[0]
> >>+#define ARM_ORIG_x0	orig_x0
> >
> >I replied some time ago on this part. I don't see the point these
> >macros.
> 
> I replied belatedly on April 20 saying what I did matches (more or less) how
> it's done on various other platforms, including arm and powerpc.
> It looks like this comes from the pt_regs structure defining the
> registers as an array instead of a list of structure fields. It looks
> to me like that design choice is pretty widely depended upon now and
> would be quite disruptive to change.  It also seems to me a relatively
> clean way to do it on systems with a uniform register set.

I see why we need to cope with the regs[] array but why do we need these
definitions in a uapi file?

> >>+
> >>  /*
> >>   * User structures for general purpose, floating point and debug registers.
> >>   */
> >>diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> >>index d882b83..a889f79 100644
> >>--- a/arch/arm64/kernel/ptrace.c
> >>+++ b/arch/arm64/kernel/ptrace.c
> >>@@ -48,6 +48,122 @@
> >>  #define CREATE_TRACE_POINTS
> >>  #include <trace/events/syscalls.h>
> >>
> >>+struct pt_regs_offset {
> >>+	const char *name;
> >>+	int offset;
> >>+};
> >>+
> >>+#define REG_OFFSET_NAME(r) \
> >>+	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
> 
> >Can you not just use "offsetof(struct pt_regs, r)" here? That would be
> >the same as x86, powerpc.
> 
> The registers (except for pc, pstate, and sp) are not separate structure
> fields, they are slots in a single array. To reference them the symbolic
> name has to be converted to an index (integer register number) somehow.

Can we not keep them local to this file, say __reg_x0 etc. (something to
make it clear they are for internal use)?

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
@ 2015-05-21 17:55         ` Catalin Marinas
  0 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-21 17:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 20, 2015 at 11:29:24PM -0400, David Long wrote:
> On 05/20/15 09:39, Catalin Marinas wrote:
> >On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
> >>diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
> >>index 6913643..58c0223 100644
> >>--- a/arch/arm64/include/uapi/asm/ptrace.h
> >>+++ b/arch/arm64/include/uapi/asm/ptrace.h
> >>@@ -61,6 +61,42 @@
> >>
> >>  #ifndef __ASSEMBLY__
> >>
> >>+#define ARM_pstate	pstate
> >>+#define ARM_pc		pc
> >>+#define ARM_sp		sp
> >>+#define ARM_lr		regs[30]
> >>+#define ARM_fp		regs[29]
> >>+#define ARM_x28		regs[28]
> >>+#define ARM_x27		regs[27]
> >>+#define ARM_x26		regs[26]
> >>+#define ARM_x25		regs[25]
> >>+#define ARM_x24		regs[24]
> >>+#define ARM_x23		regs[23]
> >>+#define ARM_x22		regs[22]
> >>+#define ARM_x21		regs[21]
> >>+#define ARM_x20		regs[20]
> >>+#define ARM_x19		regs[19]
> >>+#define ARM_x18		regs[18]
> >>+#define ARM_ip1		regs[17]
> >>+#define ARM_ip0		regs[16]
> >>+#define ARM_x15		regs[15]
> >>+#define ARM_x14		regs[14]
> >>+#define ARM_x13		regs[13]
> >>+#define ARM_x12		regs[12]
> >>+#define ARM_x11		regs[11]
> >>+#define ARM_x10		regs[10]
> >>+#define ARM_x9		regs[9]
> >>+#define ARM_x8		regs[8]
> >>+#define ARM_x7		regs[7]
> >>+#define ARM_x6		regs[6]
> >>+#define ARM_x5		regs[5]
> >>+#define ARM_x4		regs[4]
> >>+#define ARM_x3		regs[3]
> >>+#define ARM_x2		regs[2]
> >>+#define ARM_x1		regs[1]
> >>+#define ARM_x0		regs[0]
> >>+#define ARM_ORIG_x0	orig_x0
> >
> >I replied some time ago on this part. I don't see the point these
> >macros.
> 
> I replied belatedly on April 20 saying what I did matches (more or less) how
> it's done on various other platforms, including arm and powerpc.
> It looks like this comes from the pt_regs structure defining the
> registers as an array instead of a list of structure fields. It looks
> to me like that design choice is pretty widely depended upon now and
> would be quite disruptive to change.  It also seems to me a relatively
> clean way to do it on systems with a uniform register set.

I see why we need to cope with the regs[] array but why do we need these
definitions in a uapi file?

> >>+
> >>  /*
> >>   * User structures for general purpose, floating point and debug registers.
> >>   */
> >>diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> >>index d882b83..a889f79 100644
> >>--- a/arch/arm64/kernel/ptrace.c
> >>+++ b/arch/arm64/kernel/ptrace.c
> >>@@ -48,6 +48,122 @@
> >>  #define CREATE_TRACE_POINTS
> >>  #include <trace/events/syscalls.h>
> >>
> >>+struct pt_regs_offset {
> >>+	const char *name;
> >>+	int offset;
> >>+};
> >>+
> >>+#define REG_OFFSET_NAME(r) \
> >>+	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
> 
> >Can you not just use "offsetof(struct pt_regs, r)" here? That would be
> >the same as x86, powerpc.
> 
> The registers (except for pc, pstate, and sp) are not separate structure
> fields, they are slots in a single array. To reference them the symbolic
> name has to be converted to an index (integer register number) somehow.

Can we not keep them local to this file, say __reg_x0 etc. (something to
make it clear they are for internal use)?

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-05-21  4:44       ` David Long
@ 2015-05-22 11:00         ` Catalin Marinas
  -1 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-22 11:00 UTC (permalink / raw)
  To: David Long
  Cc: Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, sandeepa.s.prabhu,
	Masami Hiramatsu, Russell King, William Cohen, davem,
	linux-arm-kernel

On Thu, May 21, 2015 at 12:44:45AM -0400, David Long wrote:
> On 05/20/15 12:39, Catalin Marinas wrote:
> >On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
> >>Add support for basic kernel probes(kprobes) and jump probes
> >>(jprobes) for ARM64.
> >>
> >>Kprobes utilizes software breakpoint and single step debug
> >>exceptions supported on ARM v8.
> >>
> >>A software breakpoint is placed at the probe address to trap the
> >>kernel execution into the kprobe handler.
> >>
> >>ARM v8 supports enabling single stepping before the break exception
> >>return (ERET), with next PC in exception return address (ELR_EL1). The
> >>kprobe handler prepares an executable memory slot for out-of-line
> >>execution with a copy of the original instruction being probed, and
> >>enables single stepping. The PC is set to the out-of-line slot address
> >>before the ERET. With this scheme, the instruction is executed with the
> >>exact same register context except for the PC (and DAIF) registers.
> >
> >I wonder whether it would be simpler to use another software breakpoint
> >after the out of line instruction copy. You won't run the instructions
> >that change the PC anyway.
> 
> We put quite a bit of work into making single-step work.  I don't see any
> obvious advantage to trying to switch to a software breakpoint. Both are
> debug exceptions but SS does leave open the possibility of maybe eventually
> running some instructions that do change the PC.

I'm not trying to get this re-written, just as a potential workaround
for the unexpected single-step error reported but I need to read some
more before I understand it properly (and I can see patches already for
fixing this).

> >Since an unconditional branch instruction within the kernel address
> >space can reach any point in the kernel (and modules), could we go a
> >step further and avoid the software breakpoint altogether, just generate
> >a branch instruction to the original location (after the software
> >breakpoint)?
> 
> Wouldn't a branch instruction have to make use of a register in order to
> span the whole address space?  How could you do that and have all the
> registers unmolested when you land back after the original probe point?  The
> thing that really kills this though is the fact we need to be able to run
> the pre and post functions before and *after* the XOL stepping.

A "b #imm" would be able to cover a wide range (+/-128MB), but, as you
said, it doesn't help with the post function call.

Any plans to post an updated version with the "unexpected single-step
error" fixed?

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-05-22 11:00         ` Catalin Marinas
  0 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-22 11:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 21, 2015 at 12:44:45AM -0400, David Long wrote:
> On 05/20/15 12:39, Catalin Marinas wrote:
> >On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
> >>Add support for basic kernel probes(kprobes) and jump probes
> >>(jprobes) for ARM64.
> >>
> >>Kprobes utilizes software breakpoint and single step debug
> >>exceptions supported on ARM v8.
> >>
> >>A software breakpoint is placed at the probe address to trap the
> >>kernel execution into the kprobe handler.
> >>
> >>ARM v8 supports enabling single stepping before the break exception
> >>return (ERET), with next PC in exception return address (ELR_EL1). The
> >>kprobe handler prepares an executable memory slot for out-of-line
> >>execution with a copy of the original instruction being probed, and
> >>enables single stepping. The PC is set to the out-of-line slot address
> >>before the ERET. With this scheme, the instruction is executed with the
> >>exact same register context except for the PC (and DAIF) registers.
> >
> >I wonder whether it would be simpler to use another software breakpoint
> >after the out of line instruction copy. You won't run the instructions
> >that change the PC anyway.
> 
> We put quite a bit of work into making single-step work.  I don't see any
> obvious advantage to trying to switch to a software breakpoint. Both are
> debug exceptions but SS does leave open the possibility of maybe eventually
> running some instructions that do change the PC.

I'm not trying to get this re-written, just as a potential workaround
for the unexpected single-step error reported but I need to read some
more before I understand it properly (and I can see patches already for
fixing this).

> >Since an unconditional branch instruction within the kernel address
> >space can reach any point in the kernel (and modules), could we go a
> >step further and avoid the software breakpoint altogether, just generate
> >a branch instruction to the original location (after the software
> >breakpoint)?
> 
> Wouldn't a branch instruction have to make use of a register in order to
> span the whole address space?  How could you do that and have all the
> registers unmolested when you land back after the original probe point?  The
> thing that really kills this though is the fact we need to be able to run
> the pre and post functions before and *after* the XOL stepping.

A "b #imm" would be able to cover a wide range (+/-128MB), but, as you
said, it doesn't help with the post function call.

Any plans to post an updated version with the "unexpected single-step
error" fixed?

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-05-22 11:00         ` Catalin Marinas
@ 2015-05-22 15:49           ` William Cohen
  -1 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-22 15:49 UTC (permalink / raw)
  To: Catalin Marinas, David Long
  Cc: Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, sandeepa.s.prabhu,
	Masami Hiramatsu, Russell King, davem, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 3348 bytes --]

On 05/22/2015 07:00 AM, Catalin Marinas wrote:
> On Thu, May 21, 2015 at 12:44:45AM -0400, David Long wrote:
>> On 05/20/15 12:39, Catalin Marinas wrote:
>>> On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
>>>> Add support for basic kernel probes(kprobes) and jump probes
>>>> (jprobes) for ARM64.
>>>>
>>>> Kprobes utilizes software breakpoint and single step debug
>>>> exceptions supported on ARM v8.
>>>>
>>>> A software breakpoint is placed at the probe address to trap the
>>>> kernel execution into the kprobe handler.
>>>>
>>>> ARM v8 supports enabling single stepping before the break exception
>>>> return (ERET), with next PC in exception return address (ELR_EL1). The
>>>> kprobe handler prepares an executable memory slot for out-of-line
>>>> execution with a copy of the original instruction being probed, and
>>>> enables single stepping. The PC is set to the out-of-line slot address
>>>> before the ERET. With this scheme, the instruction is executed with the
>>>> exact same register context except for the PC (and DAIF) registers.
>>>
>>> I wonder whether it would be simpler to use another software breakpoint
>>> after the out of line instruction copy. You won't run the instructions
>>> that change the PC anyway.
>>
>> We put quite a bit of work into making single-step work.  I don't see any
>> obvious advantage to trying to switch to a software breakpoint. Both are
>> debug exceptions but SS does leave open the possibility of maybe eventually
>> running some instructions that do change the PC.
> 
> I'm not trying to get this re-written, just as a potential workaround
> for the unexpected single-step error reported but I need to read some
> more before I understand it properly (and I can see patches already for
> fixing this).
> 
>>> Since an unconditional branch instruction within the kernel address
>>> space can reach any point in the kernel (and modules), could we go a
>>> step further and avoid the software breakpoint altogether, just generate
>>> a branch instruction to the original location (after the software
>>> breakpoint)?
>>
>> Wouldn't a branch instruction have to make use of a register in order to
>> span the whole address space?  How could you do that and have all the
>> registers unmolested when you land back after the original probe point?  The
>> thing that really kills this though is the fact we need to be able to run
>> the pre and post functions before and *after* the XOL stepping.
> 
> A "b #imm" would be able to cover a wide range (+/-128MB), but, as you
> said, it doesn't help with the post function call.
> 
> Any plans to post an updated version with the "unexpected single-step
> error" fixed?
> 

Hi Catalin,

The only place this issue with the "unexpected single-step error" has been observed is with the arm64 kretporbe handler code calling kprobed functions.  Experiments with kprobed functions being called in the kprobe handlers showed that situation was handled appropriately. 

There is proposed fix to address the issue with the trampoline, the attached patch.  This is modeled after the way that the x86 handles the kretprobe.  The trampoline directly save and restores the registers and uses a normal call to the kretprobe handler.  It operates similarly to what you are suggesting above, but just for the special case of the kretprobes.

-Will Cohen

[-- Attachment #2: 0001-Avoid-using-kprobe-in-the-arm64-kretprobe-trampoline.patch --]
[-- Type: text/x-patch, Size: 5995 bytes --]

>From 3ee0894279693822132fa43cf5a0eefe898955d9 Mon Sep 17 00:00:00 2001
From: William Cohen <wcohen@redhat.com>
Date: Tue, 19 May 2015 10:03:30 -0400
Subject: [PATCH] Avoid using kprobe in the arm64 kretprobe trampoline

The aarch64 exception handling does not allow nesting of debug exceptions.
Using a kprobe in the kretprobe trampoline can cause problems if any of
the functions used by the kretprobe handler are instrumented with kprobes.
This problem was observed with the systemtap functioncallcount.stp
test when it instrumented the kfree function.  The kretprobe handler
under some conditions can all kfree.

Instead of using a kprobe to trigger an exception to save the processor state
and calling the kretprobe handler from the kprobei, the trampoline can
directly save the register state and call the kretprobe handler.  This
avoids the possible nested debug exceptions and reduces the overhead of
handling a kretprobe.  This code for the arm64 was based on the x86 code.

Signed-off-by: William Cohen <wcohen@redhat.com>
---
 arch/arm64/kernel/kprobes-arm64.h | 43 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/kprobes.c       | 51 +++++++++++++++------------------------
 2 files changed, 63 insertions(+), 31 deletions(-)

diff --git a/arch/arm64/kernel/kprobes-arm64.h b/arch/arm64/kernel/kprobes-arm64.h
index ff8a55f..46dab24 100644
--- a/arch/arm64/kernel/kprobes-arm64.h
+++ b/arch/arm64/kernel/kprobes-arm64.h
@@ -27,4 +27,47 @@ extern kprobes_pstate_check_t * const kprobe_condition_checks[16];
 enum kprobe_insn __kprobes
 arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi);
 
+#define SAVE_REGS_STRING\
+	"	stp x0, x1, [sp, #16 * 0]\n"	\
+	"	stp x2, x3, [sp, #16 * 1]\n"	\
+	"	stp x4, x5, [sp, #16 * 2]\n"	\
+	"	stp x6, x7, [sp, #16 * 3]\n"	\
+	"	stp x8, x9, [sp, #16 * 4]\n"	\
+	"	stp x10, x11, [sp, #16 * 5]\n"	\
+	"	stp x12, x13, [sp, #16 * 6]\n"	\
+	"	stp x14, x15, [sp, #16 * 7]\n"	\
+	"	stp x16, x17, [sp, #16 * 8]\n"	\
+	"	stp x18, x19, [sp, #16 * 9]\n"	\
+	"	stp x20, x21, [sp, #16 * 10]\n"	\
+	"	stp x22, x23, [sp, #16 * 11]\n"	\
+	"	stp x24, x25, [sp, #16 * 12]\n"	\
+	"	stp x26, x27, [sp, #16 * 13]\n"	\
+	"	stp x28, x29, [sp, #16 * 14]\n"	\
+	"	str x30,   [sp, #16 * 15]\n"    \
+	"	mrs x0, nzcv\n"			\
+	"	str x0, [sp, #8 * 33]\n"
+	
+
+#define RESTORE_REGS_STRING\
+	"	ldr x0, [sp, #8 * 33]\n"	\
+	"	msr nzcv, x0\n"			\
+	"	ldp x0, x1, [sp, #16 * 0]\n"	\
+	"	ldp x2, x3, [sp, #16 * 1]\n"	\
+	"	ldp x4, x5, [sp, #16 * 2]\n"	\
+	"	ldp x6, x7, [sp, #16 * 3]\n"	\
+	"	ldp x8, x9, [sp, #16 * 4]\n"	\
+	"	ldp x10, x11, [sp, #16 * 5]\n"	\
+	"	ldp x12, x13, [sp, #16 * 6]\n"	\
+	"	ldp x14, x15, [sp, #16 * 7]\n"	\
+	"	ldp x16, x17, [sp, #16 * 8]\n"	\
+	"	ldp x18, x19, [sp, #16 * 9]\n"	\
+	"	ldp x20, x21, [sp, #16 * 10]\n"	\
+	"	ldp x22, x23, [sp, #16 * 11]\n"	\
+	"	ldp x24, x25, [sp, #16 * 12]\n"	\
+	"	ldp x26, x27, [sp, #16 * 13]\n"	\
+	"	ldp x28, x29, [sp, #16 * 14]\n"	\
+	"	ldr x30,   [sp, #16 * 15]\n"	\
+
+
+
 #endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/kprobes.c b/arch/arm64/kernel/kprobes.c
index d2aa4bc..af55e37 100644
--- a/arch/arm64/kernel/kprobes.c
+++ b/arch/arm64/kernel/kprobes.c
@@ -565,32 +565,27 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 }
 
 /*
- * Kretprobes: kernel return probes handling
- *
- * AArch64 mode does not support popping the PC value from the
- * stack like on ARM 32-bit (ldmia {..,pc}), so atleast one
- * register need to be used to achieve branching/return.
- * It means return probes cannot return back to the original
- * return address directly without modifying the register context.
- *
- * So like other architectures, we prepare a global routine
- * with NOPs, which serve as trampoline address that hack away the
- * function return, with the exact register context.
- * Placing a kprobe on trampoline routine entry will trap again to
- * execute return probe handlers and restore original return address
- * in ELR_EL1, this way saved pt_regs still hold the original
- * register values to be carried back to the caller.
+ * When a retprobed function returns, this code saves registers and
+ * calls trampoline_handler() runs, which calls the kretprobe's handler.
  */
-static void __used kretprobe_trampoline_holder(void)
+static void __used __kprobes kretprobe_trampoline_holder(void)
 {
 	asm volatile (".global kretprobe_trampoline\n"
 			"kretprobe_trampoline:\n"
-			"NOP\n\t"
-			"NOP\n\t");
+		        "sub sp, sp, %0\n"
+			SAVE_REGS_STRING
+			"mov x0, sp\n"
+			"bl trampoline_probe_handler\n"
+			/* Replace trampoline address in lr with actual
+			   orig_ret_addr return address. */
+			"str x0, [sp, #16 * 15]\n"
+			RESTORE_REGS_STRING
+		        "add sp, sp, %0\n"
+			"ret\n"
+		      : : "I"(sizeof(struct pt_regs)) : "memory");
 }
 
-static int __kprobes
-trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
 {
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
@@ -651,7 +646,7 @@ trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 	}
 
 	/* return 1 so that post handlers not called */
-	return 1;
+	return (void *) orig_ret_addr;
 }
 
 void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
@@ -663,18 +658,12 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 	regs->regs[30] = (long)&kretprobe_trampoline;
 }
 
-static struct kprobe trampoline = {
-	.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
-	.pre_handler = trampoline_probe_handler
-};
-
-int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+int __init arch_init_kprobes(void)
 {
-	return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline;
+	return 0;
 }
 
-int __init arch_init_kprobes(void)
+int arch_trampoline_kprobe(struct kprobe *p)
 {
-	/* register trampoline for kret probe */
-	return register_kprobe(&trampoline);
+	return 0;
 }
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-05-22 15:49           ` William Cohen
  0 siblings, 0 replies; 74+ messages in thread
From: William Cohen @ 2015-05-22 15:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/22/2015 07:00 AM, Catalin Marinas wrote:
> On Thu, May 21, 2015 at 12:44:45AM -0400, David Long wrote:
>> On 05/20/15 12:39, Catalin Marinas wrote:
>>> On Mon, Apr 20, 2015 at 04:19:44PM -0400, David Long wrote:
>>>> Add support for basic kernel probes(kprobes) and jump probes
>>>> (jprobes) for ARM64.
>>>>
>>>> Kprobes utilizes software breakpoint and single step debug
>>>> exceptions supported on ARM v8.
>>>>
>>>> A software breakpoint is placed at the probe address to trap the
>>>> kernel execution into the kprobe handler.
>>>>
>>>> ARM v8 supports enabling single stepping before the break exception
>>>> return (ERET), with next PC in exception return address (ELR_EL1). The
>>>> kprobe handler prepares an executable memory slot for out-of-line
>>>> execution with a copy of the original instruction being probed, and
>>>> enables single stepping. The PC is set to the out-of-line slot address
>>>> before the ERET. With this scheme, the instruction is executed with the
>>>> exact same register context except for the PC (and DAIF) registers.
>>>
>>> I wonder whether it would be simpler to use another software breakpoint
>>> after the out of line instruction copy. You won't run the instructions
>>> that change the PC anyway.
>>
>> We put quite a bit of work into making single-step work.  I don't see any
>> obvious advantage to trying to switch to a software breakpoint. Both are
>> debug exceptions but SS does leave open the possibility of maybe eventually
>> running some instructions that do change the PC.
> 
> I'm not trying to get this re-written, just as a potential workaround
> for the unexpected single-step error reported but I need to read some
> more before I understand it properly (and I can see patches already for
> fixing this).
> 
>>> Since an unconditional branch instruction within the kernel address
>>> space can reach any point in the kernel (and modules), could we go a
>>> step further and avoid the software breakpoint altogether, just generate
>>> a branch instruction to the original location (after the software
>>> breakpoint)?
>>
>> Wouldn't a branch instruction have to make use of a register in order to
>> span the whole address space?  How could you do that and have all the
>> registers unmolested when you land back after the original probe point?  The
>> thing that really kills this though is the fact we need to be able to run
>> the pre and post functions before and *after* the XOL stepping.
> 
> A "b #imm" would be able to cover a wide range (+/-128MB), but, as you
> said, it doesn't help with the post function call.
> 
> Any plans to post an updated version with the "unexpected single-step
> error" fixed?
> 

Hi Catalin,

The only place this issue with the "unexpected single-step error" has been observed is with the arm64 kretporbe handler code calling kprobed functions.  Experiments with kprobed functions being called in the kprobe handlers showed that situation was handled appropriately. 

There is proposed fix to address the issue with the trampoline, the attached patch.  This is modeled after the way that the x86 handles the kretprobe.  The trampoline directly save and restores the registers and uses a normal call to the kretprobe handler.  It operates similarly to what you are suggesting above, but just for the special case of the kretprobes.

-Will Cohen
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Avoid-using-kprobe-in-the-arm64-kretprobe-trampoline.patch
Type: text/x-patch
Size: 5995 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150522/0a7af59e/attachment.bin>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-05-22 15:49           ` William Cohen
@ 2015-05-22 16:54             ` Catalin Marinas
  -1 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-22 16:54 UTC (permalink / raw)
  To: William Cohen
  Cc: David Long, Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, Masami Hiramatsu,
	sandeepa.s.prabhu, Russell King, davem, linux-arm-kernel

On Fri, May 22, 2015 at 11:49:37AM -0400, William Cohen wrote:
> On 05/22/2015 07:00 AM, Catalin Marinas wrote:
> > Any plans to post an updated version with the "unexpected single-step
> > error" fixed?
> 
> The only place this issue with the "unexpected single-step error" has
> been observed is with the arm64 kretporbe handler code calling kprobed
> functions.  Experiments with kprobed functions being called in the
> kprobe handlers showed that situation was handled appropriately. 
> 
> There is proposed fix to address the issue with the trampoline, the
> attached patch.  This is modeled after the way that the x86 handles
> the kretprobe.  The trampoline directly save and restores the
> registers and uses a normal call to the kretprobe handler.  It
> operates similarly to what you are suggesting above, but just for the
> special case of the kretprobes.

Thanks. I guess David will post a v7 series with this patch included and
other comments addressed.

BTW, I'll be on holiday for a week, back on the 1st of June. Hopefully
this series gets some more reviews by then ;)

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-05-22 16:54             ` Catalin Marinas
  0 siblings, 0 replies; 74+ messages in thread
From: Catalin Marinas @ 2015-05-22 16:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 22, 2015 at 11:49:37AM -0400, William Cohen wrote:
> On 05/22/2015 07:00 AM, Catalin Marinas wrote:
> > Any plans to post an updated version with the "unexpected single-step
> > error" fixed?
> 
> The only place this issue with the "unexpected single-step error" has
> been observed is with the arm64 kretporbe handler code calling kprobed
> functions.  Experiments with kprobed functions being called in the
> kprobe handlers showed that situation was handled appropriately. 
> 
> There is proposed fix to address the issue with the trampoline, the
> attached patch.  This is modeled after the way that the x86 handles
> the kretprobe.  The trampoline directly save and restores the
> registers and uses a normal call to the kretprobe handler.  It
> operates similarly to what you are suggesting above, but just for the
> special case of the kretprobes.

Thanks. I guess David will post a v7 series with this patch included and
other comments addressed.

BTW, I'll be on holiday for a week, back on the 1st of June. Hopefully
this series gets some more reviews by then ;)

-- 
Catalin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 3/6] arm64: Kprobes with single stepping support
  2015-05-22 16:54             ` Catalin Marinas
@ 2015-05-22 16:57               ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-22 16:57 UTC (permalink / raw)
  To: Catalin Marinas, William Cohen
  Cc: Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, Masami Hiramatsu,
	sandeepa.s.prabhu, Russell King, davem, linux-arm-kernel

On 05/22/15 12:54, Catalin Marinas wrote:
> On Fri, May 22, 2015 at 11:49:37AM -0400, William Cohen wrote:
>> On 05/22/2015 07:00 AM, Catalin Marinas wrote:
>>> Any plans to post an updated version with the "unexpected single-step
>>> error" fixed?
>>
>> The only place this issue with the "unexpected single-step error" has
>> been observed is with the arm64 kretporbe handler code calling kprobed
>> functions.  Experiments with kprobed functions being called in the
>> kprobe handlers showed that situation was handled appropriately.
>>
>> There is proposed fix to address the issue with the trampoline, the
>> attached patch.  This is modeled after the way that the x86 handles
>> the kretprobe.  The trampoline directly save and restores the
>> registers and uses a normal call to the kretprobe handler.  It
>> operates similarly to what you are suggesting above, but just for the
>> special case of the kretprobes.
>
> Thanks. I guess David will post a v7 series with this patch included and
> other comments addressed.
>
> BTW, I'll be on holiday for a week, back on the 1st of June. Hopefully
> this series gets some more reviews by then ;)
>

Yes, the v7 patch is in the works, with Will Cohen's trampoline fixes as 
well as your feedback.

-fl




^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 3/6] arm64: Kprobes with single stepping support
@ 2015-05-22 16:57               ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-22 16:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/22/15 12:54, Catalin Marinas wrote:
> On Fri, May 22, 2015 at 11:49:37AM -0400, William Cohen wrote:
>> On 05/22/2015 07:00 AM, Catalin Marinas wrote:
>>> Any plans to post an updated version with the "unexpected single-step
>>> error" fixed?
>>
>> The only place this issue with the "unexpected single-step error" has
>> been observed is with the arm64 kretporbe handler code calling kprobed
>> functions.  Experiments with kprobed functions being called in the
>> kprobe handlers showed that situation was handled appropriately.
>>
>> There is proposed fix to address the issue with the trampoline, the
>> attached patch.  This is modeled after the way that the x86 handles
>> the kretprobe.  The trampoline directly save and restores the
>> registers and uses a normal call to the kretprobe handler.  It
>> operates similarly to what you are suggesting above, but just for the
>> special case of the kretprobes.
>
> Thanks. I guess David will post a v7 series with this patch included and
> other comments addressed.
>
> BTW, I'll be on holiday for a week, back on the 1st of June. Hopefully
> this series gets some more reviews by then ;)
>

Yes, the v7 patch is in the works, with Will Cohen's trampoline fixes as 
well as your feedback.

-fl

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
  2015-05-21 17:55         ` Catalin Marinas
@ 2015-05-22 17:05           ` David Long
  -1 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-22 17:05 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Jon Medhurst (Tixy),
	Steve Capper, Ananth N Mavinakayanahalli, Will Deacon,
	linux-kernel, Anil S Keshavamurthy, sandeepa.s.prabhu,
	Masami Hiramatsu, Russell King, William Cohen, davem,
	linux-arm-kernel

On 05/21/15 13:55, Catalin Marinas wrote:
> On Wed, May 20, 2015 at 11:29:24PM -0400, David Long wrote:
>> On 05/20/15 09:39, Catalin Marinas wrote:
>>> On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
>>>> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
>>>> index 6913643..58c0223 100644
>>>> --- a/arch/arm64/include/uapi/asm/ptrace.h
>>>> +++ b/arch/arm64/include/uapi/asm/ptrace.h
>>>> @@ -61,6 +61,42 @@
>>>>
>>>>   #ifndef __ASSEMBLY__
>>>>
>>>> +#define ARM_pstate	pstate
>>>> +#define ARM_pc		pc
>>>> +#define ARM_sp		sp
>>>> +#define ARM_lr		regs[30]
>>>> +#define ARM_fp		regs[29]
>>>> +#define ARM_x28		regs[28]
>>>> +#define ARM_x27		regs[27]
>>>> +#define ARM_x26		regs[26]
>>>> +#define ARM_x25		regs[25]
>>>> +#define ARM_x24		regs[24]
>>>> +#define ARM_x23		regs[23]
>>>> +#define ARM_x22		regs[22]
>>>> +#define ARM_x21		regs[21]
>>>> +#define ARM_x20		regs[20]
>>>> +#define ARM_x19		regs[19]
>>>> +#define ARM_x18		regs[18]
>>>> +#define ARM_ip1		regs[17]
>>>> +#define ARM_ip0		regs[16]
>>>> +#define ARM_x15		regs[15]
>>>> +#define ARM_x14		regs[14]
>>>> +#define ARM_x13		regs[13]
>>>> +#define ARM_x12		regs[12]
>>>> +#define ARM_x11		regs[11]
>>>> +#define ARM_x10		regs[10]
>>>> +#define ARM_x9		regs[9]
>>>> +#define ARM_x8		regs[8]
>>>> +#define ARM_x7		regs[7]
>>>> +#define ARM_x6		regs[6]
>>>> +#define ARM_x5		regs[5]
>>>> +#define ARM_x4		regs[4]
>>>> +#define ARM_x3		regs[3]
>>>> +#define ARM_x2		regs[2]
>>>> +#define ARM_x1		regs[1]
>>>> +#define ARM_x0		regs[0]
>>>> +#define ARM_ORIG_x0	orig_x0
>>>
>>> I replied some time ago on this part. I don't see the point these
>>> macros.
>>
>> I replied belatedly on April 20 saying what I did matches (more or less) how
>> it's done on various other platforms, including arm and powerpc.
>> It looks like this comes from the pt_regs structure defining the
>> registers as an array instead of a list of structure fields. It looks
>> to me like that design choice is pretty widely depended upon now and
>> would be quite disruptive to change.  It also seems to me a relatively
>> clean way to do it on systems with a uniform register set.
>
> I see why we need to cope with the regs[] array but why do we need these
> definitions in a uapi file?
>

I expect Sandeepa did it that way because it's the way it's done in 
other architectures.  I see your point though, these definitions are 
only referenced in a macro that's defined and used only in ptrace.c.  I 
can easily move them there.

>>>> +
>>>>   /*
>>>>    * User structures for general purpose, floating point and debug registers.
>>>>    */
>>>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>>>> index d882b83..a889f79 100644
>>>> --- a/arch/arm64/kernel/ptrace.c
>>>> +++ b/arch/arm64/kernel/ptrace.c
>>>> @@ -48,6 +48,122 @@
>>>>   #define CREATE_TRACE_POINTS
>>>>   #include <trace/events/syscalls.h>
>>>>
>>>> +struct pt_regs_offset {
>>>> +	const char *name;
>>>> +	int offset;
>>>> +};
>>>> +
>>>> +#define REG_OFFSET_NAME(r) \
>>>> +	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
>>
>>> Can you not just use "offsetof(struct pt_regs, r)" here? That would be
>>> the same as x86, powerpc.
>>
>> The registers (except for pc, pstate, and sp) are not separate structure
>> fields, they are slots in a single array. To reference them the symbolic
>> name has to be converted to an index (integer register number) somehow.
>
> Can we not keep them local to this file, say __reg_x0 etc. (something to
> make it clear they are for internal use)?
>

As above we can make it local to the file.  Given that I don't think 
there's a need to chance ARM_x* to __reg_x* though, is there?  Either 
way, no problem.

-dl


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
@ 2015-05-22 17:05           ` David Long
  0 siblings, 0 replies; 74+ messages in thread
From: David Long @ 2015-05-22 17:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/21/15 13:55, Catalin Marinas wrote:
> On Wed, May 20, 2015 at 11:29:24PM -0400, David Long wrote:
>> On 05/20/15 09:39, Catalin Marinas wrote:
>>> On Mon, Apr 20, 2015 at 04:19:42PM -0400, David Long wrote:
>>>> diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
>>>> index 6913643..58c0223 100644
>>>> --- a/arch/arm64/include/uapi/asm/ptrace.h
>>>> +++ b/arch/arm64/include/uapi/asm/ptrace.h
>>>> @@ -61,6 +61,42 @@
>>>>
>>>>   #ifndef __ASSEMBLY__
>>>>
>>>> +#define ARM_pstate	pstate
>>>> +#define ARM_pc		pc
>>>> +#define ARM_sp		sp
>>>> +#define ARM_lr		regs[30]
>>>> +#define ARM_fp		regs[29]
>>>> +#define ARM_x28		regs[28]
>>>> +#define ARM_x27		regs[27]
>>>> +#define ARM_x26		regs[26]
>>>> +#define ARM_x25		regs[25]
>>>> +#define ARM_x24		regs[24]
>>>> +#define ARM_x23		regs[23]
>>>> +#define ARM_x22		regs[22]
>>>> +#define ARM_x21		regs[21]
>>>> +#define ARM_x20		regs[20]
>>>> +#define ARM_x19		regs[19]
>>>> +#define ARM_x18		regs[18]
>>>> +#define ARM_ip1		regs[17]
>>>> +#define ARM_ip0		regs[16]
>>>> +#define ARM_x15		regs[15]
>>>> +#define ARM_x14		regs[14]
>>>> +#define ARM_x13		regs[13]
>>>> +#define ARM_x12		regs[12]
>>>> +#define ARM_x11		regs[11]
>>>> +#define ARM_x10		regs[10]
>>>> +#define ARM_x9		regs[9]
>>>> +#define ARM_x8		regs[8]
>>>> +#define ARM_x7		regs[7]
>>>> +#define ARM_x6		regs[6]
>>>> +#define ARM_x5		regs[5]
>>>> +#define ARM_x4		regs[4]
>>>> +#define ARM_x3		regs[3]
>>>> +#define ARM_x2		regs[2]
>>>> +#define ARM_x1		regs[1]
>>>> +#define ARM_x0		regs[0]
>>>> +#define ARM_ORIG_x0	orig_x0
>>>
>>> I replied some time ago on this part. I don't see the point these
>>> macros.
>>
>> I replied belatedly on April 20 saying what I did matches (more or less) how
>> it's done on various other platforms, including arm and powerpc.
>> It looks like this comes from the pt_regs structure defining the
>> registers as an array instead of a list of structure fields. It looks
>> to me like that design choice is pretty widely depended upon now and
>> would be quite disruptive to change.  It also seems to me a relatively
>> clean way to do it on systems with a uniform register set.
>
> I see why we need to cope with the regs[] array but why do we need these
> definitions in a uapi file?
>

I expect Sandeepa did it that way because it's the way it's done in 
other architectures.  I see your point though, these definitions are 
only referenced in a macro that's defined and used only in ptrace.c.  I 
can easily move them there.

>>>> +
>>>>   /*
>>>>    * User structures for general purpose, floating point and debug registers.
>>>>    */
>>>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>>>> index d882b83..a889f79 100644
>>>> --- a/arch/arm64/kernel/ptrace.c
>>>> +++ b/arch/arm64/kernel/ptrace.c
>>>> @@ -48,6 +48,122 @@
>>>>   #define CREATE_TRACE_POINTS
>>>>   #include <trace/events/syscalls.h>
>>>>
>>>> +struct pt_regs_offset {
>>>> +	const char *name;
>>>> +	int offset;
>>>> +};
>>>> +
>>>> +#define REG_OFFSET_NAME(r) \
>>>> +	{.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)}
>>
>>> Can you not just use "offsetof(struct pt_regs, r)" here? That would be
>>> the same as x86, powerpc.
>>
>> The registers (except for pc, pstate, and sp) are not separate structure
>> fields, they are slots in a single array. To reference them the symbolic
>> name has to be converted to an index (integer register number) somehow.
>
> Can we not keep them local to this file, say __reg_x0 etc. (something to
> make it clear they are for internal use)?
>

As above we can make it local to the file.  Given that I don't think 
there's a need to chance ARM_x* to __reg_x* though, is there?  Either 
way, no problem.

-dl

^ permalink raw reply	[flat|nested] 74+ messages in thread

end of thread, other threads:[~2015-05-22 17:05 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-20 20:19 [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support David Long
2015-04-20 20:19 ` David Long
2015-04-20 20:19 ` [PATCH v6 1/6] arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature David Long
2015-04-20 20:19   ` David Long
2015-05-20 13:39   ` Catalin Marinas
2015-05-20 13:39     ` Catalin Marinas
2015-05-21  3:29     ` David Long
2015-05-21  3:29       ` David Long
2015-05-21 17:55       ` Catalin Marinas
2015-05-21 17:55         ` Catalin Marinas
2015-05-22 17:05         ` David Long
2015-05-22 17:05           ` David Long
2015-04-20 20:19 ` [PATCH v6 2/6] arm64: Add more test functions to insn.c David Long
2015-04-20 20:19   ` David Long
2015-04-20 20:19 ` [PATCH v6 3/6] arm64: Kprobes with single stepping support David Long
2015-04-20 20:19   ` David Long
2015-05-20 16:39   ` Catalin Marinas
2015-05-20 16:39     ` Catalin Marinas
2015-05-21  4:44     ` David Long
2015-05-21  4:44       ` David Long
2015-05-22 11:00       ` Catalin Marinas
2015-05-22 11:00         ` Catalin Marinas
2015-05-22 15:49         ` William Cohen
2015-05-22 15:49           ` William Cohen
2015-05-22 16:54           ` Catalin Marinas
2015-05-22 16:54             ` Catalin Marinas
2015-05-22 16:57             ` David Long
2015-05-22 16:57               ` David Long
2015-04-20 20:19 ` [PATCH v6 4/6] arm64: kprobes instruction simulation support David Long
2015-04-20 20:19   ` David Long
2015-04-20 20:19 ` [PATCH v6 5/6] arm64: Add kernel return probes support (kretprobes) David Long
2015-04-20 20:19   ` David Long
2015-04-20 20:19 ` [PATCH v6 6/6] kprobes: Add arm64 case in kprobe example module David Long
2015-04-20 20:19   ` David Long
2015-04-21 11:42 ` [PATCH v6 0/6] arm64: Add kernel probes (kprobes) support Masami Hiramatsu
2015-04-21 11:42   ` Masami Hiramatsu
2015-04-21 14:07   ` William Cohen
2015-04-21 14:07     ` William Cohen
2015-04-24 21:14   ` William Cohen
2015-04-24 21:14     ` William Cohen
2015-04-28  2:58     ` William Cohen
2015-04-28  2:58       ` William Cohen
2015-04-29 10:23       ` Will Deacon
2015-04-29 10:23         ` Will Deacon
2015-05-02  1:44         ` William Cohen
2015-05-02  1:44           ` William Cohen
2015-05-05  5:14           ` David Long
2015-05-05  5:14             ` David Long
2015-05-05 15:48             ` Will Deacon
2015-05-05 15:48               ` Will Deacon
2015-05-05 16:18               ` William Cohen
2015-05-05 16:18                 ` William Cohen
2015-05-05 21:02               ` William Cohen
2015-05-05 21:02                 ` William Cohen
2015-05-06  3:14                 ` William Cohen
2015-05-06  3:14                   ` William Cohen
2015-05-12  5:54               ` David Long
2015-05-12  5:54                 ` David Long
2015-05-12 12:48                 ` William Cohen
2015-05-12 12:48                   ` William Cohen
2015-05-13  9:22                   ` Masami Hiramatsu
2015-05-13  9:22                     ` Masami Hiramatsu
2015-05-13 15:41                     ` William Cohen
2015-05-13 15:41                       ` William Cohen
2015-05-13 19:58                       ` David Long
2015-05-13 19:58                         ` David Long
2015-05-13 20:35                         ` William Cohen
2015-05-13 20:35                           ` William Cohen
2015-05-14  0:01                       ` Masami Hiramatsu
2015-05-14  0:01                         ` Masami Hiramatsu
2015-05-14  3:48                         ` Ananth N Mavinakayanahalli
2015-05-14  3:48                           ` Ananth N Mavinakayanahalli
2015-04-29  4:33   ` David Long
2015-04-29  4:33     ` David Long

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.