[PATCH 02/51] ARM: Thumb-2: Support Thumb-2 in undefined instruction handler
Nicolas Pitre
nico at fluxnic.net
Mon Jul 11 14:14:45 EDT 2011
On Sat, 9 Jul 2011, Tixy wrote:
> From: Jon Medhurst <tixy at yxit.co.uk>
>
> This patch allows undef_hook's to be specified for 32-bit Thumb
> instructions and also to be used for thumb kernel-side code.
>
> 32-bit Thumb instructions are specified in the form:
> ((first_half << 16 ) | second_half)
> which matches the layout used by the ARM ARM.
>
> ptrace was handling 32-bit Thumb instructions by hooking the first
> halfword and manually checking the second half. This method would be
> broken by this patch so it is migrated to make use of the new Thumb-2
> support.
>
> Signed-off-by: Jon Medhurst <tixy at yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre at linaro.org>
> ---
> arch/arm/include/asm/ptrace.h | 8 ++++++++
> arch/arm/kernel/ptrace.c | 28 +++-------------------------
> arch/arm/kernel/traps.c | 17 ++++++++++++++++-
> 3 files changed, 27 insertions(+), 26 deletions(-)
>
> diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
> index 312d108..d484871 100644
> --- a/arch/arm/include/asm/ptrace.h
> +++ b/arch/arm/include/asm/ptrace.h
> @@ -200,6 +200,14 @@ extern unsigned long profile_pc(struct pt_regs *regs);
> #define PREDICATE_ALWAYS 0xe0000000
>
> /*
> + * True if instr is a 32-bit thumb instruction. This works if instr
> + * is the first or only half-word of a thumb instruction. It also works
> + * when instr holds all 32-bits of a wide thumb instruction if stored
> + * in the form (first_half<<16)|(second_half)
> + */
> +#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800)
> +
> +/*
> * kprobe-based event tracer support
> */
> #include <linux/stddef.h>
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 9726006..897ade0 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = {
> .fn = break_trap,
> };
>
> -static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr)
> -{
> - unsigned int instr2;
> - void __user *pc;
> -
> - /* Check the second half of the instruction. */
> - pc = (void __user *)(instruction_pointer(regs) + 2);
> -
> - if (processor_mode(regs) == SVC_MODE) {
> - instr2 = *(u16 *) pc;
> - } else {
> - get_user(instr2, (u16 __user *)pc);
> - }
> -
> - if (instr2 == 0xa000) {
> - ptrace_break(current, regs);
> - return 0;
> - } else {
> - return 1;
> - }
> -}
> -
> static struct undef_hook thumb2_break_hook = {
> - .instr_mask = 0xffff,
> - .instr_val = 0xf7f0,
> + .instr_mask = 0xffffffff,
> + .instr_val = 0xf7f0a000,
> .cpsr_mask = PSR_T_BIT,
> .cpsr_val = PSR_T_BIT,
> - .fn = thumb2_break_trap,
> + .fn = break_trap,
> };
>
> static int __init ptrace_break_init(void)
> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
> index 6807cb1..2d3436e 100644
> --- a/arch/arm/kernel/traps.c
> +++ b/arch/arm/kernel/traps.c
> @@ -355,9 +355,24 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
> pc = (void __user *)instruction_pointer(regs);
>
> if (processor_mode(regs) == SVC_MODE) {
> - instr = *(u32 *) pc;
> +#ifdef CONFIG_THUMB2_KERNEL
> + if (thumb_mode(regs)) {
> + instr = ((u16 *)pc)[0];
> + if (is_wide_instruction(instr)) {
> + instr <<= 16;
> + instr |= ((u16 *)pc)[1];
> + }
> + } else
> +#endif
> + instr = *(u32 *) pc;
> } else if (thumb_mode(regs)) {
> get_user(instr, (u16 __user *)pc);
> + if (is_wide_instruction(instr)) {
> + unsigned int instr2;
> + get_user(instr2, (u16 __user *)pc+1);
> + instr <<= 16;
> + instr |= instr2;
> + }
> } else {
> get_user(instr, (u32 __user *)pc);
> }
> --
> 1.7.2.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
More information about the linux-arm-kernel
mailing list