aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-07-02 10:54:57 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:43 -0400
commit3b5940e81182ff26d539dcf0ee8b2310f6965833 (patch)
treec0ad6095b0a3ffca78c13250d9a7e65e8388b8b6 /arch/arm/kernel
parenta9c3c29e72cc459be0ecd597f0af11a67713175b (diff)
ARM: kprobes: Decode 16-bit Thumb special data instructions
These data-processing instructions operate on the full range of CPU registers, so to simulate them we have to modify the registers used by the instruction. We can't make use of the decoding table framework to do this because the registers aren't encoded cleanly in separate nibbles, therefore we need a custom decode function. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/kprobes-thumb.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index b457da0e7397..cd4d03d19950 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -87,6 +87,47 @@ t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs)
87 regs->ARM_cpsr = cpsr; 87 regs->ARM_cpsr = cpsr;
88} 88}
89 89
90static void __kprobes
91t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs)
92{
93 kprobe_opcode_t insn = p->opcode;
94 unsigned long pc = thumb_probe_pc(p);
95 int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
96 int rm = (insn >> 3) & 0xf;
97
98 register unsigned long rdnv asm("r1");
99 register unsigned long rmv asm("r0");
100 unsigned long cpsr = regs->ARM_cpsr;
101
102 rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
103 rmv = (rm == 15) ? pc : regs->uregs[rm];
104
105 __asm__ __volatile__ (
106 "msr cpsr_fs, %[cpsr] \n\t"
107 "blx %[fn] \n\t"
108 "mrs %[cpsr], cpsr \n\t"
109 : "=r" (rdnv), [cpsr] "=r" (cpsr)
110 : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
111 : "lr", "memory", "cc"
112 );
113
114 if (rdn == 15)
115 rdnv &= ~1;
116
117 regs->uregs[rdn] = rdnv;
118 regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
119}
120
121static enum kprobe_insn __kprobes
122t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi)
123{
124 insn &= ~0x00ff;
125 insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
126 ((u16 *)asi->insn)[0] = insn;
127 asi->insn_handler = t16_emulate_hiregs;
128 return INSN_GOOD;
129}
130
90static const union decode_item t16_table_1011[] = { 131static const union decode_item t16_table_1011[] = {
91 /* Miscellaneous 16-bit instructions */ 132 /* Miscellaneous 16-bit instructions */
92 133
@@ -168,6 +209,14 @@ const union decode_item kprobe_decode_thumb16_table[] = {
168 /* BLX (register) 0100 0111 1xxx xxxx */ 209 /* BLX (register) 0100 0111 1xxx xxxx */
169 DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), 210 DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx),
170 211
212 /* ADD pc, pc 0100 0100 1111 1111 */
213 DECODE_REJECT (0xffff, 0x44ff),
214
215 /* ADD (register) 0100 0100 xxxx xxxx */
216 /* CMP (register) 0100 0101 xxxx xxxx */
217 /* MOV (register) 0100 0110 xxxx xxxx */
218 DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs),
219
171 /* 220 /*
172 * Miscellaneous 16-bit instructions 221 * Miscellaneous 16-bit instructions
173 * 1011 xxxx xxxx xxxx 222 * 1011 xxxx xxxx xxxx