aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben.dooks@codethink.co.uk>2013-11-08 13:29:25 -0500
committerTaras Kondratiuk <taras@ti.com>2014-04-01 09:45:19 -0400
commit888be25402021a425da3e85e2d5a954d7509286e (patch)
tree5f6a556112fe3098370272c57e482501956d8f6c
parentc7edc9e326d53ca5ef9bed82de0740c6b107d55b (diff)
ARM: probes: fix instruction fetch order with <asm/opcodes.h>
If we are running BE8, the data and instruction endianness do not match, so use <asm/opcodes.h> to correctly translate memory accesses into ARM instructions. Acked-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk> [taras.kondratiuk@linaro.org: fixed Thumb instruction fetch order] Signed-off-by: Taras Kondratiuk <taras.kondratiuk@linaro.org>
-rw-r--r--arch/arm/kernel/kprobes-common.c4
-rw-r--r--arch/arm/kernel/kprobes-thumb.c20
-rw-r--r--arch/arm/kernel/kprobes.c9
-rw-r--r--arch/arm/kernel/probes.c15
4 files changed, 28 insertions, 20 deletions
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index c311ed94ff1c..0bf5d64eba1d 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -13,6 +13,7 @@
13 13
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/kprobes.h> 15#include <linux/kprobes.h>
16#include <asm/opcodes.h>
16 17
17#include "kprobes.h" 18#include "kprobes.h"
18 19
@@ -153,7 +154,8 @@ kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
153 154
154 if (handler) { 155 if (handler) {
155 /* We can emulate the instruction in (possibly) modified form */ 156 /* We can emulate the instruction in (possibly) modified form */
156 asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist; 157 asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
158 (rn << 16) | reglist);
157 asi->insn_handler = handler; 159 asi->insn_handler = handler;
158 return INSN_GOOD; 160 return INSN_GOOD;
159 } 161 }
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index 6619188619ae..9495d7f3516f 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -149,9 +149,9 @@ t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
149 enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d); 149 enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
150 150
151 /* Fixup modified instruction to have halfwords in correct order...*/ 151 /* Fixup modified instruction to have halfwords in correct order...*/
152 insn = asi->insn[0]; 152 insn = __mem_to_opcode_arm(asi->insn[0]);
153 ((u16 *)asi->insn)[0] = insn >> 16; 153 ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
154 ((u16 *)asi->insn)[1] = insn & 0xffff; 154 ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
155 155
156 return ret; 156 return ret;
157} 157}
@@ -516,7 +516,7 @@ t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
516{ 516{
517 insn &= ~0x00ff; 517 insn &= ~0x00ff;
518 insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ 518 insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
519 ((u16 *)asi->insn)[0] = insn; 519 ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
520 asi->insn_handler = t16_emulate_hiregs; 520 asi->insn_handler = t16_emulate_hiregs;
521 return INSN_GOOD; 521 return INSN_GOOD;
522} 522}
@@ -547,8 +547,10 @@ t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
547 * and call it with R9=SP and LR in the register list represented 547 * and call it with R9=SP and LR in the register list represented
548 * by R8. 548 * by R8.
549 */ 549 */
550 ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ 550 /* 1st half STMDB R9!,{} */
551 ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ 551 ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
552 /* 2nd half (register list) */
553 ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
552 asi->insn_handler = t16_emulate_push; 554 asi->insn_handler = t16_emulate_push;
553 return INSN_GOOD; 555 return INSN_GOOD;
554} 556}
@@ -600,8 +602,10 @@ t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
600 * and call it with R9=SP and PC in the register list represented 602 * and call it with R9=SP and PC in the register list represented
601 * by R8. 603 * by R8.
602 */ 604 */
603 ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ 605 /* 1st half LDMIA R9!,{} */
604 ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ 606 ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
607 /* 2nd half (register list) */
608 ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
605 asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc 609 asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
606 : t16_emulate_pop_nopc; 610 : t16_emulate_pop_nopc;
607 return INSN_GOOD; 611 return INSN_GOOD;
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index 8795f9f819d5..6d644202c8dc 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -26,6 +26,7 @@
26#include <linux/stop_machine.h> 26#include <linux/stop_machine.h>
27#include <linux/stringify.h> 27#include <linux/stringify.h>
28#include <asm/traps.h> 28#include <asm/traps.h>
29#include <asm/opcodes.h>
29#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
30#include <linux/percpu.h> 31#include <linux/percpu.h>
31#include <linux/bug.h> 32#include <linux/bug.h>
@@ -67,10 +68,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
67#ifdef CONFIG_THUMB2_KERNEL 68#ifdef CONFIG_THUMB2_KERNEL
68 thumb = true; 69 thumb = true;
69 addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */ 70 addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
70 insn = ((u16 *)addr)[0]; 71 insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
71 if (is_wide_instruction(insn)) { 72 if (is_wide_instruction(insn)) {
72 insn <<= 16; 73 u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
73 insn |= ((u16 *)addr)[1]; 74 insn = __opcode_thumb32_compose(insn, inst2);
74 decode_insn = thumb32_probes_decode_insn; 75 decode_insn = thumb32_probes_decode_insn;
75 actions = kprobes_t32_actions; 76 actions = kprobes_t32_actions;
76 } else { 77 } else {
@@ -81,7 +82,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
81 thumb = false; 82 thumb = false;
82 if (addr & 0x3) 83 if (addr & 0x3)
83 return -EINVAL; 84 return -EINVAL;
84 insn = *p->addr; 85 insn = __mem_to_opcode_arm(*p->addr);
85 decode_insn = arm_probes_decode_insn; 86 decode_insn = arm_probes_decode_insn;
86 actions = kprobes_arm_actions; 87 actions = kprobes_arm_actions;
87#endif 88#endif
diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c
index b41873f33e69..a8ab540d7e73 100644
--- a/arch/arm/kernel/probes.c
+++ b/arch/arm/kernel/probes.c
@@ -202,13 +202,14 @@ prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
202#ifdef CONFIG_THUMB2_KERNEL 202#ifdef CONFIG_THUMB2_KERNEL
203 if (thumb) { 203 if (thumb) {
204 u16 *thumb_insn = (u16 *)asi->insn; 204 u16 *thumb_insn = (u16 *)asi->insn;
205 thumb_insn[1] = 0x4770; /* Thumb bx lr */ 205 /* Thumb bx lr */
206 thumb_insn[2] = 0x4770; /* Thumb bx lr */ 206 thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
207 thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
207 return insn; 208 return insn;
208 } 209 }
209 asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ 210 asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
210#else 211#else
211 asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ 212 asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
212#endif 213#endif
213 /* Make an ARM instruction unconditional */ 214 /* Make an ARM instruction unconditional */
214 if (insn < 0xe0000000) 215 if (insn < 0xe0000000)
@@ -228,12 +229,12 @@ set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
228 if (thumb) { 229 if (thumb) {
229 u16 *ip = (u16 *)asi->insn; 230 u16 *ip = (u16 *)asi->insn;
230 if (is_wide_instruction(insn)) 231 if (is_wide_instruction(insn))
231 *ip++ = insn >> 16; 232 *ip++ = __opcode_to_mem_thumb16(insn >> 16);
232 *ip++ = insn; 233 *ip++ = __opcode_to_mem_thumb16(insn);
233 return; 234 return;
234 } 235 }
235#endif 236#endif
236 asi->insn[0] = insn; 237 asi->insn[0] = __opcode_to_mem_arm(insn);
237} 238}
238 239
239/* 240/*