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 * 395 ThumbMRegList ( 396 UINT32 RegBitMask 397 ) 398 { 399 UINTN Index, Start, End; 400 BOOLEAN First; 401 402 mThumbMregListStr[0] = '\0'; 403 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "{"); 404 405 for (Index = 0, First = TRUE; Index <= 15; Index++) { 406 if ((RegBitMask & (1 << Index)) != 0) { 407 Start = End = Index; 408 for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) { 409 End = Index; 410 } 411 412 if (!First) { 413 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, ","); 414 } else { 415 First = FALSE; 416 } 417 418 if (Start == End) { 419 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[Start]); 420 } else { 421 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[Start]); 422 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "-"); 423 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[End]); 424 } 425 } 426 } 427 if (First) { 428 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "ERROR"); 429 } 430 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "}"); 431 432 // BugBug: Make caller pass in buffer it is cleaner 433 return mThumbMregListStr; 434 } 435 436 UINT32 437 SignExtend32 ( 438 IN UINT32 Data, 439 IN UINT32 TopBit 440 ) 441 { 442 if (((Data & TopBit) == 0) || (TopBit == BIT31)) { 443 return Data; 444 } 445 446 do { 447 TopBit <<= 1; 448 Data |= TopBit; 449 } while ((TopBit & BIT31) != BIT31); 450 451 return Data; 452 } 453 454 // 455 // Some instructions specify the PC is always considered aligned 456 // The PC is after the instruction that is excuting. So you pass 457 // in the instruction address and you get back the aligned answer 458 // 459 UINT32 460 PCAlign4 ( 461 IN UINT32 Data 462 ) 463 { 464 return (Data + 4) & 0xfffffffc; 465 } 466 467 /** 468 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to 469 point to next instructin. 470 471 We cheat and only decode instructions that access 472 memory. If the instruction is not found we dump the instruction in hex. 473 474 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. 475 @param Buf Buffer to sprintf disassembly into. 476 @param Size Size of Buf in bytes. 477 @param Extended TRUE dump hex for instruction too. 478 479 **/ 480 VOID 481 DisassembleThumbInstruction ( 482 IN UINT16 **OpCodePtrPtr, 483 OUT CHAR8 *Buf, 484 OUT UINTN Size, 485 OUT UINT32 *ItBlock, 486 IN BOOLEAN Extended 487 ) 488 { 489 UINT16 *OpCodePtr; 490 UINT16 OpCode; 491 UINT32 OpCode32; 492 UINT32 Index; 493 UINT32 Offset; 494 UINT16 Rd, Rn, Rm, Rt, Rt2; 495 BOOLEAN H1, H2, imod; 496 //BOOLEAN ItFlag; 497 UINT32 PC, Target, msbit, lsbit; 498 CHAR8 *Cond; 499 BOOLEAN S, J1, J2, P, U, W; 500 UINT32 coproc, opc1, opc2, CRd, CRn, CRm; 501 UINT32 Mask; 502 503 OpCodePtr = *OpCodePtrPtr; 504 OpCode = **OpCodePtrPtr; 505 506 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction. 507 OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1); 508 509 // These register names match branch form, but not others 510 Rd = OpCode & 0x7; 511 Rn = (OpCode >> 3) & 0x7; 512 Rm = (OpCode >> 6) & 0x7; 513 H1 = (OpCode & BIT7) != 0; 514 H2 = (OpCode & BIT6) != 0; 515 imod = (OpCode & BIT4) != 0; 516 PC = (UINT32)(UINTN)OpCodePtr; 517 518 // Increment by the minimum instruction size, Thumb2 could be bigger 519 *OpCodePtrPtr += 1; 520 521 // Manage IT Block ItFlag TRUE means we are in an IT block 522 /*if (*ItBlock != 0) { 523 ItFlag = TRUE; 524 *ItBlock -= 1; 525 } else { 526 ItFlag = FALSE; 527 }*/ 528 529 for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) { 530 if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) { 531 if (Extended) { 532 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode, gOpThumb[Index].Start); 533 } else { 534 Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start); 535 } 536 switch (gOpThumb[Index].AddressMode) { 537 case LOAD_STORE_FORMAT1: 538 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>] 539 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 4) & 0x7c); 540 return; 541 case LOAD_STORE_FORMAT1_H: 542 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>] 543 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 5) & 0x3e); 544 return; 545 case LOAD_STORE_FORMAT1_B: 546 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>] 547 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 6) & 0x1f); 548 return; 549 550 case LOAD_STORE_FORMAT2: 551 // A6.5.1 <Rd>, [<Rn>, <Rm>] 552 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, Rn, Rm); 553 return; 554 case LOAD_STORE_FORMAT3: 555 // A6.5.1 <Rd>, [PC, #<8_bit_offset>] 556 Target = (OpCode & 0xff) << 2; 557 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x] ;0x%08x", (OpCode >> 8) & 7, Target, PCAlign4 (PC) + Target); 558 return; 559 case LOAD_STORE_FORMAT4: 560 // Rt, [SP, #imm8] 561 Target = (OpCode & 0xff) << 2; 562 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target); 563 return; 564 565 case LOAD_STORE_MULTIPLE_FORMAT1: 566 // <Rn>!, {r0-r7} 567 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff)); 568 return; 569 570 case POP_FORMAT: 571 // POP {r0-r7,pc} 572 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0))); 573 return; 574 575 case PUSH_FORMAT: 576 // PUSH {r0-r7,lr} 577 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0))); 578 return; 579 580 581 case IMMED_8: 582 // A6.7 <immed_8> 583 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff); 584 return; 585 586 case CONDITIONAL_BRANCH: 587 // A6.3.1 B<cond> <target_address> 588 // Patch in the condition code. A little hack but based on "%-6a" 589 Cond = gCondition[(OpCode >> 8) & 0xf]; 590 Buf[Offset-5] = *Cond++; 591 Buf[Offset-4] = *Cond; 592 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0xff) << 1, BIT8)); 593 return; 594 case UNCONDITIONAL_BRANCH_SHORT: 595 // A6.3.2 B <target_address> 596 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0x3ff) << 1, BIT11)); 597 return; 598 599 case BRANCH_EXCHANGE: 600 // A6.3.3 BX|BLX <Rm> 601 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]); 602 return; 603 604 case DATA_FORMAT1: 605 // A6.4.3 <Rd>, <Rn>, <Rm> 606 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm); 607 return; 608 case DATA_FORMAT2: 609 // A6.4.3 <Rd>, <Rn>, #3_bit_immed 610 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm); 611 return; 612 case DATA_FORMAT3: 613 // A6.4.3 <Rd>|<Rn>, #imm8 614 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff); 615 return; 616 case DATA_FORMAT4: 617 // A6.4.3 <Rd>|<Rm>, #immed_5 618 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f); 619 return; 620 case DATA_FORMAT5: 621 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs> 622 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn); 623 return; 624 case DATA_FORMAT6_SP: 625 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed> 626 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2); 627 return; 628 case DATA_FORMAT6_PC: 629 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed> 630 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2); 631 return; 632 case DATA_FORMAT7: 633 // A6.4.3 SP, SP, #<7_Bit_immed> 634 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4); 635 return; 636 case DATA_FORMAT8: 637 // A6.4.3 <Rd>|<Rn>, <Rm> 638 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]); 639 return; 640 641 case CPS_FORMAT: 642 // A7.1.24 643 AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a", ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f"); 644 return; 645 646 case ENDIAN_FORMAT: 647 // A7.1.24 648 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE"); 649 return; 650 651 case DATA_CBZ: 652 // CB{N}Z <Rn>, <Lable> 653 Target = ((OpCode >> 2) & 0x3e) | (((OpCode & BIT9) == BIT9) ? BIT6 : 0); 654 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[Rd], PC + 4 + Target); 655 return; 656 657 case ADR_FORMAT: 658 // ADR <Rd>, <Label> 659 Target = (OpCode & 0xff) << 2; 660 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PCAlign4 (PC) + Target); 661 return; 662 663 case IT_BLOCK: 664 // ITSTATE = cond:mask OpCode[7:4]:OpCode[3:0] 665 // ITSTATE[7:5] == cond[3:1] 666 // ITSTATE[4] == 1st Instruction cond[0] 667 // ITSTATE[3] == 2st Instruction cond[0] 668 // ITSTATE[2] == 3st Instruction cond[0] 669 // ITSTATE[1] == 4st Instruction cond[0] 670 // ITSTATE[0] == 1 4 instruction IT block. 0 means 0,1,2 or 3 instructions 671 // 1st one in ITSTATE low bits defines the number of instructions 672 Mask = (OpCode & 0xf); 673 if ((Mask & 0x1) == 0x1) { 674 *ItBlock = 4; 675 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, "%a%a%a", (Mask & BIT3)?"T":"E", (Mask & BIT2)?"T":"E", (Mask & BIT1)?"T":"E"); 676 } else if ((OpCode & 0x3) == 0x2) { 677 *ItBlock = 3; 678 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, "%a%a", (Mask & BIT3)?"T":"E", (Mask & BIT2)?"T":"E"); 679 } else if ((OpCode & 0x7) == 0x4) { 680 *ItBlock = 2; 681 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, "%a", (Mask & BIT3)?"T":"E"); 682 } else if ((OpCode & 0xf) == 0x8) { 683 *ItBlock = 1; 684 } 685 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gCondition[(OpCode >> 4) & 0xf]); 686 return; 687 } 688 } 689 } 690 691 692 // Thumb2 are 32-bit instructions 693 *OpCodePtrPtr += 1; 694 Rt = (OpCode32 >> 12) & 0xf; 695 Rt2 = (OpCode32 >> 8) & 0xf; 696 Rd = (OpCode32 >> 8) & 0xf; 697 Rm = (OpCode32 & 0xf); 698 Rn = (OpCode32 >> 16) & 0xf; 699 for (Index = 0; Index < sizeof (gOpThumb2)/sizeof (THUMB_INSTRUCTIONS); Index++) { 700 if ((OpCode32 & gOpThumb2[Index].Mask) == gOpThumb2[Index].OpCode) { 701 if (Extended) { 702 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode32, gOpThumb2[Index].Start); 703 } else { 704 Offset = AsciiSPrint (Buf, Size, " %-6a", gOpThumb2[Index].Start); 705 } 706 switch (gOpThumb2[Index].AddressMode) { 707 case B_T3: 708 Cond = gCondition[(OpCode32 >> 22) & 0xf]; 709 Buf[Offset-5] = *Cond++; 710 Buf[Offset-4] = *Cond; 711 // S:J2:J1:imm6:imm11:0 712 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3f000); 713 Target |= ((OpCode32 & BIT11) == BIT11)? BIT19 : 0; // J2 714 Target |= ((OpCode32 & BIT13) == BIT13)? BIT18 : 0; // J1 715 Target |= ((OpCode32 & BIT26) == BIT26)? BIT20 : 0; // S 716 Target = SignExtend32 (Target, BIT20); 717 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); 718 return; 719 case B_T4: 720 // S:I1:I2:imm10:imm11:0 721 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3ff000); 722 S = (OpCode32 & BIT26) == BIT26; 723 J1 = (OpCode32 & BIT13) == BIT13; 724 J2 = (OpCode32 & BIT11) == BIT11; 725 Target |= (!(J2 ^ S) ? BIT22 : 0); // I2 726 Target |= (!(J1 ^ S) ? BIT23 : 0); // I1 727 Target |= (S ? BIT24 : 0); // S 728 Target = SignExtend32 (Target, BIT24); 729 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); 730 return; 731 732 case BL_T2: 733 // BLX S:I1:I2:imm10:imm11:0 734 Target = ((OpCode32 << 1) & 0xffc) + ((OpCode32 >> 4) & 0x3ff000); 735 S = (OpCode32 & BIT26) == BIT26; 736 J1 = (OpCode32 & BIT13) == BIT13; 737 J2 = (OpCode32 & BIT11) == BIT11; 738 Target |= (!(J2 ^ S) ? BIT23 : 0); // I2 739 Target |= (!(J1 ^ S) ? BIT24 : 0); // I1 740 Target |= (S ? BIT25 : 0); // S 741 Target = SignExtend32 (Target, BIT25); 742 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PCAlign4 (PC) + Target); 743 return; 744 745 case POP_T2: 746 // <reglist> some must be zero, handled in table 747 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff)); 748 return; 749 750 case POP_T3: 751 // <register> 752 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]); 753 return; 754 755 case STM_FORMAT: 756 // <Rn>{!}, <registers> 757 W = (OpCode32 & BIT21) == BIT21; 758 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, %a", gReg[(OpCode32 >> 16) & 0xf], W ? "!":"", ThumbMRegList (OpCode32 & 0xffff)); 759 return; 760 761 case LDM_REG_IMM12_SIGNED: 762 // <rt>, <label> 763 Target = OpCode32 & 0xfff; 764 if ((OpCode32 & BIT23) == 0) { 765 // U == 0 means subtrack, U == 1 means add 766 Target = -Target; 767 } 768 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PCAlign4 (PC) + Target); 769 return; 770 771 case LDM_REG_INDIRECT_LSL: 772 // <rt>, [<rn>, <rm> {, LSL #<imm2>]} 773 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a, %a", gReg[Rt], gReg[Rn], gReg[Rm]); 774 if (((OpCode32 >> 4) & 3) == 0) { 775 AsciiSPrint (&Buf[Offset], Size - Offset, "]"); 776 } else { 777 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) & 3); 778 } 779 return; 780 781 case LDM_REG_IMM12: 782 // <rt>, [<rn>, {, #<imm12>]} 783 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]); 784 if ((OpCode32 & 0xfff) == 0) { 785 AsciiSPrint (&Buf[Offset], Size - Offset, "]"); 786 } else { 787 AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff); 788 } 789 return; 790 791 case LDM_REG_IMM8: 792 // <rt>, [<rn>, {, #<imm8>}]{!} 793 W = (OpCode32 & BIT8) == BIT8; 794 U = (OpCode32 & BIT9) == BIT9; 795 P = (OpCode32 & BIT10) == BIT10; 796 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]); 797 if (P) { 798 if ((OpCode32 & 0xff) == 0) { 799 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":""); 800 } else { 801 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-" , OpCode32 & 0xff, W?"!":""); 802 } 803 } else { 804 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x", U?"":"-", OpCode32 & 0xff); 805 } 806 return; 807 808 case LDRD_REG_IMM8_SIGNED: 809 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!} 810 P = (OpCode32 & BIT24) == BIT24; // index = P 811 U = (OpCode32 & BIT23) == BIT23; 812 W = (OpCode32 & BIT21) == BIT21; 813 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]); 814 if (P) { 815 if ((OpCode32 & 0xff) == 0) { 816 AsciiSPrint (&Buf[Offset], Size - Offset, "]"); 817 } else { 818 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":""); 819 } 820 } else { 821 if ((OpCode32 & 0xff) != 0) { 822 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2); 823 } 824 } 825 return; 826 827 case LDRD_REG_IMM8: 828 // LDRD <rt>, <rt2>, <label> 829 Target = (OpCode32 & 0xff) << 2; 830 if ((OpCode32 & BIT23) == 0) { 831 // U == 0 means subtrack, U == 1 means add 832 Target = -Target; 833 } 834 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target); 835 return; 836 837 case LDREXB: 838 // LDREXB <Rt>, [Rn] 839 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]); 840 return; 841 842 case LDREXD: 843 // LDREXD <Rt>, <Rt2>, [<Rn>] 844 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]); 845 return; 846 847 case SRS_FORMAT: 848 // SP{!}, #<mode> 849 W = (OpCode32 & BIT21) == BIT21; 850 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f); 851 return; 852 853 case RFE_FORMAT: 854 // <Rn>{!} 855 W = (OpCode32 & BIT21) == BIT21; 856 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":""); 857 return; 858 859 case ADD_IMM12: 860 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8 861 if ((OpCode32 & BIT20) == BIT20) { 862 Buf[Offset - 3] = 'S'; // assume %-6a 863 } 864 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0); 865 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #0x%x", gReg[Rd], gReg[Rn], Target); 866 return; 867 868 case ADD_IMM12_1REG: 869 // MOV{S} <Rd>, #<const> i:imm3:imm8 870 if ((OpCode32 & BIT20) == BIT20) { 871 Buf[Offset - 3] = 'S'; // assume %-6a 872 } 873 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0); 874 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target); 875 return; 876 877 case THUMB2_IMM16: 878 // MOVW <Rd>, #<const> i:imm3:imm8 879 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0); 880 Target |= ((OpCode32 >> 4) & 0xf0000); 881 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target); 882 return; 883 884 case ADD_IMM5: 885 // ADC{S} <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2 886 if ((OpCode32 & BIT20) == BIT20) { 887 Buf[Offset - 3] = 'S'; // assume %-6a 888 } 889 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0); 890 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm]); 891 if (Target != 0) { 892 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target); 893 } 894 return; 895 896 case ADD_IMM5_2REG: 897 // CMP <Rn>, <Rm> {,LSL #<const>} imm3:imm2 898 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0); 899 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rn], gReg[Rm]); 900 if (Target != 0) { 901 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target); 902 } 903 904 905 case ASR_IMM5: 906 // ARS <Rd>, <Rm> #<const>} imm3:imm2 907 if ((OpCode32 & BIT20) == BIT20) { 908 Buf[Offset - 3] = 'S'; // assume %-6a 909 } 910 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0); 911 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a #%d", gReg[Rd], gReg[Rm], Target); 912 return; 913 914 case ASR_3REG: 915 // ARS <Rd>, <Rn>, <Rm> 916 if ((OpCode32 & BIT20) == BIT20) { 917 Buf[Offset - 3] = 'S'; // assume %-6a 918 } 919 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a %a", gReg[Rd], gReg[Rn], gReg[Rm]); 920 return; 921 922 case ADR_THUMB2: 923 // ADDR <Rd>, <label> 924 Target = (OpCode32 & 0xff) | ((OpCode32 >> 8) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0); 925 if ((OpCode & (BIT23 | BIT21)) == (BIT23 | BIT21)) { 926 Target = PCAlign4 (PC) - Target; 927 } else { 928 Target = PCAlign4 (PC) + Target; 929 } 930 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target); 931 return; 932 933 case CMN_THUMB2: 934 // CMN <Rn>, #<const>} 935 Target = (OpCode32 & 0xff) | ((OpCode >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0); 936 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rn], Target); 937 return; 938 939 case BFC_THUMB2: 940 // BFI <Rd>, <Rn>, #<lsb>, #<width> 941 msbit = OpCode32 & 0x1f; 942 lsbit = ((OpCode32 >> 6) & 3) | ((OpCode >> 10) & 0x1c); 943 if ((Rn == 0xf) & (AsciiStrCmp (gOpThumb2[Index].Start, "BFC") == 0)){ 944 // BFC <Rd>, #<lsb>, #<width> 945 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #%d, #%d", gReg[Rd], lsbit, msbit - lsbit + 1); 946 } else if (AsciiStrCmp (gOpThumb2[Index].Start, "BFI") == 0) { 947 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit - lsbit + 1); 948 } else { 949 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit + 1); 950 } 951 return; 952 953 case CPD_THUMB2: 954 // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> 955 coproc = (OpCode32 >> 8) & 0xf; 956 opc1 = (OpCode32 >> 20) & 0xf; 957 opc2 = (OpCode32 >> 5) & 0x7; 958 CRd = (OpCode32 >> 12) & 0xf; 959 CRn = (OpCode32 >> 16) & 0xf; 960 CRm = OpCode32 & 0xf; 961 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,c%d,c%d,c%d", coproc, opc1, CRd, CRn, CRm); 962 if (opc2 != 0) { 963 AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2); 964 } 965 return; 966 967 case MRC_THUMB2: 968 // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2> 969 coproc = (OpCode32 >> 8) & 0xf; 970 opc1 = (OpCode32 >> 20) & 0xf; 971 opc2 = (OpCode32 >> 5) & 0x7; 972 CRn = (OpCode32 >> 16) & 0xf; 973 CRm = OpCode32 & 0xf; 974 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,c%d,c%d", coproc, opc1, gReg[Rt], CRn, CRm); 975 if (opc2 != 0) { 976 AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2); 977 } 978 return; 979 980 case MRRC_THUMB2: 981 // MRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2> 982 coproc = (OpCode32 >> 8) & 0xf; 983 opc1 = (OpCode32 >> 20) & 0xf; 984 CRn = (OpCode32 >> 16) & 0xf; 985 CRm = OpCode32 & 0xf; 986 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,%a,c%d", coproc, opc1, gReg[Rt], gReg[Rt2], CRm); 987 return; 988 989 case THUMB2_2REGS: 990 // <Rd>, <Rm> 991 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd], gReg[Rm]); 992 return; 993 994 case THUMB2_4REGS: 995 // <Rd>, <Rn>, <Rm>, <Ra> 996 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm], gReg[Rt]); 997 return; 998 999 case THUMB2_MRS: 1000 // MRS <Rd>, CPSR 1001 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, CPSR", gReg[Rd]); 1002 return; 1003 1004 case THUMB2_MSR: 1005 // MRS CPSR_<fields>, <Rd> 1006 Target = (OpCode32 >> 10) & 3; 1007 AsciiSPrint (&Buf[Offset], Size - Offset, " CPSR_%a%a, %a", (Target & 2) == 0 ? "":"f", (Target & 1) == 0 ? "":"s", gReg[Rd]); 1008 return; 1009 1010 case THUMB2_NO_ARGS: 1011 default: 1012 break; 1013 } 1014 } 1015 } 1016 1017 AsciiSPrint (Buf, Size, "0x%08x", OpCode32); 1018 } 1019 1020 1021 1022 VOID 1023 DisassembleArmInstruction ( 1024 IN UINT32 **OpCodePtr, 1025 OUT CHAR8 *Buf, 1026 OUT UINTN Size, 1027 IN BOOLEAN Extended 1028 ); 1029 1030 1031 /** 1032 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to 1033 point to next instructin. 1034 1035 We cheat and only decode instructions that access 1036 memory. If the instruction is not found we dump the instruction in hex. 1037 1038 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. 1039 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream 1040 @param Extended TRUE dump hex for instruction too. 1041 @param ItBlock Size of IT Block 1042 @param Buf Buffer to sprintf disassembly into. 1043 @param Size Size of Buf in bytes. 1044 1045 **/ 1046 VOID 1047 DisassembleInstruction ( 1048 IN UINT8 **OpCodePtr, 1049 IN BOOLEAN Thumb, 1050 IN BOOLEAN Extended, 1051 IN OUT UINT32 *ItBlock, 1052 OUT CHAR8 *Buf, 1053 OUT UINTN Size 1054 ) 1055 { 1056 if (Thumb) { 1057 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, ItBlock, Extended); 1058 } else { 1059 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended); 1060 } 1061 } 1062 1063