diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-04-19 05:52:17 -0400 |
---|---|---|
committer | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-04-28 23:40:59 -0400 |
commit | c9836777d5f22e64eefc759d682511560b6d6d78 (patch) | |
tree | 37dbdb0ad5465fd1b290cc4742dd9f380b6f7ed6 /arch/arm/kernel/kprobes-decode.c | |
parent | f704a6e25bd07e1381af81f19fb1d123975807b1 (diff) |
ARM: kprobes: Add emulation of MOVW and MOVT instructions
The MOVW and MOVT instructions account for approximately 7% of all
instructions in a ARMv7 kernel as GCC uses them instead of a literal
pool.
Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel/kprobes-decode.c')
-rw-r--r-- | arch/arm/kernel/kprobes-decode.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 4715537b490c..a063f152d9b3 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c | |||
@@ -661,6 +661,17 @@ static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) | |||
661 | { | 661 | { |
662 | } | 662 | } |
663 | 663 | ||
664 | static void __kprobes | ||
665 | emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) | ||
666 | { | ||
667 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
668 | kprobe_opcode_t insn = p->opcode; | ||
669 | int rd = (insn >> 12) & 0xf; | ||
670 | long rdv = regs->uregs[rd]; | ||
671 | |||
672 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); | ||
673 | } | ||
674 | |||
664 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | 675 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) |
665 | { | 676 | { |
666 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | 677 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; |
@@ -847,6 +858,18 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
847 | } | 858 | } |
848 | 859 | ||
849 | static enum kprobe_insn __kprobes | 860 | static enum kprobe_insn __kprobes |
861 | prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
862 | { | ||
863 | if (is_r15(insn, 12)) | ||
864 | return INSN_REJECTED; /* Rd is PC */ | ||
865 | |||
866 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
867 | asi->insn[0] = insn; | ||
868 | asi->insn_handler = emulate_rd12_modify; | ||
869 | return INSN_GOOD; | ||
870 | } | ||
871 | |||
872 | static enum kprobe_insn __kprobes | ||
850 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 873 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
851 | { | 874 | { |
852 | if (is_r15(insn, 12)) | 875 | if (is_r15(insn, 12)) |
@@ -1170,14 +1193,17 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1170 | static enum kprobe_insn __kprobes | 1193 | static enum kprobe_insn __kprobes |
1171 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 1194 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
1172 | { | 1195 | { |
1196 | /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | ||
1197 | /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
1198 | if ((insn & 0x0fb00000) == 0x03000000) | ||
1199 | return prep_emulate_rd12_modify(insn, asi); | ||
1200 | |||
1173 | /* | 1201 | /* |
1174 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx | 1202 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx |
1175 | * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx | ||
1176 | * ALU op with S bit and Rd == 15 : | 1203 | * ALU op with S bit and Rd == 15 : |
1177 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx | 1204 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx |
1178 | */ | 1205 | */ |
1179 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ | 1206 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ |
1180 | (insn & 0x0ff00000) == 0x03400000 || /* Undef */ | ||
1181 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ | 1207 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ |
1182 | return INSN_REJECTED; | 1208 | return INSN_REJECTED; |
1183 | 1209 | ||