aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-07-07 03:57:22 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:45 -0400
commit235a4ce79feb8d5351f9164981bc57d5e29f974b (patch)
treec3dd0e698781faf592b2b01880103cf0d57d8a92 /arch/arm/kernel
parent263e368a2f1f960db07d7524a4a3e7df951f1f72 (diff)
ARM: kprobes: Add common decoding function for LDM and STM
The encoding of these instructions is substantially the same for both ARM and Thumb, so we can have common decoding and simulation functions. This patch moves the simulation functions from kprobes-arm.c to kprobes-common.c. It also adds a new simulation function (simulate_ldm1_pc) for the case where we load into PC because this may need to interwork. The instruction decoding is done by a custom function (kprobe_decode_ldmstm) rather than just relying on decoding table entries because we will later be adding optimisation code. 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-arm.c58
-rw-r--r--arch/arm/kernel/kprobes-common.c70
-rw-r--r--arch/arm/kernel/kprobes.h3
3 files changed, 80 insertions, 51 deletions
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c
index a1143e86a09a..c6f2c693b1b6 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/kernel/kprobes-arm.c
@@ -437,54 +437,6 @@ static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
437 regs->uregs[rd] = regs->ARM_cpsr & mask; 437 regs->uregs[rd] = regs->ARM_cpsr & mask;
438} 438}
439 439
440static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
441{
442 kprobe_opcode_t insn = p->opcode;
443 int rn = (insn >> 16) & 0xf;
444 int lbit = insn & (1 << 20);
445 int wbit = insn & (1 << 21);
446 int ubit = insn & (1 << 23);
447 int pbit = insn & (1 << 24);
448 long *addr = (long *)regs->uregs[rn];
449 int reg_bit_vector;
450 int reg_count;
451
452 reg_count = 0;
453 reg_bit_vector = insn & 0xffff;
454 while (reg_bit_vector) {
455 reg_bit_vector &= (reg_bit_vector - 1);
456 ++reg_count;
457 }
458
459 if (!ubit)
460 addr -= reg_count;
461 addr += (!pbit == !ubit);
462
463 reg_bit_vector = insn & 0xffff;
464 while (reg_bit_vector) {
465 int reg = __ffs(reg_bit_vector);
466 reg_bit_vector &= (reg_bit_vector - 1);
467 if (lbit)
468 regs->uregs[reg] = *addr++;
469 else
470 *addr++ = regs->uregs[reg];
471 }
472
473 if (wbit) {
474 if (!ubit)
475 addr -= reg_count;
476 addr -= (!pbit == !ubit);
477 regs->uregs[rn] = (long)addr;
478 }
479}
480
481static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
482{
483 regs->ARM_pc = (long)p->addr + str_pc_offset;
484 simulate_ldm1stm1(p, regs);
485 regs->ARM_pc = (long)p->addr + 4;
486}
487
488static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) 440static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
489{ 441{
490 regs->uregs[12] = regs->uregs[13]; 442 regs->uregs[12] = regs->uregs[13];
@@ -1463,9 +1415,13 @@ space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1463 1415
1464 /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ 1416 /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
1465 /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ 1417 /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
1466 asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ 1418
1467 simulate_stm1_pc : simulate_ldm1stm1; 1419 /*
1468 return INSN_GOOD_NO_SLOT; 1420 * Make the instruction unconditional because the new emulation
1421 * functions don't bother to setup the PSR context.
1422 */
1423 insn = (insn | 0xe0000000) & ~0x10000000;
1424 return kprobe_decode_ldmstm(insn, asi);
1469} 1425}
1470 1426
1471static enum kprobe_insn __kprobes 1427static enum kprobe_insn __kprobes
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index 86fdc4c4c2ce..43d663cafdd1 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -166,6 +166,76 @@ void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs)
166 p->ainsn.insn_fn(); 166 p->ainsn.insn_fn();
167} 167}
168 168
169static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
170{
171 kprobe_opcode_t insn = p->opcode;
172 int rn = (insn >> 16) & 0xf;
173 int lbit = insn & (1 << 20);
174 int wbit = insn & (1 << 21);
175 int ubit = insn & (1 << 23);
176 int pbit = insn & (1 << 24);
177 long *addr = (long *)regs->uregs[rn];
178 int reg_bit_vector;
179 int reg_count;
180
181 reg_count = 0;
182 reg_bit_vector = insn & 0xffff;
183 while (reg_bit_vector) {
184 reg_bit_vector &= (reg_bit_vector - 1);
185 ++reg_count;
186 }
187
188 if (!ubit)
189 addr -= reg_count;
190 addr += (!pbit == !ubit);
191
192 reg_bit_vector = insn & 0xffff;
193 while (reg_bit_vector) {
194 int reg = __ffs(reg_bit_vector);
195 reg_bit_vector &= (reg_bit_vector - 1);
196 if (lbit)
197 regs->uregs[reg] = *addr++;
198 else
199 *addr++ = regs->uregs[reg];
200 }
201
202 if (wbit) {
203 if (!ubit)
204 addr -= reg_count;
205 addr -= (!pbit == !ubit);
206 regs->uregs[rn] = (long)addr;
207 }
208}
209
210static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
211{
212 regs->ARM_pc = (long)p->addr + str_pc_offset;
213 simulate_ldm1stm1(p, regs);
214 regs->ARM_pc = (long)p->addr + 4;
215}
216
217static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs)
218{
219 simulate_ldm1stm1(p, regs);
220 load_write_pc(regs->ARM_pc, regs);
221}
222
223enum kprobe_insn __kprobes
224kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
225{
226 kprobe_insn_handler_t *handler = 0;
227 unsigned reglist = insn & 0xffff;
228 int is_ldm = insn & 0x100000;
229
230 if (reglist & 0x8000)
231 handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
232 else
233 handler = simulate_ldm1stm1;
234 asi->insn_handler = handler;
235 return INSN_GOOD_NO_SLOT;
236}
237
238
169/* 239/*
170 * Prepare an instruction slot to receive an instruction for emulating. 240 * Prepare an instruction slot to receive an instruction for emulating.
171 * This is done by placing a subroutine return after the location where the 241 * This is done by placing a subroutine return after the location where the
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h
index 5d6bf0d0a18a..c442852e65e4 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/kernel/kprobes.h
@@ -136,6 +136,9 @@ static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
136void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); 136void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs);
137void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); 137void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs);
138 138
139enum kprobe_insn __kprobes
140kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
141
139/* 142/*
140 * Test if load/store instructions writeback the address register. 143 * Test if load/store instructions writeback the address register.
141 * if P (bit 24) == 0 or W (bit 21) == 1 144 * if P (bit 24) == 0 or W (bit 21) == 1