aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-04-06 06:17:11 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-04-28 23:40:55 -0400
commitad111ce46674a473370d302325db8f418ac4fe92 (patch)
treef99fc1a1dd357e431f8be4ca0b9784d8ad7797f8 /arch/arm
parenta539f5d46c868cb1f37b92e62e040b400571aed4 (diff)
ARM: kprobes: Fix emulation of CMP, CMN, TST and TEQ instructions.
Probing these instructions was corrupting R0 because the emulation code didn't account for the fact that they don't write a result to a register. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/kprobes-decode.c55
1 files changed, 53 insertions, 2 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index f52fac0c59f0..ee29d3350437 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -808,6 +808,17 @@ emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs)
808} 808}
809 809
810static void __kprobes 810static void __kprobes
811emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs)
812{
813 insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
814 kprobe_opcode_t insn = p->opcode;
815 int rn = (insn >> 16) & 0xf;
816 long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
817
818 insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
819}
820
821static void __kprobes
811emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) 822emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs)
812{ 823{
813 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; 824 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
@@ -843,6 +854,22 @@ emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs)
843 insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn); 854 insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
844} 855}
845 856
857static void __kprobes
858emulate_alu_tests(struct kprobe *p, struct pt_regs *regs)
859{
860 insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
861 kprobe_opcode_t insn = p->opcode;
862 long ppc = (long)p->addr + 8;
863 int rn = (insn >> 16) & 0xf;
864 int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */
865 int rm = insn & 0xf;
866 long rnv = (rn == 15) ? ppc : regs->uregs[rn];
867 long rmv = (rm == 15) ? ppc : regs->uregs[rm];
868 long rsv = regs->uregs[rs];
869
870 insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
871}
872
846static enum kprobe_insn __kprobes 873static enum kprobe_insn __kprobes
847prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) 874prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
848{ 875{
@@ -1142,8 +1169,20 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1142 insn |= 0x00000200; /* Rs = r2 */ 1169 insn |= 0x00000200; /* Rs = r2 */
1143 } 1170 }
1144 asi->insn[0] = insn; 1171 asi->insn[0] = insn;
1145 asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ 1172
1173 if ((insn & 0x0f900000) == 0x01100000) {
1174 /*
1175 * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx
1176 * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx
1177 * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx
1178 * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx
1179 */
1180 asi->insn_handler = emulate_alu_tests;
1181 } else {
1182 /* ALU ops which write to Rd */
1183 asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */
1146 emulate_alu_rwflags : emulate_alu_rflags; 1184 emulate_alu_rwflags : emulate_alu_rflags;
1185 }
1147 return INSN_GOOD; 1186 return INSN_GOOD;
1148} 1187}
1149 1188
@@ -1170,8 +1209,20 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1170 */ 1209 */
1171 insn &= 0xffff0fff; /* Rd = r0 */ 1210 insn &= 0xffff0fff; /* Rd = r0 */
1172 asi->insn[0] = insn; 1211 asi->insn[0] = insn;
1173 asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ 1212
1213 if ((insn & 0x0f900000) == 0x03100000) {
1214 /*
1215 * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx
1216 * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx
1217 * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx
1218 * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx
1219 */
1220 asi->insn_handler = emulate_alu_tests_imm;
1221 } else {
1222 /* ALU ops which write to Rd */
1223 asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */
1174 emulate_alu_imm_rwflags : emulate_alu_imm_rflags; 1224 emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
1225 }
1175 return INSN_GOOD; 1226 return INSN_GOOD;
1176} 1227}
1177 1228