diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-06-11 08:10:49 -0400 |
---|---|---|
committer | Tixy <tixy@medhuaa1.miniserver.com> | 2011-07-13 13:32:50 -0400 |
commit | 3c48fbb1478f47a95d18a56ff2662b40cb236152 (patch) | |
tree | f9347be87b549151684767be44025ebfd540e6c8 /arch/arm/kernel/kprobes-arm.c | |
parent | 12ce5d3388dab15109e94eb847c948b23b709a03 (diff) |
ARM: kprobes: Add new versions of emulate_ldr() and emulate_str()
These use the register calling conventions required by the new decoding
table framework for calling simulated instructions.
We rename the old versions of these functions to *_old for now.
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel/kprobes-arm.c')
-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; |