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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 & 0xff000010) == 0x54000000) {
248         /* B<cond> */
249     } else if ((inst & 0x7c000000) == 0x14000000) {
250         /* B, BL imm */
251         if (inst & 0x80000000) {
252             *is_link = 1;
253             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
254         }
255     } else {
256         is_direct_branch = 0;
257     }
258     return is_direct_branch;
259 }
260 
261 int inst_A64_wfiwfe(uint32_t inst)
262 {
263     /* WFI, WFE may be traced as branches in etm 4.3++ */
264     if ((inst & 0xffffffdf) == 0xd503205f)
265         return 1;
266     return 0;
267 }
268 
269 int inst_A64_is_indirect_branch(uint32_t inst, struct decode_info *info)
270 {
271     uint8_t link = 0;
272     return inst_A64_is_indirect_branch_link(inst, &link, info);
273 }
274 
275 int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info)
276 {
277     int is_indirect_branch = 1;
278 
279     if ((inst & 0xffdffc1f) == 0xd61f0000) {
280         /* BR, BLR */
281         if (inst & 0x00200000) {
282             *is_link = 1;
283             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
284         }
285     } else if ((inst & 0xfffffc1f) == 0xd65f0000) {
286         info->instr_sub_type = OCSD_S_INSTR_V8_RET;
287         /* RET */
288     } else if ((inst & 0xffffffff) == 0xd69f03e0) {
289         /* ERET */
290         info->instr_sub_type = OCSD_S_INSTR_V8_ERET;
291     } else if (info->arch_version >= 0x0803) {
292         /* new pointer auth instr for v8.3 arch */
293         if ((inst & 0xffdff800) == 0xd71f0800) {
294             /* BRAA, BRAB, BLRAA, BLRBB */
295             if (inst & 0x00200000) {
296                 *is_link = 1;
297                 info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
298             }
299         } else if ((inst & 0xffdff81F) == 0xd61f081F) {
300             /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */
301             if (inst & 0x00200000) {
302                 *is_link = 1;
303                 info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
304             }
305         } else if ((inst & 0xfffffbff) == 0xd69f0bff) {
306             /* ERETAA, ERETAB */
307             info->instr_sub_type = OCSD_S_INSTR_V8_ERET;
308         } else if ((inst & 0xfffffbff) == 0xd65f0bff) {
309             /* RETAA, RETAB */
310             info->instr_sub_type = OCSD_S_INSTR_V8_RET;
311         } else {
312             is_indirect_branch = 0;
313         }
314     } else {
315         is_indirect_branch = 0;
316     }
317     return is_indirect_branch;
318 }
319 
320 int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
321 {
322     uint32_t npc;
323     int is_direct_branch = 1;
324     if ((inst & 0x0e000000) == 0x0a000000) {
325         /*
326           B:   cccc:1010:imm24
327           BL:  cccc:1011:imm24
328           BLX: 1111:101H:imm24
329         */
330         npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6);
331         if ((inst & 0xf0000000) == 0xf0000000) {
332             npc |= 1;  /* indicate ISA is now Thumb */
333             npc |= ((inst >> 23) & 2);   /* apply the H bit */
334         }
335     } else {
336         is_direct_branch = 0;
337     }
338     if (is_direct_branch && pnpc != NULL) {
339         *pnpc = npc;
340     }
341     return is_direct_branch;
342 }
343 
344 int inst_Thumb_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 & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
349         /* B<c> (encoding T1) */
350         npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23);
351         npc |= 1;
352     } else if ((inst & 0xf8000000) == 0xe0000000) {
353         /* B (encoding T2) */
354         npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20);
355         npc |= 1;
356     } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
357         /* B (encoding T3) */
358         npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
359                                     ((inst & 0x0800) << 19) |
360                                     ((inst & 0x2000) << 16) |
361                                     ((inst & 0x003f0000) << 7) |
362                                     ((inst & 0x000007ff) << 12)) >> 11);
363         npc |= 1;
364     } else if ((inst & 0xf8009000) == 0xf0009000) {
365         /* B (encoding T4); BL (encoding T1) */
366         uint32_t S = ((inst & 0x04000000) >> 26)-1;  /* ffffffff or 0 according to S bit */
367         npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
368                                     (((inst^S) & 0x2000) << 17) |
369                                     (((inst^S) & 0x0800) << 18) |
370                                     ((inst & 0x03ff0000) << 3) |
371                                     ((inst & 0x000007ff) << 8)) >> 7);
372         npc |= 1;
373     } else if ((inst & 0xf800d001) == 0xf000c000) {
374         /* BLX (encoding T2) */
375         uint32_t S = ((inst & 0x04000000) >> 26)-1;  /* ffffffff or 0 according to S bit */
376         addr &= 0xfffffffc;   /* Align(PC,4) */
377         npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
378                                     (((inst^S) & 0x2000) << 17) |
379                                     (((inst^S) & 0x0800) << 18) |
380                                     ((inst & 0x03ff0000) << 3) |
381                                     ((inst & 0x000007fe) << 8)) >> 7);
382         /* don't set the Thumb bit, as we're transferring to ARM */
383     } else if ((inst & 0xf5000000) == 0xb1000000) {
384         /* CB(NZ) */
385         /* Note that it's zero-extended - always a forward branch */
386         npc = addr + 4 + ((((inst & 0x02000000) << 6) |
387                            ((inst & 0x00f80000) << 7)) >> 25);
388         npc |= 1;
389     } else {
390         is_direct_branch = 0;
391     }
392     if (is_direct_branch && pnpc != NULL) {
393         *pnpc = npc;
394     }
395     return is_direct_branch;
396 }
397 
398 int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc)
399 {
400     uint64_t npc;
401     int is_direct_branch = 1;
402     if ((inst & 0xff000010) == 0x54000000) {
403         /* B<cond> */
404         npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
405     } else if ((inst & 0x7c000000) == 0x14000000) {
406         /* B, BL imm */
407         npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4);
408     } else if ((inst & 0x7e000000) == 0x34000000) {
409         /* CB */
410         npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
411     } else if ((inst & 0x7e000000) == 0x36000000) {
412         /* TB */
413         npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16);
414     } else {
415         is_direct_branch = 0;
416     }
417     if (is_direct_branch && pnpc != NULL) {
418         *pnpc = npc;
419     }
420     return is_direct_branch;
421 }
422 
423 int inst_ARM_is_branch(uint32_t inst, struct decode_info *info)
424 {
425     return inst_ARM_is_indirect_branch(inst, info) ||
426            inst_ARM_is_direct_branch(inst);
427 }
428 
429 int inst_Thumb_is_branch(uint32_t inst, struct decode_info *info)
430 {
431     return inst_Thumb_is_indirect_branch(inst, info) ||
432            inst_Thumb_is_direct_branch(inst, info);
433 }
434 
435 int inst_A64_is_branch(uint32_t inst, struct decode_info *info)
436 {
437     return inst_A64_is_indirect_branch(inst, info) ||
438            inst_A64_is_direct_branch(inst, info);
439 }
440 
441 int inst_ARM_is_branch_and_link(uint32_t inst, struct decode_info *info)
442 {
443     int is_branch = 1;
444     if ((inst & 0xf0000000) == 0xf0000000) {
445         if ((inst & 0xfe000000) == 0xfa000000){
446             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
447             /* BLX (imm) */
448         } else {
449             is_branch = 0;
450         }
451     } else if ((inst & 0x0f000000) == 0x0b000000) {
452         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
453         /* BL */
454     } else if ((inst & 0x0ff000f0) == 0x01200030) {
455         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
456         /* BLX (reg) */
457     } else {
458         is_branch = 0;
459     }
460     return is_branch;
461 }
462 
463 int inst_Thumb_is_branch_and_link(uint32_t inst, struct decode_info *info)
464 {
465     int is_branch = 1;
466     if ((inst & 0xff800000) == 0x47800000) {
467         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
468         /* BLX (reg) */
469     } else if ((inst & 0xf800c000) == 0xf000c000) {
470         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
471         /* BL, BLX (imm) */
472     } else {
473         is_branch = 0;
474     }
475     return is_branch;
476 }
477 
478 int inst_A64_is_branch_and_link(uint32_t inst, struct decode_info *info)
479 {
480     int is_branch = 1;
481     if ((inst & 0xfffffc1f) == 0xd63f0000) {
482         /* BLR */
483         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
484     } else if ((inst & 0xfc000000) == 0x94000000) {
485         /* BL */
486         info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
487     }  else if (info->arch_version >= 0x0803) {
488         /* new pointer auth instr for v8.3 arch */
489         if ((inst & 0xfffff800) == 0xd73f0800) {
490             /* BLRAA, BLRBB */
491             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
492         } else if ((inst & 0xfffff81F) == 0xd63f081F) {
493             /* BLRAAZ, BLRBBZ */
494             info->instr_sub_type = OCSD_S_INSTR_BR_LINK;
495         } else {
496             is_branch = 0;
497         }
498     } else {
499         is_branch = 0;
500     }
501     return is_branch;
502 }
503 
504 int inst_ARM_is_conditional(uint32_t inst)
505 {
506     return (inst & 0xe0000000) != 0xe0000000;
507 }
508 
509 int inst_Thumb_is_conditional(uint32_t inst)
510 {
511     if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
512         /* B<c> (encoding T1) */
513         return 1;
514     } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
515         /* B<c> (encoding T3) */
516         return 1;
517     } else if ((inst & 0xf5000000) == 0xb1000000) {
518         /* CB(N)Z */
519         return 1;
520     }
521     return 0;
522 }
523 
524 unsigned int inst_Thumb_is_IT(uint32_t inst)
525 {
526     if ((inst & 0xff000000) == 0xbf000000 &&
527         (inst & 0x000f0000) != 0x00000000) {
528         if (inst & 0x00010000) {
529             return 4;
530         } else if (inst & 0x00020000) {
531             return 3;
532         } else if (inst & 0x00040000) {
533             return 2;
534         } else {
535             assert(inst & 0x00080000);
536             return 1;
537         }
538     } else {
539         return 0;
540     }
541 }
542 
543 /*
544 Test whether an A64 instruction is conditional.
545 
546 Instructions like CSEL, CSINV, CCMP are not classed as conditional.
547 They use the condition code but do one of two things with it,
548 neither a NOP.  The "intruction categories" section of ETMv4
549 lists no (non branch) conditional instructions for A64.
550 */
551 int inst_A64_is_conditional(uint32_t inst)
552 {
553     if ((inst & 0x7c000000) == 0x34000000) {
554         /* CB, TB */
555         return 1;
556     } else if ((inst & 0xff000010) == 0x54000000) {
557         /* B.cond */
558         return 1;
559     }
560     return 0;
561 }
562 
563 arm_barrier_t inst_ARM_barrier(uint32_t inst)
564 {
565     if ((inst & 0xfff00000) == 0xf5700000) {
566         switch (inst & 0xf0) {
567         case 0x40:
568             return ARM_BARRIER_DSB;
569         case 0x50:
570             return ARM_BARRIER_DMB;
571         case 0x60:
572             return ARM_BARRIER_ISB;
573         default:
574             return ARM_BARRIER_NONE;
575         }
576     } else if ((inst & 0x0fff0f00) == 0x0e070f00) {
577         switch (inst & 0xff) {
578         case 0x9a:
579             return ARM_BARRIER_DSB;   /* mcr p15,0,Rt,c7,c10,4 */
580         case 0xba:
581             return ARM_BARRIER_DMB;   /* mcr p15,0,Rt,c7,c10,5 */
582         case 0x95:
583             return ARM_BARRIER_ISB;   /* mcr p15,0,Rt,c7,c5,4 */
584         default:
585             return ARM_BARRIER_NONE;
586         }
587     } else {
588         return ARM_BARRIER_NONE;
589     }
590 }
591 
592 arm_barrier_t inst_Thumb_barrier(uint32_t inst)
593 {
594     if ((inst & 0xffffff00) == 0xf3bf8f00) {
595         switch (inst & 0xf0) {
596         case 0x40:
597             return ARM_BARRIER_DSB;
598         case 0x50:
599             return ARM_BARRIER_DMB;
600         case 0x60:
601             return ARM_BARRIER_ISB;
602         default:
603             return ARM_BARRIER_NONE;
604         }
605     } else if ((inst & 0xffff0f00) == 0xee070f00) {
606         /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */
607         switch (inst & 0xff) {
608         case 0x9a:
609             return ARM_BARRIER_DSB;   /* mcr p15,0,Rt,c7,c10,4 */
610         case 0xba:
611             return ARM_BARRIER_DMB;   /* mcr p15,0,Rt,c7,c10,5 */
612         case 0x95:
613             return ARM_BARRIER_ISB;   /* mcr p15,0,Rt,c7,c5,4 */
614         default:
615             return ARM_BARRIER_NONE;
616         }
617         return ARM_BARRIER_NONE;
618     } else {
619         return ARM_BARRIER_NONE;
620     }
621 }
622 
623 arm_barrier_t inst_A64_barrier(uint32_t inst)
624 {
625     if ((inst & 0xfffff09f) == 0xd503309f) {
626         switch (inst & 0x60) {
627         case 0x0:
628             return ARM_BARRIER_DSB;
629         case 0x20:
630             return ARM_BARRIER_DMB;
631         case 0x40:
632             return ARM_BARRIER_ISB;
633         default:
634             return ARM_BARRIER_NONE;
635         }
636     } else {
637         return ARM_BARRIER_NONE;
638     }
639 }
640 
641 int inst_ARM_is_UDF(uint32_t inst)
642 {
643     return (inst & 0xfff000f0) == 0xe7f000f0;
644 }
645 
646 int inst_Thumb_is_UDF(uint32_t inst)
647 {
648     return (inst & 0xff000000) == 0xde000000 ||   /* T1 */
649            (inst & 0xfff0f000) == 0xf7f0a000;     /* T2 */
650 }
651 
652 int inst_A64_is_UDF(uint32_t inst)
653 {
654     /* No A64 encodings are formally allocated as permanently undefined,
655        but it is intended not to allocate any instructions in the 21-bit
656        regions at the bottom or top of the range. */
657     return (inst & 0xffe00000) == 0x00000000 ||
658            (inst & 0xffe00000) == 0xffe00000;
659 }
660 
661 /* End of File trc_idec_arminst.cpp */
662