VirtualBox

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

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

Disassembler: Decode Load/Store exclusive pair instructions, bugref:10394

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