/* * arch/arm/kernel/kprobes-thumb.c * * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. * * 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 <linux/module.h>#include"kprobes.h"/* * True if current instruction is in an IT block. */#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000)/* * Return the condition code to check for the currently executing instruction. * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if * in_it_block returns true. */#define current_cond(cpsr) ((cpsr >> 12) & 0xf)/* * Return the PC value for a probe in thumb code. * This is the address of the probed instruction plus 4. * We subtract one because the address will have bit zero set to indicate * a pointer to thumb code. */staticinlineunsigned long __kprobes thumb_probe_pc(struct kprobe *p){return(unsigned long)p->addr -1+4;}static void __kprobes
t32_simulate_table_branch(struct kprobe *p,struct pt_regs *regs){
kprobe_opcode_t insn = p->opcode;unsigned long pc =thumb_probe_pc(p);int rn = (insn >>16) &0xf;int rm = insn &0xf;unsigned long rnv = (rn ==15) ? pc : regs->uregs[rn];unsigned long rmv = regs->uregs[rm];unsigned int halfwords;if(insn &0x10)/* TBH */
halfwords = ((u16 *)rnv)[rmv];else/* TBB */
halfwords = ((u8 *)rnv)[rmv];
regs->ARM_pc = pc +2* halfwords;}static void __kprobes
t32_simulate_mrs(struct kprobe *p,struct pt_regs *regs){
kprobe_opcode_t insn = p->opcode;int rd = (insn >>8) &0xf;unsigned long mask =0xf8ff03df;/* Mask out execution state */
regs->uregs[rd] = regs->ARM_cpsr & mask;}static void __kprobes
t32_simulate_cond_branch(struct kprobe *p,struct pt_regs *regs){
kprobe_opcode_t insn = p->opcode;unsigned long pc =thumb_probe_pc(p);long offset = insn &0x7ff;/* imm11 */
offset += (insn &0x003f0000) >>5;/* imm6 */
offset += (insn &0x00002000) <<4;/* J1 */
offset += (insn &0x00000800) <<7;/* J2 */
offset -= (insn &0x04000000) >>7;/* Apply sign bit */
regs->ARM_pc = pc + (offset *2);}static enum kprobe_insn __kprobes
t32_decode_cond_branch(kprobe_opcode_t insn,struct arch_specific_insn *asi){int cc = (insn >>22) &0xf;
asi->insn_check_cc = kprobe_condition_checks[cc];
asi->insn_handler = t32_simulate_cond_branch;return INSN_GOOD_NO_SLOT;}static void __kprobes
t32_simulate_branch(struct kprobe *p,struct pt_regs *regs){
kprobe_opcode_t insn = p->opcode