mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-01 02:21:16 +00:00
ARM: probes: fix instruction fetch order with <asm/opcodes.h>
commit 888be25402021a425da3e85e2d5a954d7509286e upstream. 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> [wangnan: backport to 3.10 and 3.14: - adjust context - backport all changes on arch/arm/kernel/probes.c to arch/arm/kernel/kprobes-common.c since we don't have commit c18377c303787ded44b7decd7dee694db0f205e9. - After the above adjustments, becomes same to Taras Kondratiuk's original patch: http://lists.linaro.org/pipermail/linaro-kernel/2014-January/010346.html ] Signed-off-by: Wang Nan <wangnan0@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a4ad890a7e
commit
a2ad9bef40
3 changed files with 28 additions and 20 deletions
|
@ -14,6 +14,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <asm/system_info.h>
|
||||
#include <asm/opcodes.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
|
@ -305,7 +306,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
|
||||
if (handler) {
|
||||
/* We can emulate the instruction in (possibly) modified form */
|
||||
asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist;
|
||||
asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
|
||||
(rn << 16) | reglist);
|
||||
asi->insn_handler = handler;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
@ -334,13 +336,14 @@ prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
|||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb) {
|
||||
u16 *thumb_insn = (u16 *)asi->insn;
|
||||
thumb_insn[1] = 0x4770; /* Thumb bx lr */
|
||||
thumb_insn[2] = 0x4770; /* Thumb bx lr */
|
||||
/* Thumb bx lr */
|
||||
thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
|
||||
thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
|
||||
return insn;
|
||||
}
|
||||
asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
|
||||
asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
|
||||
#else
|
||||
asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */
|
||||
asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
|
||||
#endif
|
||||
/* Make an ARM instruction unconditional */
|
||||
if (insn < 0xe0000000)
|
||||
|
@ -360,12 +363,12 @@ set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
|||
if (thumb) {
|
||||
u16 *ip = (u16 *)asi->insn;
|
||||
if (is_wide_instruction(insn))
|
||||
*ip++ = insn >> 16;
|
||||
*ip++ = insn;
|
||||
*ip++ = __opcode_to_mem_thumb16(insn >> 16);
|
||||
*ip++ = __opcode_to_mem_thumb16(insn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
asi->insn[0] = insn;
|
||||
asi->insn[0] = __opcode_to_mem_arm(insn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -163,9 +163,9 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi);
|
||||
|
||||
/* Fixup modified instruction to have halfwords in correct order...*/
|
||||
insn = asi->insn[0];
|
||||
((u16 *)asi->insn)[0] = insn >> 16;
|
||||
((u16 *)asi->insn)[1] = insn & 0xffff;
|
||||
insn = __mem_to_opcode_arm(asi->insn[0]);
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
|
||||
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1153,7 +1153,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
{
|
||||
insn &= ~0x00ff;
|
||||
insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
|
||||
((u16 *)asi->insn)[0] = insn;
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
|
||||
asi->insn_handler = t16_emulate_hiregs;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
@ -1182,8 +1182,10 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
* and call it with R9=SP and LR in the register list represented
|
||||
* by R8.
|
||||
*/
|
||||
((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */
|
||||
((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */
|
||||
/* 1st half STMDB R9!,{} */
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
|
||||
/* 2nd half (register list) */
|
||||
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
|
||||
asi->insn_handler = t16_emulate_push;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
@ -1232,8 +1234,10 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
|||
* and call it with R9=SP and PC in the register list represented
|
||||
* by R8.
|
||||
*/
|
||||
((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */
|
||||
((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */
|
||||
/* 1st half LDMIA R9!,{} */
|
||||
((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
|
||||
/* 2nd half (register list) */
|
||||
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
|
||||
asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
|
||||
: t16_emulate_pop_nopc;
|
||||
return INSN_GOOD;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/stop_machine.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/opcodes.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
@ -62,10 +63,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
thumb = true;
|
||||
addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
|
||||
insn = ((u16 *)addr)[0];
|
||||
insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
|
||||
if (is_wide_instruction(insn)) {
|
||||
insn <<= 16;
|
||||
insn |= ((u16 *)addr)[1];
|
||||
u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
|
||||
insn = __opcode_thumb32_compose(insn, inst2);
|
||||
decode_insn = thumb32_kprobe_decode_insn;
|
||||
} else
|
||||
decode_insn = thumb16_kprobe_decode_insn;
|
||||
|
@ -73,7 +74,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
thumb = false;
|
||||
if (addr & 0x3)
|
||||
return -EINVAL;
|
||||
insn = *p->addr;
|
||||
insn = __mem_to_opcode_arm(*p->addr);
|
||||
decode_insn = arm_kprobe_decode_insn;
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue