xref: /aosp_15_r20/external/OpenCSD/decoder/source/i_dec/trc_idec_arminst.cpp (revision 02ca8ccacfba7e0df68f3332a95f3180334d6649)
1 /*
2  * \file       trc_idec_arminst.cpp
3  * \brief      OpenCSD :
4  *
5  * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
6  */
7 
8 /*
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36 Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic
37 block identification and trace decode.
38 */
39 
40 #include "i_dec/trc_idec_arminst.h"
41 
42 #include <stddef.h>  /* for NULL */
43 #include <assert.h>
44 
inst_ARM_is_direct_branch(uint32_t inst)45 int inst_ARM_is_direct_branch(uint32_t inst)
46 {
47     int is_direct_branch = 1;
48     if ((inst & 0xf0000000) == 0xf0000000) {
49         /* NV space */
50         if ((inst & 0xfe000000) == 0xfa000000){
51             /* BLX (imm) */
52         } else {
53             is_direct_branch = 0;
54         }
55     } else if ((inst & 0x0e000000) == 0x0a000000) {
56         /* B, BL */
57     } else {
58         is_direct_branch = 0;
59     }
60     return is_direct_branch;
61 }
62 
inst_ARM_wfiwfe(uint32_t inst)63 int inst_ARM_wfiwfe(uint32_t inst)
64 {
65     if ( ((inst & 0xf0000000) != 0xf0000000) &&
66          ((inst & 0x0ffffffe) == 0x0320f002)
67         )
68         /* WFI & WFE may be traced as branches in etm4.3 ++ */
69         return 1;
70     return 0;
71 }
72 
inst_ARM_is_indirect_branch(uint32_t inst,struct decode_info * info)73 int inst_ARM_is_indirect_branch(uint32_t inst, struct decode_info *info)
74 {
75     int is_indirect_branch = 1;
76     if ((inst & 0xf0000000) == 0xf0000000) {
77         /* NV space */
78         if ((inst & 0xfe500000) == 0xf8100000) {
79             /* RFE */
80         } else {
81             is_indirect_branch = 0;
82         }
83     } else if ((inst & 0x0ff000d0) == 0x01200010) {
84         /* BLX (register), BX */
85         if ((inst & 0xFF) == 0x1E)
86             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */
87     } else if ((inst & 0x0ff000f0) == 0x01200020) {
88         /* BXJ: in v8 this behaves like BX */
89     } else if ((inst & 0x0e108000) == 0x08108000) {
90         /* POP {...,pc} or LDMxx {...,pc} */
91         if ((inst & 0x0FFFA000) == 0x08BD8000) /* LDMIA SP!,{...,pc} */
92             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;
93     } else if ((inst & 0x0e50f000) == 0x0410f000) {
94         /* LDR PC,imm... inc. POP {PC} */
95         if ( (inst & 0x01ff0000) == 0x009D0000)
96             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm */
97     } else if ((inst & 0x0e50f010) == 0x0610f000) {
98         /* LDR PC,reg */
99     } else if ((inst & 0x0fe0f000) == 0x01a0f000) {
100         /* MOV PC,rx */
101         if ((inst & 0x00100FFF) == 0x00E) /* ensure the S=0, LSL #0 variant - i.e plain MOV */
102             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC, R14 */
103     } else if ((inst & 0x0f900080) == 0x01000000) {
104         /* "Miscellaneous instructions" - in DP space */
105         is_indirect_branch = 0;
106     } else if ((inst & 0x0f9000f0) == 0x01800090) {
107         /* Some extended loads and stores */
108         is_indirect_branch = 0;
109     } else if ((inst & 0x0fb0f000) == 0x0320f000) {
110         /* MSR #imm */
111         is_indirect_branch = 0;
112     } else if ((inst & 0x0e00f000) == 0x0200f000) {
113         /* DP PC,imm shift */
114         if ((inst & 0x0f90f000) == 0x0310f000) {
115             /* TST/CMP */
116            is_indirect_branch = 0;
117         }
118     } else if ((inst & 0x0e00f000) == 0x0000f000) {
119         /* DP PC,reg */
120     } else {
121         is_indirect_branch = 0;
122     }
123     return is_indirect_branch;
124 }
125 
inst_Thumb_is_direct_branch(uint32_t inst,struct decode_info * info)126 int inst_Thumb_is_direct_branch(uint32_t inst, struct decode_info *info)
127 {
128     uint8_t link, cond;
129     return inst_Thumb_is_direct_branch_link(inst, &link, &cond, info);
130 }
131 
inst_Thumb_is_direct_branch_link(uint32_t inst,uint8_t * is_link,uint8_t * is_cond,struct decode_info * info)132 int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond, struct decode_info *info)
133 {
134     int is_direct_branch = 1;
135 
136     if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
137         /* B<c> (encoding T1) */
138         *is_cond = 1;
139     } else if ((inst & 0xf8000000) == 0xe0000000) {
140         /* B (encoding T2) */
141     } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
142         /* B (encoding T3) */
143         *is_cond = 1;
144     } else if ((inst & 0xf8009000) == 0xf0009000) {
145         /* B (encoding T4); BL (encoding T1) */
146         if (inst & 0x00004000) {
147             *is_link = 1;
148             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
149         }
150     } else if ((inst & 0xf800d001) == 0xf000c000) {
151         /* BLX (imm) (encoding T2) */
152         *is_link = 1;
153         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
154     } else if ((inst & 0xf5000000) == 0xb1000000) {
155         /* CB(NZ) */
156         *is_cond = 1;
157     } else {
158         is_direct_branch = 0;
159     }
160     return is_direct_branch;
161 }
162 
inst_Thumb_wfiwfe(uint32_t inst)163 int inst_Thumb_wfiwfe(uint32_t inst)
164 {
165     int is_wfiwfe = 1;
166     /* WFI, WFE may be branches in etm4.3++ */
167     if ((inst & 0xfffffffe) == 0xf3af8002) {
168         /* WFI & WFE (encoding T2) */
169     }
170     else if ((inst & 0xffef0000) == 0xbf200000) {
171         /* WFI & WFE (encoding T1) */
172     }
173     else {
174         is_wfiwfe = 0;
175     }
176     return is_wfiwfe;
177 }
178 
inst_Thumb_is_indirect_branch(uint32_t inst,struct decode_info * info)179 int inst_Thumb_is_indirect_branch(uint32_t inst, struct decode_info *info)
180 {
181     uint8_t link;
182     return inst_Thumb_is_indirect_branch_link(inst, &link, info);
183 }
184 
inst_Thumb_is_indirect_branch_link(uint32_t inst,uint8_t * is_link,struct decode_info * info)185 int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
186 {
187     /* See e.g. PFT Table 2-3 and Table 2-5 */
188     int is_branch = 1;
189 
190     if ((inst & 0xff000000) == 0x47000000) {
191         /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */
192         if (inst & 0x00800000) {
193             *is_link = 1;
194             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
195         }
196         else if ((inst & 0x00780000) == 0x00700000) {
197             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;  /* BX LR */
198         }
199     } else if ((inst & 0xfff0d000) == 0xf3c08000) {
200         /* BXJ: in v8 this behaves like BX */
201     } else if ((inst & 0xff000000) == 0xbd000000) {
202         /* POP {pc} */
203         info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;
204     } else if ((inst & 0xfd870000) == 0x44870000) {
205         /* MOV PC,reg or ADD PC,reg */
206         if ((inst & 0xffff0000) == 0x46f70000)
207             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC,LR */
208     } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) {
209         /* TBB/TBH */
210     } else if ((inst & 0xffd00000) == 0xe8100000) {
211         /* RFE (T1) */
212     } else if ((inst & 0xffd00000) == 0xe9900000) {
213         /* RFE (T2) */
214     } else if ((inst & 0xfff0d000) == 0xf3d08000) {
215         /* SUBS PC,LR,#imm inc.ERET */
216     } else if ((inst & 0xfff0f000) == 0xf8d0f000) {
217         /* LDR PC,imm (T3) */
218     } else if ((inst & 0xff7ff000) == 0xf85ff000) {
219         /* LDR PC,literal (T2) */
220     } else if ((inst & 0xfff0f800) == 0xf850f800) {
221         /* LDR PC,imm (T4) */
222         if((inst & 0x000f0f00) == 0x000d0b00)
223             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm*/
224     } else if ((inst & 0xfff0ffc0) == 0xf850f000) {
225         /* LDR PC,reg (T2) */
226     } else if ((inst & 0xfe508000) == 0xe8108000) {
227         /* LDM PC */
228         if ((inst & 0x0FFF0000) == 0x08BD0000) /* LDMIA [SP]!, */
229             info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* POP {...,pc} */
230     } else {
231         is_branch = 0;
232     }
233     return is_branch;
234 }
235 
inst_A64_is_direct_branch(uint32_t inst,struct decode_info * info)236 int inst_A64_is_direct_branch(uint32_t inst, struct decode_info *info)
237 {
238     uint8_t link = 0;
239     return inst_A64_is_direct_branch_link(inst, &link, info);
240 }
241 
inst_A64_is_direct_branch_link(uint32_t inst,uint8_t * is_link,struct decode_info * info)242 int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
243 {
244     int is_direct_branch = 1;
245     if ((inst & 0x7c000000) == 0x34000000) {
246         /* CB, TB */
247     } else if ((inst & 0xff000000) == 0x54000000) {
248         /* B<cond> */
249         /* BC<cond> 8.8 / 9.3 arch - bit 4 = 1'b1 */
250     } else if ((inst & 0x7c000000) == 0x14000000) {
251         /* B, BL imm */
252         if (inst & 0x80000000) {
253             *is_link = 1;
254             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
255         }
256     } else {
257         is_direct_branch = 0;
258     }
259     return is_direct_branch;
260 }
261 
inst_A64_wfiwfe(uint32_t inst,struct decode_info * info)262 int inst_A64_wfiwfe(uint32_t inst, struct decode_info *info)
263 {
264     /* WFI, WFE may be traced as branches in etm 4.3++ */
265     if ((inst & 0xffffffdf) == 0xd503205f)
266         return 1;
267 
268     /* new feature introduced post v8.3 */
269     if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64))
270     {
271         /* WFIT / WFET for later archs */
272         if ((inst & 0xffffffc0) == 0xd5031000)
273             return 1;
274     }
275     return 0;
276 }
277 
inst_A64_Tstart(uint32_t inst)278 int inst_A64_Tstart(uint32_t inst)
279 {
280     if ((inst & 0xffffffe0) == 0xd5233060)
281         return 1;
282     return 0;
283 }
284 
inst_A64_is_indirect_branch(uint32_t inst,struct decode_info * info)285 int inst_A64_is_indirect_branch(uint32_t inst, struct decode_info *info)
286 {
287     uint8_t link = 0;
288     return inst_A64_is_indirect_branch_link(inst, &link, info);
289 }
290 
inst_A64_is_indirect_branch_link(uint32_t inst,uint8_t * is_link,struct decode_info * info)291 int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
292 {
293     int is_indirect_branch = 1;
294 
295     if ((inst & 0xffdffc1f) == 0xd61f0000) {
296         /* BR, BLR */
297         if (inst & 0x00200000) {
298             *is_link = 1;
299             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
300         }
301     } else if ((inst & 0xfffffc1f) == 0xd65f0000) {
302         info->instr_sub_type = OCSD_S_INSTR_V8_RET;
303         /* RET */
304     } else if ((inst & 0xffffffff) == 0xd69f03e0) {
305         /* ERET */
306         info->instr_sub_type = OCSD_S_INSTR_V8_ERET;
307     } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) {
308         /* new pointer auth instr for v8.3 arch */
309         if ((inst & 0xffdff800) == 0xd71f0800) {
310             /* BRAA, BRAB, BLRAA, BLRBB */
311             if (inst & 0x00200000) {
312                 *is_link = 1;
313                 info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
314             }
315         } else if ((inst & 0xffdff81F) == 0xd61f081F) {
316             /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */
317             if (inst & 0x00200000) {
318                 *is_link = 1;
319                 info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
320             }
321         } else if ((inst & 0xfffffbff) == 0xd69f0bff) {
322             /* ERETAA, ERETAB */
323             info->instr_sub_type = OCSD_S_INSTR_V8_ERET;
324         } else if ((inst & 0xfffffbff) == 0xd65f0bff) {
325             /* RETAA, RETAB */
326             info->instr_sub_type = OCSD_S_INSTR_V8_RET;
327 
328         } else if ((inst & 0xffc0001f) == 0x5500001f) {
329             /* RETA<k>SPPC label*/
330              info->instr_sub_type = OCSD_S_INSTR_V8_RET;
331         } else if (((inst & 0xfffffbe0) == 0xd65f0be0) &&
332                    ((inst & 0x1f) != 0x1f)) {
333             /* RETA<k>SPPC <register>*/
334              info->instr_sub_type = OCSD_S_INSTR_V8_RET;
335         } else {
336             is_indirect_branch = 0;
337         }
338     } else {
339         is_indirect_branch = 0;
340     }
341     return is_indirect_branch;
342 }
343 
inst_ARM_branch_destination(uint32_t addr,uint32_t inst,uint32_t * pnpc)344 int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
345 {
346     uint32_t npc;
347     int is_direct_branch = 1;
348     if ((inst & 0x0e000000) == 0x0a000000) {
349         /*
350           B:   cccc:1010:imm24
351           BL:  cccc:1011:imm24
352           BLX: 1111:101H:imm24
353         */
354         npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6);
355         if ((inst & 0xf0000000) == 0xf0000000) {
356             npc |= 1;  /* indicate ISA is now Thumb */
357             npc |= ((inst >> 23) & 2);   /* apply the H bit */
358         }
359     } else {
360         is_direct_branch = 0;
361     }
362     if (is_direct_branch && pnpc != NULL) {
363         *pnpc = npc;
364     }
365     return is_direct_branch;
366 }
367 
inst_Thumb_branch_destination(uint32_t addr,uint32_t inst,uint32_t * pnpc)368 int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
369 {
370     uint32_t npc;
371     int is_direct_branch = 1;
372     if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
373         /* B<c> (encoding T1) */
374         npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23);
375         npc |= 1;
376     } else if ((inst & 0xf8000000) == 0xe0000000) {
377         /* B (encoding T2) */
378         npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20);
379         npc |= 1;
380     } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
381         /* B (encoding T3) */
382         npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
383                                     ((inst & 0x0800) << 19) |
384                                     ((inst & 0x2000) << 16) |
385                                     ((inst & 0x003f0000) << 7) |
386                                     ((inst & 0x000007ff) << 12)) >> 11);
387         npc |= 1;
388     } else if ((inst & 0xf8009000) == 0xf0009000) {
389         /* B (encoding T4); BL (encoding T1) */
390         uint32_t S = ((inst & 0x04000000) >> 26)-1;  /* ffffffff or 0 according to S bit */
391         npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
392                                     (((inst^S) & 0x2000) << 17) |
393                                     (((inst^S) & 0x0800) << 18) |
394                                     ((inst & 0x03ff0000) << 3) |
395                                     ((inst & 0x000007ff) << 8)) >> 7);
396         npc |= 1;
397     } else if ((inst & 0xf800d001) == 0xf000c000) {
398         /* BLX (encoding T2) */
399         uint32_t S = ((inst & 0x04000000) >> 26)-1;  /* ffffffff or 0 according to S bit */
400         addr &= 0xfffffffc;   /* Align(PC,4) */
401         npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
402                                     (((inst^S) & 0x2000) << 17) |
403                                     (((inst^S) & 0x0800) << 18) |
404                                     ((inst & 0x03ff0000) << 3) |
405                                     ((inst & 0x000007fe) << 8)) >> 7);
406         /* don't set the Thumb bit, as we're transferring to ARM */
407     } else if ((inst & 0xf5000000) == 0xb1000000) {
408         /* CB(NZ) */
409         /* Note that it's zero-extended - always a forward branch */
410         npc = addr + 4 + ((((inst & 0x02000000) << 6) |
411                            ((inst & 0x00f80000) << 7)) >> 25);
412         npc |= 1;
413     } else {
414         is_direct_branch = 0;
415     }
416     if (is_direct_branch && pnpc != NULL) {
417         *pnpc = npc;
418     }
419     return is_direct_branch;
420 }
421 
inst_A64_branch_destination(uint64_t addr,uint32_t inst,uint64_t * pnpc)422 int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc)
423 {
424     uint64_t npc;
425     int is_direct_branch = 1;
426     if ((inst & 0xff000000) == 0x54000000) {
427         /* B<cond> */
428         /* BC<cond> */
429         npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
430     } else if ((inst & 0x7c000000) == 0x14000000) {
431         /* B, BL imm */
432         npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4);
433     } else if ((inst & 0x7e000000) == 0x34000000) {
434         /* CB */
435         npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
436     } else if ((inst & 0x7e000000) == 0x36000000) {
437         /* TB */
438         npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16);
439     } else {
440         is_direct_branch = 0;
441     }
442     if (is_direct_branch && pnpc != NULL) {
443         *pnpc = npc;
444     }
445     return is_direct_branch;
446 }
447 
inst_ARM_is_branch(uint32_t inst,struct decode_info * info)448 int inst_ARM_is_branch(uint32_t inst, struct decode_info *info)
449 {
450     return inst_ARM_is_indirect_branch(inst, info) ||
451            inst_ARM_is_direct_branch(inst);
452 }
453 
inst_Thumb_is_branch(uint32_t inst,struct decode_info * info)454 int inst_Thumb_is_branch(uint32_t inst, struct decode_info *info)
455 {
456     return inst_Thumb_is_indirect_branch(inst, info) ||
457            inst_Thumb_is_direct_branch(inst, info);
458 }
459 
inst_A64_is_branch(uint32_t inst,struct decode_info * info)460 int inst_A64_is_branch(uint32_t inst, struct decode_info *info)
461 {
462     return inst_A64_is_indirect_branch(inst, info) ||
463            inst_A64_is_direct_branch(inst, info);
464 }
465 
inst_ARM_is_branch_and_link(uint32_t inst,struct decode_info * info)466 int inst_ARM_is_branch_and_link(uint32_t inst, struct decode_info *info)
467 {
468     int is_branch = 1;
469     if ((inst & 0xf0000000) == 0xf0000000) {
470         if ((inst & 0xfe000000) == 0xfa000000){
471             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
472             /* BLX (imm) */
473         } else {
474             is_branch = 0;
475         }
476     } else if ((inst & 0x0f000000) == 0x0b000000) {
477         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
478         /* BL */
479     } else if ((inst & 0x0ff000f0) == 0x01200030) {
480         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
481         /* BLX (reg) */
482     } else {
483         is_branch = 0;
484     }
485     return is_branch;
486 }
487 
inst_Thumb_is_branch_and_link(uint32_t inst,struct decode_info * info)488 int inst_Thumb_is_branch_and_link(uint32_t inst, struct decode_info *info)
489 {
490     int is_branch = 1;
491     if ((inst & 0xff800000) == 0x47800000) {
492         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
493         /* BLX (reg) */
494     } else if ((inst & 0xf800c000) == 0xf000c000) {
495         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
496         /* BL, BLX (imm) */
497     } else {
498         is_branch = 0;
499     }
500     return is_branch;
501 }
502 
inst_A64_is_branch_and_link(uint32_t inst,struct decode_info * info)503 int inst_A64_is_branch_and_link(uint32_t inst, struct decode_info *info)
504 {
505     int is_branch = 1;
506     if ((inst & 0xfffffc1f) == 0xd63f0000) {
507         /* BLR */
508         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
509     } else if ((inst & 0xfc000000) == 0x94000000) {
510         /* BL */
511         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
512     }  else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) {
513         /* new pointer auth instr for v8.3 arch */
514         if ((inst & 0xfffff800) == 0xd73f0800) {
515             /* BLRAA, BLRBB */
516             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
517         } else if ((inst & 0xfffff81F) == 0xd63f081F) {
518             /* BLRAAZ, BLRBBZ */
519             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
520         } else {
521             is_branch = 0;
522         }
523     } else {
524         is_branch = 0;
525     }
526     return is_branch;
527 }
528 
inst_ARM_is_conditional(uint32_t inst)529 int inst_ARM_is_conditional(uint32_t inst)
530 {
531     return (inst & 0xe0000000) != 0xe0000000;
532 }
533 
inst_Thumb_is_conditional(uint32_t inst)534 int inst_Thumb_is_conditional(uint32_t inst)
535 {
536     if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
537         /* B<c> (encoding T1) */
538         return 1;
539     } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
540         /* B<c> (encoding T3) */
541         return 1;
542     } else if ((inst & 0xf5000000) == 0xb1000000) {
543         /* CB(N)Z */
544         return 1;
545     }
546     return 0;
547 }
548 
inst_Thumb_is_IT(uint32_t inst)549 unsigned int inst_Thumb_is_IT(uint32_t inst)
550 {
551     if ((inst & 0xff000000) == 0xbf000000 &&
552         (inst & 0x000f0000) != 0x00000000) {
553         if (inst & 0x00010000) {
554             return 4;
555         } else if (inst & 0x00020000) {
556             return 3;
557         } else if (inst & 0x00040000) {
558             return 2;
559         } else {
560             assert(inst & 0x00080000);
561             return 1;
562         }
563     } else {
564         return 0;
565     }
566 }
567 
568 /*
569 Test whether an A64 instruction is conditional.
570 
571 Instructions like CSEL, CSINV, CCMP are not classed as conditional.
572 They use the condition code but do one of two things with it,
573 neither a NOP.  The "intruction categories" section of ETMv4
574 lists no (non branch) conditional instructions for A64.
575 */
inst_A64_is_conditional(uint32_t inst)576 int inst_A64_is_conditional(uint32_t inst)
577 {
578     if ((inst & 0x7c000000) == 0x34000000) {
579         /* CB, TB */
580         return 1;
581     } else if ((inst & 0xff000000) == 0x54000000) {
582         /* B.cond */
583         /* BC.cond */
584         return 1;
585     }
586     return 0;
587 }
588 
inst_ARM_barrier(uint32_t inst)589 arm_barrier_t inst_ARM_barrier(uint32_t inst)
590 {
591     if ((inst & 0xfff00000) == 0xf5700000) {
592         switch (inst & 0xf0) {
593         case 0x40:
594             return ARM_BARRIER_DSB;
595         case 0x50:
596             return ARM_BARRIER_DMB;
597         case 0x60:
598             return ARM_BARRIER_ISB;
599         default:
600             return ARM_BARRIER_NONE;
601         }
602     } else if ((inst & 0x0fff0f00) == 0x0e070f00) {
603         switch (inst & 0xff) {
604         case 0x9a:
605             return ARM_BARRIER_DSB;   /* mcr p15,0,Rt,c7,c10,4 */
606         case 0xba:
607             return ARM_BARRIER_DMB;   /* mcr p15,0,Rt,c7,c10,5 */
608         case 0x95:
609             return ARM_BARRIER_ISB;   /* mcr p15,0,Rt,c7,c5,4 */
610         default:
611             return ARM_BARRIER_NONE;
612         }
613     } else {
614         return ARM_BARRIER_NONE;
615     }
616 }
617 
inst_Thumb_barrier(uint32_t inst)618 arm_barrier_t inst_Thumb_barrier(uint32_t inst)
619 {
620     if ((inst & 0xffffff00) == 0xf3bf8f00) {
621         switch (inst & 0xf0) {
622         case 0x40:
623             return ARM_BARRIER_DSB;
624         case 0x50:
625             return ARM_BARRIER_DMB;
626         case 0x60:
627             return ARM_BARRIER_ISB;
628         default:
629             return ARM_BARRIER_NONE;
630         }
631     } else if ((inst & 0xffff0f00) == 0xee070f00) {
632         /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */
633         switch (inst & 0xff) {
634         case 0x9a:
635             return ARM_BARRIER_DSB;   /* mcr p15,0,Rt,c7,c10,4 */
636         case 0xba:
637             return ARM_BARRIER_DMB;   /* mcr p15,0,Rt,c7,c10,5 */
638         case 0x95:
639             return ARM_BARRIER_ISB;   /* mcr p15,0,Rt,c7,c5,4 */
640         default:
641             return ARM_BARRIER_NONE;
642         }
643         return ARM_BARRIER_NONE;
644     } else {
645         return ARM_BARRIER_NONE;
646     }
647 }
648 
inst_A64_barrier(uint32_t inst)649 arm_barrier_t inst_A64_barrier(uint32_t inst)
650 {
651     if ((inst & 0xfffff09f) == 0xd503309f) {
652         switch (inst & 0x60) {
653         case 0x0:
654             return ARM_BARRIER_DSB;
655         case 0x20:
656             return ARM_BARRIER_DMB;
657         case 0x40:
658             return ARM_BARRIER_ISB;
659         default:
660             return ARM_BARRIER_NONE;
661         }
662     } else {
663         return ARM_BARRIER_NONE;
664     }
665 }
666 
inst_ARM_is_UDF(uint32_t inst)667 int inst_ARM_is_UDF(uint32_t inst)
668 {
669     return (inst & 0xfff000f0) == 0xe7f000f0;
670 }
671 
inst_Thumb_is_UDF(uint32_t inst)672 int inst_Thumb_is_UDF(uint32_t inst)
673 {
674     return (inst & 0xff000000) == 0xde000000 ||   /* T1 */
675            (inst & 0xfff0f000) == 0xf7f0a000;     /* T2 */
676 }
677 
inst_A64_is_UDF(uint32_t inst)678 int inst_A64_is_UDF(uint32_t inst)
679 {
680     /* No A64 encodings are formally allocated as permanently undefined,
681        but it is intended not to allocate any instructions in the 21-bit
682        regions at the bottom or top of the range. */
683     return (inst & 0xffe00000) == 0x00000000 ||
684            (inst & 0xffe00000) == 0xffe00000;
685 }
686 
687 /* End of File trc_idec_arminst.cpp */
688