Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * arch/arm/probes/kprobes/checkers-thumb.c
0004  *
0005  * Copyright (C) 2014 Huawei Inc.
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include "../decode.h"
0010 #include "../decode-thumb.h"
0011 #include "checkers.h"
0012 
0013 static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn,
0014         struct arch_probes_insn *asi,
0015         const struct decode_header *h)
0016 {
0017     /*
0018      * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR
0019      * may get here. Simply mark all normal insns as STACK_USE_NONE.
0020      */
0021     static const union decode_item table[] = {
0022 
0023         /*
0024          * First, filter out all ldr insns to make our life easier.
0025          * Following load insns may come here:
0026          * LDM, LDRD, LDR.
0027          * In T32 encoding, bit 20 is enough for distinguishing
0028          * load and store. All load insns have this bit set, when
0029          * all store insns have this bit clear.
0030          */
0031         DECODE_CUSTOM   (0x00100000, 0x00100000, STACK_USE_NONE),
0032 
0033         /*
0034          * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN
0035          * if Rn or Rm is SP. T32 doesn't encode STRD.
0036          */
0037         /*                                 xx | Rn | Rt |         | Rm |*/
0038         /* STR (register)   1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
0039         /* STRB (register)  1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
0040         /* STRH (register)  1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
0041         /* INVALID INSN     1111 1000 0110 xxxx xxxx 0000 00xx xxxx */
0042         /* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */
0043         DECODE_OR   (0xff9f0fc0, 0xf80d0000),
0044         DECODE_CUSTOM   (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN),
0045 
0046 
0047         /*                                 xx | Rn | Rt | PUW|   imm8  |*/
0048         /* STR (imm 8)      1111 1000 0100 1101 xxxx 110x xxxx xxxx */
0049         /* STRB (imm 8)     1111 1000 0000 1101 xxxx 110x xxxx xxxx */
0050         /* STRH (imm 8)     1111 1000 0010 1101 xxxx 110x xxxx xxxx */
0051         /* INVALID INSN     1111 1000 0110 1101 xxxx 110x xxxx xxxx */
0052         /* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */
0053         DECODE_CUSTOM   (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX),
0054 
0055         /* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */
0056 
0057         /*                              P U W | Rn | Rt | Rt2|   imm8  |*/
0058         /* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */
0059         /*
0060          * Only consider U == 0 and P == 1.
0061          * Also note that STRD in T32 encoding is special:
0062          * imm = ZeroExtend(imm8:'00', 32)
0063          */
0064         DECODE_CUSTOM   (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD),
0065 
0066         /*                                    | Rn | */
0067         /* STMDB        1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */
0068         DECODE_CUSTOM   (0xffdf0000, 0xe90d0000, STACK_USE_STMDX),
0069 
0070         /* fall through */
0071         DECODE_CUSTOM   (0, 0, STACK_USE_NONE),
0072         DECODE_END
0073     };
0074 
0075     return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
0076 }
0077 
0078 const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = {
0079     [PROBES_T32_LDMSTM] = {.checker = t32_check_stack},
0080     [PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack},
0081     [PROBES_T32_LDRSTR] = {.checker = t32_check_stack},
0082 };
0083 
0084 /*
0085  * See following comments. This insn must be 'push'.
0086  */
0087 static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn,
0088         struct arch_probes_insn *asi,
0089         const struct decode_header *h)
0090 {
0091     unsigned int reglist = insn & 0x1ff;
0092     asi->stack_space = hweight32(reglist) * 4;
0093     return INSN_GOOD;
0094 }
0095 
0096 /*
0097  * T16 encoding is simple: only the 'push' insn can need extra stack space.
0098  * Other insns, like str, can only use r0-r7 as Rn.
0099  */
0100 const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = {
0101     [PROBES_T16_PUSH] = {.checker = t16_check_stack},
0102 };