[99241] | 1 | /* $Id: DisasmCore-armv8.cpp 101539 2023-10-22 02:43:09Z 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/assert.h>
|
---|
[99242] | 36 | #include <iprt/errcore.h>
|
---|
[99241] | 37 | #include <iprt/param.h>
|
---|
| 38 | #include <iprt/string.h>
|
---|
| 39 | #include <iprt/stdarg.h>
|
---|
| 40 | #include "DisasmInternal-armv8.h"
|
---|
| 41 |
|
---|
| 42 |
|
---|
| 43 | /*********************************************************************************************************************************
|
---|
[99319] | 44 | * Structures and Typedefs *
|
---|
| 45 | *********************************************************************************************************************************/
|
---|
| 46 |
|
---|
| 47 | /** Parser callback.
|
---|
| 48 | * @remark no DECLCALLBACK() here because it's considered to be internal and
|
---|
| 49 | * there is no point in enforcing CDECL. */
|
---|
| 50 | typedef int FNDISPARSEARMV8(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit);
|
---|
| 51 | /** Pointer to a disassembler parser function. */
|
---|
| 52 | typedef FNDISPARSEARMV8 *PFNDISPARSEARMV8;
|
---|
| 53 |
|
---|
| 54 |
|
---|
| 55 | /** Opcode decoder callback.
|
---|
| 56 | * @remark no DECLCALLBACK() here because it's considered to be internal and
|
---|
| 57 | * there is no point in enforcing CDECL. */
|
---|
| 58 | typedef uint32_t FNDISDECODEARMV8(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass);
|
---|
| 59 | /** Pointer to a disassembler parser function. */
|
---|
| 60 | typedef FNDISDECODEARMV8 *PFNDISDECODEARMV8;
|
---|
| 61 |
|
---|
| 62 |
|
---|
| 63 | /*********************************************************************************************************************************
|
---|
[99241] | 64 | * Defined Constants And Macros *
|
---|
| 65 | *********************************************************************************************************************************/
|
---|
| 66 |
|
---|
| 67 |
|
---|
| 68 | /*********************************************************************************************************************************
|
---|
| 69 | * Internal Functions *
|
---|
| 70 | *********************************************************************************************************************************/
|
---|
| 71 | /** @name Parsers
|
---|
| 72 | * @{ */
|
---|
| 73 | static FNDISPARSEARMV8 disArmV8ParseIllegal;
|
---|
[99319] | 74 | static FNDISPARSEARMV8 disArmV8ParseImm;
|
---|
| 75 | static FNDISPARSEARMV8 disArmV8ParseImmRel;
|
---|
| 76 | static FNDISPARSEARMV8 disArmV8ParseImmAdr;
|
---|
| 77 | static FNDISPARSEARMV8 disArmV8ParseReg;
|
---|
| 78 | static FNDISPARSEARMV8 disArmV8ParseImmsImmrN;
|
---|
| 79 | static FNDISPARSEARMV8 disArmV8ParseHw;
|
---|
| 80 | static FNDISPARSEARMV8 disArmV8ParseCond;
|
---|
[99334] | 81 | static FNDISPARSEARMV8 disArmV8ParsePState;
|
---|
[99241] | 82 | /** @} */
|
---|
| 83 |
|
---|
| 84 |
|
---|
[99319] | 85 | /** @name Decoders
|
---|
| 86 | * @{ */
|
---|
| 87 | static FNDISDECODEARMV8 disArmV8DecodeIllegal;
|
---|
[99334] | 88 | static FNDISDECODEARMV8 disArmV8DecodeLookup;
|
---|
[99319] | 89 | /** @} */
|
---|
| 90 |
|
---|
| 91 |
|
---|
[99241] | 92 | /*********************************************************************************************************************************
|
---|
| 93 | * Global Variables *
|
---|
| 94 | *********************************************************************************************************************************/
|
---|
| 95 | /** Parser opcode table for full disassembly. */
|
---|
[99319] | 96 | static PFNDISPARSEARMV8 const g_apfnDisasm[kDisParmParseMax] =
|
---|
[99241] | 97 | {
|
---|
| 98 | disArmV8ParseIllegal,
|
---|
[99319] | 99 | disArmV8ParseImm,
|
---|
| 100 | disArmV8ParseImmRel,
|
---|
| 101 | disArmV8ParseImmAdr,
|
---|
| 102 | disArmV8ParseReg,
|
---|
| 103 | disArmV8ParseImmsImmrN,
|
---|
| 104 | disArmV8ParseHw,
|
---|
[99334] | 105 | disArmV8ParseCond,
|
---|
| 106 | disArmV8ParsePState,
|
---|
[99241] | 107 | };
|
---|
| 108 |
|
---|
[99319] | 109 |
|
---|
| 110 | /** Opcode decoder table. */
|
---|
| 111 | static PFNDISDECODEARMV8 const g_apfnOpcDecode[kDisArmV8OpcDecodeMax] =
|
---|
[99241] | 112 | {
|
---|
[99319] | 113 | disArmV8DecodeIllegal,
|
---|
[99334] | 114 | disArmV8DecodeLookup,
|
---|
[99319] | 115 | };
|
---|
| 116 |
|
---|
| 117 |
|
---|
| 118 | DECLINLINE(uint32_t) disArmV8ExtractBitVecFromInsn(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
|
---|
| 119 | {
|
---|
| 120 | uint32_t fMask = RT_BIT_32(idxBitStart + cBits) - 1;
|
---|
| 121 | return (u32Insn & fMask) >> idxBitStart;
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 |
|
---|
| 125 | DECLINLINE(int32_t) disArmV8ExtractBitVecFromInsnSignExtend(uint32_t u32Insn, uint8_t idxBitStart, uint8_t cBits)
|
---|
| 126 | {
|
---|
| 127 | uint32_t fMask = RT_BIT_32(idxBitStart + cBits) - 1;
|
---|
| 128 | uint32_t fSign = ~(UINT32_MAX & (RT_BIT_32(cBits - 1) - 1));
|
---|
| 129 | uint32_t fValue = (u32Insn & fMask) >> idxBitStart;
|
---|
| 130 | if (fValue & fSign)
|
---|
| 131 | return (int32_t)(fValue | fSign);
|
---|
| 132 |
|
---|
| 133 | return (int32_t)fValue;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 |
|
---|
| 137 | static int disArmV8ParseIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 138 | {
|
---|
| 139 | RT_NOREF(pDis, u32Insn, pInsnClass, pParam, pInsnParm, f64Bit);
|
---|
[99241] | 140 | AssertFailed();
|
---|
[99319] | 141 | return VERR_INTERNAL_ERROR;
|
---|
[99241] | 142 | }
|
---|
| 143 |
|
---|
| 144 |
|
---|
[99319] | 145 | static int disArmV8ParseImm(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 146 | {
|
---|
| 147 | RT_NOREF(pDis, pInsnClass, f64Bit);
|
---|
| 148 |
|
---|
| 149 | AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
|
---|
| 150 |
|
---|
| 151 | pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
|
---|
| 152 | if (pInsnParm->cBits <= 8)
|
---|
| 153 | {
|
---|
[101539] | 154 | pParam->armv8.cb = sizeof(uint8_t);
|
---|
[99319] | 155 | pParam->fUse |= DISUSE_IMMEDIATE8;
|
---|
| 156 | }
|
---|
| 157 | else if (pInsnParm->cBits <= 16)
|
---|
| 158 | {
|
---|
[101539] | 159 | pParam->armv8.cb = sizeof(uint16_t);
|
---|
[99319] | 160 | pParam->fUse |= DISUSE_IMMEDIATE16;
|
---|
| 161 | }
|
---|
| 162 | else if (pInsnParm->cBits <= 32)
|
---|
| 163 | {
|
---|
[101539] | 164 | pParam->armv8.cb = sizeof(uint32_t);
|
---|
[99319] | 165 | pParam->fUse |= DISUSE_IMMEDIATE32;
|
---|
| 166 | }
|
---|
| 167 | else
|
---|
| 168 | AssertReleaseFailed();
|
---|
| 169 |
|
---|
| 170 | return VINF_SUCCESS;
|
---|
| 171 | }
|
---|
| 172 |
|
---|
| 173 |
|
---|
| 174 | static int disArmV8ParseImmRel(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 175 | {
|
---|
| 176 | RT_NOREF(pDis, pInsnClass, f64Bit);
|
---|
| 177 |
|
---|
| 178 | AssertReturn(pInsnParm->idxBitStart + pInsnParm->cBits < 32, VERR_INTERNAL_ERROR_2);
|
---|
| 179 |
|
---|
| 180 | pParam->uValue = (int64_t)disArmV8ExtractBitVecFromInsnSignExtend(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
|
---|
| 181 | if (pInsnParm->cBits <= 8)
|
---|
| 182 | {
|
---|
[101539] | 183 | pParam->armv8.cb = sizeof(int8_t);
|
---|
[99319] | 184 | pParam->fUse |= DISUSE_IMMEDIATE8_REL;
|
---|
| 185 | }
|
---|
| 186 | else if (pInsnParm->cBits <= 16)
|
---|
| 187 | {
|
---|
[101539] | 188 | pParam->armv8.cb = sizeof(int16_t);
|
---|
[99319] | 189 | pParam->fUse |= DISUSE_IMMEDIATE16_REL;
|
---|
| 190 | }
|
---|
| 191 | else if (pInsnParm->cBits <= 32)
|
---|
| 192 | {
|
---|
[101539] | 193 | pParam->armv8.cb = sizeof(int32_t);
|
---|
[99319] | 194 | pParam->fUse |= DISUSE_IMMEDIATE32_REL;
|
---|
| 195 | }
|
---|
| 196 | else
|
---|
| 197 | AssertReleaseFailed();
|
---|
| 198 |
|
---|
| 199 | return VINF_SUCCESS;
|
---|
| 200 | }
|
---|
| 201 |
|
---|
| 202 |
|
---|
| 203 | static int disArmV8ParseImmAdr(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 204 | {
|
---|
| 205 | RT_NOREF(pDis, pInsnClass, f64Bit, pInsnParm);
|
---|
| 206 |
|
---|
| 207 | pParam->uValue = disArmV8ExtractBitVecFromInsn(u32Insn, 5, 19);
|
---|
| 208 | pParam->uValue |= disArmV8ExtractBitVecFromInsn(u32Insn, 29, 2) << 29;
|
---|
| 209 | pParam->fUse |= DISUSE_IMMEDIATE32;
|
---|
| 210 | return VINF_SUCCESS;
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 |
|
---|
| 214 | static int disArmV8ParseReg(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 215 | {
|
---|
| 216 | RT_NOREF(pDis, pInsnClass);
|
---|
[101539] | 217 | pParam->armv8.Reg.idxGenReg = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
|
---|
| 218 | pParam->armv8.cb = f64Bit ? sizeof(uint64_t) : sizeof(uint32_t);
|
---|
[99319] | 219 | pParam->fUse |= f64Bit ? DISUSE_REG_GEN64 : DISUSE_REG_GEN32;
|
---|
| 220 | return VINF_SUCCESS;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 |
|
---|
| 224 | static int disArmV8ParseImmsImmrN(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 225 | {
|
---|
| 226 | RT_NOREF(pDis);
|
---|
| 227 | AssertReturn(pInsnParm->cBits == 13, VERR_INTERNAL_ERROR_2);
|
---|
| 228 |
|
---|
| 229 | uint32_t u32ImmRaw = disArmV8ExtractBitVecFromInsn(u32Insn, pInsnParm->idxBitStart, pInsnParm->cBits);
|
---|
| 230 | /* N bit must be 0 if 32-bit variant is used. */
|
---|
| 231 | if ( ( (u32ImmRaw & RT_BIT_32(12))
|
---|
| 232 | && !f64Bit)
|
---|
| 233 | || ( !(u32ImmRaw & RT_BIT_32(12))
|
---|
| 234 | && f64Bit
|
---|
| 235 | && (pInsnClass->fClass & DISARMV8INSNCLASS_F_N_FORCED_1_ON_64BIT)))
|
---|
| 236 | return VERR_DIS_INVALID_OPCODE;
|
---|
| 237 |
|
---|
| 238 | /** @todo Decode according to spec. */
|
---|
| 239 | pParam->uValue = u32ImmRaw;
|
---|
[101539] | 240 | pParam->armv8.cb = sizeof(uint32_t);
|
---|
[99319] | 241 | pParam->fUse |= DISUSE_IMMEDIATE32;
|
---|
| 242 | return VINF_SUCCESS;
|
---|
| 243 | }
|
---|
| 244 |
|
---|
| 245 |
|
---|
| 246 | static int disArmV8ParseHw(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 247 | {
|
---|
| 248 | RT_NOREF(pDis, u32Insn, pInsnClass, pParam, pInsnParm, f64Bit);
|
---|
| 249 | AssertFailed();
|
---|
| 250 | /** @todo */
|
---|
| 251 | return VINF_SUCCESS;
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 |
|
---|
| 255 | static int disArmV8ParseCond(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 256 | {
|
---|
| 257 | RT_NOREF(pDis, u32Insn, pInsnClass, pParam, pInsnParm, f64Bit);
|
---|
| 258 | //AssertFailed();
|
---|
| 259 | /** @todo */
|
---|
| 260 | return VINF_SUCCESS;
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 |
|
---|
[99334] | 264 | static int disArmV8ParsePState(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass, PDISOPPARAM pParam, PCDISARMV8INSNPARAM pInsnParm, bool f64Bit)
|
---|
| 265 | {
|
---|
| 266 | RT_NOREF(pDis, u32Insn, pInsnClass, pParam, pInsnParm, f64Bit);
|
---|
| 267 | //AssertFailed();
|
---|
| 268 | /** @todo */
|
---|
| 269 | return VINF_SUCCESS;
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 |
|
---|
[99319] | 273 | static uint32_t disArmV8DecodeIllegal(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
|
---|
| 274 | {
|
---|
| 275 | RT_NOREF(pDis, u32Insn, pInsnClass);
|
---|
| 276 | AssertFailed();
|
---|
| 277 | return UINT32_MAX;
|
---|
| 278 | }
|
---|
| 279 |
|
---|
| 280 |
|
---|
[99334] | 281 | static uint32_t disArmV8DecodeLookup(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8INSNCLASS pInsnClass)
|
---|
[99319] | 282 | {
|
---|
[99334] | 283 | RT_NOREF(pDis);
|
---|
| 284 |
|
---|
| 285 | for (uint32_t i = 0; i < pInsnClass->Hdr.cDecode; i++)
|
---|
| 286 | {
|
---|
| 287 | PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[i];
|
---|
| 288 | if (u32Insn == pOp->fValue)
|
---|
| 289 | return i;
|
---|
| 290 | }
|
---|
| 291 |
|
---|
| 292 | return UINT32_MAX;
|
---|
| 293 | }
|
---|
| 294 |
|
---|
| 295 |
|
---|
| 296 | static int disArmV8A64ParseInstruction(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8OPCODE pOp, PCDISARMV8INSNCLASS pInsnClass)
|
---|
| 297 | {
|
---|
[99319] | 298 | AssertPtr(pOp);
|
---|
| 299 | AssertPtr(pDis);
|
---|
[99334] | 300 | Assert((u32Insn & pOp->fMask) == pOp->fValue);
|
---|
[99319] | 301 |
|
---|
| 302 | /* Should contain the parameter type on input. */
|
---|
[101539] | 303 | pDis->Param1.armv8.fParam = pOp->Opc.fParam1;
|
---|
| 304 | pDis->Param2.armv8.fParam = pOp->Opc.fParam2;
|
---|
| 305 | pDis->Param3.armv8.fParam = pOp->Opc.fParam3;
|
---|
| 306 | pDis->Param4.armv8.fParam = pOp->Opc.fParam4;
|
---|
[99319] | 307 |
|
---|
[99334] | 308 | pDis->pCurInstr = &pOp->Opc;
|
---|
| 309 | Assert(&pOp->Opc != &g_ArmV8A64InvalidOpcode[0]);
|
---|
[99319] | 310 |
|
---|
| 311 | bool f64Bit = false;
|
---|
| 312 |
|
---|
| 313 | if (pInsnClass->fClass & DISARMV8INSNCLASS_F_SF)
|
---|
| 314 | f64Bit = RT_BOOL(u32Insn & RT_BIT_32(31));
|
---|
| 315 | else if (pInsnClass->fClass & DISARMV8INSNCLASS_F_FORCED_64BIT)
|
---|
| 316 | f64Bit = true;
|
---|
| 317 |
|
---|
| 318 | int rc = VINF_SUCCESS;
|
---|
| 319 | if (pInsnClass->aParms[0].idxParse != kDisParmParseNop)
|
---|
| 320 | rc = g_apfnDisasm[pInsnClass->aParms[0].idxParse](pDis, u32Insn, pInsnClass, &pDis->Param1, &pInsnClass->aParms[0], f64Bit);
|
---|
| 321 |
|
---|
| 322 | if ( pInsnClass->aParms[1].idxParse != kDisParmParseNop
|
---|
| 323 | && RT_SUCCESS(rc))
|
---|
| 324 | rc = g_apfnDisasm[pInsnClass->aParms[1].idxParse](pDis, u32Insn, pInsnClass, &pDis->Param2, &pInsnClass->aParms[1], f64Bit);
|
---|
| 325 |
|
---|
| 326 | if ( pInsnClass->aParms[2].idxParse != kDisParmParseNop
|
---|
| 327 | && RT_SUCCESS(rc))
|
---|
| 328 | rc = g_apfnDisasm[pInsnClass->aParms[2].idxParse](pDis, u32Insn, pInsnClass, &pDis->Param3, &pInsnClass->aParms[2], f64Bit);
|
---|
| 329 |
|
---|
| 330 | if ( pInsnClass->aParms[3].idxParse != kDisParmParseNop
|
---|
| 331 | && RT_SUCCESS(rc))
|
---|
| 332 | rc = g_apfnDisasm[pInsnClass->aParms[3].idxParse](pDis, u32Insn, pInsnClass, &pDis->Param4, &pInsnClass->aParms[3], f64Bit);
|
---|
| 333 |
|
---|
| 334 | /* If parameter parsing returned an invalid opcode error the encoding is invalid. */
|
---|
| 335 | if (rc == VERR_DIS_INVALID_OPCODE)
|
---|
| 336 | {
|
---|
| 337 | pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
|
---|
| 338 |
|
---|
[101539] | 339 | pDis->Param1.armv8.fParam = g_ArmV8A64InvalidOpcode[0].fParam1;
|
---|
| 340 | pDis->Param2.armv8.fParam = g_ArmV8A64InvalidOpcode[0].fParam2;
|
---|
| 341 | pDis->Param3.armv8.fParam = g_ArmV8A64InvalidOpcode[0].fParam3;
|
---|
| 342 | pDis->Param4.armv8.fParam = g_ArmV8A64InvalidOpcode[0].fParam4;
|
---|
[99319] | 343 | }
|
---|
| 344 | pDis->rc = rc;
|
---|
| 345 | return rc;
|
---|
| 346 | }
|
---|
| 347 |
|
---|
| 348 |
|
---|
| 349 | static int disArmV8A64ParseInvOpcode(PDISSTATE pDis)
|
---|
| 350 | {
|
---|
| 351 | pDis->pCurInstr = &g_ArmV8A64InvalidOpcode[0];
|
---|
| 352 | pDis->rc = VERR_DIS_INVALID_OPCODE;
|
---|
| 353 | return VERR_DIS_INVALID_OPCODE;
|
---|
| 354 | }
|
---|
| 355 |
|
---|
| 356 |
|
---|
| 357 | static int disInstrArmV8DecodeWorker(PDISSTATE pDis, uint32_t u32Insn, PCDISARMV8DECODEHDR pHdr)
|
---|
| 358 | {
|
---|
| 359 | while ( pHdr
|
---|
| 360 | && pHdr->enmDecodeType != kDisArmV8DecodeType_InsnClass)
|
---|
| 361 | {
|
---|
| 362 | if (pHdr->enmDecodeType == kDisArmV8DecodeType_Map)
|
---|
| 363 | {
|
---|
| 364 | PCDISARMV8DECODEMAP pMap = (PCDISARMV8DECODEMAP)pHdr;
|
---|
| 365 |
|
---|
| 366 | uint32_t idxNext = (u32Insn & pMap->fMask) >> pMap->cShift;
|
---|
| 367 | if (RT_LIKELY(idxNext < pMap->Hdr.cDecode))
|
---|
| 368 | pHdr = pMap->papNext[idxNext];
|
---|
| 369 | else
|
---|
| 370 | {
|
---|
| 371 | pHdr = NULL;
|
---|
| 372 | break;
|
---|
| 373 | }
|
---|
| 374 | }
|
---|
| 375 | else
|
---|
| 376 | {
|
---|
| 377 | Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_Table);
|
---|
| 378 | PCDISARMV8DECODETBL pTbl = (PCDISARMV8DECODETBL)pHdr;
|
---|
| 379 |
|
---|
| 380 | /* Walk all entries in the table and select the best match. */
|
---|
| 381 | pHdr = NULL;
|
---|
| 382 | for (uint32_t i = 0; i < pTbl->Hdr.cDecode; i++)
|
---|
| 383 | {
|
---|
| 384 | PCDISARMV8DECODETBLENTRY pEntry = &pTbl->paEntries[i];
|
---|
| 385 | if ((u32Insn & pEntry->fMask) == pEntry->fValue)
|
---|
| 386 | {
|
---|
| 387 | pHdr = pEntry->pHdrNext;
|
---|
| 388 | break;
|
---|
| 389 | }
|
---|
| 390 | }
|
---|
| 391 | }
|
---|
| 392 | }
|
---|
| 393 |
|
---|
| 394 | if (pHdr)
|
---|
| 395 | {
|
---|
| 396 | Assert(pHdr->enmDecodeType == kDisArmV8DecodeType_InsnClass);
|
---|
| 397 | PCDISARMV8INSNCLASS pInsnClass = (PCDISARMV8INSNCLASS)pHdr;
|
---|
| 398 |
|
---|
| 399 | /* Decode the opcode from the instruction class. */
|
---|
[99334] | 400 | uint32_t uOpcRaw = 0;
|
---|
| 401 | if (pInsnClass->Hdr.cDecode > 1)
|
---|
| 402 | {
|
---|
| 403 | uOpcRaw = (u32Insn & pInsnClass->fMask) >> pInsnClass->cShift;
|
---|
| 404 | if (pInsnClass->enmOpcDecode != kDisArmV8OpcDecodeNop)
|
---|
| 405 | uOpcRaw = g_apfnOpcDecode[pInsnClass->enmOpcDecode](pDis, uOpcRaw, pInsnClass);
|
---|
| 406 | }
|
---|
[99319] | 407 |
|
---|
| 408 | if (uOpcRaw < pInsnClass->Hdr.cDecode)
|
---|
| 409 | {
|
---|
[99334] | 410 | PCDISARMV8OPCODE pOp = &pInsnClass->paOpcodes[uOpcRaw];
|
---|
[99319] | 411 | return disArmV8A64ParseInstruction(pDis, u32Insn, pOp, pInsnClass);
|
---|
| 412 | }
|
---|
| 413 | }
|
---|
| 414 |
|
---|
| 415 | return disArmV8A64ParseInvOpcode(pDis);
|
---|
| 416 | }
|
---|
| 417 |
|
---|
| 418 |
|
---|
[99241] | 419 | /**
|
---|
| 420 | * Internal worker for DISInstrEx and DISInstrWithPrefetchedBytes.
|
---|
| 421 | *
|
---|
| 422 | * @returns VBox status code.
|
---|
| 423 | * @param pDis Initialized disassembler state.
|
---|
| 424 | * @param paOneByteMap The one byte opcode map to use.
|
---|
| 425 | * @param pcbInstr Where to store the instruction size. Can be NULL.
|
---|
| 426 | */
|
---|
| 427 | DECLHIDDEN(int) disInstrWorkerArmV8(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
|
---|
| 428 | {
|
---|
[99319] | 429 | RT_NOREF(paOneByteMap);
|
---|
| 430 |
|
---|
| 431 | if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
|
---|
| 432 | {
|
---|
| 433 | *pcbInstr = sizeof(uint32_t);
|
---|
| 434 |
|
---|
| 435 | /* Instructions are always little endian and 4 bytes. */
|
---|
| 436 | uint32_t u32Insn = disReadDWord(pDis, 0 /*offInstr*/);
|
---|
| 437 | if (RT_FAILURE(pDis->rc))
|
---|
| 438 | return pDis->rc;
|
---|
| 439 |
|
---|
[101539] | 440 | /** @todo r=bird: This is a waste of time if the host is little endian... */
|
---|
| 441 | pDis->Instr.u32 = RT_LE2H_U32(u32Insn);
|
---|
| 442 | pDis->cbInstr = sizeof(u32Insn);
|
---|
[99319] | 443 |
|
---|
| 444 | return disInstrArmV8DecodeWorker(pDis, u32Insn, &g_ArmV8A64DecodeL0.Hdr);
|
---|
| 445 | }
|
---|
| 446 |
|
---|
| 447 | AssertReleaseFailed();
|
---|
[99241] | 448 | return VERR_NOT_IMPLEMENTED;
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 |
|
---|
| 452 | /**
|
---|
| 453 | * Inlined worker that initializes the disassembler state.
|
---|
| 454 | *
|
---|
| 455 | * @returns The primary opcode map to use.
|
---|
| 456 | * @param pDis The disassembler state.
|
---|
| 457 | * @param uInstrAddr The instruction address.
|
---|
| 458 | * @param enmCpuMode The CPU mode.
|
---|
| 459 | * @param fFilter The instruction filter settings.
|
---|
| 460 | * @param pfnReadBytes The byte reader, can be NULL.
|
---|
| 461 | * @param pvUser The user data for the reader.
|
---|
| 462 | */
|
---|
| 463 | DECLHIDDEN(PCDISOPCODE) disInitializeStateArmV8(PDISSTATE pDis, DISCPUMODE enmCpuMode, uint32_t fFilter)
|
---|
| 464 | {
|
---|
| 465 | RT_NOREF(pDis, enmCpuMode, fFilter);
|
---|
| 466 | return NULL;
|
---|
| 467 | }
|
---|