diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 58 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-common.c | 70 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.h | 3 |
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 | ||
440 | static 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 | |||
481 | static 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 | |||
488 | static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | 440 | static 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 | ||
1471 | static enum kprobe_insn __kprobes | 1427 | static 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 | ||
169 | static 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 | |||
210 | static 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 | |||
217 | static 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 | |||
223 | enum kprobe_insn __kprobes | ||
224 | kprobe_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) | |||
136 | void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); | 136 | void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); |
137 | void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); | 137 | void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); |
138 | 138 | ||
139 | enum kprobe_insn __kprobes | ||
140 | kprobe_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 |