diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-01-09 10:19:49 +0800 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2015-01-09 09:36:50 +0000 |
commit | fca08f326ae0423f03b097ff54de432fe77b95d0 (patch) | |
tree | 40d680c04ec5ec613c0b8bb9ec9ff8b5821bc237 /arch/arm/probes/kprobes/actions-common.c | |
parent | b1940cd21c0f4abdce101253e860feff547291b0 (diff) |
ARM: probes: move all probe code to dedicate directory
In discussion on LKML (https://lkml.org/lkml/2014/11/28/158), Russell
King suggests to move all probe related code to arch/arm/probes. This
patch does the work. Due to dependency on 'arch/arm/kernel/patch.h', this
patch also moves patch.h to 'arch/arm/include/asm/patch.h', and related
'#include' directives are also midified to '#include <asm/patch.h>'.
Following is an overview of this patch:
./arch/arm/kernel/ ./arch/arm/probes/
|-- Makefile |-- Makefile
|-- probes-arm.c ==> |-- decode-arm.c
|-- probes-arm.h ==> |-- decode-arm.h
|-- probes-thumb.c ==> |-- decode-thumb.c
|-- probes-thumb.h ==> |-- decode-thumb.h
|-- probes.c ==> |-- decode.c
|-- probes.h ==> |-- decode.h
| |-- kprobes
| | |-- Makefile
|-- kprobes-arm.c ==> | |-- actions-arm.c
|-- kprobes-common.c ==> | |-- actions-common.c
|-- kprobes-thumb.c ==> | |-- actions-thumb.c
|-- kprobes.c ==> | |-- core.c
|-- kprobes.h ==> | |-- core.h
|-- kprobes-test-arm.c ==> | |-- test-arm.c
|-- kprobes-test.c ==> | |-- test-core.c
|-- kprobes-test.h ==> | |-- test-core.h
|-- kprobes-test-thumb.c ==> | `-- test-thumb.c
| `-- uprobes
| |-- Makefile
|-- uprobes-arm.c ==> |-- actions-arm.c
|-- uprobes.c ==> |-- core.c
|-- uprobes.h ==> `-- core.h
|
`-- patch.h ==> arch/arm/include/asm/patch.h
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Jon Medhurst <tixy@linaro.org>
Diffstat (limited to 'arch/arm/probes/kprobes/actions-common.c')
-rw-r--r-- | arch/arm/probes/kprobes/actions-common.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/arch/arm/probes/kprobes/actions-common.c b/arch/arm/probes/kprobes/actions-common.c new file mode 100644 index 000000000000..bd20a71cd34a --- /dev/null +++ b/arch/arm/probes/kprobes/actions-common.c @@ -0,0 +1,171 @@ +/* + * arch/arm/probes/kprobes/actions-common.c + * + * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. + * + * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is + * Copyright (C) 2006, 2007 Motorola Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/kprobes.h> +#include <asm/opcodes.h> + +#include "core.h" + + +static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, + struct arch_probes_insn *asi, + struct pt_regs *regs) +{ + int rn = (insn >> 16) & 0xf; + int lbit = insn & (1 << 20); + int wbit = insn & (1 << 21); + int ubit = insn & (1 << 23); + int pbit = insn & (1 << 24); + long *addr = (long *)regs->uregs[rn]; + int reg_bit_vector; + int reg_count; + + reg_count = 0; + reg_bit_vector = insn & 0xffff; + while (reg_bit_vector) { + reg_bit_vector &= (reg_bit_vector - 1); + ++reg_count; + } + + if (!ubit) + addr -= reg_count; + addr += (!pbit == !ubit); + + reg_bit_vector = insn & 0xffff; + while (reg_bit_vector) { + int reg = __ffs(reg_bit_vector); + reg_bit_vector &= (reg_bit_vector - 1); + if (lbit) + regs->uregs[reg] = *addr++; + else + *addr++ = regs->uregs[reg]; + } + + if (wbit) { + if (!ubit) + addr -= reg_count; + addr -= (!pbit == !ubit); + regs->uregs[rn] = (long)addr; + } +} + +static void __kprobes simulate_stm1_pc(probes_opcode_t insn, + struct arch_probes_insn *asi, + struct pt_regs *regs) +{ + unsigned long addr = regs->ARM_pc - 4; + + regs->ARM_pc = (long)addr + str_pc_offset; + simulate_ldm1stm1(insn, asi, regs); + regs->ARM_pc = (long)addr + 4; +} + +static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, + struct arch_probes_insn *asi, + struct pt_regs *regs) +{ + simulate_ldm1stm1(insn, asi, regs); + load_write_pc(regs->ARM_pc, regs); +} + +static void __kprobes +emulate_generic_r0_12_noflags(probes_opcode_t insn, + struct arch_probes_insn *asi, struct pt_regs *regs) +{ + register void *rregs asm("r1") = regs; + register void *rfn asm("lr") = asi->insn_fn; + + __asm__ __volatile__ ( + "stmdb sp!, {%[regs], r11} \n\t" + "ldmia %[regs], {r0-r12} \n\t" +#if __LINUX_ARM_ARCH__ >= 6 + "blx %[fn] \n\t" +#else + "str %[fn], [sp, #-4]! \n\t" + "adr lr, 1f \n\t" + "ldr pc, [sp], #4 \n\t" + "1: \n\t" +#endif + "ldr lr, [sp], #4 \n\t" /* lr = regs */ + "stmia lr, {r0-r12} \n\t" + "ldr r11, [sp], #4 \n\t" + : [regs] "=r" (rregs), [fn] "=r" (rfn) + : "0" (rregs), "1" (rfn) + : "r0", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r12", "memory", "cc" + ); +} + +static void __kprobes +emulate_generic_r2_14_noflags(probes_opcode_t insn, + struct arch_probes_insn *asi, struct pt_regs *regs) +{ + emulate_generic_r0_12_noflags(insn, asi, + (struct pt_regs *)(regs->uregs+2)); +} + +static void __kprobes +emulate_ldm_r3_15(probes_opcode_t insn, + struct arch_probes_insn *asi, struct pt_regs *regs) +{ + emulate_generic_r0_12_noflags(insn, asi, + (struct pt_regs *)(regs->uregs+3)); + load_write_pc(regs->ARM_pc, regs); +} + +enum probes_insn __kprobes +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *h) +{ + probes_insn_handler_t *handler = 0; + unsigned reglist = insn & 0xffff; + int is_ldm = insn & 0x100000; + int rn = (insn >> 16) & 0xf; + + if (rn <= 12 && (reglist & 0xe000) == 0) { + /* Instruction only uses registers in the range R0..R12 */ + handler = emulate_generic_r0_12_noflags; + + } else if (rn >= 2 && (reglist & 0x8003) == 0) { + /* Instruction only uses registers in the range R2..R14 */ + rn -= 2; + reglist >>= 2; + handler = emulate_generic_r2_14_noflags; + + } else if (rn >= 3 && (reglist & 0x0007) == 0) { + /* Instruction only uses registers in the range R3..R15 */ + if (is_ldm && (reglist & 0x8000)) { + rn -= 3; + reglist >>= 3; + handler = emulate_ldm_r3_15; + } + } + + if (handler) { + /* We can emulate the instruction in (possibly) modified form */ + asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) | + (rn << 16) | reglist); + asi->insn_handler = handler; + return INSN_GOOD; + } + + /* Fallback to slower simulation... */ + if (reglist & 0x8000) + handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc; + else + handler = simulate_ldm1stm1; + asi->insn_handler = handler; + return INSN_GOOD_NO_SLOT; +} + |