VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmFormatArmV8.cpp@ 107044

Last change on this file since 107044 was 106816, checked in by vboxsync, 3 weeks ago

Disassembler: Decode SIMD load/store multiple structures (post-indexed) instructions, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.8 KB
Line 
1/* $Id: DisasmFormatArmV8.cpp 106816 2024-11-01 09:24:29Z vboxsync $ */
2/** @file
3 * VBox Disassembler - ARMv8 Style Formatter.
4 */
5
6/*
7 * Copyright (C) 2008-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#include <VBox/dis.h>
33#include "DisasmInternal.h"
34#include "DisasmInternal-armv8.h"
35#include <iprt/armv8.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38#include <iprt/errcore.h>
39#include <iprt/string.h>
40
41
42/*********************************************************************************************************************************
43* Global Variables *
44*********************************************************************************************************************************/
45static const char g_szSpaces[] =
46" ";
47static const char g_aszArmV8RegGen32[32][4] =
48{
49 "w0\0", "w1\0", "w2\0", "w3\0", "w4\0", "w5\0", "w6\0", "w7\0", "w8\0", "w9\0", "w10", "w11", "w12", "w13", "w14", "w15",
50 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr"
51};
52static const char g_aszArmV8RegGen64[32][4] =
53{
54 "x0\0", "x1\0", "x2\0", "x3\0", "x4\0", "x5\0", "x6\0", "x7\0", "x8\0", "x9\0", "x10", "x11", "x12", "x13", "x14", "x15",
55 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "xzr"
56};
57static const char g_aszArmV8RegFpSingle[32][4] =
58{
59 "s0\0", "s1\0", "s2\0", "s3\0", "s4\0", "s5\0", "s6\0", "s7\0", "s8\0", "s9\0", "s10", "s11", "s12", "s13", "s14", "s15",
60 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
61};
62static const char g_aszArmV8RegFpDouble[32][4] =
63{
64 "d0\0", "d1\0", "d2\0", "d3\0", "d4\0", "d5\0", "d6\0", "d7\0", "d8\0", "d9\0", "d10", "d11", "d12", "d13", "d14", "d15",
65 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"
66};
67static const char g_aszArmV8RegFpHalf[32][4] =
68{
69 "h0\0", "h1\0", "h2\0", "h3\0", "h4\0", "h5\0", "h6\0", "h7\0", "h8\0", "h9\0", "h10", "h11", "h12", "h13", "h14", "h15",
70 "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23", "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31"
71};
72static const char g_aszArmV8RegSimdScalar8Bit[32][4] =
73{
74 "b0\0", "b1\0", "b2\0", "b3\0", "b4\0", "b5\0", "b6\0", "b7\0", "b8\0", "b9\0", "b10", "b11", "b12", "b13", "b14", "b15",
75 "b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23", "b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31"
76};
77static const char g_aszArmV8RegSimdScalar128Bit[32][4] =
78{
79 "q0\0", "q1\0", "q2\0", "q3\0", "q4\0", "q5\0", "q6\0", "q7\0", "q8\0", "q9\0", "q10", "q11", "q12", "q13", "q14", "q15",
80 "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"
81};
82static const char g_aszArmV8RegSimdVector[32][4] =
83{
84 "v0\0", "v1\0", "v2\0", "v3\0", "v4\0", "v5\0", "v6\0", "v7\0", "v8\0", "v9\0", "v10", "v11", "v12", "v13", "v14", "v15",
85 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
86};
87static const char g_aszArmV8Cond[16][3] =
88{
89 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", "al"
90};
91static const char *g_apszArmV8PState[] =
92{
93 /* kDisArmv8InstrPState_SPSel */ "spsel",
94 /* kDisArmv8InstrPState_DAIFSet */ "daifset",
95 /* kDisArmv8InstrPState_DAIFClr */ "daifclr",
96 /* kDisArmv8InstrPState_UAO */ "uao",
97 /* kDisArmv8InstrPState_PAN */ "pan",
98 /* kDisArmv8InstrPState_ALLINT */ "allint",
99 /* kDisArmv8InstrPState_PM */ "pm",
100 /* kDisArmv8InstrPState_SSBS */ "ssbs",
101 /* kDisArmv8InstrPState_DIT */ "dit",
102 /* kDisArmv8InstrPState_SVCRSM */ "svcrsm",
103 /* kDisArmv8InstrPState_SVCRZA */ "svcrza",
104 /* kDisArmv8InstrPState_SVCRSMZA */ "svcrsmza",
105 /* kDisArmv8InstrPState_TCO */ "tco"
106};
107static const char g_aszArmV8VecRegType[9][4] =
108{
109 /* kDisOpParamArmV8VecRegType_None */ "\0\0\0",
110 /* kDisOpParamArmV8VecRegType_8B */ "8B\0",
111 /* kDisOpParamArmV8VecRegType_16B */ "16B",
112 /* kDisOpParamArmV8VecRegType_4H */ "4H\0",
113 /* kDisOpParamArmV8VecRegType_8H */ "8H\0",
114 /* kDisOpParamArmV8VecRegType_2S */ "2S\0",
115 /* kDisOpParamArmV8VecRegType_4S */ "4S\0",
116 /* kDisOpParamArmV8VecRegType_1D */ "1D\0",
117 /* kDisOpParamArmV8VecRegType_2D */ "2D\0"
118};
119
120
121/**
122 * List of known system registers.
123 *
124 * The list MUST be in ascending order of the system register ID!
125 */
126static const struct
127{
128 /** IPRT system register ID. */
129 uint32_t idSysReg;
130 /** Name of the system register. */
131 const char *pszSysReg;
132 /** Character count of the system register name. */
133 size_t cchSysReg;
134} g_aArmV8SysReg64[] =
135{
136#define DIS_ARMV8_SYSREG(a_idSysReg) { (ARMV8_AARCH64_SYSREG_ ## a_idSysReg), #a_idSysReg, sizeof(#a_idSysReg) - 1 }
137 DIS_ARMV8_SYSREG(OSDTRRX_EL1),
138 DIS_ARMV8_SYSREG(MDSCR_EL1),
139 //DIS_ARMV8_SYSREG(DBGBVRn_EL1(a_Id)),
140 //DIS_ARMV8_SYSREG(DBGBCRn_EL1(a_Id)),
141 //DIS_ARMV8_SYSREG(DBGWVRn_EL1(a_Id)),
142 //DIS_ARMV8_SYSREG(DBGWCRn_EL1(a_Id)),
143 DIS_ARMV8_SYSREG(MDCCINT_EL1),
144 DIS_ARMV8_SYSREG(OSDTRTX_EL1),
145 DIS_ARMV8_SYSREG(OSECCR_EL1),
146 DIS_ARMV8_SYSREG(MDRAR_EL1),
147 DIS_ARMV8_SYSREG(OSLAR_EL1),
148 DIS_ARMV8_SYSREG(OSLSR_EL1),
149 DIS_ARMV8_SYSREG(OSDLR_EL1),
150 DIS_ARMV8_SYSREG(MIDR_EL1),
151 DIS_ARMV8_SYSREG(MPIDR_EL1),
152 DIS_ARMV8_SYSREG(REVIDR_EL1),
153 DIS_ARMV8_SYSREG(ID_PFR0_EL1),
154 DIS_ARMV8_SYSREG(ID_PFR1_EL1),
155 DIS_ARMV8_SYSREG(ID_DFR0_EL1),
156 DIS_ARMV8_SYSREG(ID_AFR0_EL1),
157 DIS_ARMV8_SYSREG(ID_MMFR0_EL1),
158 DIS_ARMV8_SYSREG(ID_MMFR1_EL1),
159 DIS_ARMV8_SYSREG(ID_MMFR2_EL1),
160 DIS_ARMV8_SYSREG(ID_MMFR3_EL1),
161 DIS_ARMV8_SYSREG(ID_ISAR0_EL1),
162 DIS_ARMV8_SYSREG(ID_ISAR1_EL1),
163 DIS_ARMV8_SYSREG(ID_ISAR2_EL1),
164 DIS_ARMV8_SYSREG(ID_ISAR3_EL1),
165 DIS_ARMV8_SYSREG(ID_ISAR4_EL1),
166 DIS_ARMV8_SYSREG(ID_ISAR5_EL1),
167 DIS_ARMV8_SYSREG(ID_MMFR4_EL1),
168 DIS_ARMV8_SYSREG(ID_ISAR6_EL1),
169 DIS_ARMV8_SYSREG(MVFR0_EL1),
170 DIS_ARMV8_SYSREG(MVFR1_EL1),
171 DIS_ARMV8_SYSREG(MVFR2_EL1),
172 DIS_ARMV8_SYSREG(ID_PFR2_EL1),
173 DIS_ARMV8_SYSREG(ID_DFR1_EL1),
174 DIS_ARMV8_SYSREG(ID_MMFR5_EL1),
175 DIS_ARMV8_SYSREG(ID_AA64PFR0_EL1),
176 DIS_ARMV8_SYSREG(ID_AA64PFR1_EL1),
177 DIS_ARMV8_SYSREG(ID_AA64ZFR0_EL1),
178 DIS_ARMV8_SYSREG(ID_AA64SMFR0_EL1),
179 DIS_ARMV8_SYSREG(ID_AA64DFR0_EL1),
180 DIS_ARMV8_SYSREG(ID_AA64DFR1_EL1),
181 DIS_ARMV8_SYSREG(ID_AA64AFR0_EL1),
182 DIS_ARMV8_SYSREG(ID_AA64AFR1_EL1),
183 DIS_ARMV8_SYSREG(ID_AA64ISAR0_EL1),
184 DIS_ARMV8_SYSREG(ID_AA64ISAR1_EL1),
185 DIS_ARMV8_SYSREG(ID_AA64ISAR2_EL1),
186 DIS_ARMV8_SYSREG(ID_AA64MMFR0_EL1),
187 DIS_ARMV8_SYSREG(ID_AA64MMFR1_EL1),
188 DIS_ARMV8_SYSREG(ID_AA64MMFR2_EL1),
189 DIS_ARMV8_SYSREG(SCTRL_EL1),
190 DIS_ARMV8_SYSREG(ACTRL_EL1),
191 DIS_ARMV8_SYSREG(CPACR_EL1),
192 DIS_ARMV8_SYSREG(RGSR_EL1),
193 DIS_ARMV8_SYSREG(GCR_EL1),
194 DIS_ARMV8_SYSREG(ZCR_EL1),
195 DIS_ARMV8_SYSREG(TRFCR_EL1),
196 DIS_ARMV8_SYSREG(SMPRI_EL1),
197 DIS_ARMV8_SYSREG(SMCR_EL1),
198 DIS_ARMV8_SYSREG(TTBR0_EL1),
199 DIS_ARMV8_SYSREG(TTBR1_EL1),
200 DIS_ARMV8_SYSREG(TCR_EL1),
201 DIS_ARMV8_SYSREG(APIAKeyLo_EL1),
202 DIS_ARMV8_SYSREG(APIAKeyHi_EL1),
203 DIS_ARMV8_SYSREG(APIBKeyLo_EL1),
204 DIS_ARMV8_SYSREG(APIBKeyHi_EL1),
205 DIS_ARMV8_SYSREG(APDAKeyLo_EL1),
206 DIS_ARMV8_SYSREG(APDAKeyHi_EL1),
207 DIS_ARMV8_SYSREG(APDBKeyLo_EL1),
208 DIS_ARMV8_SYSREG(APDBKeyHi_EL1),
209 DIS_ARMV8_SYSREG(APGAKeyLo_EL1),
210 DIS_ARMV8_SYSREG(APGAKeyHi_EL1),
211 DIS_ARMV8_SYSREG(SPSR_EL1),
212 DIS_ARMV8_SYSREG(ELR_EL1),
213 DIS_ARMV8_SYSREG(SP_EL0),
214 DIS_ARMV8_SYSREG(SPSEL),
215 DIS_ARMV8_SYSREG(CURRENTEL),
216 DIS_ARMV8_SYSREG(PAN),
217 DIS_ARMV8_SYSREG(UAO),
218 DIS_ARMV8_SYSREG(ALLINT),
219 DIS_ARMV8_SYSREG(ICC_PMR_EL1),
220 DIS_ARMV8_SYSREG(AFSR0_EL1),
221 DIS_ARMV8_SYSREG(AFSR1_EL1),
222 DIS_ARMV8_SYSREG(ESR_EL1),
223 DIS_ARMV8_SYSREG(ERRIDR_EL1),
224 DIS_ARMV8_SYSREG(ERRSELR_EL1),
225 DIS_ARMV8_SYSREG(FAR_EL1),
226 DIS_ARMV8_SYSREG(PAR_EL1),
227 DIS_ARMV8_SYSREG(MAIR_EL1),
228 DIS_ARMV8_SYSREG(AMAIR_EL1),
229 DIS_ARMV8_SYSREG(VBAR_EL1),
230 DIS_ARMV8_SYSREG(ICC_IAR0_EL1),
231 DIS_ARMV8_SYSREG(ICC_EOIR0_EL1),
232 DIS_ARMV8_SYSREG(ICC_HPPIR0_EL1),
233 DIS_ARMV8_SYSREG(ICC_BPR0_EL1),
234 DIS_ARMV8_SYSREG(ICC_AP0R0_EL1),
235 DIS_ARMV8_SYSREG(ICC_AP0R1_EL1),
236 DIS_ARMV8_SYSREG(ICC_AP0R2_EL1),
237 DIS_ARMV8_SYSREG(ICC_AP0R3_EL1),
238 DIS_ARMV8_SYSREG(ICC_AP1R0_EL1),
239 DIS_ARMV8_SYSREG(ICC_AP1R1_EL1),
240 DIS_ARMV8_SYSREG(ICC_AP1R2_EL1),
241 DIS_ARMV8_SYSREG(ICC_AP1R3_EL1),
242 DIS_ARMV8_SYSREG(ICC_NMIAR1_EL1),
243 DIS_ARMV8_SYSREG(ICC_DIR_EL1),
244 DIS_ARMV8_SYSREG(ICC_RPR_EL1),
245 DIS_ARMV8_SYSREG(ICC_SGI1R_EL1),
246 DIS_ARMV8_SYSREG(ICC_ASGI1R_EL1),
247 DIS_ARMV8_SYSREG(ICC_SGI0R_EL1),
248 DIS_ARMV8_SYSREG(ICC_IAR1_EL1),
249 DIS_ARMV8_SYSREG(ICC_EOIR1_EL1),
250 DIS_ARMV8_SYSREG(ICC_HPPIR1_EL1),
251 DIS_ARMV8_SYSREG(ICC_BPR1_EL1),
252 DIS_ARMV8_SYSREG(ICC_CTLR_EL1),
253 DIS_ARMV8_SYSREG(ICC_SRE_EL1),
254 DIS_ARMV8_SYSREG(ICC_IGRPEN0_EL1),
255 DIS_ARMV8_SYSREG(ICC_IGRPEN1_EL1),
256 DIS_ARMV8_SYSREG(CONTEXTIDR_EL1),
257 DIS_ARMV8_SYSREG(TPIDR_EL1),
258 DIS_ARMV8_SYSREG(CNTKCTL_EL1),
259 DIS_ARMV8_SYSREG(CSSELR_EL1),
260 DIS_ARMV8_SYSREG(NZCV),
261 DIS_ARMV8_SYSREG(DAIF),
262 DIS_ARMV8_SYSREG(SVCR),
263 DIS_ARMV8_SYSREG(DIT),
264 DIS_ARMV8_SYSREG(SSBS),
265 DIS_ARMV8_SYSREG(TCO),
266 DIS_ARMV8_SYSREG(FPCR),
267 DIS_ARMV8_SYSREG(FPSR),
268 DIS_ARMV8_SYSREG(ICC_SRE_EL2),
269 DIS_ARMV8_SYSREG(TPIDR_EL0),
270 DIS_ARMV8_SYSREG(TPIDRRO_EL0),
271 DIS_ARMV8_SYSREG(CNTFRQ_EL0),
272 DIS_ARMV8_SYSREG(CNTVCT_EL0),
273 DIS_ARMV8_SYSREG(CNTP_TVAL_EL0),
274 DIS_ARMV8_SYSREG(CNTP_CTL_EL0),
275 DIS_ARMV8_SYSREG(CNTP_CVAL_EL0),
276 DIS_ARMV8_SYSREG(CNTV_CTL_EL0),
277 DIS_ARMV8_SYSREG(VPIDR_EL2),
278 DIS_ARMV8_SYSREG(VMPIDR_EL2),
279 DIS_ARMV8_SYSREG(SCTLR_EL2),
280 DIS_ARMV8_SYSREG(ACTLR_EL2),
281 DIS_ARMV8_SYSREG(HCR_EL2),
282 DIS_ARMV8_SYSREG(MDCR_EL2),
283 DIS_ARMV8_SYSREG(CPTR_EL2),
284 DIS_ARMV8_SYSREG(HSTR_EL2),
285 DIS_ARMV8_SYSREG(HFGRTR_EL2),
286 DIS_ARMV8_SYSREG(HFGWTR_EL2),
287 DIS_ARMV8_SYSREG(HFGITR_EL2),
288 DIS_ARMV8_SYSREG(HACR_EL2),
289 DIS_ARMV8_SYSREG(ZCR_EL2),
290 DIS_ARMV8_SYSREG(TRFCR_EL2),
291 DIS_ARMV8_SYSREG(HCRX_EL2),
292 DIS_ARMV8_SYSREG(SDER32_EL2),
293 DIS_ARMV8_SYSREG(TTBR0_EL2),
294 DIS_ARMV8_SYSREG(TTBR1_EL2),
295 DIS_ARMV8_SYSREG(TCR_EL2),
296 DIS_ARMV8_SYSREG(VTTBR_EL2),
297 DIS_ARMV8_SYSREG(VTCR_EL2),
298 DIS_ARMV8_SYSREG(VNCR_EL2),
299 DIS_ARMV8_SYSREG(VSTTBR_EL2),
300 DIS_ARMV8_SYSREG(VSTCR_EL2),
301 DIS_ARMV8_SYSREG(DACR32_EL2),
302 DIS_ARMV8_SYSREG(HDFGRTR_EL2),
303 DIS_ARMV8_SYSREG(HDFGWTR_EL2),
304 DIS_ARMV8_SYSREG(HAFGRTR_EL2),
305 DIS_ARMV8_SYSREG(SPSR_EL2),
306 DIS_ARMV8_SYSREG(ELR_EL2),
307 DIS_ARMV8_SYSREG(SP_EL1),
308 DIS_ARMV8_SYSREG(IFSR32_EL2),
309 DIS_ARMV8_SYSREG(AFSR0_EL2),
310 DIS_ARMV8_SYSREG(AFSR1_EL2),
311 DIS_ARMV8_SYSREG(ESR_EL2),
312 DIS_ARMV8_SYSREG(VSESR_EL2),
313 DIS_ARMV8_SYSREG(FPEXC32_EL2),
314 DIS_ARMV8_SYSREG(TFSR_EL2),
315 DIS_ARMV8_SYSREG(FAR_EL2),
316 DIS_ARMV8_SYSREG(HPFAR_EL2),
317 DIS_ARMV8_SYSREG(PMSCR_EL2),
318 DIS_ARMV8_SYSREG(MAIR_EL2),
319 DIS_ARMV8_SYSREG(AMAIR_EL2),
320 DIS_ARMV8_SYSREG(MPAMHCR_EL2),
321 DIS_ARMV8_SYSREG(MPAMVPMV_EL2),
322 DIS_ARMV8_SYSREG(MPAM2_EL2),
323 DIS_ARMV8_SYSREG(MPAMVPM0_EL2),
324 DIS_ARMV8_SYSREG(MPAMVPM1_EL2),
325 DIS_ARMV8_SYSREG(MPAMVPM2_EL2),
326 DIS_ARMV8_SYSREG(MPAMVPM3_EL2),
327 DIS_ARMV8_SYSREG(MPAMVPM4_EL2),
328 DIS_ARMV8_SYSREG(MPAMVPM5_EL2),
329 DIS_ARMV8_SYSREG(MPAMVPM6_EL2),
330 DIS_ARMV8_SYSREG(MPAMVPM7_EL2),
331 DIS_ARMV8_SYSREG(VBAR_EL2),
332 DIS_ARMV8_SYSREG(RVBAR_EL2),
333 DIS_ARMV8_SYSREG(RMR_EL2),
334 DIS_ARMV8_SYSREG(VDISR_EL2),
335 DIS_ARMV8_SYSREG(CONTEXTIDR_EL2),
336 DIS_ARMV8_SYSREG(TPIDR_EL2),
337 DIS_ARMV8_SYSREG(SCXTNUM_EL2),
338 DIS_ARMV8_SYSREG(CNTVOFF_EL2),
339 DIS_ARMV8_SYSREG(CNTPOFF_EL2),
340 DIS_ARMV8_SYSREG(CNTHCTL_EL2),
341 DIS_ARMV8_SYSREG(CNTHP_TVAL_EL2),
342 DIS_ARMV8_SYSREG(CNTHP_CTL_EL2),
343 DIS_ARMV8_SYSREG(CNTHP_CVAL_EL2),
344 DIS_ARMV8_SYSREG(CNTHV_TVAL_EL2),
345 DIS_ARMV8_SYSREG(CNTHV_CTL_EL2),
346 DIS_ARMV8_SYSREG(CNTHV_CVAL_EL2),
347 DIS_ARMV8_SYSREG(CNTHVS_TVAL_EL2),
348 DIS_ARMV8_SYSREG(CNTHVS_CTL_EL2),
349 DIS_ARMV8_SYSREG(CNTHVS_CVAL_EL2),
350 DIS_ARMV8_SYSREG(CNTHPS_TVAL_EL2),
351 DIS_ARMV8_SYSREG(CNTHPS_CTL_EL2),
352 DIS_ARMV8_SYSREG(CNTHPS_CVAL_EL2),
353 DIS_ARMV8_SYSREG(SP_EL2)
354#undef DIS_ARMV8_SYSREG
355};
356
357
358/**
359 * Gets the base register name for the given parameter.
360 *
361 * @returns Pointer to the register name.
362 * @param pDis The disassembler state.
363 * @param enmRegType The register type.
364 * @param idReg The register ID.
365 * @param pcchReg Where to store the length of the name.
366 */
367DECLINLINE(const char *) disasmFormatArmV8Reg(PCDISSTATE pDis, uint8_t enmRegType, uint8_t idReg, size_t *pcchReg)
368{
369 RT_NOREF_PV(pDis);
370
371 switch (enmRegType)
372 {
373 case kDisOpParamArmV8RegType_Gpr_32Bit:
374 {
375 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegGen32));
376 const char *psz = g_aszArmV8RegGen32[idReg];
377 *pcchReg = 2 + !!psz[2];
378 return psz;
379 }
380 case kDisOpParamArmV8RegType_Gpr_64Bit:
381 {
382 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegGen64));
383 const char *psz = g_aszArmV8RegGen64[idReg];
384 *pcchReg = 2 + !!psz[2];
385 return psz;
386 }
387 case kDisOpParamArmV8RegType_FpReg_Single:
388 {
389 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
390 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegFpSingle));
391 const char *psz = g_aszArmV8RegFpSingle[idReg];
392 *pcchReg = 2 + !!psz[2];
393 return psz;
394 }
395 case kDisOpParamArmV8RegType_FpReg_Double:
396 {
397 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
398 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegFpDouble));
399 const char *psz = g_aszArmV8RegFpDouble[idReg];
400 *pcchReg = 2 + !!psz[2];
401 return psz;
402 }
403 case kDisOpParamArmV8RegType_FpReg_Half:
404 {
405 Assert(pDis->armv8.enmFpType != kDisArmv8InstrFpType_Invalid);
406 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegFpHalf));
407 const char *psz = g_aszArmV8RegFpHalf[idReg];
408 *pcchReg = 2 + !!psz[2];
409 return psz;
410 }
411 case kDisOpParamArmV8RegType_Simd_Scalar_8Bit:
412 {
413 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegSimdScalar8Bit));
414 const char *psz = g_aszArmV8RegSimdScalar8Bit[idReg];
415 *pcchReg = 2 + !!psz[2];
416 return psz;
417 }
418 case kDisOpParamArmV8RegType_Simd_Scalar_16Bit:
419 {
420 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegFpHalf));
421 const char *psz = g_aszArmV8RegFpHalf[idReg];
422 *pcchReg = 2 + !!psz[2];
423 return psz;
424 }
425 case kDisOpParamArmV8RegType_Simd_Scalar_32Bit:
426 {
427 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegFpSingle));
428 const char *psz = g_aszArmV8RegFpSingle[idReg];
429 *pcchReg = 2 + !!psz[2];
430 return psz;
431 }
432 case kDisOpParamArmV8RegType_Simd_Scalar_64Bit:
433 {
434 /* Using the floating point double register names here. */
435 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegFpDouble));
436 const char *psz = g_aszArmV8RegFpDouble[idReg];
437 *pcchReg = 2 + !!psz[2];
438 return psz;
439 }
440 case kDisOpParamArmV8RegType_Simd_Scalar_128Bit:
441 {
442 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegSimdScalar128Bit));
443 const char *psz = g_aszArmV8RegSimdScalar128Bit[idReg];
444 *pcchReg = 2 + !!psz[2];
445 return psz;
446 }
447 case kDisOpParamArmV8RegType_Sp:
448 {
449 *pcchReg = 2;
450 return "sp";
451 }
452 case kDisOpParamArmV8RegType_Simd_Vector:
453 case kDisOpParamArmV8RegType_Simd_Vector_Group:
454 {
455 Assert(idReg < RT_ELEMENTS(g_aszArmV8RegSimdVector));
456 const char *psz = g_aszArmV8RegSimdVector[idReg];
457 *pcchReg = 2 + !!psz[2];
458 return psz;
459 }
460 default:
461 AssertFailed();
462 *pcchReg = 0;
463 return NULL;
464 }
465}
466
467
468/**
469 * Gets the vector register type for the given parameter.
470 *
471 * @returns Pointer to the register type.
472 * @param enmVecType THe vector type.
473 * @param pcchType Where to store the length of the type.
474 */
475DECLINLINE(const char *) disasmFormatArmV8VecRegType(uint8_t enmVecType, size_t *pcchType)
476{
477 Assert( enmVecType != kDisOpParamArmV8VecRegType_None
478 && enmVecType < RT_ELEMENTS(g_aszArmV8VecRegType));
479
480 const char *psz = g_aszArmV8VecRegType[enmVecType];
481 *pcchType = 2 + !!psz[2];
482 return psz;
483}
484
485
486/**
487 * Gets the base register name for the given parameter.
488 *
489 * @returns Pointer to the register name.
490 * @param pDis The disassembler state.
491 * @param pParam The parameter.
492 * @param pachTmp Pointer to temporary string storage when building
493 * the register name.
494 * @param pcchReg Where to store the length of the name.
495 */
496static const char *disasmFormatArmV8SysReg(PCDISSTATE pDis, PCDISOPPARAM pParam, char *pachTmp, size_t *pcchReg)
497{
498 RT_NOREF_PV(pDis);
499
500 /* Try to find the system register ID in the table. */
501 /** @todo Binary search (lazy). */
502 for (uint32_t i = 0; i < RT_ELEMENTS(g_aArmV8SysReg64); i++)
503 {
504 if (g_aArmV8SysReg64[i].idSysReg == pParam->armv8.Op.idSysReg)
505 {
506 *pcchReg = g_aArmV8SysReg64[i].cchSysReg;
507 return g_aArmV8SysReg64[i].pszSysReg;
508 }
509 }
510
511 /* Generate S<op0>_<op1>_<Cn>_<Cm>_<op2> identifier. */
512 uint32_t const idSysReg = pParam->armv8.Op.idSysReg;
513 uint8_t idx = 0;
514 pachTmp[idx++] = 'S';
515 pachTmp[idx++] = '2' + ((idSysReg >> 14) & 0x1);
516 pachTmp[idx++] = '_';
517 pachTmp[idx++] = '0' + ((idSysReg >> 11) & 0x7);
518 pachTmp[idx++] = '_';
519
520 uint8_t bTmp = (idSysReg >> 7) & 0xf;
521 if (bTmp >= 10)
522 {
523 pachTmp[idx++] = '1' + (bTmp - 10);
524 bTmp -= 10;
525 }
526 pachTmp[idx++] = '0' + bTmp;
527 pachTmp[idx++] = '_';
528
529 bTmp = (idSysReg >> 3) & 0xf;
530 if (bTmp >= 10)
531 {
532 pachTmp[idx++] = '1' + (bTmp - 10);
533 bTmp -= 10;
534 }
535 pachTmp[idx++] = '0' + bTmp;
536
537 pachTmp[idx++] = '_';
538 pachTmp[idx++] = '0' + (idSysReg & 0x7);
539 pachTmp[idx] = '\0';
540 *pcchReg = idx;
541 return pachTmp;
542}
543
544
545/**
546 * Formats the current instruction in ARMv8 style.
547 *
548 *
549 * @returns The number of output characters. If this is >= cchBuf, then the content
550 * of pszBuf will be truncated.
551 * @param pDis Pointer to the disassembler state.
552 * @param pszBuf The output buffer.
553 * @param cchBuf The size of the output buffer.
554 * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
555 * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
556 * @param pvUser User argument for pfnGetSymbol.
557 */
558DISDECL(size_t) DISFormatArmV8Ex(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags,
559 PFNDISGETSYMBOL pfnGetSymbol, void *pvUser)
560{
561 /*
562 * Input validation and massaging.
563 */
564 AssertPtr(pDis);
565 AssertPtrNull(pszBuf);
566 Assert(pszBuf || !cchBuf);
567 AssertPtrNull(pfnGetSymbol);
568 AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
569 if (fFlags & DIS_FMT_FLAGS_ADDR_COMMENT)
570 fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
571 if (fFlags & DIS_FMT_FLAGS_BYTES_COMMENT)
572 fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
573
574 PCDISOPCODE const pOp = pDis->pCurInstr;
575
576 /*
577 * Output macros
578 */
579 char *pszDst = pszBuf;
580 size_t cchDst = cchBuf;
581 size_t cchOutput = 0;
582#define PUT_C(ch) \
583 do { \
584 cchOutput++; \
585 if (cchDst > 1) \
586 { \
587 cchDst--; \
588 *pszDst++ = (ch); \
589 } \
590 } while (0)
591#define PUT_STR(pszSrc, cchSrc) \
592 do { \
593 cchOutput += (cchSrc); \
594 if (cchDst > (cchSrc)) \
595 { \
596 memcpy(pszDst, (pszSrc), (cchSrc)); \
597 pszDst += (cchSrc); \
598 cchDst -= (cchSrc); \
599 } \
600 else if (cchDst > 1) \
601 { \
602 memcpy(pszDst, (pszSrc), cchDst - 1); \
603 pszDst += cchDst - 1; \
604 cchDst = 1; \
605 } \
606 } while (0)
607#define PUT_SZ(sz) \
608 PUT_STR((sz), sizeof(sz) - 1)
609#define PUT_SZ_STRICT(szStrict, szRelaxed) \
610 do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0)
611#define PUT_PSZ(psz) \
612 do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
613#define PUT_NUM(cch, fmt, num) \
614 do { \
615 cchOutput += (cch); \
616 if (cchDst > 1) \
617 { \
618 const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \
619 pszDst += cchTmp; \
620 cchDst -= cchTmp; \
621 Assert(cchTmp == (cch) || cchDst == 1); \
622 } \
623 } while (0)
624/** @todo add two flags for choosing between %X / %x and h / 0x. */
625#define PUT_NUM_8(num) PUT_NUM(4, "0x%02x", (uint8_t)(num))
626#define PUT_NUM_16(num) PUT_NUM(6, "0x%04x", (uint16_t)(num))
627#define PUT_NUM_32(num) PUT_NUM(10, "0x%08x", (uint32_t)(num))
628#define PUT_NUM_64(num) PUT_NUM(18, "0x%016RX64", (uint64_t)(num))
629
630#define PUT_NUM_SIGN(cch, fmt, num, stype, utype) \
631 do { \
632 if ((stype)(num) >= 0) \
633 { \
634 PUT_C('+'); \
635 PUT_NUM(cch, fmt, (utype)(num)); \
636 } \
637 else \
638 { \
639 PUT_C('-'); \
640 PUT_NUM(cch, fmt, (utype)-(stype)(num)); \
641 } \
642 } while (0)
643#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0x%02x", num, int8_t, uint8_t)
644#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0x%04x", num, int16_t, uint16_t)
645#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0x%08x", num, int32_t, uint32_t)
646#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0x%016RX64", num, int64_t, uint64_t)
647
648#define PUT_SYMBOL_TWO(a_rcSym, a_szStart, a_chEnd) \
649 do { \
650 if (RT_SUCCESS(a_rcSym)) \
651 { \
652 PUT_SZ(a_szStart); \
653 PUT_PSZ(szSymbol); \
654 if (off != 0) \
655 { \
656 if ((int8_t)off == off) \
657 PUT_NUM_S8(off); \
658 else if ((int16_t)off == off) \
659 PUT_NUM_S16(off); \
660 else if ((int32_t)off == off) \
661 PUT_NUM_S32(off); \
662 else \
663 PUT_NUM_S64(off); \
664 } \
665 PUT_C(a_chEnd); \
666 } \
667 } while (0)
668
669#define PUT_SYMBOL(a_uSeg, a_uAddr, a_szStart, a_chEnd) \
670 do { \
671 if (pfnGetSymbol) \
672 { \
673 int rcSym = pfnGetSymbol(pDis, a_uSeg, a_uAddr, szSymbol, sizeof(szSymbol), &off, pvUser); \
674 PUT_SYMBOL_TWO(rcSym, a_szStart, a_chEnd); \
675 } \
676 } while (0)
677
678
679 /*
680 * The address?
681 */
682 if (fFlags & DIS_FMT_FLAGS_ADDR_LEFT)
683 {
684#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
685 if (pDis->uInstrAddr >= _4G)
686 PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32));
687#endif
688 PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr);
689 PUT_C(' ');
690 }
691
692 /*
693 * The opcode bytes?
694 */
695 if (fFlags & DIS_FMT_FLAGS_BYTES_LEFT)
696 {
697 size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags);
698 cchOutput += cchTmp;
699 if (cchDst > 1)
700 {
701 if (cchTmp <= cchDst)
702 {
703 cchDst -= cchTmp;
704 pszDst += cchTmp;
705 }
706 else
707 {
708 pszDst += cchDst - 1;
709 cchDst = 1;
710 }
711 }
712
713 /* Some padding to align the instruction. */
714 size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED)))
715 + !!(fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) * 2
716 + 2;
717 cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp;
718 PUT_STR(g_szSpaces, cchPadding);
719 }
720
721
722 /*
723 * Filter out invalid opcodes first as they need special
724 * treatment. UDF is an exception and should be handled normally.
725 */
726 size_t const offInstruction = cchOutput;
727 if (pOp->uOpcode == OP_INVALID)
728 PUT_SZ("Illegal opcode");
729 else
730 {
731 /* Start with the instruction. */
732 PUT_PSZ(pOp->pszOpcode);
733
734 /* Add any conditionals. */
735 if (pDis->armv8.enmCond != kDisArmv8InstrCond_Al)
736 {
737 PUT_C('.');
738 Assert((uint16_t)pDis->armv8.enmCond < RT_ELEMENTS(g_aszArmV8Cond));
739 PUT_STR(g_aszArmV8Cond[pDis->armv8.enmCond], sizeof(g_aszArmV8Cond[0]) - 1);
740 }
741
742 /*
743 * Format the parameters.
744 */
745 RTINTPTR off;
746 char szSymbol[128];
747 for (uint32_t i = 0; i < RT_ELEMENTS(pDis->aParams); i++)
748 {
749 PCDISOPPARAM pParam = &pDis->aParams[i];
750
751 /* First None parameter marks end of parameters. */
752 if (pParam->armv8.enmType == kDisArmv8OpParmNone)
753 break;
754
755 if (i > 0)
756 PUT_C(',');
757 PUT_C(' '); /** @todo Make the indenting configurable. */
758
759 switch (pParam->armv8.enmType)
760 {
761 case kDisArmv8OpParmImm:
762 {
763 PUT_C('#');
764 switch (pParam->fUse & ( DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64
765 | DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
766 {
767 case DISUSE_IMMEDIATE8:
768 PUT_NUM_8(pParam->uValue);
769 break;
770 case DISUSE_IMMEDIATE16:
771 PUT_NUM_16(pParam->uValue);
772 break;
773 case DISUSE_IMMEDIATE16_SX8:
774 PUT_NUM_16(pParam->uValue);
775 break;
776 case DISUSE_IMMEDIATE32:
777 PUT_NUM_32(pParam->uValue);
778 /** @todo Symbols */
779 break;
780 case DISUSE_IMMEDIATE32_SX8:
781 PUT_NUM_32(pParam->uValue);
782 break;
783 case DISUSE_IMMEDIATE64_SX8:
784 PUT_NUM_64(pParam->uValue);
785 break;
786 case DISUSE_IMMEDIATE64:
787 PUT_NUM_64(pParam->uValue);
788 /** @todo Symbols */
789 break;
790 default:
791 AssertFailed();
792 break;
793 }
794 break;
795 }
796 case kDisArmv8OpParmImmRel:
797 /*case kDisParmParseImmAdr:*/
798 {
799 int32_t offDisplacement;
800
801 PUT_C('#');
802 if (pParam->fUse & DISUSE_IMMEDIATE8_REL)
803 {
804 offDisplacement = (int8_t)pParam->uValue;
805 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
806 PUT_NUM_S8(offDisplacement);
807 }
808 else if (pParam->fUse & DISUSE_IMMEDIATE16_REL)
809 {
810 offDisplacement = (int16_t)pParam->uValue;
811 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
812 PUT_NUM_S16(offDisplacement);
813 }
814 else
815 {
816 offDisplacement = (int32_t)pParam->uValue;
817 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
818 PUT_NUM_S32(offDisplacement);
819 }
820 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
821 PUT_SZ(" ; (");
822
823 RTUINTPTR uTrgAddr = pDis->uInstrAddr + offDisplacement;
824 if ( pDis->uCpuMode == DISCPUMODE_ARMV8_A32
825 || pDis->uCpuMode == DISCPUMODE_ARMV8_T32)
826 PUT_NUM_32(uTrgAddr);
827 else if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
828 PUT_NUM_64(uTrgAddr);
829 else
830 AssertReleaseFailed();
831
832 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
833 {
834 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " = ", ' ');
835 PUT_C(')');
836 }
837 else
838 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " (", ')');
839 break;
840 }
841 case kDisArmv8OpParmReg:
842 {
843 Assert(!(pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)));
844
845 if (pParam->armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Simd_Vector_Group)
846 {
847 PUT_C('{');
848
849 Assert( pParam->armv8.Op.Reg.cRegs > 0
850 && pParam->armv8.Op.Reg.cRegs <= 4);
851 Assert(pParam->armv8.Op.Reg.enmVecType != kDisOpParamArmV8VecRegType_None);
852
853 for (uint8_t idReg = pParam->armv8.Op.Reg.idReg; idReg < (pParam->armv8.Op.Reg.idReg + pParam->armv8.Op.Reg.cRegs); idReg++)
854 {
855 if (idReg > pParam->armv8.Op.Reg.idReg)
856 PUT_C(',');
857 PUT_C(' '); /** @todo Make the indenting configurable. */
858
859 size_t cchTmp;
860 const char *pszTmp = disasmFormatArmV8Reg(pDis, kDisOpParamArmV8RegType_Simd_Vector_Group,
861 idReg % RT_ELEMENTS(g_aszArmV8RegSimdVector), &cchTmp);
862 PUT_STR(pszTmp, cchTmp);
863 PUT_C('.');
864 pszTmp = disasmFormatArmV8VecRegType(pParam->armv8.Op.Reg.enmVecType, &cchTmp);
865 PUT_STR(pszTmp, cchTmp);
866 }
867
868 PUT_C('}');
869 }
870 else
871 {
872 if (pParam->armv8.Op.Reg.cRegs > 1)
873 {
874 for (uint8_t idReg = pParam->armv8.Op.Reg.idReg; idReg < (pParam->armv8.Op.Reg.idReg + pParam->armv8.Op.Reg.cRegs); idReg++)
875 {
876 if (idReg > pParam->armv8.Op.Reg.idReg)
877 PUT_C(',');
878 PUT_C(' '); /** @todo Make the indenting configurable. */
879
880 size_t cchTmp;
881 const char *pszTmp = disasmFormatArmV8Reg(pDis, pParam->armv8.Op.Reg.enmRegType,
882 idReg, &cchTmp);
883 PUT_STR(pszTmp, cchTmp);
884
885 if ( pParam->armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Simd_Vector
886 && pParam->armv8.Op.Reg.enmVecType != kDisOpParamArmV8VecRegType_None)
887 {
888 PUT_C('.');
889 pszTmp = disasmFormatArmV8VecRegType(pParam->armv8.Op.Reg.enmVecType, &cchTmp);
890 PUT_STR(pszTmp, cchTmp);
891 }
892 }
893 }
894 else
895 {
896 size_t cchTmp;
897 const char *pszTmp = disasmFormatArmV8Reg(pDis, pParam->armv8.Op.Reg.enmRegType,
898 pParam->armv8.Op.Reg.idReg, &cchTmp);
899 PUT_STR(pszTmp, cchTmp);
900
901 if ( pParam->armv8.Op.Reg.enmRegType == kDisOpParamArmV8RegType_Simd_Vector
902 && pParam->armv8.Op.Reg.enmVecType != kDisOpParamArmV8VecRegType_None)
903 {
904 PUT_C('.');
905 pszTmp = disasmFormatArmV8VecRegType(pParam->armv8.Op.Reg.enmVecType, &cchTmp);
906 PUT_STR(pszTmp, cchTmp);
907 }
908 }
909 }
910 break;
911 }
912 case kDisArmv8OpParmSysReg:
913 {
914 Assert(pParam->fUse == DISUSE_REG_SYSTEM);
915
916 size_t cchReg;
917 char achTmp[32];
918 const char *pszReg = disasmFormatArmV8SysReg(pDis, pParam, &achTmp[0], &cchReg);
919 PUT_STR(pszReg, cchReg);
920 break;
921 }
922 case kDisArmv8OpParmAddrInGpr:
923 {
924 Assert( (pParam->fUse & (DISUSE_PRE_INDEXED | DISUSE_POST_INDEXED))
925 != (DISUSE_PRE_INDEXED | DISUSE_POST_INDEXED));
926
927 PUT_C('[');
928
929 size_t cchReg;
930 const char *pszReg = disasmFormatArmV8Reg(pDis, pParam->armv8.Op.Reg.enmRegType,
931 pParam->armv8.Op.Reg.idReg, &cchReg);
932 PUT_STR(pszReg, cchReg);
933
934 if (pParam->fUse & DISUSE_POST_INDEXED)
935 {
936 Assert(pParam->armv8.enmExtend == kDisArmv8OpParmExtendNone);
937 PUT_C(']');
938 if (pParam->fUse & DISUSE_INDEX)
939 {
940 PUT_SZ(", ");
941
942 pszReg = disasmFormatArmV8Reg(pDis, pParam->armv8.GprIndex.enmRegType,
943 pParam->armv8.GprIndex.idReg, &cchReg);
944 PUT_STR(pszReg, cchReg);
945 }
946 else if ( pParam->armv8.u.offBase
947 || (pParam->fUse & (DISUSE_POST_INDEXED | DISUSE_PRE_INDEXED)))
948 {
949 PUT_SZ(", #");
950 if ( pParam->armv8.u.offBase >= INT16_MIN
951 && pParam->armv8.u.offBase <= INT16_MAX)
952 PUT_NUM_S16(pParam->armv8.u.offBase);
953 else
954 PUT_NUM_S32(pParam->armv8.u.offBase);
955 }
956 }
957 else
958 {
959 if (pParam->fUse & DISUSE_INDEX)
960 {
961 PUT_SZ(", ");
962
963 pszReg = disasmFormatArmV8Reg(pDis, pParam->armv8.GprIndex.enmRegType,
964 pParam->armv8.GprIndex.idReg, &cchReg);
965 PUT_STR(pszReg, cchReg);
966 }
967 else if ( pParam->armv8.u.offBase
968 || (pParam->fUse & (DISUSE_POST_INDEXED | DISUSE_PRE_INDEXED)))
969 {
970 PUT_SZ(", #");
971 if ( pParam->armv8.u.offBase >= INT16_MIN
972 && pParam->armv8.u.offBase <= INT16_MAX)
973 PUT_NUM_S16(pParam->armv8.u.offBase);
974 else
975 PUT_NUM_S32(pParam->armv8.u.offBase);
976 }
977
978 if (pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone)
979 {
980 PUT_SZ(", ");
981 switch (pParam->armv8.enmExtend)
982 {
983 case kDisArmv8OpParmExtendUxtX: /* UXTX is same as LSL which is preferred by most disassemblers/assemblers. */
984 case kDisArmv8OpParmExtendLsl:
985 PUT_SZ("LSL #");
986 break;
987 case kDisArmv8OpParmExtendUxtB: PUT_SZ("UXTB #"); break;
988 case kDisArmv8OpParmExtendUxtH: PUT_SZ("UXTH #"); break;
989 case kDisArmv8OpParmExtendUxtW: PUT_SZ("UXTW #"); break;
990 case kDisArmv8OpParmExtendSxtB: PUT_SZ("SXTB #"); break;
991 case kDisArmv8OpParmExtendSxtH: PUT_SZ("SXTH #"); break;
992 case kDisArmv8OpParmExtendSxtW: PUT_SZ("SXTW #"); break;
993 case kDisArmv8OpParmExtendSxtX: PUT_SZ("SXTX #"); break;
994 default:
995 AssertFailed();
996 }
997 PUT_NUM_8(pParam->armv8.u.cExtend);
998 }
999
1000 PUT_C(']');
1001
1002 if (pParam->fUse & DISUSE_PRE_INDEXED)
1003 PUT_C('!');
1004 }
1005
1006 break;
1007 }
1008 case kDisArmv8OpParmCond:
1009 {
1010 Assert((uint16_t)pParam->armv8.Op.enmCond < RT_ELEMENTS(g_aszArmV8Cond));
1011 PUT_STR(g_aszArmV8Cond[pParam->armv8.Op.enmCond], sizeof(g_aszArmV8Cond[0]) - 1);
1012 break;
1013 }
1014 case kDisArmv8OpParmPState:
1015 {
1016 Assert((uint16_t)pParam->armv8.Op.enmPState < RT_ELEMENTS(g_apszArmV8PState));
1017 PUT_PSZ(g_apszArmV8PState[pParam->armv8.Op.enmPState]);
1018 break;
1019 }
1020 default:
1021 AssertFailed();
1022 }
1023
1024 if ( pParam->armv8.enmType != kDisArmv8OpParmAddrInGpr
1025 && pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone)
1026 {
1027 Assert( pParam->armv8.enmType == kDisArmv8OpParmImm
1028 || pParam->armv8.enmType == kDisArmv8OpParmReg);
1029 PUT_SZ(", ");
1030 switch (pParam->armv8.enmExtend)
1031 {
1032 case kDisArmv8OpParmExtendLsl:
1033 PUT_SZ("LSL #");
1034 break;
1035 case kDisArmv8OpParmExtendLsr:
1036 PUT_SZ("LSR #");
1037 break;
1038 case kDisArmv8OpParmExtendAsr:
1039 PUT_SZ("ASR #");
1040 break;
1041 case kDisArmv8OpParmExtendRor:
1042 PUT_SZ("ROR #");
1043 break;
1044 case kDisArmv8OpParmExtendUxtB:
1045 PUT_SZ("UXTB #");
1046 break;
1047 case kDisArmv8OpParmExtendUxtH:
1048 PUT_SZ("UXTH #");
1049 break;
1050 case kDisArmv8OpParmExtendUxtW:
1051 PUT_SZ("UXTW #");
1052 break;
1053 case kDisArmv8OpParmExtendUxtX:
1054 PUT_SZ("UXTX #");
1055 break;
1056 case kDisArmv8OpParmExtendSxtB:
1057 PUT_SZ("SXTB #");
1058 break;
1059 case kDisArmv8OpParmExtendSxtH:
1060 PUT_SZ("SXTH #");
1061 break;
1062 case kDisArmv8OpParmExtendSxtW:
1063 PUT_SZ("SXTW #");
1064 break;
1065 case kDisArmv8OpParmExtendSxtX:
1066 PUT_SZ("SXTX #");
1067 break;
1068 default:
1069 AssertFailed();
1070 }
1071 PUT_NUM_8(pParam->armv8.u.cExtend);
1072 }
1073 }
1074 }
1075
1076 /*
1077 * Any additional output to the right of the instruction?
1078 */
1079 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
1080 {
1081 /* some up front padding. */
1082 size_t cchPadding = cchOutput - offInstruction;
1083 cchPadding = cchPadding + 1 >= 42 ? 1 : 42 - cchPadding;
1084 PUT_STR(g_szSpaces, cchPadding);
1085
1086 /* comment? */
1087 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
1088 PUT_SZ(";");
1089
1090 /*
1091 * The address?
1092 */
1093 if (fFlags & DIS_FMT_FLAGS_ADDR_RIGHT)
1094 {
1095 PUT_C(' ');
1096#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
1097 if (pDis->uInstrAddr >= _4G)
1098 PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32));
1099#endif
1100 PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr);
1101 }
1102
1103 /*
1104 * Opcode bytes?
1105 */
1106 if (fFlags & DIS_FMT_FLAGS_BYTES_RIGHT)
1107 {
1108 PUT_C(' ');
1109 size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags);
1110 cchOutput += cchTmp;
1111 if (cchTmp >= cchDst)
1112 cchTmp = cchDst - (cchDst != 0);
1113 cchDst -= cchTmp;
1114 pszDst += cchTmp;
1115 }
1116 }
1117
1118 /*
1119 * Terminate it - on overflow we'll have reserved one byte for this.
1120 */
1121 if (cchDst > 0)
1122 *pszDst = '\0';
1123 else
1124 Assert(!cchBuf);
1125
1126 /* clean up macros */
1127#undef PUT_PSZ
1128#undef PUT_SZ
1129#undef PUT_STR
1130#undef PUT_C
1131 return cchOutput;
1132}
1133
1134
1135/**
1136 * Formats the current instruction in ARMv8 style.
1137 *
1138 * This is a simplified version of DISFormatArmV8Ex() provided for your convenience.
1139 *
1140 *
1141 * @returns The number of output characters. If this is >= cchBuf, then the content
1142 * of pszBuf will be truncated.
1143 * @param pDis Pointer to the disassembler state.
1144 * @param pszBuf The output buffer.
1145 * @param cchBuf The size of the output buffer.
1146 */
1147DISDECL(size_t) DISFormatArmV8(PCDISSTATE pDis, char *pszBuf, size_t cchBuf)
1148{
1149 return DISFormatArmV8Ex(pDis, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */);
1150}
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