/src/capstonenext/arch/ARM/ARMDisassemblerExtension.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ |
3 | | /* Rot127 <unisono@quyllur.org>, 2022-2023 */ |
4 | | |
5 | | #include "ARMDisassemblerExtension.h" |
6 | | #include "ARMBaseInfo.h" |
7 | | |
8 | | bool ITBlock_push_back(ARM_ITBlock *it, char v) |
9 | 66.4k | { |
10 | 66.4k | if (it->size >= sizeof(it->ITStates)) { |
11 | | // TODO: consider warning user. |
12 | 3.15k | it->size = 0; |
13 | 3.15k | } |
14 | 66.4k | it->ITStates[it->size] = v; |
15 | 66.4k | it->size++; |
16 | | |
17 | 66.4k | return true; |
18 | 66.4k | } |
19 | | |
20 | | // Returns true if the current instruction is in an IT block |
21 | | bool ITBlock_instrInITBlock(ARM_ITBlock *it) |
22 | 1.81M | { |
23 | 1.81M | return (it->size > 0); |
24 | 1.81M | } |
25 | | |
26 | | // Returns true if current instruction is the last instruction in an IT block |
27 | | bool ITBlock_instrLastInITBlock(ARM_ITBlock *it) |
28 | 1.56k | { |
29 | 1.56k | return (it->size == 1); |
30 | 1.56k | } |
31 | | |
32 | | // Returns the condition code for instruction in IT block |
33 | | unsigned ITBlock_getITCC(ARM_ITBlock *it) |
34 | 54.9k | { |
35 | 54.9k | unsigned CC = ARMCC_AL; |
36 | | |
37 | 54.9k | if (ITBlock_instrInITBlock(it)) |
38 | 40.6k | CC = it->ITStates[it->size - 1]; |
39 | | |
40 | 54.9k | return CC; |
41 | 54.9k | } |
42 | | |
43 | | // Advances the IT block state to the next T or E |
44 | | void ITBlock_advanceITState(ARM_ITBlock *it) |
45 | 40.6k | { |
46 | 40.6k | it->size--; |
47 | 40.6k | } |
48 | | |
49 | | // Called when decoding an IT instruction. Sets the IT state for the following |
50 | | // instructions that for the IT block. Firstcond and Mask correspond to the |
51 | | // fields in the IT instruction encoding. |
52 | | void ITBlock_setITState(ARM_ITBlock *it, char Firstcond, char Mask) |
53 | 18.3k | { |
54 | | // (3 - the number of trailing zeros) is the number of then / else. |
55 | 18.3k | unsigned NumTZ = CountTrailingZeros_8(Mask); |
56 | 18.3k | unsigned char CCBits = (unsigned char)(Firstcond & 0xf); |
57 | 18.3k | assert(NumTZ <= 3 && "Invalid IT mask!"); |
58 | | // push condition codes onto the stack the correct order for the pops |
59 | 66.4k | for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { |
60 | 48.1k | unsigned Else = (Mask >> Pos) & 1; |
61 | 48.1k | ITBlock_push_back(it, CCBits ^ Else); |
62 | 48.1k | } |
63 | 18.3k | ITBlock_push_back(it, CCBits); |
64 | 18.3k | } |
65 | | |
66 | | bool VPTBlock_push_back(ARM_VPTBlock *it, char v) |
67 | 34.6k | { |
68 | 34.6k | if (it->size >= sizeof(it->VPTStates)) { |
69 | | // TODO: consider warning user. |
70 | 713 | it->size = 0; |
71 | 713 | } |
72 | 34.6k | it->VPTStates[it->size] = v; |
73 | 34.6k | it->size++; |
74 | | |
75 | 34.6k | return true; |
76 | 34.6k | } |
77 | | |
78 | | bool VPTBlock_instrInVPTBlock(ARM_VPTBlock *VPT) |
79 | 2.24M | { |
80 | 2.24M | return VPT->size > 0; |
81 | 2.24M | } |
82 | | |
83 | | unsigned VPTBlock_getVPTPred(ARM_VPTBlock *VPT) |
84 | 28.4k | { |
85 | 28.4k | unsigned Pred = ARMVCC_None; |
86 | 28.4k | if (VPTBlock_instrInVPTBlock(VPT)) |
87 | 28.4k | Pred = VPT->VPTStates[VPT->size - 1]; |
88 | 28.4k | return Pred; |
89 | 28.4k | } |
90 | | |
91 | | void VPTBlock_advanceVPTState(ARM_VPTBlock *VPT) |
92 | 28.4k | { |
93 | 28.4k | VPT->size--; |
94 | 28.4k | } |
95 | | |
96 | | void VPTBlock_setVPTState(ARM_VPTBlock *VPT, char Mask) |
97 | 9.96k | { |
98 | | // (3 - the number of trailing zeros) is the number of then / else. |
99 | 9.96k | unsigned NumTZ = CountTrailingZeros_8(Mask); |
100 | 9.96k | assert(NumTZ <= 3 && "Invalid VPT mask!"); |
101 | | // push predicates onto the stack the correct order for the pops |
102 | 34.6k | for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { |
103 | 24.6k | bool T = ((Mask >> Pos) & 1) == 0; |
104 | 24.6k | if (T) |
105 | 15.9k | VPTBlock_push_back(VPT, ARMVCC_Then); |
106 | 8.75k | else |
107 | 8.75k | VPTBlock_push_back(VPT, ARMVCC_Else); |
108 | 24.6k | } |
109 | 9.96k | VPTBlock_push_back(VPT, ARMVCC_Then); |
110 | 9.96k | } |
111 | | |
112 | | /// ThumbDisassembler - Thumb disassembler for all Thumb platforms. |
113 | | |
114 | | bool Check(DecodeStatus *Out, DecodeStatus In) |
115 | 5.85M | { |
116 | 5.85M | switch (In) { |
117 | 5.65M | case MCDisassembler_Success: |
118 | | // Out stays the same. |
119 | 5.65M | return true; |
120 | 165k | case MCDisassembler_SoftFail: |
121 | 165k | *Out = In; |
122 | 165k | return true; |
123 | 33.1k | case MCDisassembler_Fail: |
124 | 33.1k | *Out = In; |
125 | 33.1k | return false; |
126 | 0 | default: // never reached |
127 | 0 | return false; |
128 | 5.85M | } |
129 | 5.85M | } |
130 | | |
131 | | // Imported from ARMBaseInstrInfo.h |
132 | | // |
133 | | /// isValidCoprocessorNumber - decide whether an explicit coprocessor |
134 | | /// number is legal in generic instructions like CDP. The answer can |
135 | | /// vary with the subtarget. |
136 | | bool isValidCoprocessorNumber(MCInst *Inst, unsigned Num) |
137 | 40.1k | { |
138 | | // In Armv7 and Armv8-M CP10 and CP11 clash with VFP/NEON, however, the |
139 | | // coprocessor is still valid for CDP/MCR/MRC and friends. Allowing it is |
140 | | // useful for code which is shared with older architectures which do not |
141 | | // know the new VFP/NEON mnemonics. |
142 | | |
143 | | // Armv8-A disallows everything *other* than 111x (CP14 and CP15). |
144 | 40.1k | if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8Ops) && |
145 | 40.1k | (Num & 0xE) != 0xE) |
146 | 39 | return false; |
147 | | |
148 | | // Armv8.1-M disallows 100x (CP8,CP9) and 111x (CP14,CP15) |
149 | | // which clash with MVE. |
150 | 40.1k | if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8_1MMainlineOps) && |
151 | 40.1k | ((Num & 0xE) == 0x8 || (Num & 0xE) == 0xE)) |
152 | 9 | return false; |
153 | | |
154 | 40.1k | return true; |
155 | 40.1k | } |
156 | | |
157 | | // Imported from ARMMCTargetDesc.h |
158 | | bool ARM_isVpred(arm_op_type op) |
159 | 23.7M | { |
160 | 23.7M | return op == ARM_OP_VPRED_R || op == ARM_OP_VPRED_N; |
161 | 23.7M | } |
162 | | |
163 | | // Imported from ARMBaseInstrInfo.h |
164 | | // |
165 | | // This table shows the VPT instruction variants, i.e. the different |
166 | | // mask field encodings, see also B5.6. Predication/conditional execution in |
167 | | // the ArmARM. |
168 | | bool isVPTOpcode(int Opc) |
169 | 105k | { |
170 | 105k | return Opc == ARM_MVE_VPTv16i8 || Opc == ARM_MVE_VPTv16u8 || |
171 | 105k | Opc == ARM_MVE_VPTv16s8 || Opc == ARM_MVE_VPTv8i16 || |
172 | 105k | Opc == ARM_MVE_VPTv8u16 || Opc == ARM_MVE_VPTv8s16 || |
173 | 105k | Opc == ARM_MVE_VPTv4i32 || Opc == ARM_MVE_VPTv4u32 || |
174 | 105k | Opc == ARM_MVE_VPTv4s32 || Opc == ARM_MVE_VPTv4f32 || |
175 | 105k | Opc == ARM_MVE_VPTv8f16 || Opc == ARM_MVE_VPTv16i8r || |
176 | 105k | Opc == ARM_MVE_VPTv16u8r || Opc == ARM_MVE_VPTv16s8r || |
177 | 105k | Opc == ARM_MVE_VPTv8i16r || Opc == ARM_MVE_VPTv8u16r || |
178 | 105k | Opc == ARM_MVE_VPTv8s16r || Opc == ARM_MVE_VPTv4i32r || |
179 | 105k | Opc == ARM_MVE_VPTv4u32r || Opc == ARM_MVE_VPTv4s32r || |
180 | 105k | Opc == ARM_MVE_VPTv4f32r || Opc == ARM_MVE_VPTv8f16r || |
181 | 105k | Opc == ARM_MVE_VPST; |
182 | 105k | } |
183 | | |
184 | | // Imported from ARMMCTargetDesc.cpp |
185 | | bool ARM_isCDECoproc(size_t Coproc, const MCInst *MI) |
186 | 59.7k | { |
187 | | // Unfortunately we don't have ARMTargetInfo in the disassembler, so we have |
188 | | // to rely on feature bits. |
189 | 59.7k | if (Coproc >= 8) |
190 | 38.2k | return false; |
191 | | |
192 | 21.5k | return ARM_getFeatureBits(MI->csh->mode, |
193 | 21.5k | ARM_FeatureCoprocCDE0 + Coproc); |
194 | 59.7k | } |
195 | | |
196 | | // Hacky: enable all features for disassembler |
197 | | bool ARM_getFeatureBits(unsigned int mode, unsigned int feature) |
198 | 4.26M | { |
199 | 4.26M | if (feature == ARM_ModeThumb) { |
200 | 2.37M | if (mode & CS_MODE_THUMB) |
201 | 2.16M | return true; |
202 | 211k | return false; |
203 | 2.37M | } |
204 | | |
205 | 1.89M | if (feature == ARM_FeatureDFB) |
206 | 147 | return false; |
207 | | |
208 | 1.89M | if (feature == ARM_FeatureRAS) |
209 | 975 | return false; |
210 | | |
211 | 1.89M | if (feature == ARM_FeatureMClass && (mode & CS_MODE_MCLASS) == 0) |
212 | 67.2k | return false; |
213 | | |
214 | 1.82M | if ((feature == ARM_HasMVEIntegerOps || feature == ARM_HasMVEFloatOps || |
215 | 1.82M | feature == ARM_FeatureMVEVectorCostFactor1 || |
216 | 1.82M | feature == ARM_FeatureMVEVectorCostFactor2 || |
217 | 1.82M | feature == ARM_FeatureMVEVectorCostFactor4) && |
218 | 1.82M | (mode & CS_MODE_MCLASS) == 0) |
219 | 12.5k | return false; |
220 | | |
221 | 1.81M | if ((feature == ARM_HasV8Ops || feature == ARM_HasV8_1MMainlineOps || |
222 | 1.81M | feature == ARM_HasV8_1aOps || feature == ARM_HasV8_2aOps || |
223 | 1.81M | feature == ARM_HasV8_3aOps || feature == ARM_HasV8_4aOps || |
224 | 1.81M | feature == ARM_HasV8_5aOps || feature == ARM_HasV8_6aOps || |
225 | 1.81M | feature == ARM_HasV8_7aOps || feature == ARM_HasV8_8aOps || |
226 | 1.81M | feature == ARM_HasV8_9aOps) && |
227 | 1.81M | (mode & CS_MODE_V8) == 0) |
228 | 250k | return false; |
229 | | |
230 | 1.56M | if (feature >= ARM_FeatureCoprocCDE0 && |
231 | 1.56M | feature <= ARM_FeatureCoprocCDE7) |
232 | | // We currently have no way to detect CDE (Custom-Datapath-Extension) |
233 | | // coprocessors. |
234 | 21.5k | return false; |
235 | | |
236 | | // we support everything |
237 | 1.53M | return true; |
238 | 1.56M | } |