/* * arch/arm/kernel/kprobes-common.c * * Copyright (C) 2011 Jon Medhurst . * * 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 #include #include "kprobes.h" /* * For STR and STM instructions, an ARM core may choose to use either * a +8 or a +12 displacement from the current instruction's address. * Whichever value is chosen for a given core, it must be the same for * both instructions and may not change. This function measures it. */ int str_pc_offset; void __init find_str_pc_offset(void) { int addr, scratch, ret; __asm__ ( "sub %[ret], pc, #4 \n\t" "str pc, %[addr] \n\t" "ldr %[scr], %[addr] \n\t" "sub %[ret], %[scr], %[ret] \n\t" : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); str_pc_offset = ret; } void __init arm_kprobe_decode_init(void) { find_str_pc_offset(); } static unsigned long __kprobes __check_eq(unsigned long cpsr) { return cpsr & PSR_Z_BIT; } static unsigned long __kprobes __check_ne(unsigned long cpsr) { return (~cpsr) & PSR_Z_BIT; } static unsigned long __kprobes __check_cs(unsigned long cpsr) { return cpsr & PSR_C_BIT; } static unsigned long __kprobes __check_cc(unsigned long cpsr) { return (~cpsr) & PSR_C_BIT; } static unsigned long __kprobes __check_mi(unsigned long cpsr) { return cpsr & PSR_N_BIT; } static unsigned long __kprobes __check_pl(unsigned long cpsr) { return (~cpsr) & PSR_N_BIT; } static unsigned long __kprobes __check_vs(unsigned long cpsr) { return cpsr & PSR_V_BIT; } static unsigned long __kprobes __check_vc(unsigned long cpsr) { return (~cpsr) & PSR_V_BIT; } static unsigned long __kprobes __check_hi(unsigned long cpsr) { cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ return cpsr & PSR_C_BIT; } static unsigned long __kprobes __check_ls(unsigned long cpsr) { cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ return (~cpsr) & PSR_C_BIT; } static unsigned long __kprobes __check_ge(unsigned long cpsr) { cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ return (~cpsr) & PSR_N_BIT; } static unsigned long __kprobes __check_lt(unsigned long cpsr) { cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ return cpsr & PSR_N_BIT; } static unsigned long __kprobes __check_gt(unsigned long cpsr) { unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ return (~temp) & PSR_N_BIT; } static unsigned long __kprobes __check_le(unsigned long cpsr) { unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ return temp & PSR_N_BIT; } static unsigned long __kprobes __check_al(unsigned long cpsr) { return true; } kprobe_check_cc * const kprobe_condition_checks[16] = { &__check_eq, &__check_ne, &__check_cs, &__check_cc, &__check_mi, &__check_pl, &__check_vs, &__check_vc, &__check_hi, &__check_ls, &__check_ge, &__check_lt, &__check_gt, &__check_le, &__check_al, &__check_al };