16624cf65SWang Nan /* 26624cf65SWang Nan * arch/arm/probes/kprobes/checkers-thumb.c 36624cf65SWang Nan * 46624cf65SWang Nan * Copyright (C) 2014 Huawei Inc. 56624cf65SWang Nan * 66624cf65SWang Nan * This program is free software; you can redistribute it and/or modify 76624cf65SWang Nan * it under the terms of the GNU General Public License version 2 as 86624cf65SWang Nan * published by the Free Software Foundation. 96624cf65SWang Nan * 106624cf65SWang Nan * This program is distributed in the hope that it will be useful, 116624cf65SWang Nan * but WITHOUT ANY WARRANTY; without even the implied warranty of 126624cf65SWang Nan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 136624cf65SWang Nan * General Public License for more details. 146624cf65SWang Nan */ 156624cf65SWang Nan 166624cf65SWang Nan #include <linux/kernel.h> 176624cf65SWang Nan #include "../decode.h" 186624cf65SWang Nan #include "../decode-thumb.h" 196624cf65SWang Nan #include "checkers.h" 206624cf65SWang Nan 216624cf65SWang Nan static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn, 226624cf65SWang Nan struct arch_probes_insn *asi, 236624cf65SWang Nan const struct decode_header *h) 246624cf65SWang Nan { 256624cf65SWang Nan /* 266624cf65SWang Nan * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR 276624cf65SWang Nan * may get here. Simply mark all normal insns as STACK_USE_NONE. 286624cf65SWang Nan */ 296624cf65SWang Nan static const union decode_item table[] = { 306624cf65SWang Nan 316624cf65SWang Nan /* 326624cf65SWang Nan * First, filter out all ldr insns to make our life easier. 336624cf65SWang Nan * Following load insns may come here: 346624cf65SWang Nan * LDM, LDRD, LDR. 356624cf65SWang Nan * In T32 encoding, bit 20 is enough for distinguishing 366624cf65SWang Nan * load and store. All load insns have this bit set, when 376624cf65SWang Nan * all store insns have this bit clear. 386624cf65SWang Nan */ 396624cf65SWang Nan DECODE_CUSTOM (0x00100000, 0x00100000, STACK_USE_NONE), 406624cf65SWang Nan 416624cf65SWang Nan /* 426624cf65SWang Nan * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN 436624cf65SWang Nan * if Rn or Rm is SP. T32 doesn't encode STRD. 446624cf65SWang Nan */ 456624cf65SWang Nan /* xx | Rn | Rt | | Rm |*/ 466624cf65SWang Nan /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ 476624cf65SWang Nan /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ 486624cf65SWang Nan /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ 496624cf65SWang Nan /* INVALID INSN 1111 1000 0110 xxxx xxxx 0000 00xx xxxx */ 506624cf65SWang Nan /* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */ 516624cf65SWang Nan DECODE_OR (0xff9f0fc0, 0xf80d0000), 526624cf65SWang Nan DECODE_CUSTOM (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN), 536624cf65SWang Nan 546624cf65SWang Nan 556624cf65SWang Nan /* xx | Rn | Rt | PUW| imm8 |*/ 566624cf65SWang Nan /* STR (imm 8) 1111 1000 0100 1101 xxxx 110x xxxx xxxx */ 576624cf65SWang Nan /* STRB (imm 8) 1111 1000 0000 1101 xxxx 110x xxxx xxxx */ 586624cf65SWang Nan /* STRH (imm 8) 1111 1000 0010 1101 xxxx 110x xxxx xxxx */ 596624cf65SWang Nan /* INVALID INSN 1111 1000 0110 1101 xxxx 110x xxxx xxxx */ 606624cf65SWang Nan /* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */ 616624cf65SWang Nan DECODE_CUSTOM (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX), 626624cf65SWang Nan 636624cf65SWang Nan /* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */ 646624cf65SWang Nan 656624cf65SWang Nan /* P U W | Rn | Rt | Rt2| imm8 |*/ 666624cf65SWang Nan /* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */ 676624cf65SWang Nan /* 686624cf65SWang Nan * Only consider U == 0 and P == 1. 696624cf65SWang Nan * Also note that STRD in T32 encoding is special: 706624cf65SWang Nan * imm = ZeroExtend(imm8:'00', 32) 716624cf65SWang Nan */ 726624cf65SWang Nan DECODE_CUSTOM (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD), 736624cf65SWang Nan 746624cf65SWang Nan /* | Rn | */ 756624cf65SWang Nan /* STMDB 1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */ 766624cf65SWang Nan DECODE_CUSTOM (0xffdf0000, 0xe90d0000, STACK_USE_STMDX), 776624cf65SWang Nan 786624cf65SWang Nan /* fall through */ 796624cf65SWang Nan DECODE_CUSTOM (0, 0, STACK_USE_NONE), 806624cf65SWang Nan DECODE_END 816624cf65SWang Nan }; 826624cf65SWang Nan 836624cf65SWang Nan return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); 846624cf65SWang Nan } 856624cf65SWang Nan 866624cf65SWang Nan const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = { 876624cf65SWang Nan [PROBES_T32_LDMSTM] = {.checker = t32_check_stack}, 886624cf65SWang Nan [PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack}, 896624cf65SWang Nan [PROBES_T32_LDRSTR] = {.checker = t32_check_stack}, 906624cf65SWang Nan }; 916624cf65SWang Nan 926624cf65SWang Nan /* 936624cf65SWang Nan * See following comments. This insn must be 'push'. 946624cf65SWang Nan */ 956624cf65SWang Nan static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn, 966624cf65SWang Nan struct arch_probes_insn *asi, 976624cf65SWang Nan const struct decode_header *h) 986624cf65SWang Nan { 996624cf65SWang Nan unsigned int reglist = insn & 0x1ff; 1006624cf65SWang Nan asi->stack_space = hweight32(reglist) * 4; 1016624cf65SWang Nan return INSN_GOOD; 1026624cf65SWang Nan } 1036624cf65SWang Nan 1046624cf65SWang Nan /* 1056624cf65SWang Nan * T16 encoding is simple: only the 'push' insn can need extra stack space. 1066624cf65SWang Nan * Other insns, like str, can only use r0-r7 as Rn. 1076624cf65SWang Nan */ 1086624cf65SWang Nan const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = { 1096624cf65SWang Nan [PROBES_T16_PUSH] = {.checker = t16_check_stack}, 1106624cf65SWang Nan }; 111