1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * arch/arm/probes/kprobes/checkers-common.c |
4 | * |
5 | * Copyright (C) 2014 Huawei Inc. |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include "../decode.h" |
10 | #include "../decode-arm.h" |
11 | #include "checkers.h" |
12 | |
13 | enum probes_insn checker_stack_use_none(probes_opcode_t insn, |
14 | struct arch_probes_insn *asi, |
15 | const struct decode_header *h) |
16 | { |
17 | asi->stack_space = 0; |
18 | return INSN_GOOD_NO_SLOT; |
19 | } |
20 | |
21 | enum probes_insn checker_stack_use_unknown(probes_opcode_t insn, |
22 | struct arch_probes_insn *asi, |
23 | const struct decode_header *h) |
24 | { |
25 | asi->stack_space = -1; |
26 | return INSN_GOOD_NO_SLOT; |
27 | } |
28 | |
29 | #ifdef CONFIG_THUMB2_KERNEL |
30 | enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn, |
31 | struct arch_probes_insn *asi, |
32 | const struct decode_header *h) |
33 | { |
34 | int imm = insn & 0xff; |
35 | asi->stack_space = imm; |
36 | return INSN_GOOD_NO_SLOT; |
37 | } |
38 | |
39 | /* |
40 | * Different from other insn uses imm8, the real addressing offset of |
41 | * STRD in T32 encoding should be imm8 * 4. See ARMARM description. |
42 | */ |
43 | static enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn, |
44 | struct arch_probes_insn *asi, |
45 | const struct decode_header *h) |
46 | { |
47 | int imm = insn & 0xff; |
48 | asi->stack_space = imm << 2; |
49 | return INSN_GOOD_NO_SLOT; |
50 | } |
51 | #else |
52 | enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn, |
53 | struct arch_probes_insn *asi, |
54 | const struct decode_header *h) |
55 | { |
56 | int imm = ((insn & 0xf00) >> 4) + (insn & 0xf); |
57 | asi->stack_space = imm; |
58 | return INSN_GOOD_NO_SLOT; |
59 | } |
60 | #endif |
61 | |
62 | enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn, |
63 | struct arch_probes_insn *asi, |
64 | const struct decode_header *h) |
65 | { |
66 | int imm = insn & 0xfff; |
67 | asi->stack_space = imm; |
68 | return INSN_GOOD_NO_SLOT; |
69 | } |
70 | |
71 | enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn, |
72 | struct arch_probes_insn *asi, |
73 | const struct decode_header *h) |
74 | { |
75 | unsigned int reglist = insn & 0xffff; |
76 | int pbit = insn & (1 << 24); |
77 | asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4; |
78 | |
79 | return INSN_GOOD_NO_SLOT; |
80 | } |
81 | |
82 | const union decode_action stack_check_actions[] = { |
83 | [STACK_USE_NONE] = {.decoder = checker_stack_use_none}, |
84 | [STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown}, |
85 | #ifdef CONFIG_THUMB2_KERNEL |
86 | [STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx}, |
87 | [STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd}, |
88 | #else |
89 | [STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x}, |
90 | #endif |
91 | [STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx}, |
92 | [STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx}, |
93 | }; |
94 | |