/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 | 46.2k | { |
10 | 46.2k | if (it->size >= sizeof(it->ITStates)) { |
11 | | // TODO: consider warning user. |
12 | 2.07k | it->size = 0; |
13 | 2.07k | } |
14 | 46.2k | it->ITStates[it->size] = v; |
15 | 46.2k | it->size++; |
16 | | |
17 | 46.2k | return true; |
18 | 46.2k | } |
19 | | |
20 | | // Returns true if the current instruction is in an IT block |
21 | | bool ITBlock_instrInITBlock(ARM_ITBlock *it) |
22 | 1.42M | { |
23 | 1.42M | return (it->size > 0); |
24 | 1.42M | } |
25 | | |
26 | | // Returns true if current instruction is the last instruction in an IT block |
27 | | bool ITBlock_instrLastInITBlock(ARM_ITBlock *it) |
28 | 873 | { |
29 | 873 | return (it->size == 1); |
30 | 873 | } |
31 | | |
32 | | // Returns the condition code for instruction in IT block |
33 | | unsigned ITBlock_getITCC(ARM_ITBlock *it) |
34 | 40.4k | { |
35 | 40.4k | unsigned CC = ARMCC_AL; |
36 | | |
37 | 40.4k | if (ITBlock_instrInITBlock(it)) |
38 | 29.0k | CC = it->ITStates[it->size - 1]; |
39 | | |
40 | 40.4k | return CC; |
41 | 40.4k | } |
42 | | |
43 | | // Advances the IT block state to the next T or E |
44 | | void ITBlock_advanceITState(ARM_ITBlock *it) |
45 | 29.0k | { |
46 | 29.0k | it->size--; |
47 | 29.0k | } |
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 | 12.4k | { |
54 | | // (3 - the number of trailing zeros) is the number of then / else. |
55 | 12.4k | unsigned NumTZ = CountTrailingZeros_8(Mask); |
56 | 12.4k | unsigned char CCBits = (unsigned char)(Firstcond & 0xf); |
57 | 12.4k | assert(NumTZ <= 3 && "Invalid IT mask!"); |
58 | | // push condition codes onto the stack the correct order for the pops |
59 | 46.2k | for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { |
60 | 33.7k | unsigned Else = (Mask >> Pos) & 1; |
61 | 33.7k | ITBlock_push_back(it, CCBits ^ Else); |
62 | 33.7k | } |
63 | 12.4k | ITBlock_push_back(it, CCBits); |
64 | 12.4k | } |
65 | | |
66 | | bool VPTBlock_push_back(ARM_VPTBlock *it, char v) |
67 | 31.1k | { |
68 | 31.1k | if (it->size >= sizeof(it->VPTStates)) { |
69 | | // TODO: consider warning user. |
70 | 657 | it->size = 0; |
71 | 657 | } |
72 | 31.1k | it->VPTStates[it->size] = v; |
73 | 31.1k | it->size++; |
74 | | |
75 | 31.1k | return true; |
76 | 31.1k | } |
77 | | |
78 | | bool VPTBlock_instrInVPTBlock(ARM_VPTBlock *VPT) |
79 | 1.78M | { |
80 | 1.78M | return VPT->size > 0; |
81 | 1.78M | } |
82 | | |
83 | | unsigned VPTBlock_getVPTPred(ARM_VPTBlock *VPT) |
84 | 25.5k | { |
85 | 25.5k | unsigned Pred = ARMVCC_None; |
86 | 25.5k | if (VPTBlock_instrInVPTBlock(VPT)) |
87 | 25.5k | Pred = VPT->VPTStates[VPT->size - 1]; |
88 | 25.5k | return Pred; |
89 | 25.5k | } |
90 | | |
91 | | void VPTBlock_advanceVPTState(ARM_VPTBlock *VPT) |
92 | 25.5k | { |
93 | 25.5k | VPT->size--; |
94 | 25.5k | } |
95 | | |
96 | | void VPTBlock_setVPTState(ARM_VPTBlock *VPT, char Mask) |
97 | 8.54k | { |
98 | | // (3 - the number of trailing zeros) is the number of then / else. |
99 | 8.54k | unsigned NumTZ = CountTrailingZeros_8(Mask); |
100 | 8.54k | assert(NumTZ <= 3 && "Invalid VPT mask!"); |
101 | | // push predicates onto the stack the correct order for the pops |
102 | 31.1k | for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { |
103 | 22.6k | bool T = ((Mask >> Pos) & 1) == 0; |
104 | 22.6k | if (T) |
105 | 15.0k | VPTBlock_push_back(VPT, ARMVCC_Then); |
106 | 7.56k | else |
107 | 7.56k | VPTBlock_push_back(VPT, ARMVCC_Else); |
108 | 22.6k | } |
109 | 8.54k | VPTBlock_push_back(VPT, ARMVCC_Then); |
110 | 8.54k | } |
111 | | |
112 | | /// ThumbDisassembler - Thumb disassembler for all Thumb platforms. |
113 | | |
114 | | bool Check(DecodeStatus *Out, DecodeStatus In) |
115 | 4.71M | { |
116 | 4.71M | switch (In) { |
117 | 4.54M | case MCDisassembler_Success: |
118 | | // Out stays the same. |
119 | 4.54M | return true; |
120 | 147k | case MCDisassembler_SoftFail: |
121 | 147k | *Out = In; |
122 | 147k | return true; |
123 | 24.0k | case MCDisassembler_Fail: |
124 | 24.0k | *Out = In; |
125 | 24.0k | return false; |
126 | 0 | default: // never reached |
127 | 0 | return false; |
128 | 4.71M | } |
129 | 4.71M | } |
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 | 35.9k | { |
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 | 35.9k | if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8Ops) && |
145 | 35.9k | (Num & 0xE) != 0xE) |
146 | 19 | return false; |
147 | | |
148 | | // Armv8.1-M disallows 100x (CP8,CP9) and 111x (CP14,CP15) |
149 | | // which clash with MVE. |
150 | 35.9k | if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8_1MMainlineOps) && |
151 | 35.9k | ((Num & 0xE) == 0x8 || (Num & 0xE) == 0xE)) |
152 | 4 | return false; |
153 | | |
154 | 35.9k | return true; |
155 | 35.9k | } |
156 | | |
157 | | // Imported from ARMMCTargetDesc.h |
158 | | bool ARM_isVpred(arm_op_type op) |
159 | 18.8M | { |
160 | 18.8M | return op == ARM_OP_VPRED_R || op == ARM_OP_VPRED_N; |
161 | 18.8M | } |
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 | 78.0k | { |
170 | 78.0k | return Opc == ARM_MVE_VPTv16i8 || Opc == ARM_MVE_VPTv16u8 || |
171 | 78.0k | Opc == ARM_MVE_VPTv16s8 || Opc == ARM_MVE_VPTv8i16 || |
172 | 78.0k | Opc == ARM_MVE_VPTv8u16 || Opc == ARM_MVE_VPTv8s16 || |
173 | 78.0k | Opc == ARM_MVE_VPTv4i32 || Opc == ARM_MVE_VPTv4u32 || |
174 | 78.0k | Opc == ARM_MVE_VPTv4s32 || Opc == ARM_MVE_VPTv4f32 || |
175 | 78.0k | Opc == ARM_MVE_VPTv8f16 || Opc == ARM_MVE_VPTv16i8r || |
176 | 78.0k | Opc == ARM_MVE_VPTv16u8r || Opc == ARM_MVE_VPTv16s8r || |
177 | 78.0k | Opc == ARM_MVE_VPTv8i16r || Opc == ARM_MVE_VPTv8u16r || |
178 | 78.0k | Opc == ARM_MVE_VPTv8s16r || Opc == ARM_MVE_VPTv4i32r || |
179 | 78.0k | Opc == ARM_MVE_VPTv4u32r || Opc == ARM_MVE_VPTv4s32r || |
180 | 78.0k | Opc == ARM_MVE_VPTv4f32r || Opc == ARM_MVE_VPTv8f16r || |
181 | 78.0k | Opc == ARM_MVE_VPST; |
182 | 78.0k | } |
183 | | |
184 | | // Imported from ARMMCTargetDesc.cpp |
185 | | bool ARM_isCDECoproc(size_t Coproc, const MCInst *MI) |
186 | 53.8k | { |
187 | | // Unfortunately we don't have ARMTargetInfo in the disassembler, so we have |
188 | | // to rely on feature bits. |
189 | 53.8k | if (Coproc >= 8) |
190 | 36.7k | return false; |
191 | | |
192 | 17.0k | return ARM_getFeatureBits(MI->csh->mode, |
193 | 17.0k | ARM_FeatureCoprocCDE0 + Coproc); |
194 | 53.8k | } |
195 | | |
196 | | // Hacky: enable all features for disassembler |
197 | | bool ARM_getFeatureBits(unsigned int mode, unsigned int feature) |
198 | 3.37M | { |
199 | 3.37M | if (feature == ARM_ModeThumb) { |
200 | 1.88M | if (mode & CS_MODE_THUMB) |
201 | 1.71M | return true; |
202 | 174k | return false; |
203 | 1.88M | } |
204 | | |
205 | 1.48M | if (feature == ARM_FeatureDFB) |
206 | 51 | return false; |
207 | | |
208 | 1.48M | if (feature == ARM_FeatureRAS) |
209 | 160 | return false; |
210 | | |
211 | 1.48M | if (feature == ARM_FeatureMClass && (mode & CS_MODE_MCLASS) == 0) |
212 | 56.9k | return false; |
213 | | |
214 | 1.43M | if ((feature == ARM_HasMVEIntegerOps || feature == ARM_HasMVEFloatOps || |
215 | 1.43M | feature == ARM_FeatureMVEVectorCostFactor1 || |
216 | 1.43M | feature == ARM_FeatureMVEVectorCostFactor2 || |
217 | 1.43M | feature == ARM_FeatureMVEVectorCostFactor4) && |
218 | 1.43M | (mode & CS_MODE_MCLASS) == 0) |
219 | 8.72k | return false; |
220 | | |
221 | 1.42M | if ((feature == ARM_HasV8Ops || feature == ARM_HasV8_1MMainlineOps || |
222 | 1.42M | feature == ARM_HasV8_1aOps || feature == ARM_HasV8_2aOps || |
223 | 1.42M | feature == ARM_HasV8_3aOps || feature == ARM_HasV8_4aOps || |
224 | 1.42M | feature == ARM_HasV8_5aOps || feature == ARM_HasV8_6aOps || |
225 | 1.42M | feature == ARM_HasV8_7aOps || feature == ARM_HasV8_8aOps || |
226 | 1.42M | feature == ARM_HasV8_9aOps) && |
227 | 1.42M | (mode & CS_MODE_V8) == 0) |
228 | 222k | return false; |
229 | | |
230 | 1.19M | if (feature >= ARM_FeatureCoprocCDE0 && |
231 | 1.19M | feature <= ARM_FeatureCoprocCDE7) |
232 | | // We currently have no way to detect CDE (Custom-Datapath-Extension) |
233 | | // coprocessors. |
234 | 17.0k | return false; |
235 | | |
236 | | // we support everything |
237 | 1.18M | return true; |
238 | 1.19M | } |