Re: [PATCH v3 14/15] ARM: add uprobes support
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
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
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
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