• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
set_mem_access(MCInst * MI,bool status)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 
AArch64_printInst(MCInst * MI,SStream * O,void * Info)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 
printSysAlias(MCInst * MI,SStream * O)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 
printOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printHexImm(MCInst * MI,unsigned OpNo,SStream * O)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 
printPostIncOperand(MCInst * MI,unsigned OpNo,unsigned Imm,SStream * O)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 
printPostIncOperand2(MCInst * MI,unsigned OpNo,SStream * O,int Amount)665 static void printPostIncOperand2(MCInst *MI, unsigned OpNo, SStream *O, int Amount)
666 {
667 	printPostIncOperand(MI, OpNo, Amount, O);
668 }
669 
printVRegOperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printSysCROperand(MCInst * MI,unsigned OpNo,SStream * O)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 
printAddSubImm(MCInst * MI,unsigned OpNum,SStream * O)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 
printLogicalImm32(MCInst * MI,unsigned OpNum,SStream * O)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 
printLogicalImm64(MCInst * MI,unsigned OpNum,SStream * O)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 
printShifter(MCInst * MI,unsigned OpNum,SStream * O)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 
printShiftedRegister(MCInst * MI,unsigned OpNum,SStream * O)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 
printArithExtend(MCInst * MI,unsigned OpNum,SStream * O)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 
printExtendedRegister(MCInst * MI,unsigned OpNum,SStream * O)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 
printMemExtend(MCInst * MI,unsigned OpNum,SStream * O,char SrcRegKind,unsigned Width)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 
printCondCode(MCInst * MI,unsigned OpNum,SStream * O)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 
printInverseCondCode(MCInst * MI,unsigned OpNum,SStream * O)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 
printImmScale(MCInst * MI,unsigned OpNum,SStream * O,int Scale)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 
printUImm12Offset(MCInst * MI,unsigned OpNum,unsigned Scale,SStream * O)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 
printUImm12Offset2(MCInst * MI,unsigned OpNum,SStream * O,int Scale)1005 static void printUImm12Offset2(MCInst *MI, unsigned OpNum, SStream *O, int Scale)
1006 {
1007 	printUImm12Offset(MI, OpNum, Scale, O);
1008 }
1009 
printPrefetchOp(MCInst * MI,unsigned OpNum,SStream * O)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 
printFPImmOperand(MCInst * MI,unsigned OpNum,SStream * O)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)
getNextVectorRegister(unsigned Reg,unsigned Stride)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 
printVectorList(MCInst * MI,unsigned OpNum,SStream * O,char * LayoutSuffix,MCRegisterInfo * MRI,arm64_vas vas,arm64_vess vess)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 
printTypedVectorList(MCInst * MI,unsigned OpNum,SStream * O,unsigned NumLanes,char LaneKind,MCRegisterInfo * MRI)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 
printVectorIndex(MCInst * MI,unsigned OpNum,SStream * O)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 
printAlignedLabel(MCInst * MI,unsigned OpNum,SStream * O)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 
printAdrpLabel(MCInst * MI,unsigned OpNum,SStream * O)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 
printBarrierOption(MCInst * MI,unsigned OpNo,SStream * O)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 
printMRSSystemRegister(MCInst * MI,unsigned OpNo,SStream * O)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 
printMSRSystemRegister(MCInst * MI,unsigned OpNo,SStream * O)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 
printSystemPStateField(MCInst * MI,unsigned OpNo,SStream * O)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 
printSIMDType10Operand(MCInst * MI,unsigned OpNo,SStream * O)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 
AArch64_post_printer(csh handle,cs_insn * flat_insn,char * insn_asm,MCInst * mci)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