diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 113 |
1 files changed, 11 insertions, 102 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 8391dac41855..ff3970741653 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c | |||
@@ -520,17 +520,6 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | |||
520 | regs->uregs[12] = regs->uregs[13]; | 520 | regs->uregs[12] = regs->uregs[13]; |
521 | } | 521 | } |
522 | 522 | ||
523 | static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs) | ||
524 | { | ||
525 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
526 | kprobe_opcode_t insn = p->opcode; | ||
527 | int rn = (insn >> 16) & 0xf; | ||
528 | long rnv = regs->uregs[rn]; | ||
529 | |||
530 | /* Save Rn in case of writeback. */ | ||
531 | regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
532 | } | ||
533 | |||
534 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | 523 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) |
535 | { | 524 | { |
536 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | 525 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; |
@@ -635,31 +624,6 @@ static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | |||
635 | regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ | 624 | regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ |
636 | } | 625 | } |
637 | 626 | ||
638 | static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs) | ||
639 | { | ||
640 | insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0]; | ||
641 | kprobe_opcode_t insn = p->opcode; | ||
642 | union reg_pair fnr; | ||
643 | int rd = (insn >> 12) & 0xf; | ||
644 | int rn = (insn >> 16) & 0xf; | ||
645 | |||
646 | fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
647 | regs->uregs[rn] = fnr.r0; | ||
648 | regs->uregs[rd] = fnr.r1; | ||
649 | } | ||
650 | |||
651 | static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs) | ||
652 | { | ||
653 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
654 | kprobe_opcode_t insn = p->opcode; | ||
655 | int rd = (insn >> 12) & 0xf; | ||
656 | int rn = (insn >> 16) & 0xf; | ||
657 | long rnv = regs->uregs[rn]; | ||
658 | long rdv = regs->uregs[rd]; | ||
659 | |||
660 | insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn); | ||
661 | } | ||
662 | |||
663 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | 627 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) |
664 | { | 628 | { |
665 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | 629 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; |
@@ -693,24 +657,6 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | |||
693 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | 657 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); |
694 | } | 658 | } |
695 | 659 | ||
696 | static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs) | ||
697 | { | ||
698 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
699 | kprobe_opcode_t insn = p->opcode; | ||
700 | int rd = (insn >> 12) & 0xf; | ||
701 | |||
702 | regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
703 | } | ||
704 | |||
705 | static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs) | ||
706 | { | ||
707 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
708 | kprobe_opcode_t insn = p->opcode; | ||
709 | int ird = (insn >> 12) & 0xf; | ||
710 | |||
711 | insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn); | ||
712 | } | ||
713 | |||
714 | static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) | 660 | static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) |
715 | { | 661 | { |
716 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | 662 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; |
@@ -1010,40 +956,22 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1010 | } | 956 | } |
1011 | 957 | ||
1012 | /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | 958 | /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ |
1013 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | 959 | if ((insn & 0xffff00f0) == 0xf1010000) { |
1014 | if ((insn & 0xffff00f0) == 0xf1010000 || | ||
1015 | (insn & 0xff000010) == 0xfe000000) { | ||
1016 | asi->insn[0] = insn; | 960 | asi->insn[0] = insn; |
1017 | asi->insn_handler = emulate_none; | 961 | asi->insn_handler = emulate_none; |
1018 | return INSN_GOOD; | 962 | return INSN_GOOD; |
1019 | } | 963 | } |
1020 | 964 | ||
965 | /* Coprocessor instructions... */ | ||
1021 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | 966 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ |
1022 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | 967 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ |
1023 | if ((insn & 0xffe00000) == 0xfc400000) { | 968 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ |
1024 | insn &= 0xfff00fff; /* Rn = r0 */ | 969 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ |
1025 | insn |= 0x00001000; /* Rd = r1 */ | 970 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ |
1026 | asi->insn[0] = insn; | 971 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ |
1027 | asi->insn_handler = | 972 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ |
1028 | (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | ||
1029 | return INSN_GOOD; | ||
1030 | } | ||
1031 | 973 | ||
1032 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | 974 | return INSN_REJECTED; |
1033 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1034 | if ((insn & 0xfe000000) == 0xfc000000) { | ||
1035 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
1036 | asi->insn[0] = insn; | ||
1037 | asi->insn_handler = emulate_ldcstc; | ||
1038 | return INSN_GOOD; | ||
1039 | } | ||
1040 | |||
1041 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
1042 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
1043 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
1044 | asi->insn[0] = insn; | ||
1045 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | ||
1046 | return INSN_GOOD; | ||
1047 | } | 975 | } |
1048 | 976 | ||
1049 | static enum kprobe_insn __kprobes | 977 | static enum kprobe_insn __kprobes |
@@ -1504,14 +1432,7 @@ space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1504 | { | 1432 | { |
1505 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | 1433 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ |
1506 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | 1434 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ |
1507 | if (is_r15(insn, 16) || is_r15(insn, 12)) | 1435 | return INSN_REJECTED; |
1508 | return INSN_REJECTED; /* Rn or Rd is PC */ | ||
1509 | |||
1510 | insn &= 0xfff00fff; | ||
1511 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | ||
1512 | asi->insn[0] = insn; | ||
1513 | asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | ||
1514 | return INSN_GOOD; | ||
1515 | } | 1436 | } |
1516 | 1437 | ||
1517 | static enum kprobe_insn __kprobes | 1438 | static enum kprobe_insn __kprobes |
@@ -1519,10 +1440,7 @@ space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1519 | { | 1440 | { |
1520 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | 1441 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ |
1521 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | 1442 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ |
1522 | insn &= 0xfff0ffff; /* Rn = r0 */ | 1443 | return INSN_REJECTED; |
1523 | asi->insn[0] = insn; | ||
1524 | asi->insn_handler = emulate_ldcstc; | ||
1525 | return INSN_GOOD; | ||
1526 | } | 1444 | } |
1527 | 1445 | ||
1528 | static enum kprobe_insn __kprobes | 1446 | static enum kprobe_insn __kprobes |
@@ -1535,18 +1453,9 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1535 | return INSN_REJECTED; | 1453 | return INSN_REJECTED; |
1536 | 1454 | ||
1537 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | 1455 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ |
1538 | if ((insn & 0x0f000010) == 0x0e000000) { | ||
1539 | asi->insn[0] = insn; | ||
1540 | asi->insn_handler = emulate_none; | ||
1541 | return INSN_GOOD; | ||
1542 | } | ||
1543 | |||
1544 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | 1456 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ |
1545 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | 1457 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ |
1546 | insn &= 0xffff0fff; /* Rd = r0 */ | 1458 | return INSN_REJECTED; |
1547 | asi->insn[0] = insn; | ||
1548 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | ||
1549 | return INSN_GOOD; | ||
1550 | } | 1459 | } |
1551 | 1460 | ||
1552 | static unsigned long __kprobes __check_eq(unsigned long cpsr) | 1461 | static unsigned long __kprobes __check_eq(unsigned long cpsr) |