diff options
| -rw-r--r-- | arch/arm/kernel/kprobes-arm.c | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index bb38ae3601c8..d252e7821fcc 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c | |||
| @@ -502,7 +502,7 @@ static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) | |||
| 502 | regs->uregs[rn] = rnv_wb; | 502 | regs->uregs[rn] = rnv_wb; |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | 505 | static void __kprobes emulate_ldr_old(struct kprobe *p, struct pt_regs *regs) |
| 506 | { | 506 | { |
| 507 | insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; | 507 | insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; |
| 508 | kprobe_opcode_t insn = p->opcode; | 508 | kprobe_opcode_t insn = p->opcode; |
| @@ -535,7 +535,7 @@ static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | |||
| 535 | regs->uregs[rd] = rdv; | 535 | regs->uregs[rd] = rdv; |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | 538 | static void __kprobes emulate_str_old(struct kprobe *p, struct pt_regs *regs) |
| 539 | { | 539 | { |
| 540 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | 540 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; |
| 541 | kprobe_opcode_t insn = p->opcode; | 541 | kprobe_opcode_t insn = p->opcode; |
| @@ -795,7 +795,7 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
| 795 | insn |= 2; /* Rm = r2 */ | 795 | insn |= 2; /* Rm = r2 */ |
| 796 | } | 796 | } |
| 797 | asi->insn[0] = insn; | 797 | asi->insn[0] = insn; |
| 798 | asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str; | 798 | asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr_old : emulate_str_old; |
| 799 | return INSN_GOOD; | 799 | return INSN_GOOD; |
| 800 | } | 800 | } |
| 801 | 801 | ||
| @@ -923,6 +923,63 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | |||
| 923 | } | 923 | } |
| 924 | 924 | ||
| 925 | static void __kprobes | 925 | static void __kprobes |
| 926 | emulate_ldr(struct kprobe *p, struct pt_regs *regs) | ||
| 927 | { | ||
| 928 | kprobe_opcode_t insn = p->opcode; | ||
| 929 | unsigned long pc = (unsigned long)p->addr + 8; | ||
| 930 | int rt = (insn >> 12) & 0xf; | ||
| 931 | int rn = (insn >> 16) & 0xf; | ||
| 932 | int rm = insn & 0xf; | ||
| 933 | |||
| 934 | register unsigned long rtv asm("r0"); | ||
| 935 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
| 936 | : regs->uregs[rn]; | ||
| 937 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
| 938 | |||
| 939 | __asm__ __volatile__ ( | ||
| 940 | BLX("%[fn]") | ||
| 941 | : "=r" (rtv), "=r" (rnv) | ||
| 942 | : "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
| 943 | : "lr", "memory", "cc" | ||
| 944 | ); | ||
| 945 | |||
| 946 | if (rt == 15) | ||
| 947 | load_write_pc(rtv, regs); | ||
| 948 | else | ||
| 949 | regs->uregs[rt] = rtv; | ||
| 950 | |||
| 951 | if (is_writeback(insn)) | ||
| 952 | regs->uregs[rn] = rnv; | ||
| 953 | } | ||
| 954 | |||
| 955 | static void __kprobes | ||
| 956 | emulate_str(struct kprobe *p, struct pt_regs *regs) | ||
| 957 | { | ||
| 958 | kprobe_opcode_t insn = p->opcode; | ||
| 959 | unsigned long rtpc = (unsigned long)p->addr + str_pc_offset; | ||
| 960 | unsigned long rnpc = (unsigned long)p->addr + 8; | ||
| 961 | int rt = (insn >> 12) & 0xf; | ||
| 962 | int rn = (insn >> 16) & 0xf; | ||
| 963 | int rm = insn & 0xf; | ||
| 964 | |||
| 965 | register unsigned long rtv asm("r0") = (rt == 15) ? rtpc | ||
| 966 | : regs->uregs[rt]; | ||
| 967 | register unsigned long rnv asm("r2") = (rn == 15) ? rnpc | ||
| 968 | : regs->uregs[rn]; | ||
| 969 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
| 970 | |||
| 971 | __asm__ __volatile__ ( | ||
| 972 | BLX("%[fn]") | ||
| 973 | : "=r" (rnv) | ||
| 974 | : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
| 975 | : "lr", "memory", "cc" | ||
| 976 | ); | ||
| 977 | |||
| 978 | if (is_writeback(insn)) | ||
| 979 | regs->uregs[rn] = rnv; | ||
| 980 | } | ||
| 981 | |||
| 982 | static void __kprobes | ||
| 926 | emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) | 983 | emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) |
| 927 | { | 984 | { |
| 928 | kprobe_opcode_t insn = p->opcode; | 985 | kprobe_opcode_t insn = p->opcode; |
