• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Thumb Dissassembler. Still a work in progress.
3 
4   Wrong output is a bug, so please fix it.
5   Hex output means there is not yet an entry or a decode bug.
6   gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit
7   16-bit stream of Thumb2 instruction. Then there are big case
8   statements to print everything out. If you are adding instructions
9   try to reuse existing case entries if possible.
10 
11   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
12 
13   This program and the accompanying materials
14   are licensed and made available under the terms and conditions of the BSD License
15   which accompanies this distribution.  The full text of the license may be found at
16   http://opensource.org/licenses/bsd-license.php
17 
18   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 
21 **/
22 
23 #include <Base.h>
24 #include <Library/BaseLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/PrintLib.h>
27 
28 extern CHAR8 *gCondition[];
29 
30 extern CHAR8 *gReg[];
31 
32 // Thumb address modes
33 #define LOAD_STORE_FORMAT1            1
34 #define LOAD_STORE_FORMAT1_H        101
35 #define LOAD_STORE_FORMAT1_B        111
36 #define LOAD_STORE_FORMAT2            2
37 #define LOAD_STORE_FORMAT3            3
38 #define LOAD_STORE_FORMAT4            4
39 #define LOAD_STORE_MULTIPLE_FORMAT1   5
40 #define PUSH_FORMAT                   6
41 #define POP_FORMAT                  106
42 #define IMMED_8                       7
43 #define CONDITIONAL_BRANCH            8
44 #define UNCONDITIONAL_BRANCH          9
45 #define UNCONDITIONAL_BRANCH_SHORT  109
46 #define BRANCH_EXCHANGE              10
47 #define DATA_FORMAT1                 11
48 #define DATA_FORMAT2                 12
49 #define DATA_FORMAT3                 13
50 #define DATA_FORMAT4                 14
51 #define DATA_FORMAT5                 15
52 #define DATA_FORMAT6_SP              16
53 #define DATA_FORMAT6_PC             116
54 #define DATA_FORMAT7                 17
55 #define DATA_FORMAT8                 19
56 #define CPS_FORMAT                   20
57 #define ENDIAN_FORMAT                21
58 #define DATA_CBZ                     22
59 #define ADR_FORMAT                   23
60 #define IT_BLOCK                     24
61 
62 // Thumb2 address modes
63 #define B_T3                        200
64 #define B_T4                        201
65 #define BL_T2                       202
66 #define POP_T2                      203
67 #define POP_T3                      204
68 #define STM_FORMAT                  205
69 #define LDM_REG_IMM12_SIGNED        206
70 #define LDM_REG_IMM12_LSL           207
71 #define LDM_REG_IMM8                208
72 #define LDM_REG_IMM12               209
73 #define LDM_REG_INDIRECT_LSL        210
74 #define LDM_REG_IMM8_SIGNED         211
75 #define LDRD_REG_IMM8               212
76 #define LDREXB                      213
77 #define LDREXD                      214
78 #define SRS_FORMAT                  215
79 #define RFE_FORMAT                  216
80 #define LDRD_REG_IMM8_SIGNED        217
81 #define ADD_IMM12                   218
82 #define ADD_IMM5                    219
83 #define ADR_THUMB2                  220
84 #define CMN_THUMB2                  221
85 #define ASR_IMM5                    222
86 #define ASR_3REG                    223
87 #define BFC_THUMB2                  224
88 #define CDP_THUMB2                  225
89 #define THUMB2_NO_ARGS              226
90 #define THUMB2_2REGS                227
91 #define ADD_IMM5_2REG               228
92 #define CPD_THUMB2                  229
93 #define THUMB2_4REGS                230
94 #define ADD_IMM12_1REG              231
95 #define THUMB2_IMM16                232
96 #define MRC_THUMB2                  233
97 #define MRRC_THUMB2                 234
98 #define THUMB2_MRS                  235
99 #define THUMB2_MSR                  236
100 
101 
102 
103 
104 typedef struct {
105   CHAR8   *Start;
106   UINT32  OpCode;
107   UINT32  Mask;
108   UINT32  AddressMode;
109 } THUMB_INSTRUCTIONS;
110 
111 THUMB_INSTRUCTIONS gOpThumb[] = {
112 // Thumb 16-bit instrucitons
113 //          Op       Mask   Format
114   { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 },  // ADC <Rndn>, <Rm>
115   { "ADR",  0xa000, 0xf800, ADR_FORMAT   },  // ADR <Rd>, <label>
116   { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },
117   { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },
118   { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },
119   { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 },   // A8.6.9
120   { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },
121   { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP },
122   { "ADD" , 0xb000, 0xff80, DATA_FORMAT7 },
123 
124   { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },
125 
126   { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },
127   { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },
128 
129   { "B"   , 0xd000, 0xf000, CONDITIONAL_BRANCH },
130   { "B"   , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT },
131   { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },
132   { "BX"  , 0x4700, 0xff87, BRANCH_EXCHANGE },
133 
134   { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },
135   { "BKPT", 0xdf00, 0xff00, IMMED_8 },
136   { "CBZ",  0xb100, 0xfd00, DATA_CBZ },
137   { "CBNZ", 0xb900, 0xfd00, DATA_CBZ },
138   { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },
139 
140   { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },
141   { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },
142   { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },
143 
144   { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },
145   { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
146   { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },
147 
148   { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
149   { "LDR"   , 0x6800, 0xf800, LOAD_STORE_FORMAT1 },  // LDR <Rt>, [<Rn> {,#<imm>}]
150   { "LDR"   , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },  // STR <Rt>, [<Rn>, <Rm>]
151   { "LDR"   , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },
152   { "LDR"   , 0x9800, 0xf800, LOAD_STORE_FORMAT4 },  // LDR <Rt>, [SP, #<imm>]
153   { "LDRB"  , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B },
154   { "LDRB"  , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 },  // STR <Rt>, [<Rn>, <Rm>]
155   { "LDRH"  , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H },
156   { "LDRH"  , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },
157   { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 },  // STR <Rt>, [<Rn>, <Rm>]
158   { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },
159 
160   { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5 },   // LSL with imm5 == 0 is a MOVS, so this must go before LSL
161   { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },
162   { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },
163   { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },
164   { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },
165   { "LSRS", 0x0800, 0xf800, DATA_FORMAT4 },  // LSRS <Rd>, <Rm>, #<imm5>
166 
167   { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },
168   { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },
169   { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
170 
171   { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },
172   { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },
173   { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },
174   { "ORR" , 0x4300, 0xffc0, DATA_FORMAT5 },
175   { "POP" , 0xbc00, 0xfe00, POP_FORMAT },
176   { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT },
177 
178   { "REV"   , 0xba00, 0xffc0, DATA_FORMAT5 },
179   { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },
180   { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },
181 
182   { "ROR"    , 0x41c0, 0xffc0, DATA_FORMAT5 },
183   { "SBC"    , 0x4180, 0xffc0, DATA_FORMAT5 },
184   { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },
185 
186   { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
187   { "STR"   , 0x6000, 0xf800, LOAD_STORE_FORMAT1 },   // STR  <Rt>, [<Rn> {,#<imm>}]
188   { "STR"   , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 },   // STR  <Rt>, [<Rn>, <Rm>]
189   { "STR"   , 0x9000, 0xf800, LOAD_STORE_FORMAT4 },   // STR  <Rt>, [SP, #<imm>]
190   { "STRB"  , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B }, // STRB <Rt>, [<Rn>, #<imm5>]
191   { "STRB"  , 0x5400, 0xfe00, LOAD_STORE_FORMAT2 },   // STRB <Rt>, [<Rn>, <Rm>]
192   { "STRH"  , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H }, // STRH <Rt>, [<Rn>{,#<imm>}]
193   { "STRH"  , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 },   // STRH <Rt>, [<Rn>, <Rm>]
194 
195   { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },
196   { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },
197   { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },
198   { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },
199 
200   { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
201 
202   { "SWI" , 0xdf00, 0xff00, IMMED_8 },
203   { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },
204   { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },
205   { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },
206   { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },
207   { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 },
208 
209   { "IT",   0xbf00, 0xff00, IT_BLOCK }
210 
211 };
212 
213 THUMB_INSTRUCTIONS gOpThumb2[] = {
214 //Instruct  OpCode      OpCode Mask  Addressig Mode
215 
216   { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2    },  // ADDR <Rd>, <label> ;Needs to go before ADDW
217   { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2    },  // CMN <Rn>, #<const> ;Needs to go before ADD
218   { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG },  // CMN <Rn>, <Rm> {,<shift> #<const>}
219   { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2    },  // CMP <Rn>, #<const>
220   { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2    },  // CMP <Rn>, #<const>
221   { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG },  // CMN <Rn>, <Rm> {,<shift> #<const>}
222   { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2    },  // CMP <Rn>, #<const>
223   { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG },  // TST <Rn>, <Rm> {,<shift> #<const>}
224 
225   { "MOV",  0xf04f0000, 0xfbef8000, ADD_IMM12_1REG }, // MOV  <Rd>, #<const>
226   { "MOVW", 0xf2400000, 0xfbe08000, THUMB2_IMM16 },   // MOVW <Rd>, #<const>
227   { "MOVT", 0xf2c00000, 0xfbe08000, THUMB2_IMM16 },   // MOVT <Rd>, #<const>
228 
229   { "ADC",  0xf1400000, 0xfbe08000, ADD_IMM12 }, // ADC{S}  <Rd>, <Rn>, #<const>
230   { "ADC",  0xeb400000, 0xffe08000, ADD_IMM5  }, // ADC{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
231   { "ADD",  0xf1000000, 0xfbe08000, ADD_IMM12 }, // ADD{S}  <Rd>, <Rn>, #<const>
232   { "ADD",  0xeb000000, 0xffe08000, ADD_IMM5  }, // ADD{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
233   { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12 }, // ADDW{S} <Rd>, <Rn>, #<const>
234   { "AND",  0xf0000000, 0xfbe08000, ADD_IMM12 }, // AND{S}  <Rd>, <Rn>, #<const>
235   { "AND",  0xea000000, 0xffe08000, ADD_IMM5  }, // AND{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
236   { "BIC",  0xf0200000, 0xfbe08000, ADD_IMM12 }, // BIC{S}  <Rd>, <Rn>, #<const>
237   { "BIC",  0xea200000, 0xffe08000, ADD_IMM5  }, // BIC{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
238   { "EOR",  0xf0800000, 0xfbe08000, ADD_IMM12 }, // EOR{S}  <Rd>, <Rn>, #<const>
239   { "EOR",  0xea800000, 0xffe08000, ADD_IMM5  }, // EOR{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
240   { "ORN",  0xf0600000, 0xfbe08000, ADD_IMM12 }, // ORN{S}  <Rd>, <Rn>, #<const>
241   { "ORN",  0xea600000, 0xffe08000, ADD_IMM5  }, // ORN{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
242   { "ORR",  0xf0400000, 0xfbe08000, ADD_IMM12 }, // ORR{S}  <Rd>, <Rn>, #<const>
243   { "ORR",  0xea400000, 0xffe08000, ADD_IMM5  }, // ORR{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
244   { "RSB",  0xf1c00000, 0xfbe08000, ADD_IMM12 }, // RSB{S}  <Rd>, <Rn>, #<const>
245   { "RSB",  0xebc00000, 0xffe08000, ADD_IMM5  }, // RSB{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
246   { "SBC",  0xf1600000, 0xfbe08000, ADD_IMM12 }, // SBC{S}  <Rd>, <Rn>, #<const>
247   { "SBC",  0xeb600000, 0xffe08000, ADD_IMM5  }, // SBC{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
248   { "SUB",  0xf1a00000, 0xfbe08000, ADD_IMM12 }, // SUB{S}  <Rd>, <Rn>, #<const>
249   { "SUB",  0xeba00000, 0xffe08000, ADD_IMM5  }, // SUB{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
250 
251   { "ASR",  0xea4f0020, 0xffef8030, ASR_IMM5 },  // ARS  <Rd>, <Rm> #<const>} imm3:imm2
252   { "ASR",  0xfa40f000, 0xffe0f0f0, ASR_3REG },  // ARS  <Rd>, <Rn>, <Rm>
253   { "LSR",  0xea4f0010, 0xffef8030, ASR_IMM5 },  // LSR  <Rd>, <Rm> #<const>} imm3:imm2
254   { "LSR",  0xfa20f000, 0xffe0f0f0, ASR_3REG },  // LSR  <Rd>, <Rn>, <Rm>
255   { "ROR",  0xea4f0030, 0xffef8030, ASR_IMM5 },  // ROR  <Rd>, <Rm> #<const>} imm3:imm2
256   { "ROR",  0xfa60f000, 0xffe0f0f0, ASR_3REG },  // ROR  <Rd>, <Rn>, <Rm>
257 
258   { "BFC",  0xf36f0000, 0xffff8010, BFC_THUMB2 },   // BFC  <Rd>, #<lsb>, #<width>
259   { "BIC",  0xf3600000, 0xfff08010, BFC_THUMB2 },   // BIC  <Rn>, <Rd>, #<lsb>, #<width>
260   { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2 },   // SBFX <Rn>, <Rd>, #<lsb>, #<width>
261   { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2 },   // UBFX <Rn>, <Rd>, #<lsb>, #<width>
262 
263   { "CPD",  0xee000000, 0xff000010, CPD_THUMB2 },  // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
264   { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2 },  // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
265 
266   { "MRC",   0xee100000, 0xff100000, MRC_THUMB2 },  // MRC  <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
267   { "MRC2",  0xfe100000, 0xff100000, MRC_THUMB2 },  // MRC2 <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
268   { "MRRC",  0xec500000, 0xfff00000, MRRC_THUMB2 },  // MRRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
269   { "MRRC2", 0xfc500000, 0xfff00000, MRRC_THUMB2 },  // MRR2 <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
270 
271   { "MRS",   0xf3ef8000, 0xfffff0ff, THUMB2_MRS  }, // MRS  <Rd>, CPSR
272   { "MSR",   0xf3808000, 0xfff0fcff, THUMB2_MSR  }, // MSR  CPSR_fs, <Rn>
273 
274   { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS }, // CLREX
275 
276   { "CLZ",   0xfab0f080, 0xfff0f0f0, THUMB2_2REGS },  // CLZ    <Rd>,<Rm>
277   { "MOV",   0xec4f0000, 0xfff0f0f0, THUMB2_2REGS },  // MOV    <Rd>,<Rm>
278   { "MOVS",  0xec5f0000, 0xfff0f0f0, THUMB2_2REGS },  // MOVS   <Rd>,<Rm>
279   { "RBIT",  0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS },  // RBIT   <Rd>,<Rm>
280   { "REV",   0xfb90f080, 0xfff0f0f0, THUMB2_2REGS },  // REV    <Rd>,<Rm>
281   { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS },  // REV16  <Rd>,<Rm>
282   { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS },  // REVSH  <Rd>,<Rm>
283   { "RRX",   0xea4f0030, 0xfffff0f0, THUMB2_2REGS },  // RRX    <Rd>,<Rm>
284   { "RRXS",  0xea5f0030, 0xfffff0f0, THUMB2_2REGS },  // RRXS   <Rd>,<Rm>
285 
286   { "MLA",   0xfb000000, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>
287   { "MLS",   0xfb000010, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>
288 
289 
290   { "SMLABB",  0xfb100000, 0xfff000f0, THUMB2_4REGS }, // SMLABB   <Rd>, <Rn>, <Rm>, <Ra>
291   { "SMLABT",  0xfb100010, 0xfff000f0, THUMB2_4REGS }, // SMLABT   <Rd>, <Rn>, <Rm>, <Ra>
292   { "SMLABB",  0xfb100020, 0xfff000f0, THUMB2_4REGS }, // SMLATB   <Rd>, <Rn>, <Rm>, <Ra>
293   { "SMLATT",  0xfb100030, 0xfff000f0, THUMB2_4REGS }, // SMLATT   <Rd>, <Rn>, <Rm>, <Ra>
294   { "SMLAWB",  0xfb300000, 0xfff000f0, THUMB2_4REGS }, // SMLAWB   <Rd>, <Rn>, <Rm>, <Ra>
295   { "SMLAWT",  0xfb300010, 0xfff000f0, THUMB2_4REGS }, // SMLAWT   <Rd>, <Rn>, <Rm>, <Ra>
296   { "SMLSD",   0xfb400000, 0xfff000f0, THUMB2_4REGS }, // SMLSD    <Rd>, <Rn>, <Rm>, <Ra>
297   { "SMLSDX",  0xfb400010, 0xfff000f0, THUMB2_4REGS }, // SMLSDX   <Rd>, <Rn>, <Rm>, <Ra>
298   { "SMMLA",   0xfb500000, 0xfff000f0, THUMB2_4REGS }, // SMMLA    <Rd>, <Rn>, <Rm>, <Ra>
299   { "SMMLAR",  0xfb500010, 0xfff000f0, THUMB2_4REGS }, // SMMLAR   <Rd>, <Rn>, <Rm>, <Ra>
300   { "SMMLS",   0xfb600000, 0xfff000f0, THUMB2_4REGS }, // SMMLS    <Rd>, <Rn>, <Rm>, <Ra>
301   { "SMMLSR",  0xfb600010, 0xfff000f0, THUMB2_4REGS }, // SMMLSR   <Rd>, <Rn>, <Rm>, <Ra>
302   { "USADA8",  0xfb700000, 0xfff000f0, THUMB2_4REGS }, // USADA8   <Rd>, <Rn>, <Rm>, <Ra>
303   { "SMLAD",   0xfb200000, 0xfff000f0, THUMB2_4REGS }, // SMLAD    <Rd>, <Rn>, <Rm>, <Ra>
304   { "SMLADX",  0xfb200010, 0xfff000f0, THUMB2_4REGS }, // SMLADX   <Rd>, <Rn>, <Rm>, <Ra>
305 
306 
307   { "B",    0xf0008000, 0xf800d000, B_T3  },             // B<c> <label>
308   { "B",    0xf0009000, 0xf800d000, B_T4  },             // B<c> <label>
309   { "BL",   0xf000d000, 0xf800d000, B_T4  },             // BL<c> <label>
310   { "BLX",  0xf000c000, 0xf800d000, BL_T2 },             // BLX<c> <label>
311 
312   { "POP",   0xe8bd0000, 0xffff2000, POP_T2 },           // POP <registers>
313   { "POP",   0xf85d0b04, 0xffff0fff, POP_T3 },           // POP <register>
314   { "PUSH",  0xe8ad0000, 0xffffa000, POP_T2 },           // PUSH <registers>
315   { "PUSH",  0xf84d0d04, 0xffff0fff, POP_T3 },           // PUSH <register>
316   { "STM"  , 0xe8800000, 0xffd0a000,  STM_FORMAT },      // STM <Rn>{!},<registers>
317   { "STMDB", 0xe9800000, 0xffd0a000,  STM_FORMAT },      // STMDB <Rn>{!},<registers>
318   { "LDM"  , 0xe8900000, 0xffd02000,  STM_FORMAT },      // LDM <Rn>{!},<registers>
319   { "LDMDB", 0xe9100000, 0xffd02000,  STM_FORMAT },      // LDMDB <Rn>{!},<registers>
320 
321   { "LDR",   0xf8d00000, 0xfff00000,  LDM_REG_IMM12 },          // LDR   <rt>, [<rn>, {, #<imm12>]}
322   { "LDRB",  0xf8900000, 0xfff00000,  LDM_REG_IMM12 },          // LDRB  <rt>, [<rn>, {, #<imm12>]}
323   { "LDRH",  0xf8b00000, 0xfff00000,  LDM_REG_IMM12 },          // LDRH  <rt>, [<rn>, {, #<imm12>]}
324   { "LDRSB", 0xf9900000, 0xfff00000,  LDM_REG_IMM12 },          // LDRSB <rt>, [<rn>, {, #<imm12>]}
325   { "LDRSH", 0xf9b00000, 0xfff00000,  LDM_REG_IMM12 },          // LDRSH <rt>, [<rn>, {, #<imm12>]}
326 
327   { "LDR",   0xf85f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDR   <Rt>, <label>
328   { "LDRB",  0xf81f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRB  <Rt>, <label>
329   { "LDRH",  0xf83f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRH  <Rt>, <label>
330   { "LDRSB", 0xf91f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRSB <Rt>, <label>
331   { "LDRSH", 0xf93f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRSB <Rt>, <label>
332 
333   { "LDR",   0xf8500000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDR   <rt>, [<rn>, <rm> {, LSL #<imm2>]}
334   { "LDRB",  0xf8100000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRB  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
335   { "LDRH",  0xf8300000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRH  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
336   { "LDRSB", 0xf9100000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
337   { "LDRSH", 0xf9300000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
338 
339   { "LDR",   0xf8500800, 0xfff00800,  LDM_REG_IMM8 },           // LDR    <rt>, [<rn>, {, #<imm8>]}
340   { "LDRBT", 0xf8100e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRBT  <rt>, [<rn>, {, #<imm8>]}
341   { "LDRHT", 0xf8300e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRHT  <rt>, [<rn>, {, #<imm8>]}
342   { "LDRSB", 0xf9100800, 0xfff00800,  LDM_REG_IMM8 },           // LDRHT  <rt>, [<rn>, {, #<imm8>]}  {!} form?
343   { "LDRSBT",0xf9100e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRHBT <rt>, [<rn>, {, #<imm8>]}  {!} form?
344   { "LDRSH" ,0xf9300800, 0xfff00800,  LDM_REG_IMM8 },           // LDRSH  <rt>, [<rn>, {, #<imm8>]}
345   { "LDRSHT",0xf9300e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRSHT <rt>, [<rn>, {, #<imm8>]}
346   { "LDRT",  0xf8500e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRT   <rt>, [<rn>, {, #<imm8>]}
347 
348   { "LDRD",  0xe8500000, 0xfe500000,  LDRD_REG_IMM8_SIGNED },   // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
349   { "LDRD",  0xe8500000, 0xfe500000,  LDRD_REG_IMM8       },    // LDRD <rt>, <rt2>, <label>
350 
351   { "LDREX",  0xe8500f00, 0xfff00f00,  LDM_REG_IMM8 },           // LDREX <Rt>, [Rn, {#imm8}]]
352   { "LDREXB", 0xe8d00f4f, 0xfff00fff,  LDREXB  },                // LDREXB <Rt>, [<Rn>]
353   { "LDREXH", 0xe8d00f5f, 0xfff00fff,  LDREXB  },                // LDREXH <Rt>, [<Rn>]
354 
355   { "LDREXD", 0xe8d00f4f, 0xfff00fff,  LDREXD  },                // LDREXD <Rt>, <Rt2>, [<Rn>]
356 
357   { "STR",   0xf8c00000, 0xfff00000,  LDM_REG_IMM12 },          // STR   <rt>, [<rn>, {, #<imm12>]}
358   { "STRB",  0xf8800000, 0xfff00000,  LDM_REG_IMM12 },          // STRB  <rt>, [<rn>, {, #<imm12>]}
359   { "STRH",  0xf8a00000, 0xfff00000,  LDM_REG_IMM12 },          // STRH  <rt>, [<rn>, {, #<imm12>]}
360 
361   { "STR",   0xf8400000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // STR   <rt>, [<rn>, <rm> {, LSL #<imm2>]}
362   { "STRB",  0xf8000000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // STRB  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
363   { "STRH",  0xf8200000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // STRH  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
364 
365   { "STR",   0xf8400800, 0xfff00800,  LDM_REG_IMM8 },           // STR    <rt>, [<rn>, {, #<imm8>]}
366   { "STRH",  0xf8200800, 0xfff00800,  LDM_REG_IMM8 },           // STRH   <rt>, [<rn>, {, #<imm8>]}
367   { "STRBT", 0xf8000e00, 0xfff00f00,  LDM_REG_IMM8 },           // STRBT  <rt>, [<rn>, {, #<imm8>]}
368   { "STRHT", 0xf8200e00, 0xfff00f00,  LDM_REG_IMM8 },           // STRHT  <rt>, [<rn>, {, #<imm8>]}
369   { "STRT",  0xf8400e00, 0xfff00f00,  LDM_REG_IMM8 },           // STRT   <rt>, [<rn>, {, #<imm8>]}
370 
371   { "STRD",  0xe8400000, 0xfe500000,  LDRD_REG_IMM8_SIGNED },    // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
372 
373   { "STREX",  0xe8400f00, 0xfff00f00,  LDM_REG_IMM8 },           // STREX <Rt>, [Rn, {#imm8}]]
374   { "STREXB", 0xe8c00f4f, 0xfff00fff,  LDREXB  },                // STREXB <Rd>, <Rt>, [<Rn>]
375   { "STREXH", 0xe8c00f5f, 0xfff00fff,  LDREXB  },                // STREXH <Rd>, <Rt>, [<Rn>]
376 
377   { "STREXD", 0xe8d00f4f, 0xfff00fff,  LDREXD  },                // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
378 
379   { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT },       // SRSDB<c> SP{!},#<mode>
380   { "SRS"  , 0xe98dc000, 0xffdffff0, SRS_FORMAT },       // SRS{IA}<c> SP{!},#<mode>
381   { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT },       // RFEDB<c> <Rn>{!}
382   { "RFE"  , 0xe990c000, 0xffd0ffff, RFE_FORMAT }        // RFE{IA}<c> <Rn>{!}
383 };
384 
385 CHAR8 *gShiftType[] = {
386   "LSL",
387   "LSR",
388   "ASR",
389   "ROR"
390 };
391 
392 CHAR8 mThumbMregListStr[4*15 + 1];
393 
394 CHAR8 *
ThumbMRegList(UINT32 RegBitMask)395 ThumbMRegList (
396   UINT32  RegBitMask
397   )
398 {
399   UINTN     Index, Start, End;
400   CHAR8     *Str;
401   BOOLEAN   First;
402 
403   Str = mThumbMregListStr;
404   *Str = '\0';
405   AsciiStrCat  (Str, "{");
406 
407   for (Index = 0, First = TRUE; Index <= 15; Index++) {
408     if ((RegBitMask & (1 << Index)) != 0) {
409       Start = End = Index;
410       for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {
411         End = Index;
412       }
413 
414       if (!First) {
415         AsciiStrCat  (Str, ",");
416       } else {
417         First = FALSE;
418       }
419 
420       if (Start == End) {
421         AsciiStrCat  (Str, gReg[Start]);
422       } else {
423         AsciiStrCat  (Str, gReg[Start]);
424         AsciiStrCat  (Str, "-");
425         AsciiStrCat  (Str, gReg[End]);
426       }
427     }
428   }
429   if (First) {
430     AsciiStrCat  (Str, "ERROR");
431   }
432   AsciiStrCat  (Str, "}");
433 
434   // BugBug: Make caller pass in buffer it is cleaner
435   return mThumbMregListStr;
436 }
437 
438 UINT32
SignExtend32(IN UINT32 Data,IN UINT32 TopBit)439 SignExtend32 (
440   IN  UINT32  Data,
441   IN  UINT32  TopBit
442   )
443 {
444   if (((Data & TopBit) == 0) || (TopBit == BIT31)) {
445     return Data;
446   }
447 
448   do {
449     TopBit <<= 1;
450     Data |= TopBit;
451   } while ((TopBit & BIT31) != BIT31);
452 
453   return Data;
454 }
455 
456 //
457 // Some instructions specify the PC is always considered aligned
458 // The PC is after the instruction that is excuting. So you pass
459 // in the instruction address and you get back the aligned answer
460 //
461 UINT32
PCAlign4(IN UINT32 Data)462 PCAlign4 (
463   IN  UINT32  Data
464   )
465 {
466   return (Data + 4) & 0xfffffffc;
467 }
468 
469 /**
470   Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
471   point to next instructin.
472 
473   We cheat and only decode instructions that access
474   memory. If the instruction is not found we dump the instruction in hex.
475 
476   @param  OpCodePtrPtr  Pointer to pointer of ARM Thumb instruction to disassemble.
477   @param  Buf           Buffer to sprintf disassembly into.
478   @param  Size          Size of Buf in bytes.
479   @param  Extended    TRUE dump hex for instruction too.
480 
481 **/
482 VOID
DisassembleThumbInstruction(IN UINT16 ** OpCodePtrPtr,OUT CHAR8 * Buf,OUT UINTN Size,OUT UINT32 * ItBlock,IN BOOLEAN Extended)483 DisassembleThumbInstruction (
484   IN  UINT16    **OpCodePtrPtr,
485   OUT CHAR8     *Buf,
486   OUT UINTN     Size,
487   OUT UINT32    *ItBlock,
488   IN  BOOLEAN   Extended
489   )
490 {
491   UINT16  *OpCodePtr;
492   UINT16  OpCode;
493   UINT32  OpCode32;
494   UINT32  Index;
495   UINT32  Offset;
496   UINT16  Rd, Rn, Rm, Rt, Rt2;
497   BOOLEAN H1, H2, imod;
498   //BOOLEAN ItFlag;
499   UINT32  PC, Target, msbit, lsbit;
500   CHAR8   *Cond;
501   BOOLEAN S, J1, J2, P, U, W;
502   UINT32  coproc, opc1, opc2, CRd, CRn, CRm;
503   UINT32  Mask;
504 
505   OpCodePtr = *OpCodePtrPtr;
506   OpCode = **OpCodePtrPtr;
507 
508   // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
509   OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);
510 
511   // These register names match branch form, but not others
512   Rd = OpCode & 0x7;
513   Rn = (OpCode >> 3) & 0x7;
514   Rm = (OpCode >> 6) & 0x7;
515   H1 = (OpCode & BIT7) != 0;
516   H2 = (OpCode & BIT6) != 0;
517   imod = (OpCode & BIT4) != 0;
518   PC = (UINT32)(UINTN)OpCodePtr;
519 
520   // Increment by the minimum instruction size, Thumb2 could be bigger
521   *OpCodePtrPtr += 1;
522 
523   // Manage IT Block ItFlag TRUE means we are in an IT block
524   /*if (*ItBlock != 0) {
525     ItFlag = TRUE;
526     *ItBlock -= 1;
527   } else {
528     ItFlag = FALSE;
529   }*/
530 
531   for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {
532     if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {
533       if (Extended) {
534         Offset = AsciiSPrint (Buf, Size, "0x%04x       %-6a", OpCode, gOpThumb[Index].Start);
535       } else {
536         Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start);
537       }
538       switch (gOpThumb[Index].AddressMode) {
539       case LOAD_STORE_FORMAT1:
540         // A6.5.1  <Rd>, [<Rn>, #<5_bit_offset>]
541         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 4) & 0x7c);
542         return;
543       case LOAD_STORE_FORMAT1_H:
544         // A6.5.1  <Rd>, [<Rn>, #<5_bit_offset>]
545         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 5) & 0x3e);
546         return;
547       case LOAD_STORE_FORMAT1_B:
548         // A6.5.1  <Rd>, [<Rn>, #<5_bit_offset>]
549         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 6) & 0x1f);
550         return;
551 
552       case LOAD_STORE_FORMAT2:
553         // A6.5.1  <Rd>, [<Rn>, <Rm>]
554         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, Rn, Rm);
555         return;
556       case LOAD_STORE_FORMAT3:
557         // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
558         Target = (OpCode & 0xff) << 2;
559         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x] ;0x%08x", (OpCode >> 8) & 7, Target, PCAlign4 (PC) + Target);
560         return;
561       case LOAD_STORE_FORMAT4:
562         // Rt, [SP, #imm8]
563         Target = (OpCode & 0xff) << 2;
564         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target);
565         return;
566 
567       case LOAD_STORE_MULTIPLE_FORMAT1:
568         // <Rn>!, {r0-r7}
569         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff));
570         return;
571 
572       case POP_FORMAT:
573         // POP {r0-r7,pc}
574         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0)));
575         return;
576 
577       case PUSH_FORMAT:
578         // PUSH {r0-r7,lr}
579         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0)));
580         return;
581 
582 
583       case IMMED_8:
584         // A6.7 <immed_8>
585         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff);
586         return;
587 
588       case CONDITIONAL_BRANCH:
589         // A6.3.1 B<cond> <target_address>
590         // Patch in the condition code. A little hack but based on "%-6a"
591         Cond = gCondition[(OpCode >> 8) & 0xf];
592         Buf[Offset-5] = *Cond++;
593         Buf[Offset-4] = *Cond;
594         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x",  PC + 4 + SignExtend32 ((OpCode & 0xff) << 1, BIT8));
595         return;
596       case UNCONDITIONAL_BRANCH_SHORT:
597         // A6.3.2 B  <target_address>
598         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0x3ff) << 1, BIT11));
599         return;
600 
601       case BRANCH_EXCHANGE:
602         // A6.3.3 BX|BLX <Rm>
603         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]);
604         return;
605 
606       case DATA_FORMAT1:
607         // A6.4.3  <Rd>, <Rn>, <Rm>
608         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm);
609         return;
610       case DATA_FORMAT2:
611         // A6.4.3  <Rd>, <Rn>, #3_bit_immed
612         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm);
613         return;
614       case DATA_FORMAT3:
615         // A6.4.3  <Rd>|<Rn>, #imm8
616         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
617         return;
618       case DATA_FORMAT4:
619         // A6.4.3  <Rd>|<Rm>, #immed_5
620         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f);
621         return;
622       case DATA_FORMAT5:
623         // A6.4.3  <Rd>|<Rm>, <Rm>|<Rs>
624         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn);
625         return;
626       case DATA_FORMAT6_SP:
627         // A6.4.3  <Rd>, <reg>, #<8_Bit_immed>
628         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2);
629         return;
630       case DATA_FORMAT6_PC:
631         // A6.4.3  <Rd>, <reg>, #<8_Bit_immed>
632         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2);
633         return;
634       case DATA_FORMAT7:
635         // A6.4.3  SP, SP, #<7_Bit_immed>
636         AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4);
637         return;
638       case DATA_FORMAT8:
639         // A6.4.3  <Rd>|<Rn>, <Rm>
640         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]);
641         return;
642 
643       case CPS_FORMAT:
644         // A7.1.24
645         AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a",  ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f");
646         return;
647 
648       case ENDIAN_FORMAT:
649         // A7.1.24
650         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE");
651         return;
652 
653       case DATA_CBZ:
654         // CB{N}Z <Rn>, <Lable>
655         Target = ((OpCode >> 2) & 0x3e) | (((OpCode & BIT9) == BIT9) ? BIT6 : 0);
656         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[Rd], PC + 4 + Target);
657         return;
658 
659       case ADR_FORMAT:
660         // ADR <Rd>, <Label>
661         Target = (OpCode & 0xff) << 2;
662         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PCAlign4 (PC) + Target);
663         return;
664 
665       case IT_BLOCK:
666         // ITSTATE = cond:mask   OpCode[7:4]:OpCode[3:0]
667         // ITSTATE[7:5] == cond[3:1]
668         // ITSTATE[4] == 1st Instruction cond[0]
669         // ITSTATE[3] == 2st Instruction cond[0]
670         // ITSTATE[2] == 3st Instruction cond[0]
671         // ITSTATE[1] == 4st Instruction cond[0]
672         // ITSTATE[0] == 1 4 instruction IT block. 0 means 0,1,2 or 3 instructions
673         // 1st one  in ITSTATE low bits defines the number of instructions
674         Mask = (OpCode & 0xf);
675         if ((Mask & 0x1) == 0x1) {
676           *ItBlock = 4;
677           Offset +=  AsciiSPrint (&Buf[Offset], Size - Offset, "%a%a%a", (Mask & BIT3)?"T":"E", (Mask & BIT2)?"T":"E", (Mask & BIT1)?"T":"E");
678         } else if ((OpCode & 0x3) == 0x2) {
679           *ItBlock = 3;
680           Offset +=  AsciiSPrint (&Buf[Offset], Size - Offset, "%a%a", (Mask & BIT3)?"T":"E", (Mask & BIT2)?"T":"E");
681         } else if ((OpCode & 0x7) == 0x4) {
682           *ItBlock = 2;
683           Offset +=  AsciiSPrint (&Buf[Offset], Size - Offset, "%a", (Mask & BIT3)?"T":"E");
684         } else if ((OpCode & 0xf) == 0x8) {
685           *ItBlock = 1;
686         }
687         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gCondition[(OpCode >> 4) & 0xf]);
688         return;
689       }
690     }
691   }
692 
693 
694   // Thumb2 are 32-bit instructions
695   *OpCodePtrPtr += 1;
696   Rt  = (OpCode32 >> 12) & 0xf;
697   Rt2 = (OpCode32 >> 8) & 0xf;
698   Rd  = (OpCode32 >> 8) & 0xf;
699   Rm  = (OpCode32 & 0xf);
700   Rn  = (OpCode32 >> 16) & 0xf;
701   for (Index = 0; Index < sizeof (gOpThumb2)/sizeof (THUMB_INSTRUCTIONS); Index++) {
702     if ((OpCode32 & gOpThumb2[Index].Mask) == gOpThumb2[Index].OpCode) {
703       if (Extended) {
704         Offset = AsciiSPrint (Buf, Size, "0x%04x   %-6a", OpCode32, gOpThumb2[Index].Start);
705       } else {
706         Offset = AsciiSPrint (Buf, Size, "   %-6a", gOpThumb2[Index].Start);
707       }
708       switch (gOpThumb2[Index].AddressMode) {
709       case B_T3:
710         Cond = gCondition[(OpCode32 >> 22) & 0xf];
711         Buf[Offset-5] = *Cond++;
712         Buf[Offset-4] = *Cond;
713         // S:J2:J1:imm6:imm11:0
714         Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3f000);
715         Target |= ((OpCode32 & BIT11) == BIT11)? BIT19 : 0;  // J2
716         Target |= ((OpCode32 & BIT13) == BIT13)? BIT18 : 0;  // J1
717         Target |= ((OpCode32 & BIT26) == BIT26)? BIT20 : 0;  // S
718         Target = SignExtend32 (Target, BIT20);
719         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
720         return;
721       case B_T4:
722         // S:I1:I2:imm10:imm11:0
723         Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3ff000);
724         S  = (OpCode32 & BIT26) == BIT26;
725         J1 = (OpCode32 & BIT13) == BIT13;
726         J2 = (OpCode32 & BIT11) == BIT11;
727         Target |= (!(J2 ^ S) ? BIT22 : 0);  // I2
728         Target |= (!(J1 ^ S) ? BIT23 : 0);  // I1
729         Target |= (S ? BIT24 : 0);  // S
730         Target = SignExtend32 (Target, BIT24);
731         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
732         return;
733 
734       case BL_T2:
735         // BLX  S:I1:I2:imm10:imm11:0
736         Target = ((OpCode32 << 1) & 0xffc) + ((OpCode32 >> 4) & 0x3ff000);
737         S  = (OpCode32 & BIT26) == BIT26;
738         J1 = (OpCode32 & BIT13) == BIT13;
739         J2 = (OpCode32 & BIT11) == BIT11;
740         Target |= (!(J2 ^ S) ? BIT23 : 0);  // I2
741         Target |= (!(J1 ^ S) ? BIT24 : 0);  // I1
742         Target |= (S ? BIT25 : 0);  // S
743         Target = SignExtend32 (Target, BIT25);
744         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PCAlign4 (PC) + Target);
745         return;
746 
747       case POP_T2:
748         // <reglist>  some must be zero, handled in table
749         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));
750         return;
751 
752       case POP_T3:
753         // <register>
754         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);
755         return;
756 
757       case STM_FORMAT:
758         // <Rn>{!}, <registers>
759         W = (OpCode32 & BIT21) == BIT21;
760         AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, %a", gReg[(OpCode32 >> 16) & 0xf], W ? "!":"", ThumbMRegList (OpCode32 & 0xffff));
761         return;
762 
763       case LDM_REG_IMM12_SIGNED:
764         // <rt>, <label>
765         Target = OpCode32 & 0xfff;
766         if ((OpCode32 & BIT23) == 0) {
767           // U == 0 means subtrack, U == 1 means add
768           Target = -Target;
769         }
770         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PCAlign4 (PC) + Target);
771         return;
772 
773       case LDM_REG_INDIRECT_LSL:
774         // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
775         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a, %a", gReg[Rt], gReg[Rn], gReg[Rm]);
776         if (((OpCode32 >> 4) & 3) == 0) {
777           AsciiSPrint (&Buf[Offset], Size - Offset, "]");
778         } else {
779           AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) & 3);
780         }
781         return;
782 
783       case LDM_REG_IMM12:
784         // <rt>, [<rn>, {, #<imm12>]}
785         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
786         if ((OpCode32 & 0xfff) == 0) {
787           AsciiSPrint (&Buf[Offset], Size - Offset, "]");
788         } else {
789           AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);
790         }
791         return;
792 
793       case LDM_REG_IMM8:
794         // <rt>, [<rn>, {, #<imm8>}]{!}
795         W = (OpCode32 & BIT8) == BIT8;
796         U = (OpCode32 & BIT9) == BIT9;
797         P = (OpCode32 & BIT10) == BIT10;
798         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
799         if (P) {
800           if ((OpCode32 & 0xff) == 0) {
801             AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");
802           } else {
803             AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-" , OpCode32 & 0xff, W?"!":"");
804           }
805         } else {
806           AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x", U?"":"-", OpCode32 & 0xff);
807         }
808         return;
809 
810       case LDRD_REG_IMM8_SIGNED:
811         // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
812         P = (OpCode32 & BIT24) == BIT24;  // index = P
813         U = (OpCode32 & BIT23) == BIT23;
814         W = (OpCode32 & BIT21) == BIT21;
815         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]);
816         if (P) {
817           if ((OpCode32 & 0xff) == 0) {
818             AsciiSPrint (&Buf[Offset], Size - Offset, "]");
819           } else {
820             AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");
821           }
822         } else {
823           if ((OpCode32 & 0xff) != 0) {
824             AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);
825           }
826         }
827         return;
828 
829       case LDRD_REG_IMM8:
830         // LDRD <rt>, <rt2>, <label>
831         Target = (OpCode32 & 0xff) << 2;
832         if ((OpCode32 & BIT23) == 0) {
833           // U == 0 means subtrack, U == 1 means add
834           Target = -Target;
835         }
836         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);
837         return;
838 
839       case LDREXB:
840         // LDREXB <Rt>, [Rn]
841         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);
842         return;
843 
844       case LDREXD:
845         // LDREXD <Rt>, <Rt2>, [<Rn>]
846         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);
847         return;
848 
849       case SRS_FORMAT:
850         // SP{!}, #<mode>
851         W = (OpCode32 & BIT21) == BIT21;
852         AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);
853         return;
854 
855       case RFE_FORMAT:
856         // <Rn>{!}
857         W = (OpCode32 & BIT21) == BIT21;
858         AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");
859         return;
860 
861       case ADD_IMM12:
862         // ADD{S} <Rd>, <Rn>, #<const>   i:imm3:imm8
863         if ((OpCode32 & BIT20) == BIT20) {
864           Buf[Offset - 3] = 'S';  // assume %-6a
865         }
866         Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
867         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #0x%x", gReg[Rd], gReg[Rn], Target);
868         return;
869 
870       case ADD_IMM12_1REG:
871         // MOV{S} <Rd>, #<const>   i:imm3:imm8
872         if ((OpCode32 & BIT20) == BIT20) {
873           Buf[Offset - 3] = 'S';  // assume %-6a
874         }
875         Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
876         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target);
877         return;
878 
879       case THUMB2_IMM16:
880         // MOVW <Rd>, #<const>   i:imm3:imm8
881         Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
882         Target |= ((OpCode32 >> 4) & 0xf0000);
883         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target);
884         return;
885 
886       case ADD_IMM5:
887         // ADC{S}  <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
888         if ((OpCode32 & BIT20) == BIT20) {
889           Buf[Offset - 3] = 'S';  // assume %-6a
890         }
891         Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
892         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm]);
893         if (Target != 0) {
894           AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
895         }
896         return;
897 
898       case ADD_IMM5_2REG:
899         // CMP  <Rn>, <Rm> {,LSL #<const>} imm3:imm2
900         Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
901         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rn], gReg[Rm]);
902         if (Target != 0) {
903           AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
904         }
905 
906 
907       case ASR_IMM5:
908         // ARS  <Rd>, <Rm> #<const>} imm3:imm2
909         if ((OpCode32 & BIT20) == BIT20) {
910           Buf[Offset - 3] = 'S';  // assume %-6a
911         }
912         Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
913         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a #%d", gReg[Rd], gReg[Rm], Target);
914         return;
915 
916       case ASR_3REG:
917         // ARS  <Rd>, <Rn>, <Rm>
918         if ((OpCode32 & BIT20) == BIT20) {
919           Buf[Offset - 3] = 'S';  // assume %-6a
920         }
921         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a %a", gReg[Rd], gReg[Rn], gReg[Rm]);
922         return;
923 
924       case ADR_THUMB2:
925         // ADDR <Rd>, <label>
926         Target = (OpCode32 & 0xff) | ((OpCode32 >> 8) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
927         if ((OpCode & (BIT23 | BIT21)) == (BIT23 | BIT21)) {
928           Target = PCAlign4 (PC) - Target;
929         } else {
930           Target = PCAlign4 (PC) + Target;
931         }
932         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target);
933         return;
934 
935       case CMN_THUMB2:
936         // CMN <Rn>, #<const>}
937         Target = (OpCode32 & 0xff) | ((OpCode >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
938         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rn], Target);
939         return;
940 
941       case BFC_THUMB2:
942         // BFI <Rd>, <Rn>, #<lsb>, #<width>
943         msbit = OpCode32 & 0x1f;
944         lsbit = ((OpCode32 >> 6) & 3) | ((OpCode >> 10) &  0x1c);
945         if ((Rn == 0xf) & (AsciiStrCmp (gOpThumb2[Index].Start, "BFC") == 0)){
946           // BFC <Rd>, #<lsb>, #<width>
947           AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #%d, #%d", gReg[Rd], lsbit, msbit - lsbit + 1);
948         } else if (AsciiStrCmp (gOpThumb2[Index].Start, "BFI") == 0) {
949           AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit - lsbit + 1);
950         } else {
951           AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit + 1);
952         }
953         return;
954 
955       case CPD_THUMB2:
956         // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
957         coproc = (OpCode32 >> 8)  & 0xf;
958         opc1   = (OpCode32 >> 20) & 0xf;
959         opc2   = (OpCode32 >> 5)  & 0x7;
960         CRd    = (OpCode32 >> 12) & 0xf;
961         CRn    = (OpCode32 >> 16) & 0xf;
962         CRm    = OpCode32 & 0xf;
963         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,c%d,c%d,c%d", coproc, opc1, CRd, CRn, CRm);
964         if (opc2 != 0) {
965           AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2);
966         }
967         return;
968 
969       case MRC_THUMB2:
970         // MRC  <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
971         coproc = (OpCode32 >> 8)  & 0xf;
972         opc1   = (OpCode32 >> 20) & 0xf;
973         opc2   = (OpCode32 >> 5)  & 0x7;
974         CRn    = (OpCode32 >> 16) & 0xf;
975         CRm    = OpCode32 & 0xf;
976         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,c%d,c%d", coproc, opc1, gReg[Rt], CRn, CRm);
977         if (opc2 != 0) {
978           AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2);
979         }
980         return;
981 
982       case MRRC_THUMB2:
983         // MRC  <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2>
984         coproc = (OpCode32 >> 8)  & 0xf;
985         opc1   = (OpCode32 >> 20) & 0xf;
986         CRn    = (OpCode32 >> 16) & 0xf;
987         CRm    = OpCode32 & 0xf;
988         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,%a,c%d", coproc, opc1, gReg[Rt], gReg[Rt2], CRm);
989         return;
990 
991       case THUMB2_2REGS:
992         // <Rd>, <Rm>
993         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd], gReg[Rm]);
994         return;
995 
996       case THUMB2_4REGS:
997         // <Rd>, <Rn>, <Rm>, <Ra>
998         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm], gReg[Rt]);
999         return;
1000 
1001       case THUMB2_MRS:
1002         // MRS <Rd>, CPSR
1003         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, CPSR", gReg[Rd]);
1004         return;
1005 
1006       case THUMB2_MSR:
1007         // MRS CPSR_<fields>, <Rd>
1008         Target = (OpCode32 >> 10) & 3;
1009         AsciiSPrint (&Buf[Offset], Size - Offset, " CPSR_%a%a, %a", (Target & 2) == 0 ? "":"f", (Target & 1) == 0 ? "":"s", gReg[Rd]);
1010         return;
1011 
1012       case THUMB2_NO_ARGS:
1013       default:
1014         break;
1015       }
1016     }
1017   }
1018 
1019   AsciiSPrint (Buf, Size, "0x%08x", OpCode32);
1020 }
1021 
1022 
1023 
1024 VOID
1025 DisassembleArmInstruction (
1026   IN  UINT32    **OpCodePtr,
1027   OUT CHAR8     *Buf,
1028   OUT UINTN     Size,
1029   IN  BOOLEAN   Extended
1030   );
1031 
1032 
1033 /**
1034   Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
1035   point to next instructin.
1036 
1037   We cheat and only decode instructions that access
1038   memory. If the instruction is not found we dump the instruction in hex.
1039 
1040   @param  OpCodePtrPtr  Pointer to pointer of ARM Thumb instruction to disassemble.
1041   @param  Thumb         TRUE for Thumb(2), FALSE for ARM instruction stream
1042   @param  Extended      TRUE dump hex for instruction too.
1043   @param  ItBlock       Size of IT Block
1044   @param  Buf           Buffer to sprintf disassembly into.
1045   @param  Size          Size of Buf in bytes.
1046 
1047 **/
1048 VOID
DisassembleInstruction(IN UINT8 ** OpCodePtr,IN BOOLEAN Thumb,IN BOOLEAN Extended,IN OUT UINT32 * ItBlock,OUT CHAR8 * Buf,OUT UINTN Size)1049 DisassembleInstruction (
1050   IN  UINT8     **OpCodePtr,
1051   IN  BOOLEAN   Thumb,
1052   IN  BOOLEAN   Extended,
1053   IN OUT UINT32 *ItBlock,
1054   OUT CHAR8     *Buf,
1055   OUT UINTN     Size
1056   )
1057 {
1058   if (Thumb) {
1059     DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, ItBlock, Extended);
1060   } else {
1061     DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);
1062   }
1063 }
1064 
1065