VirtualBox

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

Last change on this file since 106616 was 106616, checked in by vboxsync, 7 months ago

Disassembler: Fix decoding instructions which take sp as a register instead of of xzr/wzr, bugref:10394

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

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