VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmCore-armv8.cpp@ 106618

Last change on this file since 106618 was 106618, checked in by vboxsync, 5 weeks ago

Disassembler: Get rid of fClass member and convert the only real use to a decoder step, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.0 KB
Line 
1/* $Id: DisasmCore-armv8.cpp 106618 2024-10-23 11:59:34Z vboxsync $ */
2/** @file
3 * VBox Disassembler - Core Components.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DIS
33#include <VBox/dis.h>
34#include <VBox/log.h>
35#include <iprt/asm.h> /* Required to get Armv8A64ConvertImmRImmS2Mask64() from armv8.h. */
36#include <iprt/armv8.h>
37#include <iprt/assert.h>
38#include <iprt/errcore.h>
39#include <iprt/param.h>
40#include <iprt/string.h>
41#include <iprt/stdarg.h>
42#include "DisasmInternal-armv8.h"
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48
49/** Parser callback.
50 * @remark no DECLCALLBACK() here because it's considered to be internal and
51 * there is no point in enforcing CDECL. */
52typedef int FNDISPARSEARMV8(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit);
53/** Pointer to a disassembler parser function. */
54typedef FNDISPARSEARMV8 *PFNDISPARSEARMV8;
55
56
57/** Opcode decoder callback.
58 * @remark no DECLCALLBACK() here because it's considered to be internal and
59 * there is no point in enforcing CDECL. */
60typedef uint32_t FNDISDECODEARMV8(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass);
61/** Pointer to a disassembler parser function. */
62typedef FNDISDECODEARMV8 *PFNDISDECODEARMV8;
63
64
65/*********************************************************************************************************************************
66* Defined Constants And Macros *
67*********************************************************************************************************************************/
68
69
70/*********************************************************************************************************************************
71* Internal Functions *
72*********************************************************************************************************************************/
73/** @name Parsers
74 * @{ */
75static FNDISPARSEARMV8 disArmV8ParseIllegal;
76static FNDISPARSEARMV8 disArmV8ParseSize;
77static FNDISPARSEARMV8 disArmV8ParseImm;
78static FNDISPARSEARMV8 disArmV8ParseImmRel;
79static FNDISPARSEARMV8 disArmV8ParseImmAdr;
80static FNDISPARSEARMV8 disArmV8ParseImmZero;
81static FNDISPARSEARMV8 disArmV8ParseGprZr;
82static FNDISPARSEARMV8 disArmV8ParseGprSp;
83static FNDISPARSEARMV8 disArmV8ParseGprOff;
84static FNDISPARSEARMV8 disArmV8ParseImmsImmrN;
85static FNDISPARSEARMV8 disArmV8ParseHw;
86static FNDISPARSEARMV8 disArmV8ParseCond;
87static FNDISPARSEARMV8 disArmV8ParsePState;
88static FNDISPARSEARMV8 disArmV8ParseSysReg;
89static FNDISPARSEARMV8 disArmV8ParseSh12;
90static FNDISPARSEARMV8 disArmV8ParseImmTbz;
91static FNDISPARSEARMV8 disArmV8ParseShift;
92static FNDISPARSEARMV8 disArmV8ParseShiftAmount;
93static FNDISPARSEARMV8 disArmV8ParseImmMemOff;
94static FNDISPARSEARMV8 disArmV8ParseSImmMemOff;
95static FNDISPARSEARMV8 disArmV8ParseSImmMemOffUnscaled;
96static FNDISPARSEARMV8 disArmV8ParseOption;
97static FNDISPARSEARMV8 disArmV8ParseS;
98static FNDISPARSEARMV8 disArmV8ParseSetPreIndexed;
99static FNDISPARSEARMV8 disArmV8ParseSetPostIndexed;
100static FNDISPARSEARMV8 disArmV8ParseFpType;
101static FNDISPARSEARMV8 disArmV8ParseFpReg;
102static FNDISPARSEARMV8 disArmV8ParseFpScale;
103static FNDISPARSEARMV8 disArmV8ParseFpFixupFCvt;
104static FNDISPARSEARMV8 disArmV8ParseSimdRegScalar;
105static FNDISPARSEARMV8 disArmV8ParseImmHImmB;
106static FNDISPARSEARMV8 disArmV8ParseSf;
107/** @} */
108
109
110/** @name Decoders
111 * @{ */
112static FNDISDECODEARMV8 disArmV8DecodeIllegal;
113static FNDISDECODEARMV8 disArmV8DecodeLookup;
114static FNDISDECODEARMV8 disArmV8DecodeCollate;
115/** @} */
116
117
118/*********************************************************************************************************************************
119* Global Variables *
120*********************************************************************************************************************************/
121/** Parser opcode table for full disassembly. */
122static PFNDISPARSEARMV8 const g_apfnDisasm[kDisParmParseMax] =
123{
124 disArmV8ParseIllegal,
125 disArmV8ParseSize,
126 disArmV8ParseImm,
127 disArmV8ParseImmRel,
128 disArmV8ParseImmAdr,
129 disArmV8ParseImmZero,
130 disArmV8ParseGprZr,
131 disArmV8ParseGprSp,
132 disArmV8ParseGprOff,
133 disArmV8ParseImmsImmrN,
134 disArmV8ParseHw,
135 disArmV8ParseCond,
136 disArmV8ParsePState,
137 NULL,
138 disArmV8ParseSysReg,
139 disArmV8ParseSh12,
140 disArmV8ParseImmTbz,
141 disArmV8ParseShift,
142 disArmV8ParseShiftAmount,
143 disArmV8ParseImmMemOff,
144 disArmV8ParseSImmMemOff,
145 disArmV8ParseSImmMemOffUnscaled,
146 disArmV8ParseOption,
147 disArmV8ParseS,
148 disArmV8ParseSetPreIndexed,
149 disArmV8ParseSetPostIndexed,
150 disArmV8ParseFpType,
151 disArmV8ParseFpReg,
152 disArmV8ParseFpScale,
153 disArmV8ParseFpFixupFCvt,
154 disArmV8ParseSimdRegScalar,
155 disArmV8ParseImmHImmB,
156 disArmV8ParseSf
157};
158
159
160/** Opcode decoder table. */
161static PFNDISDECODEARMV8 const g_apfnOpcDecode[kDisArmV8OpcDecodeMax] =
162{
163 disArmV8DecodeIllegal,
164 disArmV8DecodeLookup,
165 disArmV8DecodeCollate
166};
167
168
169DECLINLINE(uint32_t) disArmV8ExtractBitVecFromInsn(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
170{
171 uint32_t fMask = (uint32_t)(RT_BIT_64(idxBitStart + cBits) - 1);
172 return (u32Insn & fMask) >> idxBitStart;
173}
174
175
176DECLINLINE(int32_t) disArmV8ExtractBitVecFromInsnSignExtend(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
177{
178 uint32_t fMask = RT_BIT_32(idxBitStart + cBits) - 1;
179 uint32_t fSign = ~(UINT32_MAX & (RT_BIT_32(cBits - 1) - 1));
180 uint32_t fValue = (u32Insn & fMask) >> idxBitStart;
181 if (fValue & fSign)
182 return (int32_t)(fValue | fSign);
183
184 return (int32_t)fValue;
185}
186
187
188static int disArmV8ParseIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
189{
190 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
191 AssertFailed();
192 return VERR_INTERNAL_ERROR;
193}
194
195
196static int disArmV8ParseSize(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
197{
198 RT_NOREF(pInsnClass, pParam);
199
200 Assert(pInsnParm->cBits == 2);
201 uint32_t u32Size = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
202 switch (u32Size)
203 {
204 case 0: pDis->armv8.cbOperand = sizeof(uint8_t); break;
205 case 1: pDis->armv8.cbOperand = sizeof(uint16_t); break;
206 case 2: pDis->armv8.cbOperand = sizeof(uint32_t); break;
207 case 3: pDis->armv8.cbOperand = sizeof(uint64_t); break;
208 default:
209 AssertReleaseFailed();
210 }
211 *pf64Bit = pDis->armv8.cbOperand == sizeof(uint64_t)
212 || (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT);
213 return VINF_SUCCESS;
214}
215
216
217static int disArmV8ParseImm(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
218{
219 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
220
221 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
222
223 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
224 if (pInsnParm->cBits <= 8)
225 {
226 pParam->armv8.cb = sizeof(uint8_t);
227 pParam->fUse |= DISUSE_IMMEDIATE8;
228 }
229 else if (pInsnParm->cBits <= 16)
230 {
231 pParam->armv8.cb = sizeof(uint16_t);
232 pParam->fUse |= DISUSE_IMMEDIATE16;
233 }
234 else if (pInsnParm->cBits <= 32)
235 {
236 pParam->armv8.cb = sizeof(uint32_t);
237 pParam->fUse |= DISUSE_IMMEDIATE32;
238 }
239 else
240 AssertReleaseFailed();
241
242 return VINF_SUCCESS;
243}
244
245
246static int disArmV8ParseImmRel(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
247{
248 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
249
250 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
251
252 pParam->uValue = (int64_t)disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
253 if (pInsnParm->cBits <= 8)
254 {
255 pParam->armv8.cb = sizeof(int8_t);
256 pParam->fUse |= DISUSE_IMMEDIATE8_REL;
257 }
258 else if (pInsnParm->cBits <= 16)
259 {
260 pParam->armv8.cb = sizeof(int16_t);
261 pParam->fUse |= DISUSE_IMMEDIATE16_REL;
262 }
263 else if (pInsnParm->cBits <= 32)
264 {
265 pParam->armv8.cb = sizeof(int32_t);
266 pParam->fUse |= DISUSE_IMMEDIATE32_REL;
267 }
268 else
269 AssertReleaseFailed();
270
271 return VINF_SUCCESS;
272}
273
274
275static int disArmV8ParseImmAdr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
276{
277 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit, pInsnParm);
278
279 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 19);
280 pParam->uValue |= disArmV8ExtractBitVecFromInsn(u32Insn, 29, 2) << 29;
281 pParam->fUse |= DISUSE_IMMEDIATE32;
282 return VINF_SUCCESS;
283}
284
285
286static int disArmV8ParseImmZero(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
287{
288 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pf64Bit, pInsnParm);
289
290 pParam->uValue = 0;
291 pParam->fUse |= DISUSE_IMMEDIATE8;
292 return VINF_SUCCESS;
293}
294
295
296static int disArmV8ParseGprZr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
297{
298 RT_NOREF(pDis, pOp, pInsnClass);
299 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
300 if (*pf64Bit || (pParam->armv8.enmType == kDisArmv8OpParmAddrInGpr))
301 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
302 else
303 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_32Bit;
304 return VINF_SUCCESS;
305}
306
307
308static int disArmV8ParseGprSp(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
309{
310 RT_NOREF(pDis, pOp, pInsnClass);
311 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
312 if (pParam->armv8.Op.Reg.idReg == 31)
313 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Sp;
314 else if (*pf64Bit || (pParam->armv8.enmType == kDisArmv8OpParmAddrInGpr))
315 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit;
316 else
317 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Gpr_32Bit;
318 return VINF_SUCCESS;
319}
320
321
322static int disArmV8ParseGprOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
323{
324 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
325 pParam->armv8.GprIndex.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
326 pParam->armv8.GprIndex.enmRegType = kDisOpParamArmV8RegType_Gpr_64Bit; /* Might get overwritten later on. */
327 pParam->fUse |= DISUSE_INDEX;
328 return VINF_SUCCESS;
329}
330
331
332static int disArmV8ParseImmsImmrN(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
333{
334 RT_NOREF(pDis, pOp, pInsnClass);
335 AssertReturn(pInsnParm->cBits == 13, VERR_INTERNAL_ERROR_2);
336
337 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
338 /* N bit must be 0 if 32-bit variant is used. */
339 if ( ( (u32ImmRaw & RT_BIT_32(12))
340 && !*pf64Bit)
341 || ( !(u32ImmRaw & RT_BIT_32(12))
342 && *pf64Bit))
343 return VERR_DIS_INVALID_OPCODE;
344
345 uint32_t uImm7SizeLen = ((u32ImmRaw & RT_BIT_32(12)) >> 6) | (u32ImmRaw & 0x3f);
346 uint32_t uImm6Rotations = (u32ImmRaw >> 6) & 0x3f;
347 pParam->uValue = *pf64Bit
348 ? Armv8A64ConvertImmRImmS2Mask64(uImm7SizeLen, uImm6Rotations)
349 : Armv8A64ConvertImmRImmS2Mask32(uImm7SizeLen, uImm6Rotations);
350 pParam->armv8.cb = pParam->uValue > UINT32_MAX ? sizeof(uint64_t) : sizeof(uint32_t);
351 pParam->fUse |= pParam->uValue > UINT32_MAX ? DISUSE_IMMEDIATE64 : DISUSE_IMMEDIATE32;
352 return VINF_SUCCESS;
353}
354
355
356static int disArmV8ParseHw(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
357{
358 RT_NOREF(pDis, pOp, pInsnClass, pParam);
359 Assert(pInsnParm->cBits == 2);
360
361 uint32_t u32 = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
362 /* hw<1> must be 0 if this is the 32-bit variant. */
363 if ( !*pf64Bit
364 && (u32 & RT_BIT_32(1)))
365 return VERR_DIS_INVALID_OPCODE;
366
367 Assert(pParam->armv8.enmType == kDisArmv8OpParmImm);
368 Assert(pParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32));
369 if (u32)
370 {
371 pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsl;
372 pParam->armv8.u.cExtend = ((uint8_t)u32 & 0x3) << 4;
373 }
374 return VINF_SUCCESS;
375}
376
377
378static int disArmV8ParseCond(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
379{
380 RT_NOREF(pInsnClass, pOp, pParam, pf64Bit);
381 Assert(pInsnParm->cBits <= 4);
382 if (pParam)
383 {
384 /* Conditional as a parameter (CCMP/CCMN). */
385 Assert(pParam->armv8.enmType == kDisArmv8OpParmCond);
386 pParam->armv8.Op.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
387 }
388 else /* Conditional for the base instruction. */
389 pDis->armv8.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
390 return VINF_SUCCESS;
391}
392
393
394static int disArmV8ParsePState(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
395{
396 RT_NOREF(pDis, pOp, pInsnClass, pInsnParm, pf64Bit);
397 uint32_t u32Op1 = disArmV8ExtractBitVecFromInsn(u32Insn, 16, 3);
398 uint32_t u32Op2 = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 3);
399
400 Assert(pDis->aParams[1].armv8.enmType == kDisArmv8OpParmImm);
401 Assert(pDis->aParams[1].armv8.cb == sizeof(uint8_t));
402 Assert(pDis->aParams[1].uValue < 16); /* 4 bit field. */
403
404 uint8_t bCRm = (uint8_t)pDis->aParams[1].uValue;
405
406 /* See C6.2.249 for the defined values. */
407 switch ((u32Op1 << 3) | u32Op2)
408 {
409 case 0x03: /* 000 011 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_UAO; break;
410 case 0x04: /* 000 100 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_PAN; break;
411 case 0x05: /* 000 101 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SPSel; break;
412 case 0x08: /* 001 000 */
413 {
414 pDis->aParams[1].uValue = bCRm & 0x1;
415 switch (bCRm & 0xe)
416 {
417 case 0: /* 000x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_ALLINT; break;
418 case 2: /* 001x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_PM; break;
419 default:
420 return VERR_DIS_INVALID_OPCODE;
421 }
422 break;
423 }
424 case 0x19: /* 011 001 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SSBS; break;
425 case 0x1a: /* 011 010 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DIT; break;
426 case 0x1b: /* 011 011 */
427 {
428 pDis->aParams[1].uValue = bCRm & 0x1;
429 switch (bCRm & 0xe)
430 {
431 case 2: /* 001x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRSM; break;
432 case 4: /* 010x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRZA; break;
433 case 6: /* 011x */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_SVCRSMZA; break;
434 default:
435 return VERR_DIS_INVALID_OPCODE;
436 }
437 break;
438 }
439 case 0x1c: /* 011 100 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_TCO; break;
440 case 0x1e: /* 011 110 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DAIFSet; break;
441 case 0x1f: /* 011 111 */ pParam->armv8.Op.enmPState = kDisArmv8InstrPState_DAIFClr; break;
442 default:
443 return VERR_DIS_INVALID_OPCODE;
444 }
445
446 return VINF_SUCCESS;
447}
448
449
450static int disArmV8ParseSysReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
451{
452 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
453 AssertReturn(pInsnParm->cBits == 15, VERR_INTERNAL_ERROR_2);
454
455 /* Assumes a op0:op1:CRn:CRm:op2 encoding in the instruction starting at the given bit position. */
456 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
457 pParam->armv8.Op.idSysReg = ARMV8_AARCH64_SYSREG_ID_CREATE(2 + ((u32ImmRaw >> 14) & 0x1),
458 (u32ImmRaw >> 11) & 0x7,
459 (u32ImmRaw >> 7) & 0xf,
460 (u32ImmRaw >> 3) & 0xf,
461 u32ImmRaw & 0x7);
462 pParam->armv8.cb = 0;
463 pParam->fUse |= DISUSE_REG_SYSTEM;
464 return VINF_SUCCESS;
465}
466
467
468static int disArmV8ParseSh12(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
469{
470 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
471 Assert(pInsnParm->cBits == 1);
472 if (u32Insn & RT_BIT_32(pInsnParm->idxBitStart))
473 {
474 /* Shift the immediate pointed to. */
475 pParam->uValue <<= 12;
476
477 /* Re-evaluate the immediate data size. */
478 pParam->fUse &= ~(DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32);
479 if (pParam->uValue <= UINT8_MAX)
480 {
481 pParam->armv8.cb = sizeof(uint8_t);
482 pParam->fUse |= DISUSE_IMMEDIATE8;
483 }
484 else if (pParam->uValue <= UINT16_MAX)
485 {
486 pParam->armv8.cb = sizeof(uint16_t);
487 pParam->fUse |= DISUSE_IMMEDIATE16;
488 }
489 else if (pParam->uValue <= UINT32_MAX)
490 {
491 pParam->armv8.cb = sizeof(uint32_t);
492 pParam->fUse |= DISUSE_IMMEDIATE32;
493 }
494 else
495 AssertReleaseFailed();
496
497 }
498 return VINF_SUCCESS;
499}
500
501
502static int disArmV8ParseImmTbz(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
503{
504 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
505
506 AssertReturn(!pInsnParm->idxBitStart && !pInsnParm->cBits, VERR_INTERNAL_ERROR_2);
507
508 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 19, 5);
509 pParam->uValue |= (u32Insn & RT_BIT_32(31)) >> 26;
510
511 pParam->armv8.cb = sizeof(uint8_t);
512 pParam->fUse |= DISUSE_IMMEDIATE8;
513 return VINF_SUCCESS;
514}
515
516
517static int disArmV8ParseShift(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
518{
519 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
520
521 AssertReturn(pInsnParm->cBits == 2, VERR_INTERNAL_ERROR_2);
522
523 uint32_t u32Shift = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
524 switch (u32Shift)
525 {
526 case 0: pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsl; break;
527 case 1: pParam->armv8.enmExtend = kDisArmv8OpParmExtendLsr; break;
528 case 2: pParam->armv8.enmExtend = kDisArmv8OpParmExtendAsr; break;
529 case 3: pParam->armv8.enmExtend = kDisArmv8OpParmExtendRor; break;
530 default:
531 AssertReleaseFailed();
532 }
533 return VINF_SUCCESS;
534}
535
536
537static int disArmV8ParseShiftAmount(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
538{
539 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
540
541 uint32_t u32Amount = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
542 /* For a 32-bit operand it is impossible to shift/rotate more than 31 bits. */
543 if ( !*pf64Bit
544 && u32Amount > 31)
545 return VERR_DIS_INVALID_OPCODE;
546
547 Assert(pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone);
548 Assert(u32Amount < 64);
549 pParam->armv8.u.cExtend = (uint8_t)u32Amount;
550 /* Any shift operation with a 0 is essentially no shift being applied. */
551 if (pParam->armv8.u.cExtend == 0)
552 pParam->armv8.enmExtend = kDisArmv8OpParmExtendNone;
553 return VINF_SUCCESS;
554}
555
556
557static int disArmV8ParseImmMemOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
558{
559 RT_NOREF(pInsnClass, pOp, pf64Bit);
560
561 AssertReturn(pInsnParm->cBits <= 12, VERR_INTERNAL_ERROR_2);
562 AssertReturn(pDis->armv8.cbOperand != 0, VERR_INTERNAL_ERROR_2);
563
564 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
565 switch (pDis->armv8.cbOperand)
566 {
567 case sizeof(uint8_t): break;
568 case sizeof(uint16_t): pParam->armv8.u.offBase <<= 1; break;
569 case sizeof(uint32_t): pParam->armv8.u.offBase <<= 2; break;
570 case sizeof(uint64_t): pParam->armv8.u.offBase <<= 3; break;
571 default:
572 AssertReleaseFailed();
573 }
574 pParam->armv8.cb = sizeof(int16_t);
575 return VINF_SUCCESS;
576}
577
578
579static int disArmV8ParseSImmMemOff(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
580{
581 RT_NOREF(pDis, pInsnClass, pf64Bit);
582
583 AssertReturn(pInsnParm->cBits <= 7, VERR_INTERNAL_ERROR_2);
584 AssertReturn( (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT)
585 || (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT),
586 VERR_INTERNAL_ERROR_2);
587
588 pParam->armv8.cb = sizeof(int16_t);
589 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
590 pParam->armv8.u.offBase <<= (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT) ? 2 : 3;
591 return VINF_SUCCESS;
592}
593
594
595static int disArmV8ParseSImmMemOffUnscaled(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
596{
597 RT_NOREF(pDis, pOp, pInsnClass, pf64Bit);
598
599 AssertReturn(pInsnParm->cBits <= 9, VERR_INTERNAL_ERROR_2);
600 pParam->armv8.u.offBase = disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
601 return VINF_SUCCESS;
602}
603
604
605static int disArmV8ParseOption(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
606{
607 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
608
609 AssertReturn(pInsnParm->cBits == 3, VERR_INTERNAL_ERROR_2);
610 uint32_t u32Opt = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
611
612 Assert( pParam->armv8.enmExtend == kDisArmv8OpParmExtendNone
613 && (pParam->fUse & DISUSE_INDEX));
614 switch (u32Opt)
615 {
616 case 0: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtB; break;
617 case 1: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtH; break;
618 case 2: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtW; break;
619 case 3: pParam->armv8.enmExtend = kDisArmv8OpParmExtendUxtX; break;
620 case 4: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtB; break;
621 case 5: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtH; break;
622 case 6: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtW; break;
623 case 7: pParam->armv8.enmExtend = kDisArmv8OpParmExtendSxtX; break;
624 default:
625 AssertFailed();
626 }
627
628 /* When option<0> is set to 0, the 32-bit name of the GPR is used, 64-bit when option<0> is set to 1. */
629 pParam->armv8.GprIndex.enmRegType = RT_BOOL(u32Opt & 0x1)
630 ? kDisOpParamArmV8RegType_Gpr_64Bit
631 : kDisOpParamArmV8RegType_Gpr_32Bit;
632 return VINF_SUCCESS;
633}
634
635
636static int disArmV8ParseS(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
637{
638 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
639
640 AssertReturn(pInsnParm->cBits == 1, VERR_INTERNAL_ERROR_2);
641 bool const fS = RT_BOOL(u32Insn & RT_BIT_32(pInsnParm->idxBitStart));
642
643 Assert( pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone
644 && pDis->armv8.cbOperand > 0
645 && pDis->armv8.cbOperand <= 8);
646 if (fS)
647 {
648 switch (pDis->armv8.cbOperand)
649 {
650 case sizeof(uint8_t): pParam->armv8.u.cExtend = 0; break;
651 case sizeof(uint16_t): pParam->armv8.u.cExtend = 1; break;
652 case sizeof(uint32_t): pParam->armv8.u.cExtend = 2; break;
653 case sizeof(uint64_t): pParam->armv8.u.cExtend = 3; break;
654 default:
655 AssertReleaseFailed();
656 }
657 }
658 else if (pParam->armv8.enmExtend == kDisArmv8OpParmExtendUxtX) /* UXTX aka LSL can be ignored if S is not set. */
659 {
660 pParam->armv8.u.cExtend = 0;
661 pParam->armv8.enmExtend = kDisArmv8OpParmExtendNone;
662 }
663
664 return VINF_SUCCESS;
665}
666
667
668static int disArmV8ParseSetPreIndexed(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
669{
670 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pInsnParm, pf64Bit);
671
672 pParam->fUse |= DISUSE_PRE_INDEXED;
673 return VINF_SUCCESS;
674}
675
676
677static int disArmV8ParseSetPostIndexed(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
678{
679 RT_NOREF(pDis, u32Insn, pOp, pInsnClass, pInsnParm, pf64Bit);
680
681 pParam->fUse |= DISUSE_POST_INDEXED;
682 return VINF_SUCCESS;
683}
684
685
686static int disArmV8ParseFpType(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
687{
688 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
689
690 Assert(pDis->armv8.enmFpType == kDisArmv8InstrFpType_Invalid);
691 uint32_t u32FpType = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
692 switch (u32FpType)
693 {
694 case 0: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Single; break;
695 case 1: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Double; break;
696 case 3: pDis->armv8.enmFpType = kDisArmv8InstrFpType_Half; break;
697 default: return VERR_DIS_INVALID_OPCODE;
698 }
699 return VINF_SUCCESS;
700}
701
702
703static int disArmV8ParseFpReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
704{
705 RT_NOREF(pOp, pInsnClass, pParam, pf64Bit);
706
707 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
708 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
709 switch (pDis->armv8.enmFpType)
710 {
711 case kDisArmv8InstrFpType_Single: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Single; break;
712 case kDisArmv8InstrFpType_Double: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Double; break;
713 case kDisArmv8InstrFpType_Half: pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_FpReg_Half; break;
714 default: return VERR_DIS_INVALID_OPCODE;
715 }
716 return VINF_SUCCESS;
717}
718
719
720static int disArmV8ParseFpScale(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
721{
722 RT_NOREF(pDis, pOp, pInsnClass);
723 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
724
725 uint32_t u32Scale = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
726 if ( !*pf64Bit
727 && (u32Scale & RT_BIT_32(5)) == 0)
728 return VERR_DIS_INVALID_OPCODE;
729
730 pParam->uValue = 64 - u32Scale;
731 pParam->armv8.cb = sizeof(uint8_t);
732 pParam->fUse |= DISUSE_IMMEDIATE8;
733 return VINF_SUCCESS;
734}
735
736
737static int disArmV8ParseFpFixupFCvt(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
738{
739 RT_NOREF(pDis, pInsnClass, pParam, pInsnParm, pf64Bit);
740
741 /* Nothing to do if this isn't about fcvt. */
742 if (pOp->Opc.uOpcode != OP_ARMV8_A64_FCVT)
743 return VINF_SUCCESS;
744
745 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
746 Assert( pDis->aParams[0].armv8.enmType == kDisArmv8OpParmReg
747 && pDis->aParams[1].armv8.enmType == kDisArmv8OpParmReg);
748
749 /* Convert source and guest register floating point types to the correct widths. */
750 uint32_t u32Opc = (u32Insn & (RT_BIT_32(15) | RT_BIT_32(16))) >> 15;
751#ifdef VBOX_STRICT
752 uint32_t u32FpType = disArmV8ExtractBitVecFromInsn(u32Insn, 22, 2);
753 Assert( u32Opc != u32FpType
754 && u32Opc != 2);
755#endif
756
757 static const DISOPPARAMARMV8REGTYPE s_aOpc2FpWidth[] =
758 {
759 kDisOpParamArmV8RegType_FpReg_Single,
760 kDisOpParamArmV8RegType_FpReg_Double,
761 (DISOPPARAMARMV8REGTYPE)UINT8_MAX, /* Invalid encoding. */
762 kDisOpParamArmV8RegType_FpReg_Half
763 };
764
765 pDis->aParams[0].armv8.Op.Reg.enmRegType = s_aOpc2FpWidth[u32Opc];
766 return VINF_SUCCESS;
767}
768
769
770static int disArmV8ParseSimdRegScalar(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
771{
772 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
773
774 pParam->armv8.Op.Reg.idReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
775 pParam->armv8.Op.Reg.enmRegType = kDisOpParamArmV8RegType_Simd_Scalar_64Bit;
776 return VINF_SUCCESS;
777}
778
779
780static int disArmV8ParseImmHImmB(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
781{
782 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm, pf64Bit);
783
784 Assert(pInsnParm->cBits == 7);
785 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
786 if (!(u32ImmRaw & RT_BIT_32(6))) /* immh == 0xxx is reserved for the scalar variant. */
787 return VERR_DIS_INVALID_OPCODE;
788
789 pParam->uValue = 2 * 64 - u32ImmRaw;
790 pParam->armv8.cb = sizeof(uint8_t);
791 pParam->fUse |= DISUSE_IMMEDIATE8;
792 return VINF_SUCCESS;
793}
794
795
796static int disArmV8ParseSf(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
797{
798 RT_NOREF(pDis, pOp, pInsnClass, pParam, pInsnParm);
799
800 Assert(pInsnParm->cBits == 1);
801 Assert(pInsnParm->idxBitStart == 31);
802 *pf64Bit = RT_BOOL(u32Insn & RT_BIT_32(31));
803 return VINF_SUCCESS;
804}
805
806
807static uint32_t disArmV8DecodeIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
808{
809 RT_NOREF(pDis, u32Insn, pInsnClass);
810 AssertFailed();
811 return UINT32_MAX;
812}
813
814
815static uint32_t disArmV8DecodeLookup(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
816{
817 RT_NOREF(pDis);
818
819 for (uint32_t i = 0; i < pInsnClass->Hdr.cDecode; i++)
820 {
821 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[i];
822 if (u32Insn == pOp->fValue)
823 return i;
824 }
825
826 return UINT32_MAX;
827}
828
829
830static uint32_t disArmV8DecodeCollate(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
831{
832 RT_NOREF(pDis);
833
834 /* Need to build a compact representation of the relevant bits from the mask to create an index. */
835 uint32_t fMask = pInsnClass->fMask >> pInsnClass->cShift;
836
837 /** @todo Optimize. */
838 uint32_t idx = 0;
839 uint32_t cShift = 0;
840 while (fMask)
841 {
842 if (fMask & 0x1)
843 {
844 idx |= (u32Insn & 1) << cShift;
845 cShift++;
846 }
847
848 u32Insn >>= 1;
849 fMask >>= 1;
850 }
851
852 if (RT_LIKELY(idx < pInsnClass->Hdr.cDecode))
853 return idx;
854
855 return UINT32_MAX;
856}
857
858
859/**
860 * Looks for possible alias conversions for the given disassembler state.
861 *
862 * @param pDis The disassembler state to process.
863 */
864static void disArmV8A64InsnAliasesProcess(PDISSTATE pDis)
865{
866#define DIS_ARMV8_ALIAS(a_Name) s_DisArmv8Alias ## a_Name
867#define DIS_ARMV8_ALIAS_CREATE(a_Name, a_szOpcode, a_uOpcode, a_fOpType) static const DISOPCODE DIS_ARMV8_ALIAS(a_Name) = OP(a_szOpcode, 0, 0, 0, a_uOpcode, 0, 0, 0, a_fOpType)
868#define DIS_ARMV8_ALIAS_REF(a_Name) &DIS_ARMV8_ALIAS(a_Name)
869 switch (pDis->pCurInstr->uOpcode)
870 {
871 case OP_ARMV8_A64_ORR:
872 {
873 /* Check for possible MOV conversion for the register variant when: shift is None and the first source is the zero register. */
874 Assert(pDis->aParams[1].armv8.enmType == kDisArmv8OpParmReg);
875 Assert( pDis->aParams[1].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_32Bit
876 || pDis->aParams[1].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_64Bit);
877
878 if ( pDis->aParams[2].armv8.enmType == kDisArmv8OpParmReg
879 && pDis->aParams[2].armv8.enmExtend == kDisArmv8OpParmExtendNone
880 && pDis->aParams[1].armv8.Op.Reg.idReg == ARMV8_A64_REG_XZR)
881 {
882 DIS_ARMV8_ALIAS_CREATE(Mov, "mov", OP_ARMV8_A64_MOV, DISOPTYPE_HARMLESS);
883 pDis->pCurInstr = DIS_ARMV8_ALIAS_REF(Mov);
884 pDis->aParams[1] = pDis->aParams[2];
885 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
886 }
887 /** @todo Immediate variant. */
888 break;
889 }
890 case OP_ARMV8_A64_SUBS:
891 {
892 Assert(pDis->aParams[0].armv8.enmType == kDisArmv8OpParmReg);
893 Assert( pDis->aParams[0].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_32Bit
894 || pDis->aParams[0].armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Gpr_64Bit);
895
896 if (pDis->aParams[0].armv8.Op.Reg.idReg == ARMV8_A64_REG_XZR)
897 {
898 DIS_ARMV8_ALIAS_CREATE(Cmp, "cmp", OP_ARMV8_A64_CMP, DISOPTYPE_HARMLESS);
899 pDis->pCurInstr = DIS_ARMV8_ALIAS_REF(Cmp);
900 pDis->aParams[0] = pDis->aParams[1];
901 pDis->aParams[1] = pDis->aParams[2];
902 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
903 }
904 break;
905 }
906 default:
907 break; /* No conversion */
908 }
909#undef DIS_ARMV8_ALIAS_REF
910#undef DIS_ARMV8_ALIAS_CREATE
911#undef DIS_ARMV8_ALIAS
912}
913
914
915static int disArmV8A64ParseInstruction(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass)
916{
917 AssertPtr(pOp);
918 AssertPtr(pDis);
919 //Assert((u32Insn & pInsnClass->fFixedInsn) == pOp->fValue);
920 if ((u32Insn & pInsnClass->fFixedInsn) != pOp->fValue)
921 return VERR_DIS_INVALID_OPCODE;
922
923 /* Should contain the parameter type on input. */
924 pDis->aParams[0].fUse = 0;
925 pDis->aParams[1].fUse = 0;
926 pDis->aParams[2].fUse = 0;
927 pDis->aParams[3].fUse = 0;
928 pDis->aParams[0].armv8.enmType = pInsnClass->aenmParamTypes[0];
929 pDis->aParams[1].armv8.enmType = pInsnClass->aenmParamTypes[1];
930 pDis->aParams[2].armv8.enmType = pInsnClass->aenmParamTypes[2];
931 pDis->aParams[3].armv8.enmType = pInsnClass->aenmParamTypes[3];
932 pDis->aParams[0].armv8.enmExtend = kDisArmv8OpParmExtendNone;
933 pDis->aParams[1].armv8.enmExtend = kDisArmv8OpParmExtendNone;
934 pDis->aParams[2].armv8.enmExtend = kDisArmv8OpParmExtendNone;
935 pDis->aParams[3].armv8.enmExtend = kDisArmv8OpParmExtendNone;
936 pDis->armv8.enmCond = kDisArmv8InstrCond_Al;
937 pDis->armv8.enmFpType = kDisArmv8InstrFpType_Invalid;
938 pDis->armv8.cbOperand = 0;
939
940 pDis->pCurInstr = &pOp->Opc;
941 Assert(&pOp->Opc != &g_ArmV8A64InvalidOpcode[0]);
942
943 bool f64Bit = true;
944
945 if (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_32BIT)
946 f64Bit = false;
947 else if (pOp->fFlags & DISARMV8INSNCLASS_F_FORCED_64BIT)
948 f64Bit = true;
949
950 int rc = VINF_SUCCESS;
951 PCDISARMV8INSNPARAM pDecode = &pInsnClass->paParms[0];
952 while ( (pDecode->idxParse != kDisParmParseNop)
953 && RT_SUCCESS(rc))
954 {
955 rc = g_apfnDisasm[pDecode->idxParse](pDis, u32Insn, pOp, pInsnClass,
956 pDecode->idxParam != DIS_ARMV8_INSN_PARAM_UNSET
957 ? &pDis->aParams[pDecode->idxParam]
958 : NULL,
959 pDecode, &f64Bit);
960 pDecode++;
961 }
962
963 /* If parameter parsing returned an invalid opcode error the encoding is invalid. */
964 if (RT_SUCCESS(rc)) /** @todo Introduce flag to switch alias conversion on/off. */
965 disArmV8A64InsnAliasesProcess(pDis);
966 else if (rc == VERR_DIS_INVALID_OPCODE)
967 {
968 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
969
970 pDis->aParams[0].armv8.enmType = kDisArmv8OpParmNone;
971 pDis->aParams[1].armv8.enmType = kDisArmv8OpParmNone;
972 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
973 pDis->aParams[3].armv8.enmType = kDisArmv8OpParmNone;
974 }
975 pDis->rc = rc;
976 return rc;
977}
978
979
980static int disArmV8A64ParseInvOpcode(PDISSTATE pDis)
981{
982 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
983 pDis->rc = VERR_DIS_INVALID_OPCODE;
984 return VERR_DIS_INVALID_OPCODE;
985}
986
987
988static int disInstrArmV8DecodeWorker(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8DECODEHDR pHdr)
989{
990 while ( pHdr
991 && pHdr->enmDecodeType != kDisArmV8DecodeType_InsnClass)
992 {
993 if (pHdr->enmDecodeType == kDisArmV8DecodeType_Map)
994 {
995 PCDISARMV8DECODEMAP pMap = (PCDISARMV8DECODEMAP)pHdr;
996
997 uint32_t idxNext = (u32Insn & pMap->fMask) >> pMap->cShift;
998 if (RT_LIKELY(idxNext < pMap->Hdr.cDecode))
999 pHdr = pMap->papNext[idxNext];
1000 else
1001 {
1002 pHdr = NULL;
1003 break;
1004 }
1005 }
1006 else
1007 {
1008 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_Table);
1009 PCDISARMV8DECODETBL pTbl = (PCDISARMV8DECODETBL)pHdr;
1010
1011 /* Walk all entries in the table and select the best match. */
1012 pHdr = NULL;
1013 for (uint32_t i = 0; i < pTbl->Hdr.cDecode; i++)
1014 {
1015 PCDISARMV8DECODETBLENTRY pEntry = &pTbl->paEntries[i];
1016 if ((u32Insn & pEntry->fMask) == pEntry->fValue)
1017 {
1018 pHdr = pEntry->pHdrNext;
1019 break;
1020 }
1021 }
1022 }
1023 }
1024
1025 if (pHdr)
1026 {
1027 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_InsnClass);
1028 PCDISARMV8INSNCLASS pInsnClass = (PCDISARMV8INSNCLASS)pHdr;
1029
1030 /* Decode the opcode from the instruction class. */
1031 uint32_t uOpcRaw = 0;
1032 if (pInsnClass->Hdr.cDecode > 1)
1033 {
1034 uOpcRaw = (u32Insn & pInsnClass->fMask) >> pInsnClass->cShift;
1035 if (pInsnClass->enmOpcDecode != kDisArmV8OpcDecodeNop)
1036 uOpcRaw = g_apfnOpcDecode[pInsnClass->enmOpcDecode](pDis, uOpcRaw, pInsnClass);
1037 }
1038
1039 if (uOpcRaw < pInsnClass->Hdr.cDecode)
1040 {
1041 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[uOpcRaw];
1042 return disArmV8A64ParseInstruction(pDis, u32Insn, pOp, pInsnClass);
1043 }
1044 }
1045
1046 return disArmV8A64ParseInvOpcode(pDis);
1047}
1048
1049
1050/**
1051 * Internal worker for DISInstrEx and DISInstrWithPrefetchedBytes.
1052 *
1053 * @returns VBox status code.
1054 * @param pDis Initialized disassembler state.
1055 * @param paOneByteMap The one byte opcode map to use.
1056 * @param pcbInstr Where to store the instruction size. Can be NULL.
1057 */
1058DECLHIDDEN(int) disInstrWorkerArmV8(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
1059{
1060 RT_NOREF(paOneByteMap);
1061
1062 if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
1063 {
1064 *pcbInstr = sizeof(uint32_t);
1065
1066 /* Instructions are always little endian and 4 bytes. */
1067 uint32_t u32Insn = disReadDWord(pDis, 0 /*offInstr*/);
1068 if (RT_FAILURE(pDis->rc))
1069 return pDis->rc;
1070
1071 /** @todo r=bird: This is a waste of time if the host is little endian... */
1072 pDis->Instr.u32 = RT_LE2H_U32(u32Insn);
1073 pDis->cbInstr = sizeof(u32Insn);
1074
1075 return disInstrArmV8DecodeWorker(pDis, u32Insn, &g_aArmV8A64InsnDecodeL0.Hdr);
1076 }
1077
1078 AssertReleaseFailed();
1079 return VERR_NOT_IMPLEMENTED;
1080}
1081
1082
1083/**
1084 * Inlined worker that initializes the disassembler state.
1085 *
1086 * @returns The primary opcode map to use.
1087 * @param pDis The disassembler state.
1088 * @param uInstrAddr The instruction address.
1089 * @param enmCpuMode The CPU mode.
1090 * @param fFilter The instruction filter settings.
1091 * @param pfnReadBytes The byte reader, can be NULL.
1092 * @param pvUser The user data for the reader.
1093 */
1094DECLHIDDEN(PCDISOPCODE) disInitializeStateArmV8(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter)
1095{
1096 RT_NOREF(pDis, enmCpuMode, fFilter);
1097 return NULL;
1098}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette