/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  | 35.7k  | { | 
10  | 35.7k  |   if (it->size >= sizeof(it->ITStates)) { | 
11  |  |     // TODO: consider warning user.  | 
12  | 1.51k  |     it->size = 0;  | 
13  | 1.51k  |   }  | 
14  | 35.7k  |   it->ITStates[it->size] = v;  | 
15  | 35.7k  |   it->size++;  | 
16  |  |  | 
17  | 35.7k  |   return true;  | 
18  | 35.7k  | }  | 
19  |  |  | 
20  |  | // Returns true if the current instruction is in an IT block  | 
21  |  | bool ITBlock_instrInITBlock(ARM_ITBlock *it)  | 
22  | 1.24M  | { | 
23  | 1.24M  |   return (it->size > 0);  | 
24  | 1.24M  | }  | 
25  |  |  | 
26  |  | // Returns true if current instruction is the last instruction in an IT block  | 
27  |  | bool ITBlock_instrLastInITBlock(ARM_ITBlock *it)  | 
28  | 1.26k  | { | 
29  | 1.26k  |   return (it->size == 1);  | 
30  | 1.26k  | }  | 
31  |  |  | 
32  |  | // Returns the condition code for instruction in IT block  | 
33  |  | unsigned ITBlock_getITCC(ARM_ITBlock *it)  | 
34  | 37.7k  | { | 
35  | 37.7k  |   unsigned CC = ARMCC_AL;  | 
36  |  |  | 
37  | 37.7k  |   if (ITBlock_instrInITBlock(it))  | 
38  | 22.9k  |     CC = it->ITStates[it->size - 1];  | 
39  |  |  | 
40  | 37.7k  |   return CC;  | 
41  | 37.7k  | }  | 
42  |  |  | 
43  |  | // Advances the IT block state to the next T or E  | 
44  |  | void ITBlock_advanceITState(ARM_ITBlock *it)  | 
45  | 22.9k  | { | 
46  | 22.9k  |   it->size--;  | 
47  | 22.9k  | }  | 
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  | 10.0k  | { | 
54  |  |   // (3 - the number of trailing zeros) is the number of then / else.  | 
55  | 10.0k  |   unsigned NumTZ = CountTrailingZeros_8(Mask);  | 
56  | 10.0k  |   unsigned char CCBits = (unsigned char)(Firstcond & 0xf);  | 
57  | 10.0k  |   CS_ASSERT_RET(NumTZ <= 3 && "Invalid IT mask!");  | 
58  |  |   // push condition codes onto the stack the correct order for the pops  | 
59  | 35.7k  |   for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { | 
60  | 25.6k  |     unsigned Else = (Mask >> Pos) & 1;  | 
61  | 25.6k  |     ITBlock_push_back(it, CCBits ^ Else);  | 
62  | 25.6k  |   }  | 
63  | 10.0k  |   ITBlock_push_back(it, CCBits);  | 
64  | 10.0k  | }  | 
65  |  |  | 
66  |  | bool VPTBlock_push_back(ARM_VPTBlock *it, char v)  | 
67  | 25.5k  | { | 
68  | 25.5k  |   if (it->size >= sizeof(it->VPTStates)) { | 
69  |  |     // TODO: consider warning user.  | 
70  | 838  |     it->size = 0;  | 
71  | 838  |   }  | 
72  | 25.5k  |   it->VPTStates[it->size] = v;  | 
73  | 25.5k  |   it->size++;  | 
74  |  |  | 
75  | 25.5k  |   return true;  | 
76  | 25.5k  | }  | 
77  |  |  | 
78  |  | bool VPTBlock_instrInVPTBlock(ARM_VPTBlock *VPT)  | 
79  | 1.56M  | { | 
80  | 1.56M  |   return VPT->size > 0;  | 
81  | 1.56M  | }  | 
82  |  |  | 
83  |  | unsigned VPTBlock_getVPTPred(ARM_VPTBlock *VPT)  | 
84  | 18.1k  | { | 
85  | 18.1k  |   unsigned Pred = ARMVCC_None;  | 
86  | 18.1k  |   if (VPTBlock_instrInVPTBlock(VPT))  | 
87  | 18.1k  |     Pred = VPT->VPTStates[VPT->size - 1];  | 
88  | 18.1k  |   return Pred;  | 
89  | 18.1k  | }  | 
90  |  |  | 
91  |  | void VPTBlock_advanceVPTState(ARM_VPTBlock *VPT)  | 
92  | 18.1k  | { | 
93  | 18.1k  |   VPT->size--;  | 
94  | 18.1k  | }  | 
95  |  |  | 
96  |  | void VPTBlock_setVPTState(ARM_VPTBlock *VPT, char Mask)  | 
97  | 7.35k  | { | 
98  |  |   // (3 - the number of trailing zeros) is the number of then / else.  | 
99  | 7.35k  |   unsigned NumTZ = CountTrailingZeros_8(Mask);  | 
100  | 7.35k  |   CS_ASSERT_RET(NumTZ <= 3 && "Invalid VPT mask!");  | 
101  |  |   // push predicates onto the stack the correct order for the pops  | 
102  | 25.5k  |   for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) { | 
103  | 18.2k  |     bool T = ((Mask >> Pos) & 1) == 0;  | 
104  | 18.2k  |     if (T)  | 
105  | 11.1k  |       VPTBlock_push_back(VPT, ARMVCC_Then);  | 
106  | 7.05k  |     else  | 
107  | 7.05k  |       VPTBlock_push_back(VPT, ARMVCC_Else);  | 
108  | 18.2k  |   }  | 
109  | 7.35k  |   VPTBlock_push_back(VPT, ARMVCC_Then);  | 
110  | 7.35k  | }  | 
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  | 35.3k  | { | 
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  | 35.3k  |   if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8Ops) &&  | 
126  | 38  |       (Num & 0xE) != 0xE)  | 
127  | 33  |     return false;  | 
128  |  |  | 
129  |  |   // Armv8.1-M disallows 100x (CP8,CP9) and 111x (CP14,CP15)  | 
130  |  |   // which clash with MVE.  | 
131  | 35.3k  |   if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8_1MMainlineOps) &&  | 
132  | 5  |       ((Num & 0xE) == 0x8 || (Num & 0xE) == 0xE))  | 
133  | 5  |     return false;  | 
134  |  |  | 
135  | 35.3k  |   return true;  | 
136  | 35.3k  | }  | 
137  |  |  | 
138  |  | // Imported from ARMMCTargetDesc.h  | 
139  |  | bool ARM_isVpred(arm_op_type op)  | 
140  | 16.8M  | { | 
141  | 16.8M  |   return op == ARM_OP_VPRED_R || op == ARM_OP_VPRED_N;  | 
142  | 16.8M  | }  | 
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  | 101k  | { | 
151  | 101k  |   return Opc == ARM_MVE_VPTv16i8 || Opc == ARM_MVE_VPTv16u8 ||  | 
152  | 100k  |          Opc == ARM_MVE_VPTv16s8 || Opc == ARM_MVE_VPTv8i16 ||  | 
153  | 99.7k  |          Opc == ARM_MVE_VPTv8u16 || Opc == ARM_MVE_VPTv8s16 ||  | 
154  | 98.3k  |          Opc == ARM_MVE_VPTv4i32 || Opc == ARM_MVE_VPTv4u32 ||  | 
155  | 97.1k  |          Opc == ARM_MVE_VPTv4s32 || Opc == ARM_MVE_VPTv4f32 ||  | 
156  | 96.2k  |          Opc == ARM_MVE_VPTv8f16 || Opc == ARM_MVE_VPTv16i8r ||  | 
157  | 94.9k  |          Opc == ARM_MVE_VPTv16u8r || Opc == ARM_MVE_VPTv16s8r ||  | 
158  | 92.2k  |          Opc == ARM_MVE_VPTv8i16r || Opc == ARM_MVE_VPTv8u16r ||  | 
159  | 90.8k  |          Opc == ARM_MVE_VPTv8s16r || Opc == ARM_MVE_VPTv4i32r ||  | 
160  | 90.1k  |          Opc == ARM_MVE_VPTv4u32r || Opc == ARM_MVE_VPTv4s32r ||  | 
161  | 88.8k  |          Opc == ARM_MVE_VPTv4f32r || Opc == ARM_MVE_VPTv8f16r ||  | 
162  | 86.9k  |          Opc == ARM_MVE_VPST;  | 
163  | 101k  | }  | 
164  |  |  | 
165  |  | // Imported from ARMMCTargetDesc.cpp  | 
166  |  | bool ARM_isCDECoproc(size_t Coproc, const MCInst *MI)  | 
167  | 47.3k  | { | 
168  |  |   // Unfortunately we don't have ARMTargetInfo in the disassembler, so we have  | 
169  |  |   // to rely on feature bits.  | 
170  | 47.3k  |   if (Coproc >= 8)  | 
171  | 31.1k  |     return false;  | 
172  |  |  | 
173  | 16.2k  |   return ARM_getFeatureBits(MI->csh->mode,  | 
174  | 16.2k  |           ARM_FeatureCoprocCDE0 + Coproc);  | 
175  | 47.3k  | }  | 
176  |  |  | 
177  |  | // Hacky: enable all features for disassembler  | 
178  |  | bool ARM_getFeatureBits(unsigned int mode, unsigned int feature)  | 
179  | 3.61M  | { | 
180  | 3.61M  |   if (feature == ARM_ModeThumb) { | 
181  | 1.82M  |     if (mode & CS_MODE_THUMB)  | 
182  | 1.62M  |       return true;  | 
183  | 202k  |     return false;  | 
184  | 1.82M  |   }  | 
185  |  |  | 
186  | 1.79M  |   if (feature == ARM_FeatureDFB)  | 
187  | 312  |     return false;  | 
188  |  |  | 
189  | 1.79M  |   if (feature == ARM_FeatureRAS)  | 
190  | 1.39k  |     return false;  | 
191  |  |  | 
192  | 1.78M  |   if (feature == ARM_FeatureMClass && (mode & CS_MODE_MCLASS) == 0)  | 
193  | 69.4k  |     return false;  | 
194  |  |  | 
195  | 1.71M  |   if ((feature == ARM_HasMVEIntegerOps || feature == ARM_HasMVEFloatOps ||  | 
196  | 1.60M  |        feature == ARM_FeatureMVEVectorCostFactor1 ||  | 
197  | 1.60M  |        feature == ARM_FeatureMVEVectorCostFactor2 ||  | 
198  | 1.60M  |        feature == ARM_FeatureMVEVectorCostFactor4) &&  | 
199  | 115k  |       (mode & CS_MODE_MCLASS) == 0)  | 
200  | 16.8k  |     return false;  | 
201  |  |  | 
202  | 1.70M  |   if ((feature == ARM_HasV8Ops || feature == ARM_HasV8_1MMainlineOps ||  | 
203  | 1.46M  |        feature == ARM_HasV8_1aOps || feature == ARM_HasV8_2aOps ||  | 
204  | 1.45M  |        feature == ARM_HasV8_3aOps || feature == ARM_HasV8_4aOps ||  | 
205  | 1.45M  |        feature == ARM_HasV8_5aOps || feature == ARM_HasV8_6aOps ||  | 
206  | 1.45M  |        feature == ARM_HasV8_7aOps || feature == ARM_HasV8_8aOps ||  | 
207  | 1.45M  |        feature == ARM_HasV8_9aOps) &&  | 
208  | 250k  |       (mode & CS_MODE_V8) == 0)  | 
209  | 219k  |     return false;  | 
210  |  |  | 
211  | 1.48M  |   if (feature >= ARM_FeatureCoprocCDE0 &&  | 
212  | 1.46M  |       feature <= ARM_FeatureCoprocCDE7)  | 
213  |  |     // We currently have no way to detect CDE (Custom-Datapath-Extension)  | 
214  |  |     // coprocessors.  | 
215  | 16.2k  |     return false;  | 
216  |  |  | 
217  |  |   // we support everything  | 
218  | 1.46M  |   return true;  | 
219  | 1.48M  | }  |