aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-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