VirtualBox

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

Last change on this file since 106757 was 106754, checked in by vboxsync, 3 months ago

Disassembler: Decode SIMD ldnp/stnp (no allocate register pair) instructions, bugref:10394

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