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