/src/capstonenext/arch/ARM/ARMDisassemblerExtension.c
Line | Count | Source |
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 | 48.5k | { |
10 | 48.5k | if (it->size >= sizeof(it->ITStates)) { |
11 | | // TODO: consider warning user. |
12 | 2.50k | it->size = 0; |
13 | 2.50k | } |
14 | 48.5k | it->ITStates[it->size] = v; |
15 | 48.5k | it->size++; |
16 | | |
17 | 48.5k | return true; |
18 | 48.5k | } |
19 | | |
20 | | // Returns true if the current instruction is in an IT block |
21 | | bool ITBlock_instrInITBlock(ARM_ITBlock *it) |
22 | 951k | { |
23 | 951k | return (it->size > 0); |
24 | 951k | } |
25 | | |
26 | | // Returns true if current instruction is the last instruction in an IT block |
27 | | bool ITBlock_instrLastInITBlock(ARM_ITBlock *it) |
28 | 825 | { |
29 | 825 | return (it->size == 1); |
30 | 825 | } |
31 | | |
32 | | // Returns the condition code for instruction in IT block |
33 | | unsigned ITBlock_getITCC(ARM_ITBlock *it) |
34 | 36.0k | { |
35 | 36.0k | unsigned CC = ARMCC_AL; |
36 | | |
37 | 36.0k | if (ITBlock_instrInITBlock(it)) |
38 | 28.0k | CC = it->ITStates[it->size - 1]; |
39 | | |
40 | 36.0k | return CC; |
41 | 36.0k | } |
42 | | |
43 | | // Advances the IT block state to the next T or E |
44 | | void ITBlock_advanceITState(ARM_ITBlock *it) |
45 | 28.0k | { |
46 | 28.0k | it->size--; |
47 | 28.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.8k | { |
54 | | // (3 - the number of trailing zeros) is the number of then / else. |
55 | 12.8k | unsigned NumTZ = CountTrailingZeros_8(Mask); |
56 | 12.8k | unsigned char CCBits = (unsigned char)(Firstcond & 0xf); |
57 | 12.8k | CS_ASSERT_RET(NumTZ <= 3 && "Invalid IT mask!"); |
58 | | // push condition codes onto the stack the correct order for the pops |
59 | 48.5k | for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { |
60 | 35.6k | unsigned Else = (Mask >> Pos) & 1; |
61 | 35.6k | ITBlock_push_back(it, CCBits ^ Else); |
62 | 35.6k | } |
63 | 12.8k | ITBlock_push_back(it, CCBits); |
64 | 12.8k | } |
65 | | |
66 | | bool VPTBlock_push_back(ARM_VPTBlock *it, char v) |
67 | 14.0k | { |
68 | 14.0k | if (it->size >= sizeof(it->VPTStates)) { |
69 | | // TODO: consider warning user. |
70 | 333 | it->size = 0; |
71 | 333 | } |
72 | 14.0k | it->VPTStates[it->size] = v; |
73 | 14.0k | it->size++; |
74 | | |
75 | 14.0k | return true; |
76 | 14.0k | } |
77 | | |
78 | | bool VPTBlock_instrInVPTBlock(ARM_VPTBlock *VPT) |
79 | 1.15M | { |
80 | 1.15M | return VPT->size > 0; |
81 | 1.15M | } |
82 | | |
83 | | unsigned VPTBlock_getVPTPred(ARM_VPTBlock *VPT) |
84 | 10.9k | { |
85 | 10.9k | unsigned Pred = ARMVCC_None; |
86 | 10.9k | if (VPTBlock_instrInVPTBlock(VPT)) |
87 | 10.9k | Pred = VPT->VPTStates[VPT->size - 1]; |
88 | 10.9k | return Pred; |
89 | 10.9k | } |
90 | | |
91 | | void VPTBlock_advanceVPTState(ARM_VPTBlock *VPT) |
92 | 10.9k | { |
93 | 10.9k | VPT->size--; |
94 | 10.9k | } |
95 | | |
96 | | void VPTBlock_setVPTState(ARM_VPTBlock *VPT, char Mask) |
97 | 4.04k | { |
98 | | // (3 - the number of trailing zeros) is the number of then / else. |
99 | 4.04k | unsigned NumTZ = CountTrailingZeros_8(Mask); |
100 | 4.04k | CS_ASSERT_RET(NumTZ <= 3 && "Invalid VPT mask!"); |
101 | | // push predicates onto the stack the correct order for the pops |
102 | 14.0k | for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { |
103 | 10.0k | bool T = ((Mask >> Pos) & 1) == 0; |
104 | 10.0k | if (T) |
105 | 5.76k | VPTBlock_push_back(VPT, ARMVCC_Then); |
106 | 4.26k | else |
107 | 4.26k | VPTBlock_push_back(VPT, ARMVCC_Else); |
108 | 10.0k | } |
109 | 4.04k | VPTBlock_push_back(VPT, ARMVCC_Then); |
110 | 4.04k | } |
111 | | |
112 | | // Imported from ARMBaseInstrInfo.h |
113 | | // |
114 | | /// isValidCoprocessorNumber - decide whether an explicit coprocessor |
115 | | /// number is legal in generic instructions like CDP. The answer can |
116 | | /// vary with the subtarget. |
117 | | bool isValidCoprocessorNumber(MCInst *Inst, unsigned Num) |
118 | 25.9k | { |
119 | | // In Armv7 and Armv8-M CP10 and CP11 clash with VFP/NEON, however, the |
120 | | // coprocessor is still valid for CDP/MCR/MRC and friends. Allowing it is |
121 | | // useful for code which is shared with older architectures which do not |
122 | | // know the new VFP/NEON mnemonics. |
123 | | |
124 | | // Armv8-A disallows everything *other* than 111x (CP14 and CP15). |
125 | 25.9k | if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8Ops) && |
126 | 25.9k | (Num & 0xE) != 0xE) |
127 | 11 | return false; |
128 | | |
129 | | // Armv8.1-M disallows 100x (CP8,CP9) and 111x (CP14,CP15) |
130 | | // which clash with MVE. |
131 | 25.9k | if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8_1MMainlineOps) && |
132 | 25.9k | ((Num & 0xE) == 0x8 || (Num & 0xE) == 0xE)) |
133 | 3 | return false; |
134 | | |
135 | 25.9k | return true; |
136 | 25.9k | } |
137 | | |
138 | | // Imported from ARMMCTargetDesc.h |
139 | | bool ARM_isVpred(arm_op_type op) |
140 | 12.3M | { |
141 | 12.3M | return op == ARM_OP_VPRED_R || op == ARM_OP_VPRED_N; |
142 | 12.3M | } |
143 | | |
144 | | // Imported from ARMBaseInstrInfo.h |
145 | | // |
146 | | // This table shows the VPT instruction variants, i.e. the different |
147 | | // mask field encodings, see also B5.6. Predication/conditional execution in |
148 | | // the ArmARM. |
149 | | bool isVPTOpcode(int Opc) |
150 | 45.5k | { |
151 | 45.5k | return Opc == ARM_MVE_VPTv16i8 || Opc == ARM_MVE_VPTv16u8 || |
152 | 45.5k | Opc == ARM_MVE_VPTv16s8 || Opc == ARM_MVE_VPTv8i16 || |
153 | 45.5k | Opc == ARM_MVE_VPTv8u16 || Opc == ARM_MVE_VPTv8s16 || |
154 | 45.5k | Opc == ARM_MVE_VPTv4i32 || Opc == ARM_MVE_VPTv4u32 || |
155 | 45.5k | Opc == ARM_MVE_VPTv4s32 || Opc == ARM_MVE_VPTv4f32 || |
156 | 45.5k | Opc == ARM_MVE_VPTv8f16 || Opc == ARM_MVE_VPTv16i8r || |
157 | 45.5k | Opc == ARM_MVE_VPTv16u8r || Opc == ARM_MVE_VPTv16s8r || |
158 | 45.5k | Opc == ARM_MVE_VPTv8i16r || Opc == ARM_MVE_VPTv8u16r || |
159 | 45.5k | Opc == ARM_MVE_VPTv8s16r || Opc == ARM_MVE_VPTv4i32r || |
160 | 45.5k | Opc == ARM_MVE_VPTv4u32r || Opc == ARM_MVE_VPTv4s32r || |
161 | 45.5k | Opc == ARM_MVE_VPTv4f32r || Opc == ARM_MVE_VPTv8f16r || |
162 | 45.5k | Opc == ARM_MVE_VPST; |
163 | 45.5k | } |
164 | | |
165 | | // Imported from ARMMCTargetDesc.cpp |
166 | | bool ARM_isCDECoproc(size_t Coproc, const MCInst *MI) |
167 | 33.9k | { |
168 | | // Unfortunately we don't have ARMTargetInfo in the disassembler, so we have |
169 | | // to rely on feature bits. |
170 | 33.9k | if (Coproc >= 8) |
171 | 23.6k | return false; |
172 | | |
173 | 10.2k | return ARM_getFeatureBits(MI->csh->mode, |
174 | 10.2k | ARM_FeatureCoprocCDE0 + Coproc); |
175 | 33.9k | } |
176 | | |
177 | | // Hacky: enable all features for disassembler |
178 | | bool ARM_getFeatureBits(unsigned int mode, unsigned int feature) |
179 | 2.36M | { |
180 | 2.36M | if (feature == ARM_ModeThumb) { |
181 | 1.30M | if (mode & CS_MODE_THUMB) |
182 | 1.16M | return true; |
183 | 137k | return false; |
184 | 1.30M | } |
185 | | |
186 | 1.06M | if (feature == ARM_FeatureDFB) |
187 | 70 | return false; |
188 | | |
189 | 1.06M | if (feature == ARM_FeatureRAS) |
190 | 126 | return false; |
191 | | |
192 | 1.06M | if (feature == ARM_FeatureMClass && (mode & CS_MODE_MCLASS) == 0) |
193 | 45.0k | return false; |
194 | | |
195 | 1.01M | if ((feature == ARM_HasMVEIntegerOps || feature == ARM_HasMVEFloatOps || |
196 | 1.01M | feature == ARM_FeatureMVEVectorCostFactor1 || |
197 | 1.01M | feature == ARM_FeatureMVEVectorCostFactor2 || |
198 | 1.01M | feature == ARM_FeatureMVEVectorCostFactor4) && |
199 | 1.01M | (mode & CS_MODE_MCLASS) == 0) |
200 | 6.01k | return false; |
201 | | |
202 | 1.01M | if ((feature == ARM_HasV8Ops || feature == ARM_HasV8_1MMainlineOps || |
203 | 1.01M | feature == ARM_HasV8_1aOps || feature == ARM_HasV8_2aOps || |
204 | 1.01M | feature == ARM_HasV8_3aOps || feature == ARM_HasV8_4aOps || |
205 | 1.01M | feature == ARM_HasV8_5aOps || feature == ARM_HasV8_6aOps || |
206 | 1.01M | feature == ARM_HasV8_7aOps || feature == ARM_HasV8_8aOps || |
207 | 1.01M | feature == ARM_HasV8_9aOps) && |
208 | 1.01M | (mode & CS_MODE_V8) == 0) |
209 | 151k | return false; |
210 | | |
211 | 861k | if (feature >= ARM_FeatureCoprocCDE0 && |
212 | 861k | feature <= ARM_FeatureCoprocCDE7) |
213 | | // We currently have no way to detect CDE (Custom-Datapath-Extension) |
214 | | // coprocessors. |
215 | 10.2k | return false; |
216 | | |
217 | | // we support everything |
218 | 851k | return true; |
219 | 861k | } |