1 //==-- AArch64InstPrinter.cpp - Convert AArch64 MCInst to assembly syntax --==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This class prints an AArch64 MCInst to a .s file. 11 // 12 //===----------------------------------------------------------------------===// 13 14 /* Capstone Disassembly Engine */ 15 /* By Nguyen Anh Quynh <aquynh (at) gmail.com>, 2013-2014 */ 16 17 #ifdef CAPSTONE_HAS_ARM64 18 19 #include <platform.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 23 #include "AArch64InstPrinter.h" 24 #include "AArch64BaseInfo.h" 25 #include "../../utils.h" 26 #include "../../MCInst.h" 27 #include "../../SStream.h" 28 #include "../../MCRegisterInfo.h" 29 #include "../../MathExtras.h" 30 31 #include "AArch64Mapping.h" 32 #include "AArch64AddressingModes.h" 33 34 #define GET_REGINFO_ENUM 35 #include "AArch64GenRegisterInfo.inc" 36 37 #define GET_INSTRINFO_ENUM 38 #include "AArch64GenInstrInfo.inc" 39 40 41 static char *getRegisterName(unsigned RegNo, int AltIdx); 42 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O); 43 static bool printSysAlias(MCInst *MI, SStream *O); 44 static char *printAliasInstr(MCInst *MI, SStream *OS, void *info); 45 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI); 46 static void printShifter(MCInst *MI, unsigned OpNum, SStream *O); 47 48 static void set_mem_access(MCInst *MI, bool status) 49 { 50 if (MI->csh->detail != CS_OPT_ON) 51 return; 52 53 MI->csh->doing_mem = status; 54 55 if (status) { 56 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_MEM; 57 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.base = ARM64_REG_INVALID; 58 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.index = ARM64_REG_INVALID; 59 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = 0; 60 } else { 61 // done, create the next operand slot 62 MI->flat_insn->detail->arm64.op_count++; 63 } 64 } 65 66 void AArch64_printInst(MCInst *MI, SStream *O, void *Info) 67 { 68 // Check for special encodings and print the canonical alias instead. 69 unsigned Opcode = MCInst_getOpcode(MI); 70 int LSB; 71 int Width; 72 char *mnem; 73 74 if (Opcode == AArch64_SYSxt && printSysAlias(MI, O)) 75 return; 76 77 // SBFM/UBFM should print to a nicer aliased form if possible. 78 if (Opcode == AArch64_SBFMXri || Opcode == AArch64_SBFMWri || 79 Opcode == AArch64_UBFMXri || Opcode == AArch64_UBFMWri) { 80 MCOperand *Op0 = MCInst_getOperand(MI, 0); 81 MCOperand *Op1 = MCInst_getOperand(MI, 1); 82 MCOperand *Op2 = MCInst_getOperand(MI, 2); 83 MCOperand *Op3 = MCInst_getOperand(MI, 3); 84 85 bool IsSigned = (Opcode == AArch64_SBFMXri || Opcode == AArch64_SBFMWri); 86 bool Is64Bit = (Opcode == AArch64_SBFMXri || Opcode == AArch64_UBFMXri); 87 88 if (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0 && MCOperand_isImm(Op3)) { 89 char *AsmMnemonic = NULL; 90 91 switch (MCOperand_getImm(Op3)) { 92 default: 93 break; 94 case 7: 95 if (IsSigned) 96 AsmMnemonic = "sxtb"; 97 else if (!Is64Bit) 98 AsmMnemonic = "uxtb"; 99 break; 100 case 15: 101 if (IsSigned) 102 AsmMnemonic = "sxth"; 103 else if (!Is64Bit) 104 AsmMnemonic = "uxth"; 105 break; 106 case 31: 107 // *xtw is only valid for signed 64-bit operations. 108 if (Is64Bit && IsSigned) 109 AsmMnemonic = "sxtw"; 110 break; 111 } 112 113 if (AsmMnemonic) { 114 SStream_concat(O, "%s\t%s, %s", AsmMnemonic, 115 getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName), 116 getRegisterName(getWRegFromXReg(MCOperand_getReg(Op1)), AArch64_NoRegAltName)); 117 118 if (MI->csh->detail) { 119 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 120 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0); 121 MI->flat_insn->detail->arm64.op_count++; 122 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 123 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = getWRegFromXReg(MCOperand_getReg(Op1)); 124 MI->flat_insn->detail->arm64.op_count++; 125 } 126 127 MCInst_setOpcodePub(MI, AArch64_map_insn(AsmMnemonic)); 128 129 return; 130 } 131 } 132 133 // All immediate shifts are aliases, implemented using the Bitfield 134 // instruction. In all cases the immediate shift amount shift must be in 135 // the range 0 to (reg.size -1). 136 if (MCOperand_isImm(Op2) && MCOperand_isImm(Op3)) { 137 char *AsmMnemonic = NULL; 138 int shift = 0; 139 int64_t immr = MCOperand_getImm(Op2); 140 int64_t imms = MCOperand_getImm(Op3); 141 142 if (Opcode == AArch64_UBFMWri && imms != 0x1F && ((imms + 1) == immr)) { 143 AsmMnemonic = "lsl"; 144 shift = 31 - imms; 145 } else if (Opcode == AArch64_UBFMXri && imms != 0x3f && 146 ((imms + 1 == immr))) { 147 AsmMnemonic = "lsl"; 148 shift = 63 - imms; 149 } else if (Opcode == AArch64_UBFMWri && imms == 0x1f) { 150 AsmMnemonic = "lsr"; 151 shift = immr; 152 } else if (Opcode == AArch64_UBFMXri && imms == 0x3f) { 153 AsmMnemonic = "lsr"; 154 shift = immr; 155 } else if (Opcode == AArch64_SBFMWri && imms == 0x1f) { 156 AsmMnemonic = "asr"; 157 shift = immr; 158 } else if (Opcode == AArch64_SBFMXri && imms == 0x3f) { 159 AsmMnemonic = "asr"; 160 shift = immr; 161 } 162 163 if (AsmMnemonic) { 164 SStream_concat(O, "%s\t%s, %s, ", AsmMnemonic, 165 getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName), 166 getRegisterName(MCOperand_getReg(Op1), AArch64_NoRegAltName)); 167 168 printInt32Bang(O, shift); 169 170 MCInst_setOpcodePub(MI, AArch64_map_insn(AsmMnemonic)); 171 172 if (MI->csh->detail) { 173 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 174 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0); 175 MI->flat_insn->detail->arm64.op_count++; 176 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 177 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op1); 178 MI->flat_insn->detail->arm64.op_count++; 179 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 180 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = shift; 181 MI->flat_insn->detail->arm64.op_count++; 182 } 183 184 return; 185 } 186 } 187 188 // SBFIZ/UBFIZ aliases 189 if (MCOperand_getImm(Op2) > MCOperand_getImm(Op3)) { 190 SStream_concat(O, "%s\t%s, %s, ", (IsSigned ? "sbfiz" : "ubfiz"), 191 getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName), 192 getRegisterName(MCOperand_getReg(Op1), AArch64_NoRegAltName)); 193 printInt32Bang(O, (int)((Is64Bit ? 64 : 32) - MCOperand_getImm(Op2))); 194 SStream_concat0(O, ", "); 195 printInt32Bang(O, (int)MCOperand_getImm(Op3) + 1); 196 197 MCInst_setOpcodePub(MI, AArch64_map_insn(IsSigned ? "sbfiz" : "ubfiz")); 198 199 if (MI->csh->detail) { 200 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 201 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0); 202 MI->flat_insn->detail->arm64.op_count++; 203 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 204 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op1); 205 MI->flat_insn->detail->arm64.op_count++; 206 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 207 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = (Is64Bit ? 64 : 32) - (int)MCOperand_getImm(Op2); 208 MI->flat_insn->detail->arm64.op_count++; 209 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 210 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op3) + 1; 211 MI->flat_insn->detail->arm64.op_count++; 212 } 213 214 return; 215 } 216 217 // Otherwise SBFX/UBFX is the preferred form 218 SStream_concat(O, "%s\t%s, %s, ", (IsSigned ? "sbfx" : "ubfx"), 219 getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName), 220 getRegisterName(MCOperand_getReg(Op1), AArch64_NoRegAltName)); 221 printInt32Bang(O, (int)MCOperand_getImm(Op2)); 222 SStream_concat0(O, ", "); 223 printInt32Bang(O, (int)MCOperand_getImm(Op3) - (int)MCOperand_getImm(Op2) + 1); 224 225 MCInst_setOpcodePub(MI, AArch64_map_insn(IsSigned ? "sbfx" : "ubfx")); 226 227 if (MI->csh->detail) { 228 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 229 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0); 230 MI->flat_insn->detail->arm64.op_count++; 231 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 232 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op1); 233 MI->flat_insn->detail->arm64.op_count++; 234 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 235 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op2); 236 MI->flat_insn->detail->arm64.op_count++; 237 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 238 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op3) - MCOperand_getImm(Op2) + 1; 239 MI->flat_insn->detail->arm64.op_count++; 240 } 241 242 return; 243 } 244 245 if (Opcode == AArch64_BFMXri || Opcode == AArch64_BFMWri) { 246 MCOperand *Op0 = MCInst_getOperand(MI, 0); // Op1 == Op0 247 MCOperand *Op2 = MCInst_getOperand(MI, 2); 248 int ImmR = (int)MCOperand_getImm(MCInst_getOperand(MI, 3)); 249 int ImmS = (int)MCOperand_getImm(MCInst_getOperand(MI, 4)); 250 251 // BFI alias 252 if (ImmS < ImmR) { 253 int BitWidth = Opcode == AArch64_BFMXri ? 64 : 32; 254 LSB = (BitWidth - ImmR) % BitWidth; 255 Width = ImmS + 1; 256 257 SStream_concat(O, "bfi\t%s, %s, ", 258 getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName), 259 getRegisterName(MCOperand_getReg(Op2), AArch64_NoRegAltName)); 260 printInt32Bang(O, LSB); 261 SStream_concat0(O, ", "); 262 printInt32Bang(O, Width); 263 MCInst_setOpcodePub(MI, AArch64_map_insn("bfi")); 264 265 if (MI->csh->detail) { 266 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 267 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0); 268 MI->flat_insn->detail->arm64.op_count++; 269 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 270 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op2); 271 MI->flat_insn->detail->arm64.op_count++; 272 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 273 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = LSB; 274 MI->flat_insn->detail->arm64.op_count++; 275 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 276 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Width; 277 MI->flat_insn->detail->arm64.op_count++; 278 } 279 280 return; 281 } 282 283 LSB = ImmR; 284 Width = ImmS - ImmR + 1; 285 // Otherwise BFXIL the preferred form 286 SStream_concat(O, "bfxil\t%s, %s, ", 287 getRegisterName(MCOperand_getReg(Op0), AArch64_NoRegAltName), 288 getRegisterName(MCOperand_getReg(Op2), AArch64_NoRegAltName)); 289 printInt32Bang(O, LSB); 290 SStream_concat0(O, ", "); 291 printInt32Bang(O, Width); 292 MCInst_setOpcodePub(MI, AArch64_map_insn("bfxil")); 293 294 if (MI->csh->detail) { 295 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 296 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op0); 297 MI->flat_insn->detail->arm64.op_count++; 298 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 299 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(Op2); 300 MI->flat_insn->detail->arm64.op_count++; 301 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 302 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = LSB; 303 MI->flat_insn->detail->arm64.op_count++; 304 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 305 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Width; 306 MI->flat_insn->detail->arm64.op_count++; 307 } 308 309 return; 310 } 311 312 mnem = printAliasInstr(MI, O, Info); 313 if (mnem) { 314 MCInst_setOpcodePub(MI, AArch64_map_insn(mnem)); 315 cs_mem_free(mnem); 316 } else { 317 printInstruction(MI, O, Info); 318 } 319 } 320 321 static bool printSysAlias(MCInst *MI, SStream *O) 322 { 323 // unsigned Opcode = MCInst_getOpcode(MI); 324 //assert(Opcode == AArch64_SYSxt && "Invalid opcode for SYS alias!"); 325 326 char *Asm = NULL; 327 MCOperand *Op1 = MCInst_getOperand(MI, 0); 328 MCOperand *Cn = MCInst_getOperand(MI, 1); 329 MCOperand *Cm = MCInst_getOperand(MI, 2); 330 MCOperand *Op2 = MCInst_getOperand(MI, 3); 331 332 unsigned Op1Val = (unsigned)MCOperand_getImm(Op1); 333 unsigned CnVal = (unsigned)MCOperand_getImm(Cn); 334 unsigned CmVal = (unsigned)MCOperand_getImm(Cm); 335 unsigned Op2Val = (unsigned)MCOperand_getImm(Op2); 336 unsigned insn_id = ARM64_INS_INVALID; 337 unsigned op_ic = 0, op_dc = 0, op_at = 0, op_tlbi = 0; 338 339 if (CnVal == 7) { 340 switch (CmVal) { 341 default: 342 break; 343 344 // IC aliases 345 case 1: 346 if (Op1Val == 0 && Op2Val == 0) { 347 Asm = "ic\tialluis"; 348 insn_id = ARM64_INS_IC; 349 op_ic = ARM64_IC_IALLUIS; 350 } 351 break; 352 case 5: 353 if (Op1Val == 0 && Op2Val == 0) { 354 Asm = "ic\tiallu"; 355 insn_id = ARM64_INS_IC; 356 op_ic = ARM64_IC_IALLU; 357 } else if (Op1Val == 3 && Op2Val == 1) { 358 Asm = "ic\tivau"; 359 insn_id = ARM64_INS_IC; 360 op_ic = ARM64_IC_IVAU; 361 } 362 break; 363 364 // DC aliases 365 case 4: 366 if (Op1Val == 3 && Op2Val == 1) { 367 Asm = "dc\tzva"; 368 insn_id = ARM64_INS_DC; 369 op_dc = ARM64_DC_ZVA; 370 } 371 break; 372 case 6: 373 if (Op1Val == 0 && Op2Val == 1) { 374 Asm = "dc\tivac"; 375 insn_id = ARM64_INS_DC; 376 op_dc = ARM64_DC_IVAC; 377 } 378 if (Op1Val == 0 && Op2Val == 2) { 379 Asm = "dc\tisw"; 380 insn_id = ARM64_INS_DC; 381 op_dc = ARM64_DC_ISW; 382 } 383 break; 384 case 10: 385 if (Op1Val == 3 && Op2Val == 1) { 386 Asm = "dc\tcvac"; 387 insn_id = ARM64_INS_DC; 388 op_dc = ARM64_DC_CVAC; 389 } else if (Op1Val == 0 && Op2Val == 2) { 390 Asm = "dc\tcsw"; 391 insn_id = ARM64_INS_DC; 392 op_dc = ARM64_DC_CSW; 393 } 394 break; 395 case 11: 396 if (Op1Val == 3 && Op2Val == 1) { 397 Asm = "dc\tcvau"; 398 insn_id = ARM64_INS_DC; 399 op_dc = ARM64_DC_CVAU; 400 } 401 break; 402 case 14: 403 if (Op1Val == 3 && Op2Val == 1) { 404 Asm = "dc\tcivac"; 405 insn_id = ARM64_INS_DC; 406 op_dc = ARM64_DC_CIVAC; 407 } else if (Op1Val == 0 && Op2Val == 2) { 408 Asm = "dc\tcisw"; 409 insn_id = ARM64_INS_DC; 410 op_dc = ARM64_DC_CISW; 411 } 412 break; 413 414 // AT aliases 415 case 8: 416 switch (Op1Val) { 417 default: 418 break; 419 case 0: 420 switch (Op2Val) { 421 default: 422 break; 423 case 0: Asm = "at\ts1e1r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1R; break; 424 case 1: Asm = "at\ts1e1w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1W; break; 425 case 2: Asm = "at\ts1e0r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0R; break; 426 case 3: Asm = "at\ts1e0w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0W; break; 427 } 428 break; 429 case 4: 430 switch (Op2Val) { 431 default: 432 break; 433 case 0: Asm = "at\ts1e2r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E2R; break; 434 case 1: Asm = "at\ts1e2w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E2W; break; 435 case 4: Asm = "at\ts12e1r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1R; break; 436 case 5: Asm = "at\ts12e1w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E1W; break; 437 case 6: Asm = "at\ts12e0r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0R; break; 438 case 7: Asm = "at\ts12e0w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E0W; break; 439 } 440 break; 441 case 6: 442 switch (Op2Val) { 443 default: 444 break; 445 case 0: Asm = "at\ts1e3r"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E3R; break; 446 case 1: Asm = "at\ts1e3w"; insn_id = ARM64_INS_AT; op_at = ARM64_AT_S1E3W; break; 447 } 448 break; 449 } 450 break; 451 } 452 } else if (CnVal == 8) { 453 // TLBI aliases 454 switch (CmVal) { 455 default: 456 break; 457 case 3: 458 switch (Op1Val) { 459 default: 460 break; 461 case 0: 462 switch (Op2Val) { 463 default: 464 break; 465 case 0: Asm = "tlbi\tvmalle1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLE1IS; break; 466 case 1: Asm = "tlbi\tvae1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE1IS; break; 467 case 2: Asm = "tlbi\taside1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ASIDE1IS; break; 468 case 3: Asm = "tlbi\tvaae1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAAE1IS; break; 469 case 5: Asm = "tlbi\tvale1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE1IS; break; 470 case 7: Asm = "tlbi\tvaale1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAALE1IS; break; 471 } 472 break; 473 case 4: 474 switch (Op2Val) { 475 default: 476 break; 477 case 0: Asm = "tlbi\talle2is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE2IS; break; 478 case 1: Asm = "tlbi\tvae2is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE2IS; break; 479 case 4: Asm = "tlbi\talle1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE1IS; break; 480 case 5: Asm = "tlbi\tvale2is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE2IS; break; 481 case 6: Asm = "tlbi\tvmalls12e1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLS12E1IS; break; 482 } 483 break; 484 case 6: 485 switch (Op2Val) { 486 default: 487 break; 488 case 0: Asm = "tlbi\talle3is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE3IS; break; 489 case 1: Asm = "tlbi\tvae3is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE3IS; break; 490 case 5: Asm = "tlbi\tvale3is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE3IS; break; 491 } 492 break; 493 } 494 break; 495 case 0: 496 switch (Op1Val) { 497 default: 498 break; 499 case 4: 500 switch (Op2Val) { 501 default: 502 break; 503 case 1: Asm = "tlbi\tipas2e1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2E1IS; break; 504 case 5: Asm = "tlbi\tipas2le1is"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2LE1IS; break; 505 } 506 break; 507 } 508 break; 509 case 4: 510 switch (Op1Val) { 511 default: 512 break; 513 case 4: 514 switch (Op2Val) { 515 default: 516 break; 517 case 1: Asm = "tlbi\tipas2e1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2E1; break; 518 case 5: Asm = "tlbi\tipas2le1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_IPAS2LE1; break; 519 } 520 break; 521 } 522 break; 523 case 7: 524 switch (Op1Val) { 525 default: 526 break; 527 case 0: 528 switch (Op2Val) { 529 default: 530 break; 531 case 0: Asm = "tlbi\tvmalle1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLE1; break; 532 case 1: Asm = "tlbi\tvae1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE1; break; 533 case 2: Asm = "tlbi\taside1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ASIDE1; break; 534 case 3: Asm = "tlbi\tvaae1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAAE1; break; 535 case 5: Asm = "tlbi\tvale1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE1; break; 536 case 7: Asm = "tlbi\tvaale1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAALE1; break; 537 } 538 break; 539 case 4: 540 switch (Op2Val) { 541 default: 542 break; 543 case 0: Asm = "tlbi\talle2"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE2; break; 544 case 1: Asm = "tlbi\tvae2"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE2; break; 545 case 4: Asm = "tlbi\talle1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE1; break; 546 case 5: Asm = "tlbi\tvale2"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE2; break; 547 case 6: Asm = "tlbi\tvmalls12e1"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VMALLS12E1; break; 548 } 549 break; 550 case 6: 551 switch (Op2Val) { 552 default: 553 break; 554 case 0: Asm = "tlbi\talle3"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_ALLE3; break; 555 case 1: Asm = "tlbi\tvae3"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VAE3; break; 556 case 5: Asm = "tlbi\tvale3"; insn_id = ARM64_INS_TLBI; op_tlbi = ARM64_TLBI_VALE3; break; 557 } 558 break; 559 } 560 break; 561 } 562 } 563 564 if (Asm) { 565 MCInst_setOpcodePub(MI, insn_id); 566 SStream_concat0(O, Asm); 567 if (MI->csh->detail) { 568 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_SYS; 569 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].sys = op_ic + op_dc + op_at + op_tlbi; 570 MI->flat_insn->detail->arm64.op_count++; 571 } 572 573 if (!strstr(Asm, "all")) { 574 unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, 4)); 575 SStream_concat(O, ", %s", getRegisterName(Reg, AArch64_NoRegAltName)); 576 if (MI->csh->detail) { 577 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 578 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg; 579 MI->flat_insn->detail->arm64.op_count++; 580 } 581 } 582 } 583 584 return Asm != NULL; 585 } 586 587 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) 588 { 589 MCOperand *Op = MCInst_getOperand(MI, OpNo); 590 591 if (MCOperand_isReg(Op)) { 592 unsigned Reg = MCOperand_getReg(Op); 593 SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName)); 594 if (MI->csh->detail) { 595 if (MI->csh->doing_mem) { 596 if (MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.base == ARM64_REG_INVALID) { 597 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.base = Reg; 598 } 599 else if (MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.index == ARM64_REG_INVALID) { 600 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.index = Reg; 601 } 602 } else { 603 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 604 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg; 605 MI->flat_insn->detail->arm64.op_count++; 606 } 607 } 608 } else if (MCOperand_isImm(Op)) { 609 int64_t imm = MCOperand_getImm(Op); 610 611 if (MI->Opcode == AArch64_ADR) { 612 imm += MI->address; 613 printUInt64Bang(O, imm); 614 } else 615 printUInt64Bang(O, imm); 616 if (MI->csh->detail) { 617 if (MI->csh->doing_mem) { 618 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = (int32_t)imm; 619 } else { 620 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 621 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = imm; 622 MI->flat_insn->detail->arm64.op_count++; 623 } 624 } 625 } 626 } 627 628 static void printHexImm(MCInst *MI, unsigned OpNo, SStream *O) 629 { 630 MCOperand *Op = MCInst_getOperand(MI, OpNo); 631 SStream_concat(O, "#%#llx", MCOperand_getImm(Op)); 632 if (MI->csh->detail) { 633 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 634 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op); 635 MI->flat_insn->detail->arm64.op_count++; 636 } 637 } 638 639 static void printPostIncOperand(MCInst *MI, unsigned OpNo, 640 unsigned Imm, SStream *O) 641 { 642 MCOperand *Op = MCInst_getOperand(MI, OpNo); 643 644 if (MCOperand_isReg(Op)) { 645 unsigned Reg = MCOperand_getReg(Op); 646 if (Reg == AArch64_XZR) { 647 printInt32Bang(O, Imm); 648 if (MI->csh->detail) { 649 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 650 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Imm; 651 MI->flat_insn->detail->arm64.op_count++; 652 } 653 } else { 654 SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName)); 655 if (MI->csh->detail) { 656 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 657 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg; 658 MI->flat_insn->detail->arm64.op_count++; 659 } 660 } 661 } 662 //llvm_unreachable("unknown operand kind in printPostIncOperand64"); 663 } 664 665 static void printPostIncOperand2(MCInst *MI, unsigned OpNo, SStream *O, int Amount) 666 { 667 printPostIncOperand(MI, OpNo, Amount, O); 668 } 669 670 static void printVRegOperand(MCInst *MI, unsigned OpNo, SStream *O) 671 { 672 MCOperand *Op = MCInst_getOperand(MI, OpNo); 673 //assert(Op.isReg() && "Non-register vreg operand!"); 674 unsigned Reg = MCOperand_getReg(Op); 675 SStream_concat0(O, getRegisterName(Reg, AArch64_vreg)); 676 if (MI->csh->detail) { 677 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 678 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = AArch64_map_vregister(Reg); 679 MI->flat_insn->detail->arm64.op_count++; 680 } 681 } 682 683 static void printSysCROperand(MCInst *MI, unsigned OpNo, SStream *O) 684 { 685 MCOperand *Op = MCInst_getOperand(MI, OpNo); 686 //assert(Op.isImm() && "System instruction C[nm] operands must be immediates!"); 687 SStream_concat(O, "c%u", MCOperand_getImm(Op)); 688 if (MI->csh->detail) { 689 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_CIMM; 690 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = MCOperand_getImm(Op); 691 MI->flat_insn->detail->arm64.op_count++; 692 } 693 } 694 695 static void printAddSubImm(MCInst *MI, unsigned OpNum, SStream *O) 696 { 697 MCOperand *MO = MCInst_getOperand(MI, OpNum); 698 if (MCOperand_isImm(MO)) { 699 unsigned Val = (MCOperand_getImm(MO) & 0xfff); 700 //assert(Val == MO.getImm() && "Add/sub immediate out of range!"); 701 unsigned Shift = AArch64_AM_getShiftValue((int)MCOperand_getImm(MCInst_getOperand(MI, OpNum + 1))); 702 703 printInt32Bang(O, Val); 704 705 if (MI->csh->detail) { 706 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 707 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val; 708 MI->flat_insn->detail->arm64.op_count++; 709 } 710 711 if (Shift != 0) 712 printShifter(MI, OpNum + 1, O); 713 } 714 } 715 716 static void printLogicalImm32(MCInst *MI, unsigned OpNum, SStream *O) 717 { 718 int64_t Val = MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 719 720 Val = AArch64_AM_decodeLogicalImmediate(Val, 32); 721 printUInt32Bang(O, (int)Val); 722 723 if (MI->csh->detail) { 724 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 725 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val; 726 MI->flat_insn->detail->arm64.op_count++; 727 } 728 } 729 730 static void printLogicalImm64(MCInst *MI, unsigned OpNum, SStream *O) 731 { 732 int64_t Val = MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 733 Val = AArch64_AM_decodeLogicalImmediate(Val, 64); 734 735 switch(MI->flat_insn->id) { 736 default: 737 printInt64Bang(O, Val); 738 break; 739 case ARM64_INS_ORR: 740 case ARM64_INS_AND: 741 case ARM64_INS_EOR: 742 case ARM64_INS_TST: 743 // do not print number in negative form 744 if (Val >= 0 && Val <= HEX_THRESHOLD) 745 SStream_concat(O, "#%u", (int)Val); 746 else 747 SStream_concat(O, "#0x%"PRIx64, Val); 748 break; 749 } 750 751 if (MI->csh->detail) { 752 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 753 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val; 754 MI->flat_insn->detail->arm64.op_count++; 755 } 756 } 757 758 static void printShifter(MCInst *MI, unsigned OpNum, SStream *O) 759 { 760 unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 761 762 // LSL #0 should not be printed. 763 if (AArch64_AM_getShiftType(Val) == AArch64_AM_LSL && 764 AArch64_AM_getShiftValue(Val) == 0) 765 return; 766 767 SStream_concat(O, ", %s ", AArch64_AM_getShiftExtendName(AArch64_AM_getShiftType(Val))); 768 printInt32BangDec(O, AArch64_AM_getShiftValue(Val)); 769 if (MI->csh->detail) { 770 arm64_shifter shifter = ARM64_SFT_INVALID; 771 switch(AArch64_AM_getShiftType(Val)) { 772 default: // never reach 773 case AArch64_AM_LSL: 774 shifter = ARM64_SFT_LSL; 775 break; 776 case AArch64_AM_LSR: 777 shifter = ARM64_SFT_LSR; 778 break; 779 case AArch64_AM_ASR: 780 shifter = ARM64_SFT_ASR; 781 break; 782 case AArch64_AM_ROR: 783 shifter = ARM64_SFT_ROR; 784 break; 785 case AArch64_AM_MSL: 786 shifter = ARM64_SFT_MSL; 787 break; 788 } 789 790 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.type = shifter; 791 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.value = AArch64_AM_getShiftValue(Val); 792 } 793 } 794 795 static void printShiftedRegister(MCInst *MI, unsigned OpNum, SStream *O) 796 { 797 SStream_concat0(O, getRegisterName(MCOperand_getReg(MCInst_getOperand(MI, OpNum)), AArch64_NoRegAltName)); 798 if (MI->csh->detail) { 799 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 800 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = MCOperand_getReg(MCInst_getOperand(MI, OpNum)); 801 MI->flat_insn->detail->arm64.op_count++; 802 } 803 printShifter(MI, OpNum + 1, O); 804 } 805 806 static void printArithExtend(MCInst *MI, unsigned OpNum, SStream *O) 807 { 808 unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 809 AArch64_AM_ShiftExtendType ExtType = AArch64_AM_getArithExtendType(Val); 810 unsigned ShiftVal = AArch64_AM_getArithShiftValue(Val); 811 812 // If the destination or first source register operand is [W]SP, print 813 // UXTW/UXTX as LSL, and if the shift amount is also zero, print nothing at 814 // all. 815 if (ExtType == AArch64_AM_UXTW || ExtType == AArch64_AM_UXTX) { 816 unsigned Dest = MCOperand_getReg(MCInst_getOperand(MI, 0)); 817 unsigned Src1 = MCOperand_getReg(MCInst_getOperand(MI, 1)); 818 if ( ((Dest == AArch64_SP || Src1 == AArch64_SP) && 819 ExtType == AArch64_AM_UXTX) || 820 ((Dest == AArch64_WSP || Src1 == AArch64_WSP) && 821 ExtType == AArch64_AM_UXTW) ) { 822 if (ShiftVal != 0) { 823 SStream_concat0(O, ", lsl "); 824 printInt32Bang(O, ShiftVal); 825 if (MI->csh->detail) { 826 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.type = ARM64_SFT_LSL; 827 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.value = ShiftVal; 828 } 829 } 830 831 return; 832 } 833 } 834 835 SStream_concat(O, ", %s", AArch64_AM_getShiftExtendName(ExtType)); 836 if (MI->csh->detail) { 837 arm64_extender ext = ARM64_EXT_INVALID; 838 switch(ExtType) { 839 default: // never reach 840 case AArch64_AM_UXTB: 841 ext = ARM64_EXT_UXTB; 842 break; 843 case AArch64_AM_UXTH: 844 ext = ARM64_EXT_UXTH; 845 break; 846 case AArch64_AM_UXTW: 847 ext = ARM64_EXT_UXTW; 848 break; 849 case AArch64_AM_UXTX: 850 ext = ARM64_EXT_UXTX; 851 break; 852 case AArch64_AM_SXTB: 853 ext = ARM64_EXT_SXTB; 854 break; 855 case AArch64_AM_SXTH: 856 ext = ARM64_EXT_SXTH; 857 break; 858 case AArch64_AM_SXTW: 859 ext = ARM64_EXT_SXTW; 860 break; 861 case AArch64_AM_SXTX: 862 ext = ARM64_EXT_SXTX; 863 break; 864 } 865 866 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].ext = ext; 867 } 868 869 if (ShiftVal != 0) { 870 SStream_concat0(O, " "); 871 printInt32Bang(O, ShiftVal); 872 if (MI->csh->detail) { 873 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.type = ARM64_SFT_LSL; 874 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].shift.value = ShiftVal; 875 } 876 } 877 } 878 879 static void printExtendedRegister(MCInst *MI, unsigned OpNum, SStream *O) 880 { 881 unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, OpNum)); 882 883 SStream_concat0(O, getRegisterName(Reg, AArch64_NoRegAltName)); 884 if (MI->csh->detail) { 885 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 886 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Reg; 887 MI->flat_insn->detail->arm64.op_count++; 888 } 889 890 printArithExtend(MI, OpNum + 1, O); 891 } 892 893 static void printMemExtend(MCInst *MI, unsigned OpNum, SStream *O, char SrcRegKind, unsigned Width) 894 { 895 unsigned SignExtend = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 896 unsigned DoShift = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum + 1)); 897 898 // sxtw, sxtx, uxtw or lsl (== uxtx) 899 bool IsLSL = !SignExtend && SrcRegKind == 'x'; 900 if (IsLSL) { 901 SStream_concat0(O, "lsl"); 902 if (MI->csh->detail) { 903 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].shift.type = ARM64_SFT_LSL; 904 } 905 } else { 906 SStream_concat(O, "%cxt%c", (SignExtend ? 's' : 'u'), SrcRegKind); 907 if (MI->csh->detail) { 908 if (!SignExtend) { 909 switch(SrcRegKind) { 910 default: break; 911 case 'b': 912 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTB; 913 break; 914 case 'h': 915 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTH; 916 break; 917 case 'w': 918 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_UXTW; 919 break; 920 } 921 } else { 922 switch(SrcRegKind) { 923 default: break; 924 case 'b': 925 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTB; 926 break; 927 case 'h': 928 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTH; 929 break; 930 case 'w': 931 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTW; 932 break; 933 case 'x': 934 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].ext = ARM64_EXT_SXTX; 935 break; 936 } 937 } 938 } 939 } 940 941 if (DoShift || IsLSL) { 942 SStream_concat(O, " #%u", Log2_32(Width / 8)); 943 if (MI->csh->detail) { 944 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].shift.type = ARM64_SFT_LSL; 945 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].shift.value = Log2_32(Width / 8); 946 } 947 } 948 } 949 950 static void printCondCode(MCInst *MI, unsigned OpNum, SStream *O) 951 { 952 A64CC_CondCode CC = (A64CC_CondCode)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 953 SStream_concat0(O, getCondCodeName(CC)); 954 955 if (MI->csh->detail) 956 MI->flat_insn->detail->arm64.cc = (arm64_cc)(CC + 1); 957 } 958 959 static void printInverseCondCode(MCInst *MI, unsigned OpNum, SStream *O) 960 { 961 A64CC_CondCode CC = (A64CC_CondCode)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 962 SStream_concat0(O, getCondCodeName(getInvertedCondCode(CC))); 963 964 if (MI->csh->detail) { 965 MI->flat_insn->detail->arm64.cc = (arm64_cc)(getInvertedCondCode(CC) + 1); 966 } 967 } 968 969 static void printImmScale(MCInst *MI, unsigned OpNum, SStream *O, int Scale) 970 { 971 int64_t val = Scale * MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 972 973 printInt64Bang(O, val); 974 975 if (MI->csh->detail) { 976 if (MI->csh->doing_mem) { 977 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = val; 978 } else { 979 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 980 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = val; 981 MI->flat_insn->detail->arm64.op_count++; 982 } 983 } 984 } 985 986 static void printUImm12Offset(MCInst *MI, unsigned OpNum, unsigned Scale, SStream *O) 987 { 988 MCOperand *MO = MCInst_getOperand(MI, OpNum); 989 990 if (MCOperand_isImm(MO)) { 991 int64_t val = Scale * MCOperand_getImm(MO); 992 printInt64Bang(O, val); 993 if (MI->csh->detail) { 994 if (MI->csh->doing_mem) { 995 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].mem.disp = val; 996 } else { 997 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 998 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = val; 999 MI->flat_insn->detail->arm64.op_count++; 1000 } 1001 } 1002 } 1003 } 1004 1005 static void printUImm12Offset2(MCInst *MI, unsigned OpNum, SStream *O, int Scale) 1006 { 1007 printUImm12Offset(MI, OpNum, Scale, O); 1008 } 1009 1010 static void printPrefetchOp(MCInst *MI, unsigned OpNum, SStream *O) 1011 { 1012 unsigned prfop = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 1013 bool Valid; 1014 char *Name = A64NamedImmMapper_toString(&A64PRFM_PRFMMapper, prfop, &Valid); 1015 1016 if (Valid) { 1017 SStream_concat0(O, Name); 1018 if (MI->csh->detail) { 1019 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_PREFETCH; 1020 // we have to plus 1 to prfop because 0 is a valid value of prfop 1021 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].prefetch = prfop + 1; 1022 MI->flat_insn->detail->arm64.op_count++; 1023 } 1024 } else { 1025 printInt32Bang(O, prfop); 1026 if (MI->csh->detail) { 1027 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 1028 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = prfop; 1029 MI->flat_insn->detail->arm64.op_count++; 1030 } 1031 } 1032 } 1033 1034 static void printFPImmOperand(MCInst *MI, unsigned OpNum, SStream *O) 1035 { 1036 MCOperand *MO = MCInst_getOperand(MI, OpNum); 1037 double FPImm = MCOperand_isFPImm(MO) ? MCOperand_getFPImm(MO) : AArch64_AM_getFPImmFloat((int)MCOperand_getImm(MO)); 1038 1039 // 8 decimal places are enough to perfectly represent permitted floats. 1040 #if defined(_KERNEL_MODE) 1041 // Issue #681: Windows kernel does not support formatting float point 1042 SStream_concat(O, "#<float_point_unsupported>"); 1043 #else 1044 SStream_concat(O, "#%.8f", FPImm); 1045 #endif 1046 if (MI->csh->detail) { 1047 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_FP; 1048 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].fp = FPImm; 1049 MI->flat_insn->detail->arm64.op_count++; 1050 } 1051 } 1052 1053 //static unsigned getNextVectorRegister(unsigned Reg, unsigned Stride = 1) 1054 static unsigned getNextVectorRegister(unsigned Reg, unsigned Stride) 1055 { 1056 while (Stride--) { 1057 switch (Reg) { 1058 default: 1059 // llvm_unreachable("Vector register expected!"); 1060 case AArch64_Q0: Reg = AArch64_Q1; break; 1061 case AArch64_Q1: Reg = AArch64_Q2; break; 1062 case AArch64_Q2: Reg = AArch64_Q3; break; 1063 case AArch64_Q3: Reg = AArch64_Q4; break; 1064 case AArch64_Q4: Reg = AArch64_Q5; break; 1065 case AArch64_Q5: Reg = AArch64_Q6; break; 1066 case AArch64_Q6: Reg = AArch64_Q7; break; 1067 case AArch64_Q7: Reg = AArch64_Q8; break; 1068 case AArch64_Q8: Reg = AArch64_Q9; break; 1069 case AArch64_Q9: Reg = AArch64_Q10; break; 1070 case AArch64_Q10: Reg = AArch64_Q11; break; 1071 case AArch64_Q11: Reg = AArch64_Q12; break; 1072 case AArch64_Q12: Reg = AArch64_Q13; break; 1073 case AArch64_Q13: Reg = AArch64_Q14; break; 1074 case AArch64_Q14: Reg = AArch64_Q15; break; 1075 case AArch64_Q15: Reg = AArch64_Q16; break; 1076 case AArch64_Q16: Reg = AArch64_Q17; break; 1077 case AArch64_Q17: Reg = AArch64_Q18; break; 1078 case AArch64_Q18: Reg = AArch64_Q19; break; 1079 case AArch64_Q19: Reg = AArch64_Q20; break; 1080 case AArch64_Q20: Reg = AArch64_Q21; break; 1081 case AArch64_Q21: Reg = AArch64_Q22; break; 1082 case AArch64_Q22: Reg = AArch64_Q23; break; 1083 case AArch64_Q23: Reg = AArch64_Q24; break; 1084 case AArch64_Q24: Reg = AArch64_Q25; break; 1085 case AArch64_Q25: Reg = AArch64_Q26; break; 1086 case AArch64_Q26: Reg = AArch64_Q27; break; 1087 case AArch64_Q27: Reg = AArch64_Q28; break; 1088 case AArch64_Q28: Reg = AArch64_Q29; break; 1089 case AArch64_Q29: Reg = AArch64_Q30; break; 1090 case AArch64_Q30: Reg = AArch64_Q31; break; 1091 // Vector lists can wrap around. 1092 case AArch64_Q31: Reg = AArch64_Q0; break; 1093 } 1094 } 1095 1096 return Reg; 1097 } 1098 1099 static void printVectorList(MCInst *MI, unsigned OpNum, SStream *O, char *LayoutSuffix, MCRegisterInfo *MRI, arm64_vas vas, arm64_vess vess) 1100 { 1101 #define GETREGCLASS_CONTAIN0(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), _reg) 1102 1103 unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, OpNum)); 1104 unsigned NumRegs = 1, FirstReg, i; 1105 1106 SStream_concat0(O, "{"); 1107 1108 // Work out how many registers there are in the list (if there is an actual 1109 // list). 1110 if (GETREGCLASS_CONTAIN0(AArch64_DDRegClassID , Reg) || 1111 GETREGCLASS_CONTAIN0(AArch64_QQRegClassID, Reg)) 1112 NumRegs = 2; 1113 else if (GETREGCLASS_CONTAIN0(AArch64_DDDRegClassID, Reg) || 1114 GETREGCLASS_CONTAIN0(AArch64_QQQRegClassID, Reg)) 1115 NumRegs = 3; 1116 else if (GETREGCLASS_CONTAIN0(AArch64_DDDDRegClassID, Reg) || 1117 GETREGCLASS_CONTAIN0(AArch64_QQQQRegClassID, Reg)) 1118 NumRegs = 4; 1119 1120 // Now forget about the list and find out what the first register is. 1121 if ((FirstReg = MCRegisterInfo_getSubReg(MRI, Reg, AArch64_dsub0))) 1122 Reg = FirstReg; 1123 else if ((FirstReg = MCRegisterInfo_getSubReg(MRI, Reg, AArch64_qsub0))) 1124 Reg = FirstReg; 1125 1126 // If it's a D-reg, we need to promote it to the equivalent Q-reg before 1127 // printing (otherwise getRegisterName fails). 1128 if (GETREGCLASS_CONTAIN0(AArch64_FPR64RegClassID, Reg)) { 1129 MCRegisterClass *FPR128RC = MCRegisterInfo_getRegClass(MRI, AArch64_FPR128RegClassID); 1130 Reg = MCRegisterInfo_getMatchingSuperReg(MRI, Reg, AArch64_dsub, FPR128RC); 1131 } 1132 1133 for (i = 0; i < NumRegs; ++i, Reg = getNextVectorRegister(Reg, 1)) { 1134 SStream_concat(O, "%s%s", getRegisterName(Reg, AArch64_vreg), LayoutSuffix); 1135 if (i + 1 != NumRegs) 1136 SStream_concat0(O, ", "); 1137 if (MI->csh->detail) { 1138 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG; 1139 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = AArch64_map_vregister(Reg); 1140 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].vas = vas; 1141 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].vess = vess; 1142 MI->flat_insn->detail->arm64.op_count++; 1143 } 1144 } 1145 1146 SStream_concat0(O, "}"); 1147 } 1148 1149 static void printTypedVectorList(MCInst *MI, unsigned OpNum, SStream *O, unsigned NumLanes, char LaneKind, MCRegisterInfo *MRI) 1150 { 1151 char Suffix[32]; 1152 arm64_vas vas = 0; 1153 arm64_vess vess = 0; 1154 1155 if (NumLanes) { 1156 cs_snprintf(Suffix, sizeof(Suffix), ".%u%c", NumLanes, LaneKind); 1157 switch(LaneKind) { 1158 default: break; 1159 case 'b': 1160 switch(NumLanes) { 1161 default: break; 1162 case 8: 1163 vas = ARM64_VAS_8B; 1164 break; 1165 case 16: 1166 vas = ARM64_VAS_16B; 1167 break; 1168 } 1169 break; 1170 case 'h': 1171 switch(NumLanes) { 1172 default: break; 1173 case 4: 1174 vas = ARM64_VAS_4H; 1175 break; 1176 case 8: 1177 vas = ARM64_VAS_8H; 1178 break; 1179 } 1180 break; 1181 case 's': 1182 switch(NumLanes) { 1183 default: break; 1184 case 2: 1185 vas = ARM64_VAS_2S; 1186 break; 1187 case 4: 1188 vas = ARM64_VAS_4S; 1189 break; 1190 } 1191 break; 1192 case 'd': 1193 switch(NumLanes) { 1194 default: break; 1195 case 1: 1196 vas = ARM64_VAS_1D; 1197 break; 1198 case 2: 1199 vas = ARM64_VAS_2D; 1200 break; 1201 } 1202 break; 1203 case 'q': 1204 switch(NumLanes) { 1205 default: break; 1206 case 1: 1207 vas = ARM64_VAS_1Q; 1208 break; 1209 } 1210 break; 1211 } 1212 } else { 1213 cs_snprintf(Suffix, sizeof(Suffix), ".%c", LaneKind); 1214 switch(LaneKind) { 1215 default: break; 1216 case 'b': 1217 vess = ARM64_VESS_B; 1218 break; 1219 case 'h': 1220 vess = ARM64_VESS_H; 1221 break; 1222 case 's': 1223 vess = ARM64_VESS_S; 1224 break; 1225 case 'd': 1226 vess = ARM64_VESS_D; 1227 break; 1228 } 1229 } 1230 1231 printVectorList(MI, OpNum, O, Suffix, MRI, vas, vess); 1232 } 1233 1234 static void printVectorIndex(MCInst *MI, unsigned OpNum, SStream *O) 1235 { 1236 SStream_concat0(O, "["); 1237 printInt32(O, (int)MCOperand_getImm(MCInst_getOperand(MI, OpNum))); 1238 SStream_concat0(O, "]"); 1239 if (MI->csh->detail) { 1240 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count - 1].vector_index = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNum)); 1241 } 1242 } 1243 1244 static void printAlignedLabel(MCInst *MI, unsigned OpNum, SStream *O) 1245 { 1246 MCOperand *Op = MCInst_getOperand(MI, OpNum); 1247 1248 // If the label has already been resolved to an immediate offset (say, when 1249 // we're running the disassembler), just print the immediate. 1250 if (MCOperand_isImm(Op)) { 1251 uint64_t imm = (MCOperand_getImm(Op) << 2) + MI->address; 1252 printUInt64Bang(O, imm); 1253 if (MI->csh->detail) { 1254 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 1255 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = imm; 1256 MI->flat_insn->detail->arm64.op_count++; 1257 } 1258 return; 1259 } 1260 } 1261 1262 static void printAdrpLabel(MCInst *MI, unsigned OpNum, SStream *O) 1263 { 1264 MCOperand *Op = MCInst_getOperand(MI, OpNum); 1265 1266 if (MCOperand_isImm(Op)) { 1267 // ADRP sign extends a 21-bit offset, shifts it left by 12 1268 // and adds it to the value of the PC with its bottom 12 bits cleared 1269 uint64_t imm = (MCOperand_getImm(Op) << 12) + (MI->address & ~0xfff); 1270 if (imm > HEX_THRESHOLD) 1271 SStream_concat(O, "#0x%"PRIx64, imm); 1272 else 1273 SStream_concat(O, "#%"PRIu64, imm); 1274 1275 if (MI->csh->detail) { 1276 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 1277 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = imm; 1278 MI->flat_insn->detail->arm64.op_count++; 1279 } 1280 return; 1281 } 1282 } 1283 1284 static void printBarrierOption(MCInst *MI, unsigned OpNo, SStream *O) 1285 { 1286 unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 1287 unsigned Opcode = MCInst_getOpcode(MI); 1288 bool Valid; 1289 char *Name; 1290 1291 if (Opcode == AArch64_ISB) 1292 Name = A64NamedImmMapper_toString(&A64ISB_ISBMapper, Val, &Valid); 1293 else 1294 Name = A64NamedImmMapper_toString(&A64DB_DBarrierMapper, Val, &Valid); 1295 1296 if (Valid) { 1297 SStream_concat0(O, Name); 1298 if (MI->csh->detail) { 1299 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_BARRIER; 1300 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].barrier = Val; 1301 MI->flat_insn->detail->arm64.op_count++; 1302 } 1303 } else { 1304 printUInt32Bang(O, Val); 1305 if (MI->csh->detail) { 1306 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 1307 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val; 1308 MI->flat_insn->detail->arm64.op_count++; 1309 } 1310 } 1311 } 1312 1313 static void printMRSSystemRegister(MCInst *MI, unsigned OpNo, SStream *O) 1314 { 1315 unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 1316 bool Valid; 1317 char Name[128]; 1318 1319 A64SysRegMapper_toString(&AArch64_MRSMapper, Val, &Valid, Name); 1320 1321 if (Valid) { 1322 SStream_concat0(O, Name); 1323 if (MI->csh->detail) { 1324 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG_MRS; 1325 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Val; 1326 MI->flat_insn->detail->arm64.op_count++; 1327 } 1328 } 1329 } 1330 1331 static void printMSRSystemRegister(MCInst *MI, unsigned OpNo, SStream *O) 1332 { 1333 unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 1334 bool Valid; 1335 char Name[128]; 1336 1337 A64SysRegMapper_toString(&AArch64_MSRMapper, Val, &Valid, Name); 1338 1339 if (Valid) { 1340 SStream_concat0(O, Name); 1341 if (MI->csh->detail) { 1342 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_REG_MSR; 1343 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].reg = Val; 1344 MI->flat_insn->detail->arm64.op_count++; 1345 } 1346 } 1347 } 1348 1349 static void printSystemPStateField(MCInst *MI, unsigned OpNo, SStream *O) 1350 { 1351 unsigned Val = (unsigned)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 1352 bool Valid; 1353 char *Name; 1354 1355 Name = A64NamedImmMapper_toString(&A64PState_PStateMapper, Val, &Valid); 1356 if (Valid) { 1357 SStream_concat0(O, Name); 1358 if (MI->csh->detail) { 1359 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_PSTATE; 1360 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].pstate = Val; 1361 MI->flat_insn->detail->arm64.op_count++; 1362 } 1363 } else { 1364 printInt32Bang(O, Val); 1365 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 1366 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val; 1367 MI->flat_insn->detail->arm64.op_count++; 1368 } 1369 } 1370 1371 static void printSIMDType10Operand(MCInst *MI, unsigned OpNo, SStream *O) 1372 { 1373 uint8_t RawVal = (uint8_t)MCOperand_getImm(MCInst_getOperand(MI, OpNo)); 1374 uint64_t Val = AArch64_AM_decodeAdvSIMDModImmType10(RawVal); 1375 SStream_concat(O, "#%#016llx", Val); 1376 if (MI->csh->detail) { 1377 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].type = ARM64_OP_IMM; 1378 MI->flat_insn->detail->arm64.operands[MI->flat_insn->detail->arm64.op_count].imm = Val; 1379 MI->flat_insn->detail->arm64.op_count++; 1380 } 1381 } 1382 1383 1384 #define PRINT_ALIAS_INSTR 1385 #include "AArch64GenAsmWriter.inc" 1386 1387 void AArch64_post_printer(csh handle, cs_insn *flat_insn, char *insn_asm, MCInst *mci) 1388 { 1389 if (((cs_struct *)handle)->detail != CS_OPT_ON) 1390 return; 1391 1392 // check if this insn requests write-back 1393 if (strrchr(insn_asm, '!') != NULL) 1394 flat_insn->detail->arm64.writeback = true; 1395 } 1396 1397 #endif 1398