VirtualBox

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

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

Disassembler/ARMv8: Updates, decode more instructions, add them to the testcase, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/* $Id: DisasmCore-armv8.cpp 105779 2024-08-21 16:39:51Z vboxsync $ */
2/** @file
3 * VBox Disassembler - Core Components.
4 */
5
6/*
7 * Copyright (C) 2023 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, 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 disArmV8ParseIs32Bit;
77static FNDISPARSEARMV8 disArmV8ParseImm;
78static FNDISPARSEARMV8 disArmV8ParseImmRel;
79static FNDISPARSEARMV8 disArmV8ParseImmAdr;
80static FNDISPARSEARMV8 disArmV8ParseReg;
81static FNDISPARSEARMV8 disArmV8ParseImmsImmrN;
82static FNDISPARSEARMV8 disArmV8ParseHw;
83static FNDISPARSEARMV8 disArmV8ParseCond;
84static FNDISPARSEARMV8 disArmV8ParsePState;
85static FNDISPARSEARMV8 disArmV8ParseSysReg;
86static FNDISPARSEARMV8 disArmV8ParseSh12;
87static FNDISPARSEARMV8 disArmV8ParseImmTbz;
88static FNDISPARSEARMV8 disArmV8ParseShift;
89static FNDISPARSEARMV8 disArmV8ParseShiftAmount;
90/** @} */
91
92
93/** @name Decoders
94 * @{ */
95static FNDISDECODEARMV8 disArmV8DecodeIllegal;
96static FNDISDECODEARMV8 disArmV8DecodeLookup;
97/** @} */
98
99
100/*********************************************************************************************************************************
101* Global Variables *
102*********************************************************************************************************************************/
103/** Parser opcode table for full disassembly. */
104static PFNDISPARSEARMV8 const g_apfnDisasm[kDisParmParseMax] =
105{
106 disArmV8ParseIllegal,
107 disArmV8ParseIs32Bit,
108 disArmV8ParseImm,
109 disArmV8ParseImmRel,
110 disArmV8ParseImmAdr,
111 disArmV8ParseReg,
112 disArmV8ParseImmsImmrN,
113 disArmV8ParseHw,
114 disArmV8ParseCond,
115 disArmV8ParsePState,
116 NULL,
117 disArmV8ParseSysReg,
118 disArmV8ParseSh12,
119 disArmV8ParseImmTbz,
120 disArmV8ParseShift,
121 disArmV8ParseShiftAmount
122};
123
124
125/** Opcode decoder table. */
126static PFNDISDECODEARMV8 const g_apfnOpcDecode[kDisArmV8OpcDecodeMax] =
127{
128 disArmV8DecodeIllegal,
129 disArmV8DecodeLookup,
130};
131
132
133DECLINLINE(uint32_t) disArmV8ExtractBitVecFromInsn(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
134{
135 uint32_t fMask = RT_BIT_32(idxBitStart + cBits) - 1;
136 return (u32Insn & fMask) >> idxBitStart;
137}
138
139
140DECLINLINE(int32_t) disArmV8ExtractBitVecFromInsnSignExtend(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
141{
142 uint32_t fMask = RT_BIT_32(idxBitStart + cBits) - 1;
143 uint32_t fSign = ~(UINT32_MAX & (RT_BIT_32(cBits - 1) - 1));
144 uint32_t fValue = (u32Insn & fMask) >> idxBitStart;
145 if (fValue & fSign)
146 return (int32_t)(fValue | fSign);
147
148 return (int32_t)fValue;
149}
150
151
152static int disArmV8ParseIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
153{
154 RT_NOREF(pDis, u32Insn, pInsnClass, pParam, pInsnParm, pf64Bit);
155 AssertFailed();
156 return VERR_INTERNAL_ERROR;
157}
158
159
160static int disArmV8ParseIs32Bit(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
161{
162 RT_NOREF(pDis, pInsnClass, pParam);
163
164 AssertReturn(pInsnParm->idxBitStart < 32 && pInsnParm->cBits == 1, VERR_INTERNAL_ERROR_2);
165 *pf64Bit = RT_BOOL(u32Insn & RT_BIT_32(pInsnParm->idxBitStart));
166 return VINF_SUCCESS;
167}
168
169
170static int disArmV8ParseImm(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
171{
172 RT_NOREF(pDis, pInsnClass, pf64Bit);
173
174 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
175
176 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
177 if (pInsnParm->cBits <= 8)
178 {
179 pParam->armv8.cb = sizeof(uint8_t);
180 pParam->fUse |= DISUSE_IMMEDIATE8;
181 }
182 else if (pInsnParm->cBits <= 16)
183 {
184 pParam->armv8.cb = sizeof(uint16_t);
185 pParam->fUse |= DISUSE_IMMEDIATE16;
186 }
187 else if (pInsnParm->cBits <= 32)
188 {
189 pParam->armv8.cb = sizeof(uint32_t);
190 pParam->fUse |= DISUSE_IMMEDIATE32;
191 }
192 else
193 AssertReleaseFailed();
194
195 return VINF_SUCCESS;
196}
197
198
199static int disArmV8ParseImmRel(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
200{
201 RT_NOREF(pDis, pInsnClass, pf64Bit);
202
203 AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
204
205 pParam->uValue = (int64_t)disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
206 if (pInsnParm->cBits <= 8)
207 {
208 pParam->armv8.cb = sizeof(int8_t);
209 pParam->fUse |= DISUSE_IMMEDIATE8_REL;
210 }
211 else if (pInsnParm->cBits <= 16)
212 {
213 pParam->armv8.cb = sizeof(int16_t);
214 pParam->fUse |= DISUSE_IMMEDIATE16_REL;
215 }
216 else if (pInsnParm->cBits <= 32)
217 {
218 pParam->armv8.cb = sizeof(int32_t);
219 pParam->fUse |= DISUSE_IMMEDIATE32_REL;
220 }
221 else
222 AssertReleaseFailed();
223
224 return VINF_SUCCESS;
225}
226
227
228static int disArmV8ParseImmAdr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
229{
230 RT_NOREF(pDis, pInsnClass, pf64Bit, pInsnParm);
231
232 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 19);
233 pParam->uValue |= disArmV8ExtractBitVecFromInsn(u32Insn, 29, 2) << 29;
234 pParam->fUse |= DISUSE_IMMEDIATE32;
235 return VINF_SUCCESS;
236}
237
238
239static int disArmV8ParseReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
240{
241 RT_NOREF(pDis, pInsnClass);
242 pParam->armv8.Reg.idxGenReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
243 pParam->armv8.cb = *pf64Bit ? sizeof(uint64_t) : sizeof(uint32_t);
244 pParam->fUse |= (*pf64Bit || (pInsnParm->fFlags & (DIS_ARMV8_INSN_PARAM_F_ADDR_BEGIN | DIS_ARMV8_INSN_PARAM_F_ADDR_END) ))
245 ? DISUSE_REG_GEN64
246 : DISUSE_REG_GEN32;
247 return VINF_SUCCESS;
248}
249
250
251static int disArmV8ParseImmsImmrN(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
252{
253 RT_NOREF(pDis);
254 AssertReturn(pInsnParm->cBits == 13, VERR_INTERNAL_ERROR_2);
255
256 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
257 /* N bit must be 0 if 32-bit variant is used. */
258 if ( ( (u32ImmRaw & RT_BIT_32(12))
259 && !*pf64Bit)
260 || ( !(u32ImmRaw & RT_BIT_32(12))
261 && *pf64Bit
262 && (pInsnClass->fClass & DISARMV8INSNCLASS_F_N_FORCED_1_ON_64BIT)))
263 return VERR_DIS_INVALID_OPCODE;
264
265 uint32_t uImm7SizeLen = ((u32ImmRaw & RT_BIT_32(12)) >> 6) | (u32ImmRaw & 0x3f);
266 uint32_t uImm6Rotations = (u32ImmRaw >> 6) & 0x3f;
267 pParam->uValue = *pf64Bit
268 ? Armv8A64ConvertImmRImmS2Mask64(uImm7SizeLen, uImm6Rotations)
269 : Armv8A64ConvertImmRImmS2Mask32(uImm7SizeLen, uImm6Rotations);
270 pParam->armv8.cb = pParam->uValue > UINT32_MAX ? sizeof(uint64_t) : sizeof(uint32_t);
271 pParam->fUse |= pParam->uValue > UINT32_MAX ? DISUSE_IMMEDIATE64 : DISUSE_IMMEDIATE32;
272 return VINF_SUCCESS;
273}
274
275
276static int disArmV8ParseHw(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
277{
278 RT_NOREF(pDis, pInsnClass, pParam);
279 Assert(pInsnParm->cBits == 2);
280
281 uint32_t u32 = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
282 /* hw<1> must be 0 if this is the 32-bit variant. */
283 if ( !*pf64Bit
284 && (u32 & RT_BIT_32(1)))
285 return VERR_DIS_INVALID_OPCODE;
286
287 Assert(pParam->armv8.enmType == kDisArmv8OpParmImm);
288 Assert(pParam->fUse & (DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32));
289 if (u32)
290 {
291 pParam->armv8.enmShift = kDisArmv8OpParmShiftLeft;
292 pParam->armv8.cShift = ((uint8_t)u32 & 0x3) << 4;
293 }
294 return VINF_SUCCESS;
295}
296
297
298static int disArmV8ParseCond(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
299{
300 RT_NOREF(pInsnClass, pParam, pf64Bit);
301 pDis->armv8.enmCond = (DISARMV8INSTRCOND)disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
302 return VINF_SUCCESS;
303}
304
305
306static int disArmV8ParsePState(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
307{
308 RT_NOREF(pDis, u32Insn, pInsnClass, pParam, pInsnParm, pf64Bit);
309 //AssertFailed();
310 /** @todo */
311 return VINF_SUCCESS;
312}
313
314
315static int disArmV8ParseSysReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
316{
317 RT_NOREF(pDis, pInsnClass, pf64Bit);
318 AssertReturn(pInsnParm->cBits == 15, VERR_INTERNAL_ERROR_2);
319
320 /* Assumes a op0:op1:CRn:CRm:op2 encoding in the instruction starting at the given bit position. */
321 uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
322 pParam->armv8.Reg.idSysReg = ARMV8_AARCH64_SYSREG_ID_CREATE(2 + ((u32ImmRaw >> 14) & 0x1),
323 (u32ImmRaw >> 11) & 0x7,
324 (u32ImmRaw >> 7) & 0xf,
325 (u32ImmRaw >> 3) & 0xf,
326 u32ImmRaw & 0x7);
327 pParam->armv8.cb = 0;
328 pParam->fUse |= DISUSE_REG_SYSTEM;
329 return VINF_SUCCESS;
330}
331
332
333static int disArmV8ParseSh12(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
334{
335 RT_NOREF(pDis, pInsnClass, pf64Bit);
336 Assert(pInsnParm->cBits == 1);
337 if (u32Insn & RT_BIT_32(pInsnParm->idxBitStart))
338 {
339 /* Shift the immediate pointed to. */
340 pParam->uValue <<= 12;
341
342 /* Re-evaluate the immediate data size. */
343 pParam->fUse &= ~(DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32);
344 if (pParam->uValue <= UINT8_MAX)
345 {
346 pParam->armv8.cb = sizeof(uint8_t);
347 pParam->fUse |= DISUSE_IMMEDIATE8;
348 }
349 else if (pParam->uValue <= UINT16_MAX)
350 {
351 pParam->armv8.cb = sizeof(uint16_t);
352 pParam->fUse |= DISUSE_IMMEDIATE16;
353 }
354 else if (pParam->uValue <= UINT32_MAX)
355 {
356 pParam->armv8.cb = sizeof(uint32_t);
357 pParam->fUse |= DISUSE_IMMEDIATE32;
358 }
359 else
360 AssertReleaseFailed();
361
362 }
363 return VINF_SUCCESS;
364}
365
366
367static int disArmV8ParseImmTbz(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
368{
369 RT_NOREF(pDis, pInsnClass, pf64Bit);
370
371 AssertReturn(!pInsnParm->idxBitStart && !pInsnParm->cBits, VERR_INTERNAL_ERROR_2);
372
373 pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 19, 5);
374 pParam->uValue |= (u32Insn & RT_BIT_32(31)) >> 26;
375
376 pParam->armv8.cb = sizeof(uint8_t);
377 pParam->fUse |= DISUSE_IMMEDIATE8;
378 return VINF_SUCCESS;
379}
380
381
382static int disArmV8ParseShift(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
383{
384 RT_NOREF(pDis, pInsnClass, pf64Bit);
385
386 AssertReturn(pInsnParm->cBits == 2, VERR_INTERNAL_ERROR_2);
387
388 uint32_t u32Shift = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
389 switch (u32Shift)
390 {
391 case 0: pParam->armv8.enmShift = kDisArmv8OpParmShiftLeft; break;
392 case 1: pParam->armv8.enmShift = kDisArmv8OpParmShiftRight; break;
393 case 2: pParam->armv8.enmShift = kDisArmv8OpParmShiftArithRight; break;
394 case 3: pParam->armv8.enmShift = kDisArmv8OpParmShiftRotate; break;
395 default:
396 AssertReleaseFailed();
397 }
398 return VINF_SUCCESS;
399}
400
401
402static int disArmV8ParseShiftAmount(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool *pf64Bit)
403{
404 RT_NOREF(pDis, pInsnClass, pf64Bit);
405
406 uint32_t u32Amount = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
407 /* For a 32-bit operand it is impossible to shift/rotate more than 31 bits. */
408 if ( !*pf64Bit
409 && u32Amount > 31)
410 return VERR_DIS_INVALID_OPCODE;
411
412 Assert(pParam->armv8.enmShift != kDisArmv8OpParmShiftNone);
413 Assert(u32Amount < 64);
414 pParam->armv8.cShift = (uint8_t)u32Amount;
415 /* Any shift operation with a 0 is essentially no shift being applied. */
416 if (pParam->armv8.cShift == 0)
417 pParam->armv8.enmShift = kDisArmv8OpParmShiftNone;
418 return VINF_SUCCESS;
419}
420
421
422static uint32_t disArmV8DecodeIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
423{
424 RT_NOREF(pDis, u32Insn, pInsnClass);
425 AssertFailed();
426 return UINT32_MAX;
427}
428
429
430static uint32_t disArmV8DecodeLookup(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
431{
432 RT_NOREF(pDis);
433
434 for (uint32_t i = 0; i < pInsnClass->Hdr.cDecode; i++)
435 {
436 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[i];
437 if (u32Insn == pOp->fValue)
438 return i;
439 }
440
441 return UINT32_MAX;
442}
443
444
445static int disArmV8A64ParseInstruction(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass)
446{
447 AssertPtr(pOp);
448 AssertPtr(pDis);
449 Assert((u32Insn & pOp->fMask) == pOp->fValue);
450
451 /* Should contain the parameter type on input. */
452 pDis->aParams[0].armv8.enmType = pInsnClass->aenmParamTypes[0];
453 pDis->aParams[1].armv8.enmType = pInsnClass->aenmParamTypes[1];
454 pDis->aParams[2].armv8.enmType = pInsnClass->aenmParamTypes[2];
455 pDis->aParams[3].armv8.enmType = pInsnClass->aenmParamTypes[3];
456 pDis->aParams[0].armv8.enmShift = kDisArmv8OpParmShiftNone;
457 pDis->aParams[1].armv8.enmShift = kDisArmv8OpParmShiftNone;
458 pDis->aParams[2].armv8.enmShift = kDisArmv8OpParmShiftNone;
459 pDis->aParams[3].armv8.enmShift = kDisArmv8OpParmShiftNone;
460 pDis->armv8.enmCond = kDisArmv8InstrCond_Al;
461
462 pDis->pCurInstr = &pOp->Opc;
463 Assert(&pOp->Opc != &g_ArmV8A64InvalidOpcode[0]);
464
465 bool f64Bit = false;
466
467 if (pInsnClass->fClass & DISARMV8INSNCLASS_F_SF)
468 f64Bit = RT_BOOL(u32Insn & RT_BIT_32(31));
469 else if (pInsnClass->fClass & DISARMV8INSNCLASS_F_FORCED_64BIT)
470 f64Bit = true;
471
472 int rc = VINF_SUCCESS;
473 for (uint32_t i = 0; i < RT_ELEMENTS(pInsnClass->aParms) && RT_SUCCESS(rc); i++)
474 {
475 PCDISARMV8INSNPARAM pInsnParm = &pInsnClass->aParms[i];
476 if (pInsnParm->idxParse != kDisParmParseNop)
477 rc = g_apfnDisasm[pInsnClass->aParms[i].idxParse](pDis, u32Insn, pInsnClass,
478 pInsnParm->idxParam != DIS_ARMV8_INSN_PARAM_UNSET
479 ? &pDis->aParams[pInsnParm->idxParam]
480 : NULL,
481 pInsnParm, &f64Bit);
482 else
483 break;
484 }
485
486 /* If parameter parsing returned an invalid opcode error the encoding is invalid. */
487 if (rc == VERR_DIS_INVALID_OPCODE)
488 {
489 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
490
491 pDis->aParams[0].armv8.enmType = kDisArmv8OpParmNone;
492 pDis->aParams[1].armv8.enmType = kDisArmv8OpParmNone;
493 pDis->aParams[2].armv8.enmType = kDisArmv8OpParmNone;
494 pDis->aParams[3].armv8.enmType = kDisArmv8OpParmNone;
495 }
496 pDis->rc = rc;
497 return rc;
498}
499
500
501static int disArmV8A64ParseInvOpcode(PDISSTATE pDis)
502{
503 pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
504 pDis->rc = VERR_DIS_INVALID_OPCODE;
505 return VERR_DIS_INVALID_OPCODE;
506}
507
508
509static int disInstrArmV8DecodeWorker(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8DECODEHDR pHdr)
510{
511 while ( pHdr
512 && pHdr->enmDecodeType != kDisArmV8DecodeType_InsnClass)
513 {
514 if (pHdr->enmDecodeType == kDisArmV8DecodeType_Map)
515 {
516 PCDISARMV8DECODEMAP pMap = (PCDISARMV8DECODEMAP)pHdr;
517
518 uint32_t idxNext = (u32Insn & pMap->fMask) >> pMap->cShift;
519 if (RT_LIKELY(idxNext < pMap->Hdr.cDecode))
520 pHdr = pMap->papNext[idxNext];
521 else
522 {
523 pHdr = NULL;
524 break;
525 }
526 }
527 else
528 {
529 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_Table);
530 PCDISARMV8DECODETBL pTbl = (PCDISARMV8DECODETBL)pHdr;
531
532 /* Walk all entries in the table and select the best match. */
533 pHdr = NULL;
534 for (uint32_t i = 0; i < pTbl->Hdr.cDecode; i++)
535 {
536 PCDISARMV8DECODETBLENTRY pEntry = &pTbl->paEntries[i];
537 if ((u32Insn & pEntry->fMask) == pEntry->fValue)
538 {
539 pHdr = pEntry->pHdrNext;
540 break;
541 }
542 }
543 }
544 }
545
546 if (pHdr)
547 {
548 Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_InsnClass);
549 PCDISARMV8INSNCLASS pInsnClass = (PCDISARMV8INSNCLASS)pHdr;
550
551 /* Decode the opcode from the instruction class. */
552 uint32_t uOpcRaw = 0;
553 if (pInsnClass->Hdr.cDecode > 1)
554 {
555 uOpcRaw = (u32Insn & pInsnClass->fMask) >> pInsnClass->cShift;
556 if (pInsnClass->enmOpcDecode != kDisArmV8OpcDecodeNop)
557 uOpcRaw = g_apfnOpcDecode[pInsnClass->enmOpcDecode](pDis, uOpcRaw, pInsnClass);
558 }
559
560 if (uOpcRaw < pInsnClass->Hdr.cDecode)
561 {
562 PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[uOpcRaw];
563 return disArmV8A64ParseInstruction(pDis, u32Insn, pOp, pInsnClass);
564 }
565 }
566
567 return disArmV8A64ParseInvOpcode(pDis);
568}
569
570
571/**
572 * Internal worker for DISInstrEx and DISInstrWithPrefetchedBytes.
573 *
574 * @returns VBox status code.
575 * @param pDis Initialized disassembler state.
576 * @param paOneByteMap The one byte opcode map to use.
577 * @param pcbInstr Where to store the instruction size. Can be NULL.
578 */
579DECLHIDDEN(int) disInstrWorkerArmV8(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
580{
581 RT_NOREF(paOneByteMap);
582
583 if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
584 {
585 *pcbInstr = sizeof(uint32_t);
586
587 /* Instructions are always little endian and 4 bytes. */
588 uint32_t u32Insn = disReadDWord(pDis, 0 /*offInstr*/);
589 if (RT_FAILURE(pDis->rc))
590 return pDis->rc;
591
592 /** @todo r=bird: This is a waste of time if the host is little endian... */
593 pDis->Instr.u32 = RT_LE2H_U32(u32Insn);
594 pDis->cbInstr = sizeof(u32Insn);
595
596 return disInstrArmV8DecodeWorker(pDis, u32Insn, &g_ArmV8A64DecodeL0.Hdr);
597 }
598
599 AssertReleaseFailed();
600 return VERR_NOT_IMPLEMENTED;
601}
602
603
604/**
605 * Inlined worker that initializes the disassembler state.
606 *
607 * @returns The primary opcode map to use.
608 * @param pDis The disassembler state.
609 * @param uInstrAddr The instruction address.
610 * @param enmCpuMode The CPU mode.
611 * @param fFilter The instruction filter settings.
612 * @param pfnReadBytes The byte reader, can be NULL.
613 * @param pvUser The user data for the reader.
614 */
615DECLHIDDEN(PCDISOPCODE) disInitializeStateArmV8(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter)
616{
617 RT_NOREF(pDis, enmCpuMode, fFilter);
618 return NULL;
619}
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