Re: [PATCH v3 14/15] ARM: add uprobes support

2013-12-04 Thread Taras Kondratiuk
On 11/27/2013 04:53 AM, David Long wrote:
> From: "David A. Long" 
> 
> Using Rabin Vincent's ARM uprobes patches as a base, enable uprobes
> support on ARM.
> 
> Caveats:
> 
>  - Thumb is not supported
>  - XOL abort/trap handling is not implemented
> 
> Signed-off-by: David A. Long 
> ---
>  arch/arm/Kconfig   |   4 +
>  arch/arm/include/asm/ptrace.h  |   6 +
>  arch/arm/include/asm/thread_info.h |   5 +-
>  arch/arm/include/asm/uprobes.h |  34 ++
>  arch/arm/kernel/Makefile   |   1 +
>  arch/arm/kernel/signal.c   |   4 +
>  arch/arm/kernel/uprobes-arm.c  | 223 
> +
>  arch/arm/kernel/uprobes.c  | 198 
>  arch/arm/kernel/uprobes.h  |  27 +
>  9 files changed, 501 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/include/asm/uprobes.h
>  create mode 100644 arch/arm/kernel/uprobes-arm.c
>  create mode 100644 arch/arm/kernel/uprobes.c
>  create mode 100644 arch/arm/kernel/uprobes.h
> 

[snip]

> diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c
> new file mode 100644
> index 000..0a83ad7
> --- /dev/null
> +++ b/arch/arm/kernel/uprobes-arm.c
> @@ -0,0 +1,223 @@
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "probes.h"
> +#include "probes-arm.h"
> +#include "uprobes.h"
> +
> +static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
> +{
> + probes_opcode_t insn = *pinsn;

In a current implementation pinsn points to an ixol field of arch_uprobe
structure, which has native endianness and is written via
__opcode_to_mem_arm() macro in arch_uprobe_analyze_insn() function.
So *pinsn should be wrapped with __opcode_to_mem_arm/__mem_to_opcode_arm()
macros in this function.

> + probes_opcode_t temp;
> + probes_opcode_t mask;
> + int freereg;
> + u32 free = 0x;
> + u32 regs;
> +
> + for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
> + if ((regs & 0xf) == REG_TYPE_NONE)
> + continue;
> +
> + free &= ~(1 << (insn & 0xf));
> + }
> +
> + /* No PC, no problem */
> + if (free & (1 << 15))
> + return 15;
> +
> + if (!free)
> + return -1;
> +
> + /*
> +  * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
> +  * pick LR instead of R1.
> +  */
> + freereg = free = fls(free) - 1;
> +
> + temp = *pinsn;
> + insn = *pinsn;
> + regs = oregs;
> + mask = 0xf;
> +
> + for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
> + if ((regs & 0xf) == REG_TYPE_NONE)
> + continue;
> +
> + if ((temp & 0xf) != 15)
> + continue;
> +
> + insn &= ~mask;
> + insn |= free & mask;
> + }
> +
> + *pinsn = insn;
> + return freereg;
> +}
> +

[snip]

> +
> +enum probes_insn
> +uprobe_decode_ldmstm(probes_opcode_t insn,
> +  struct arch_specific_insn *asi, struct decode_header *d)
> +{
> + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
> +asi);
> + unsigned reglist = insn & 0x;
> + int rn = (insn >> 16) & 0xf;
> + int lbit = insn & (1 << 20);
> + unsigned used = reglist | (1 << rn);
> +
> + if (rn == 15)
> + return INSN_REJECTED;
> +
> + if (!(used & (1 << 15)))
> + return INSN_GOOD;
> +
> + if (used & (1 << 14))
> + return INSN_REJECTED;
> +
> + /* Use LR instead of PC */
> + insn ^= 0xc000;
> +
> + auprobe->pcreg = 14;
> + auprobe->ixol[0] = insn;

insn contains canonical opcode, but ixol should contain
an opcode in native endianness. So it should be

auprobe->ixol[0] = __opcode_to_mem_arm(insn);

> +
> + auprobe->prehandler = uprobe_set_pc;
> + if (lbit)
> + auprobe->posthandler = uprobe_write_pc;
> + else
> + auprobe->posthandler = uprobe_unset_pc;
> +
> + return INSN_GOOD;
> +}
> +


-- 
Taras Kondratiuk
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 14/15] ARM: add uprobes support

2013-12-04 Thread Taras Kondratiuk
On 11/27/2013 04:53 AM, David Long wrote:
 From: David A. Long dave.l...@linaro.org
 
 Using Rabin Vincent's ARM uprobes patches as a base, enable uprobes
 support on ARM.
 
 Caveats:
 
  - Thumb is not supported
  - XOL abort/trap handling is not implemented
 
 Signed-off-by: David A. Long dave.l...@linaro.org
 ---
  arch/arm/Kconfig   |   4 +
  arch/arm/include/asm/ptrace.h  |   6 +
  arch/arm/include/asm/thread_info.h |   5 +-
  arch/arm/include/asm/uprobes.h |  34 ++
  arch/arm/kernel/Makefile   |   1 +
  arch/arm/kernel/signal.c   |   4 +
  arch/arm/kernel/uprobes-arm.c  | 223 
 +
  arch/arm/kernel/uprobes.c  | 198 
  arch/arm/kernel/uprobes.h  |  27 +
  9 files changed, 501 insertions(+), 1 deletion(-)
  create mode 100644 arch/arm/include/asm/uprobes.h
  create mode 100644 arch/arm/kernel/uprobes-arm.c
  create mode 100644 arch/arm/kernel/uprobes.c
  create mode 100644 arch/arm/kernel/uprobes.h
 

[snip]

 diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c
 new file mode 100644
 index 000..0a83ad7
 --- /dev/null
 +++ b/arch/arm/kernel/uprobes-arm.c
 @@ -0,0 +1,223 @@
 +#include linux/kernel.h
 +#include linux/wait.h
 +#include linux/uprobes.h
 +#include linux/module.h
 +
 +#include probes.h
 +#include probes-arm.h
 +#include uprobes.h
 +
 +static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
 +{
 + probes_opcode_t insn = *pinsn;

In a current implementation pinsn points to an ixol field of arch_uprobe
structure, which has native endianness and is written via
__opcode_to_mem_arm() macro in arch_uprobe_analyze_insn() function.
So *pinsn should be wrapped with __opcode_to_mem_arm/__mem_to_opcode_arm()
macros in this function.

 + probes_opcode_t temp;
 + probes_opcode_t mask;
 + int freereg;
 + u32 free = 0x;
 + u32 regs;
 +
 + for (regs = oregs; regs; regs = 4, insn = 4) {
 + if ((regs  0xf) == REG_TYPE_NONE)
 + continue;
 +
 + free = ~(1  (insn  0xf));
 + }
 +
 + /* No PC, no problem */
 + if (free  (1  15))
 + return 15;
 +
 + if (!free)
 + return -1;
 +
 + /*
 +  * fls instead of ffs ensures that for ldrd r0, r1, [pc] we would
 +  * pick LR instead of R1.
 +  */
 + freereg = free = fls(free) - 1;
 +
 + temp = *pinsn;
 + insn = *pinsn;
 + regs = oregs;
 + mask = 0xf;
 +
 + for (; regs; regs = 4, mask = 4, free = 4, temp = 4) {
 + if ((regs  0xf) == REG_TYPE_NONE)
 + continue;
 +
 + if ((temp  0xf) != 15)
 + continue;
 +
 + insn = ~mask;
 + insn |= free  mask;
 + }
 +
 + *pinsn = insn;
 + return freereg;
 +}
 +

[snip]

 +
 +enum probes_insn
 +uprobe_decode_ldmstm(probes_opcode_t insn,
 +  struct arch_specific_insn *asi, struct decode_header *d)
 +{
 + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
 +asi);
 + unsigned reglist = insn  0x;
 + int rn = (insn  16)  0xf;
 + int lbit = insn  (1  20);
 + unsigned used = reglist | (1  rn);
 +
 + if (rn == 15)
 + return INSN_REJECTED;
 +
 + if (!(used  (1  15)))
 + return INSN_GOOD;
 +
 + if (used  (1  14))
 + return INSN_REJECTED;
 +
 + /* Use LR instead of PC */
 + insn ^= 0xc000;
 +
 + auprobe-pcreg = 14;
 + auprobe-ixol[0] = insn;

insn contains canonical opcode, but ixol should contain
an opcode in native endianness. So it should be

auprobe-ixol[0] = __opcode_to_mem_arm(insn);

 +
 + auprobe-prehandler = uprobe_set_pc;
 + if (lbit)
 + auprobe-posthandler = uprobe_write_pc;
 + else
 + auprobe-posthandler = uprobe_unset_pc;
 +
 + return INSN_GOOD;
 +}
 +


-- 
Taras Kondratiuk
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 14/15] ARM: add uprobes support

2013-11-26 Thread David Long
From: "David A. Long" 

Using Rabin Vincent's ARM uprobes patches as a base, enable uprobes
support on ARM.

Caveats:

 - Thumb is not supported
 - XOL abort/trap handling is not implemented

Signed-off-by: David A. Long 
---
 arch/arm/Kconfig   |   4 +
 arch/arm/include/asm/ptrace.h  |   6 +
 arch/arm/include/asm/thread_info.h |   5 +-
 arch/arm/include/asm/uprobes.h |  34 ++
 arch/arm/kernel/Makefile   |   1 +
 arch/arm/kernel/signal.c   |   4 +
 arch/arm/kernel/uprobes-arm.c  | 223 +
 arch/arm/kernel/uprobes.c  | 198 
 arch/arm/kernel/uprobes.h  |  27 +
 9 files changed, 501 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/include/asm/uprobes.h
 create mode 100644 arch/arm/kernel/uprobes-arm.c
 create mode 100644 arch/arm/kernel/uprobes.c
 create mode 100644 arch/arm/kernel/uprobes.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c1f1a7e..fec5a6b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -203,6 +203,10 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
def_bool y
 
+config ARCH_SUPPORTS_UPROBES
+   depends on KPROBES
+   def_bool y
+
 config ARCH_HAS_DMA_SET_COHERENT_MASK
bool
 
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 04c99f3..ee688b0a 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -80,6 +80,12 @@ static inline long regs_return_value(struct pt_regs *regs)
 
 #define instruction_pointer(regs)  (regs)->ARM_pc
 
+static inline void instruction_pointer_set(struct pt_regs *regs,
+  unsigned long val)
+{
+   instruction_pointer(regs) = val;
+}
+
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
 #else
diff --git a/arch/arm/include/asm/thread_info.h 
b/arch/arm/include/asm/thread_info.h
index 71a06b2..f989d7c 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user 
*,
 #define TIF_SIGPENDING 0
 #define TIF_NEED_RESCHED   1
 #define TIF_NOTIFY_RESUME  2   /* callback before returning to user */
+#define TIF_UPROBE 7
 #define TIF_SYSCALL_TRACE  8
 #define TIF_SYSCALL_AUDIT  9
 #define TIF_SYSCALL_TRACEPOINT 10
@@ -165,6 +166,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user 
*,
 #define _TIF_SIGPENDING(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED  (1 << TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_UPROBE(1 << TIF_UPROBE)
 #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SYSCALL_TRACEPOINT(1 << TIF_SYSCALL_TRACEPOINT)
@@ -178,7 +180,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user 
*,
 /*
  * Change these and you break ASM code in entry-common.S
  */
-#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | 
_TIF_NOTIFY_RESUME)
+#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
+_TIF_NOTIFY_RESUME | _TIF_UPROBE)
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_ARM_THREAD_INFO_H */
diff --git a/arch/arm/include/asm/uprobes.h b/arch/arm/include/asm/uprobes.h
new file mode 100644
index 000..e5acaa3
--- /dev/null
+++ b/arch/arm/include/asm/uprobes.h
@@ -0,0 +1,34 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+
+#include 
+
+typedef u32 uprobe_opcode_t;
+
+#define MAX_UINSN_BYTES4
+#define UPROBE_XOL_SLOT_BYTES  64
+
+#define UPROBE_SWBP_INSN   0xe7f001f9
+#define UPROBE_SS_INSN 0xe7f001fa
+#define UPROBE_SWBP_INSN_SIZE  4
+
+struct arch_uprobe_task {
+   u32 backup;
+};
+
+struct arch_uprobe {
+   u8 insn[MAX_UINSN_BYTES];
+   unsigned long ixol[2];
+   uprobe_opcode_t bpinsn;
+   bool simulate;
+   u32 pcreg;
+   void (*prehandler)(struct arch_uprobe *auprobe,
+  struct arch_uprobe_task *autask,
+  struct pt_regs *regs);
+   void (*posthandler)(struct arch_uprobe *auprobe,
+   struct arch_uprobe_task *autask,
+   struct pt_regs *regs);
+   struct arch_specific_insn asi;
+};
+
+#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index bb739f2..a766bcb 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE)  += ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o insn.o
 obj-$(CONFIG_JUMP_LABEL)   += jump_label.o insn.o patch.o
 obj-$(CONFIG_KEXEC)+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_UPROBES)  += probes.o probes-arm.o uprobes.o uprobes-arm.o
 obj-$(CONFIG_KPROBES)  += probes.o 

[PATCH v3 14/15] ARM: add uprobes support

2013-11-26 Thread David Long
From: David A. Long dave.l...@linaro.org

Using Rabin Vincent's ARM uprobes patches as a base, enable uprobes
support on ARM.

Caveats:

 - Thumb is not supported
 - XOL abort/trap handling is not implemented

Signed-off-by: David A. Long dave.l...@linaro.org
---
 arch/arm/Kconfig   |   4 +
 arch/arm/include/asm/ptrace.h  |   6 +
 arch/arm/include/asm/thread_info.h |   5 +-
 arch/arm/include/asm/uprobes.h |  34 ++
 arch/arm/kernel/Makefile   |   1 +
 arch/arm/kernel/signal.c   |   4 +
 arch/arm/kernel/uprobes-arm.c  | 223 +
 arch/arm/kernel/uprobes.c  | 198 
 arch/arm/kernel/uprobes.h  |  27 +
 9 files changed, 501 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/include/asm/uprobes.h
 create mode 100644 arch/arm/kernel/uprobes-arm.c
 create mode 100644 arch/arm/kernel/uprobes.c
 create mode 100644 arch/arm/kernel/uprobes.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c1f1a7e..fec5a6b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -203,6 +203,10 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
def_bool y
 
+config ARCH_SUPPORTS_UPROBES
+   depends on KPROBES
+   def_bool y
+
 config ARCH_HAS_DMA_SET_COHERENT_MASK
bool
 
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 04c99f3..ee688b0a 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -80,6 +80,12 @@ static inline long regs_return_value(struct pt_regs *regs)
 
 #define instruction_pointer(regs)  (regs)-ARM_pc
 
+static inline void instruction_pointer_set(struct pt_regs *regs,
+  unsigned long val)
+{
+   instruction_pointer(regs) = val;
+}
+
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
 #else
diff --git a/arch/arm/include/asm/thread_info.h 
b/arch/arm/include/asm/thread_info.h
index 71a06b2..f989d7c 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user 
*,
 #define TIF_SIGPENDING 0
 #define TIF_NEED_RESCHED   1
 #define TIF_NOTIFY_RESUME  2   /* callback before returning to user */
+#define TIF_UPROBE 7
 #define TIF_SYSCALL_TRACE  8
 #define TIF_SYSCALL_AUDIT  9
 #define TIF_SYSCALL_TRACEPOINT 10
@@ -165,6 +166,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user 
*,
 #define _TIF_SIGPENDING(1  TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED  (1  TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME (1  TIF_NOTIFY_RESUME)
+#define _TIF_UPROBE(1  TIF_UPROBE)
 #define _TIF_SYSCALL_TRACE (1  TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT (1  TIF_SYSCALL_AUDIT)
 #define _TIF_SYSCALL_TRACEPOINT(1  TIF_SYSCALL_TRACEPOINT)
@@ -178,7 +180,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user 
*,
 /*
  * Change these and you break ASM code in entry-common.S
  */
-#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | 
_TIF_NOTIFY_RESUME)
+#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
+_TIF_NOTIFY_RESUME | _TIF_UPROBE)
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_ARM_THREAD_INFO_H */
diff --git a/arch/arm/include/asm/uprobes.h b/arch/arm/include/asm/uprobes.h
new file mode 100644
index 000..e5acaa3
--- /dev/null
+++ b/arch/arm/include/asm/uprobes.h
@@ -0,0 +1,34 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+
+#include asm/probes.h
+
+typedef u32 uprobe_opcode_t;
+
+#define MAX_UINSN_BYTES4
+#define UPROBE_XOL_SLOT_BYTES  64
+
+#define UPROBE_SWBP_INSN   0xe7f001f9
+#define UPROBE_SS_INSN 0xe7f001fa
+#define UPROBE_SWBP_INSN_SIZE  4
+
+struct arch_uprobe_task {
+   u32 backup;
+};
+
+struct arch_uprobe {
+   u8 insn[MAX_UINSN_BYTES];
+   unsigned long ixol[2];
+   uprobe_opcode_t bpinsn;
+   bool simulate;
+   u32 pcreg;
+   void (*prehandler)(struct arch_uprobe *auprobe,
+  struct arch_uprobe_task *autask,
+  struct pt_regs *regs);
+   void (*posthandler)(struct arch_uprobe *auprobe,
+   struct arch_uprobe_task *autask,
+   struct pt_regs *regs);
+   struct arch_specific_insn asi;
+};
+
+#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index bb739f2..a766bcb 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE)  += ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)+= ftrace.o insn.o
 obj-$(CONFIG_JUMP_LABEL)   += jump_label.o insn.o patch.o
 obj-$(CONFIG_KEXEC)+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_UPROBES)  += probes.o probes-arm.o uprobes.o uprobes-arm.o