diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/kprobes.h | 3 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 91 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 3 |
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; | |||
39 | struct kprobe; | 39 | struct kprobe; |
40 | typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); | 40 | typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); |
41 | 41 | ||
42 | typedef unsigned long (kprobe_check_cc)(unsigned long); | ||
43 | |||
42 | /* Architecture specific copy of original instruction. */ | 44 | /* Architecture specific copy of original instruction. */ |
43 | struct arch_specific_insn { | 45 | struct 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 | ||
48 | struct prev_kprobe { | 51 | struct 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 | ||
1399 | static unsigned long __kprobes __check_eq(unsigned long cpsr) | ||
1400 | { | ||
1401 | return cpsr & PSR_Z_BIT; | ||
1402 | } | ||
1403 | |||
1404 | static unsigned long __kprobes __check_ne(unsigned long cpsr) | ||
1405 | { | ||
1406 | return (~cpsr) & PSR_Z_BIT; | ||
1407 | } | ||
1408 | |||
1409 | static unsigned long __kprobes __check_cs(unsigned long cpsr) | ||
1410 | { | ||
1411 | return cpsr & PSR_C_BIT; | ||
1412 | } | ||
1413 | |||
1414 | static unsigned long __kprobes __check_cc(unsigned long cpsr) | ||
1415 | { | ||
1416 | return (~cpsr) & PSR_C_BIT; | ||
1417 | } | ||
1418 | |||
1419 | static unsigned long __kprobes __check_mi(unsigned long cpsr) | ||
1420 | { | ||
1421 | return cpsr & PSR_N_BIT; | ||
1422 | } | ||
1423 | |||
1424 | static unsigned long __kprobes __check_pl(unsigned long cpsr) | ||
1425 | { | ||
1426 | return (~cpsr) & PSR_N_BIT; | ||
1427 | } | ||
1428 | |||
1429 | static unsigned long __kprobes __check_vs(unsigned long cpsr) | ||
1430 | { | ||
1431 | return cpsr & PSR_V_BIT; | ||
1432 | } | ||
1433 | |||
1434 | static unsigned long __kprobes __check_vc(unsigned long cpsr) | ||
1435 | { | ||
1436 | return (~cpsr) & PSR_V_BIT; | ||
1437 | } | ||
1438 | |||
1439 | static 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 | |||
1445 | static 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 | |||
1451 | static 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 | |||
1457 | static 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 | |||
1463 | static 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 | |||
1470 | static 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 | |||
1477 | static unsigned long __kprobes __check_al(unsigned long cpsr) | ||
1478 | { | ||
1479 | return true; | ||
1480 | } | ||
1481 | |||
1482 | static 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) | |||
1411 | enum kprobe_insn __kprobes | 1501 | enum kprobe_insn __kprobes |
1412 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 1502 | arm_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 | /* |