diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-07-03 09:53:45 -0400 |
---|---|---|
committer | Tixy <tixy@medhuaa1.miniserver.com> | 2011-07-13 13:32:46 -0400 |
commit | ce715c772f0124f9d3f6f5cffcb85688c81d2c07 (patch) | |
tree | 98fb686d960ffb9391303af98c4284cfca14eb54 /arch | |
parent | b06f3ee34d8b817d566d15d25a21f8320b3f7c57 (diff) |
ARM: kprobes: Decode 32-bit Thumb branch instructions
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/kprobes-thumb.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index c07c2470ccaa..1677234000b2 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c | |||
@@ -49,9 +49,9 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) | |||
49 | unsigned long rmv = regs->uregs[rm]; | 49 | unsigned long rmv = regs->uregs[rm]; |
50 | unsigned int halfwords; | 50 | unsigned int halfwords; |
51 | 51 | ||
52 | if (insn & 0x10) | 52 | if (insn & 0x10) /* TBH */ |
53 | halfwords = ((u16 *)rnv)[rmv]; | 53 | halfwords = ((u16 *)rnv)[rmv]; |
54 | else | 54 | else /* TBB */ |
55 | halfwords = ((u8 *)rnv)[rmv]; | 55 | halfwords = ((u8 *)rnv)[rmv]; |
56 | 56 | ||
57 | regs->ARM_pc = pc + 2 * halfwords; | 57 | regs->ARM_pc = pc + 2 * halfwords; |
@@ -66,6 +66,58 @@ t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) | |||
66 | regs->uregs[rd] = regs->ARM_cpsr & mask; | 66 | regs->uregs[rd] = regs->ARM_cpsr & mask; |
67 | } | 67 | } |
68 | 68 | ||
69 | static void __kprobes | ||
70 | t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) | ||
71 | { | ||
72 | kprobe_opcode_t insn = p->opcode; | ||
73 | unsigned long pc = thumb_probe_pc(p); | ||
74 | |||
75 | long offset = insn & 0x7ff; /* imm11 */ | ||
76 | offset += (insn & 0x003f0000) >> 5; /* imm6 */ | ||
77 | offset += (insn & 0x00002000) << 4; /* J1 */ | ||
78 | offset += (insn & 0x00000800) << 7; /* J2 */ | ||
79 | offset -= (insn & 0x04000000) >> 7; /* Apply sign bit */ | ||
80 | |||
81 | regs->ARM_pc = pc + (offset * 2); | ||
82 | } | ||
83 | |||
84 | static enum kprobe_insn __kprobes | ||
85 | t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
86 | { | ||
87 | int cc = (insn >> 22) & 0xf; | ||
88 | asi->insn_check_cc = kprobe_condition_checks[cc]; | ||
89 | asi->insn_handler = t32_simulate_cond_branch; | ||
90 | return INSN_GOOD_NO_SLOT; | ||
91 | } | ||
92 | |||
93 | static void __kprobes | ||
94 | t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) | ||
95 | { | ||
96 | kprobe_opcode_t insn = p->opcode; | ||
97 | unsigned long pc = thumb_probe_pc(p); | ||
98 | |||
99 | long offset = insn & 0x7ff; /* imm11 */ | ||
100 | offset += (insn & 0x03ff0000) >> 5; /* imm10 */ | ||
101 | offset += (insn & 0x00002000) << 9; /* J1 */ | ||
102 | offset += (insn & 0x00000800) << 10; /* J2 */ | ||
103 | if (insn & 0x04000000) | ||
104 | offset -= 0x00800000; /* Apply sign bit */ | ||
105 | else | ||
106 | offset ^= 0x00600000; /* Invert J1 and J2 */ | ||
107 | |||
108 | if (insn & (1 << 14)) { | ||
109 | /* BL or BLX */ | ||
110 | regs->ARM_lr = (unsigned long)p->addr + 4; | ||
111 | if (!(insn & (1 << 12))) { | ||
112 | /* BLX so switch to ARM mode */ | ||
113 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
114 | pc &= ~3; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | regs->ARM_pc = pc + (offset * 2); | ||
119 | } | ||
120 | |||
69 | static enum kprobe_insn __kprobes | 121 | static enum kprobe_insn __kprobes |
70 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 122 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
71 | { | 123 | { |
@@ -425,6 +477,15 @@ static const union decode_item t32_table_1111_0xxx___1[] = { | |||
425 | */ | 477 | */ |
426 | DECODE_REJECT (0xfb80d000, 0xf3808000), | 478 | DECODE_REJECT (0xfb80d000, 0xf3808000), |
427 | 479 | ||
480 | /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ | ||
481 | DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), | ||
482 | |||
483 | /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ | ||
484 | DECODE_OR (0xf800d001, 0xf000c000), | ||
485 | /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ | ||
486 | /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ | ||
487 | DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), | ||
488 | |||
428 | DECODE_END | 489 | DECODE_END |
429 | }; | 490 | }; |
430 | 491 | ||