aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-04-06 06:17:09 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2011-04-28 23:40:54 -0400
commit073090cb701148396b1130be81f8ac84a41f196d (patch)
tree033428a02241173a7645e8f84f8382d0fb8eaab8 /arch
parentcf3cc1aa9b6d0bf1750143af65829f4368d77492 (diff)
ARM: kprobes: Fix probing of conditionally executed instructions
When a kprobe is placed onto conditionally executed ARM instructions, many of the emulation routines used to single step them produce corrupt register results. Rather than fix all of these cases we modify the framework which calls them to test the relevant condition flags and, if the test fails, skip calling the emulation code. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/kprobes.h3
-rw-r--r--arch/arm/kernel/kprobes-decode.c91
-rw-r--r--arch/arm/kernel/kprobes.c3
3 files changed, 96 insertions, 1 deletions
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index bb8a19bd5822..e46bdd0097eb 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -39,10 +39,13 @@ typedef u32 kprobe_opcode_t;
39struct kprobe; 39struct kprobe;
40typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); 40typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
41 41
42typedef unsigned long (kprobe_check_cc)(unsigned long);
43
42/* Architecture specific copy of original instruction. */ 44/* Architecture specific copy of original instruction. */
43struct arch_specific_insn { 45struct arch_specific_insn {
44 kprobe_opcode_t *insn; 46 kprobe_opcode_t *insn;
45 kprobe_insn_handler_t *insn_handler; 47 kprobe_insn_handler_t *insn_handler;
48 kprobe_check_cc *insn_check_cc;
46}; 49};
47 50
48struct prev_kprobe { 51struct prev_kprobe {
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index 3b0cf90cb449..2e84169b9e91 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -1396,6 +1396,96 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1396 return INSN_GOOD; 1396 return INSN_GOOD;
1397} 1397}
1398 1398
1399static unsigned long __kprobes __check_eq(unsigned long cpsr)
1400{
1401 return cpsr & PSR_Z_BIT;
1402}
1403
1404static unsigned long __kprobes __check_ne(unsigned long cpsr)
1405{
1406 return (~cpsr) & PSR_Z_BIT;
1407}
1408
1409static unsigned long __kprobes __check_cs(unsigned long cpsr)
1410{
1411 return cpsr & PSR_C_BIT;
1412}
1413
1414static unsigned long __kprobes __check_cc(unsigned long cpsr)
1415{
1416 return (~cpsr) & PSR_C_BIT;
1417}
1418
1419static unsigned long __kprobes __check_mi(unsigned long cpsr)
1420{
1421 return cpsr & PSR_N_BIT;
1422}
1423
1424static unsigned long __kprobes __check_pl(unsigned long cpsr)
1425{
1426 return (~cpsr) & PSR_N_BIT;
1427}
1428
1429static unsigned long __kprobes __check_vs(unsigned long cpsr)
1430{
1431 return cpsr & PSR_V_BIT;
1432}
1433
1434static unsigned long __kprobes __check_vc(unsigned long cpsr)
1435{
1436 return (~cpsr) & PSR_V_BIT;
1437}
1438
1439static unsigned long __kprobes __check_hi(unsigned long cpsr)
1440{
1441 cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
1442 return cpsr & PSR_C_BIT;
1443}
1444
1445static unsigned long __kprobes __check_ls(unsigned long cpsr)
1446{
1447 cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
1448 return (~cpsr) & PSR_C_BIT;
1449}
1450
1451static unsigned long __kprobes __check_ge(unsigned long cpsr)
1452{
1453 cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
1454 return (~cpsr) & PSR_N_BIT;
1455}
1456
1457static unsigned long __kprobes __check_lt(unsigned long cpsr)
1458{
1459 cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
1460 return cpsr & PSR_N_BIT;
1461}
1462
1463static unsigned long __kprobes __check_gt(unsigned long cpsr)
1464{
1465 unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
1466 temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
1467 return (~temp) & PSR_N_BIT;
1468}
1469
1470static unsigned long __kprobes __check_le(unsigned long cpsr)
1471{
1472 unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
1473 temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
1474 return temp & PSR_N_BIT;
1475}
1476
1477static unsigned long __kprobes __check_al(unsigned long cpsr)
1478{
1479 return true;
1480}
1481
1482static kprobe_check_cc * const condition_checks[16] = {
1483 &__check_eq, &__check_ne, &__check_cs, &__check_cc,
1484 &__check_mi, &__check_pl, &__check_vs, &__check_vc,
1485 &__check_hi, &__check_ls, &__check_ge, &__check_lt,
1486 &__check_gt, &__check_le, &__check_al, &__check_al
1487};
1488
1399/* Return: 1489/* Return:
1400 * INSN_REJECTED If instruction is one not allowed to kprobe, 1490 * INSN_REJECTED If instruction is one not allowed to kprobe,
1401 * INSN_GOOD If instruction is supported and uses instruction slot, 1491 * INSN_GOOD If instruction is supported and uses instruction slot,
@@ -1411,6 +1501,7 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1411enum kprobe_insn __kprobes 1501enum kprobe_insn __kprobes
1412arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) 1502arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
1413{ 1503{
1504 asi->insn_check_cc = condition_checks[insn>>28];
1414 asi->insn[1] = KPROBE_RETURN_INSTRUCTION; 1505 asi->insn[1] = KPROBE_RETURN_INSTRUCTION;
1415 1506
1416 if ((insn & 0xf0000000) == 0xf0000000) { 1507 if ((insn & 0xf0000000) == 0xf0000000) {
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index 2ba7deb3072e..1656c87501c0 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -134,7 +134,8 @@ static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
134 struct kprobe_ctlblk *kcb) 134 struct kprobe_ctlblk *kcb)
135{ 135{
136 regs->ARM_pc += 4; 136 regs->ARM_pc += 4;
137 p->ainsn.insn_handler(p, regs); 137 if (p->ainsn.insn_check_cc(regs->ARM_cpsr))
138 p->ainsn.insn_handler(p, regs);
138} 139}
139 140
140/* 141/*