VirtualBox

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

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

Disassembler/ARMv8: Implement decoding of the ldr/str (pre-/post-indexed) variant instructions and add testcases, bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.4 KB
Line 
1/* $Id: DisasmFormatArmV8.cpp 105858 2024-08-25 13:39:38Z vboxsync $ */
2/** @file
3 * VBox Disassembler - Yasm(/Nasm) Style Formatter.
4 */
5
6/*
7 * Copyright (C) 2008-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#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_aszArmV8Cond[16][3] =
58{
59 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "al", "al"
60};
61
62
63/**
64 * List of known system registers.
65 *
66 * The list MUST be in ascending order of the system register ID!
67 */
68static const struct
69{
70 /** IPRT system register ID. */
71 uint32_t idSysReg;
72 /** Name of the system register. */
73 const char *pszSysReg;
74 /** Character count of the system register name. */
75 size_t cchSysReg;
76} g_aArmV8SysReg64[] =
77{
78#define DIS_ARMV8_SYSREG(a_idSysReg) { (ARMV8_AARCH64_SYSREG_ ## a_idSysReg), #a_idSysReg, sizeof(#a_idSysReg) - 1 }
79 DIS_ARMV8_SYSREG(OSDTRRX_EL1),
80 DIS_ARMV8_SYSREG(MDSCR_EL1),
81 //DIS_ARMV8_SYSREG(DBGBVRn_EL1(a_Id)),
82 //DIS_ARMV8_SYSREG(DBGBCRn_EL1(a_Id)),
83 //DIS_ARMV8_SYSREG(DBGWVRn_EL1(a_Id)),
84 //DIS_ARMV8_SYSREG(DBGWCRn_EL1(a_Id)),
85 DIS_ARMV8_SYSREG(MDCCINT_EL1),
86 DIS_ARMV8_SYSREG(OSDTRTX_EL1),
87 DIS_ARMV8_SYSREG(OSECCR_EL1),
88 DIS_ARMV8_SYSREG(MDRAR_EL1),
89 DIS_ARMV8_SYSREG(OSLAR_EL1),
90 DIS_ARMV8_SYSREG(OSLSR_EL1),
91 DIS_ARMV8_SYSREG(OSDLR_EL1),
92 DIS_ARMV8_SYSREG(MIDR_EL1),
93 DIS_ARMV8_SYSREG(MPIDR_EL1),
94 DIS_ARMV8_SYSREG(REVIDR_EL1),
95 DIS_ARMV8_SYSREG(ID_PFR0_EL1),
96 DIS_ARMV8_SYSREG(ID_PFR1_EL1),
97 DIS_ARMV8_SYSREG(ID_DFR0_EL1),
98 DIS_ARMV8_SYSREG(ID_AFR0_EL1),
99 DIS_ARMV8_SYSREG(ID_MMFR0_EL1),
100 DIS_ARMV8_SYSREG(ID_MMFR1_EL1),
101 DIS_ARMV8_SYSREG(ID_MMFR2_EL1),
102 DIS_ARMV8_SYSREG(ID_MMFR3_EL1),
103 DIS_ARMV8_SYSREG(ID_ISAR0_EL1),
104 DIS_ARMV8_SYSREG(ID_ISAR1_EL1),
105 DIS_ARMV8_SYSREG(ID_ISAR2_EL1),
106 DIS_ARMV8_SYSREG(ID_ISAR3_EL1),
107 DIS_ARMV8_SYSREG(ID_ISAR4_EL1),
108 DIS_ARMV8_SYSREG(ID_ISAR5_EL1),
109 DIS_ARMV8_SYSREG(ID_MMFR4_EL1),
110 DIS_ARMV8_SYSREG(ID_ISAR6_EL1),
111 DIS_ARMV8_SYSREG(MVFR0_EL1),
112 DIS_ARMV8_SYSREG(MVFR1_EL1),
113 DIS_ARMV8_SYSREG(MVFR2_EL1),
114 DIS_ARMV8_SYSREG(ID_PFR2_EL1),
115 DIS_ARMV8_SYSREG(ID_DFR1_EL1),
116 DIS_ARMV8_SYSREG(ID_MMFR5_EL1),
117 DIS_ARMV8_SYSREG(ID_AA64PFR0_EL1),
118 DIS_ARMV8_SYSREG(ID_AA64PFR1_EL1),
119 DIS_ARMV8_SYSREG(ID_AA64ZFR0_EL1),
120 DIS_ARMV8_SYSREG(ID_AA64SMFR0_EL1),
121 DIS_ARMV8_SYSREG(ID_AA64DFR0_EL1),
122 DIS_ARMV8_SYSREG(ID_AA64DFR1_EL1),
123 DIS_ARMV8_SYSREG(ID_AA64AFR0_EL1),
124 DIS_ARMV8_SYSREG(ID_AA64AFR1_EL1),
125 DIS_ARMV8_SYSREG(ID_AA64ISAR0_EL1),
126 DIS_ARMV8_SYSREG(ID_AA64ISAR1_EL1),
127 DIS_ARMV8_SYSREG(ID_AA64ISAR2_EL1),
128 DIS_ARMV8_SYSREG(ID_AA64MMFR0_EL1),
129 DIS_ARMV8_SYSREG(ID_AA64MMFR1_EL1),
130 DIS_ARMV8_SYSREG(ID_AA64MMFR2_EL1),
131 DIS_ARMV8_SYSREG(SCTRL_EL1),
132 DIS_ARMV8_SYSREG(ACTRL_EL1),
133 DIS_ARMV8_SYSREG(CPACR_EL1),
134 DIS_ARMV8_SYSREG(RGSR_EL1),
135 DIS_ARMV8_SYSREG(GCR_EL1),
136 DIS_ARMV8_SYSREG(ZCR_EL1),
137 DIS_ARMV8_SYSREG(TRFCR_EL1),
138 DIS_ARMV8_SYSREG(SMPRI_EL1),
139 DIS_ARMV8_SYSREG(SMCR_EL1),
140 DIS_ARMV8_SYSREG(TTBR0_EL1),
141 DIS_ARMV8_SYSREG(TTBR1_EL1),
142 DIS_ARMV8_SYSREG(TCR_EL1),
143 DIS_ARMV8_SYSREG(APIAKeyLo_EL1),
144 DIS_ARMV8_SYSREG(APIAKeyHi_EL1),
145 DIS_ARMV8_SYSREG(APIBKeyLo_EL1),
146 DIS_ARMV8_SYSREG(APIBKeyHi_EL1),
147 DIS_ARMV8_SYSREG(APDAKeyLo_EL1),
148 DIS_ARMV8_SYSREG(APDAKeyHi_EL1),
149 DIS_ARMV8_SYSREG(APDBKeyLo_EL1),
150 DIS_ARMV8_SYSREG(APDBKeyHi_EL1),
151 DIS_ARMV8_SYSREG(APGAKeyLo_EL1),
152 DIS_ARMV8_SYSREG(APGAKeyHi_EL1),
153 DIS_ARMV8_SYSREG(SPSR_EL1),
154 DIS_ARMV8_SYSREG(ELR_EL1),
155 DIS_ARMV8_SYSREG(SP_EL0),
156 DIS_ARMV8_SYSREG(SPSEL),
157 DIS_ARMV8_SYSREG(CURRENTEL),
158 DIS_ARMV8_SYSREG(PAN),
159 DIS_ARMV8_SYSREG(UAO),
160 DIS_ARMV8_SYSREG(ALLINT),
161 DIS_ARMV8_SYSREG(ICC_PMR_EL1),
162 DIS_ARMV8_SYSREG(AFSR0_EL1),
163 DIS_ARMV8_SYSREG(AFSR1_EL1),
164 DIS_ARMV8_SYSREG(ESR_EL1),
165 DIS_ARMV8_SYSREG(ERRIDR_EL1),
166 DIS_ARMV8_SYSREG(ERRSELR_EL1),
167 DIS_ARMV8_SYSREG(FAR_EL1),
168 DIS_ARMV8_SYSREG(PAR_EL1),
169 DIS_ARMV8_SYSREG(MAIR_EL1),
170 DIS_ARMV8_SYSREG(AMAIR_EL1),
171 DIS_ARMV8_SYSREG(VBAR_EL1),
172 DIS_ARMV8_SYSREG(ICC_IAR0_EL1),
173 DIS_ARMV8_SYSREG(ICC_EOIR0_EL1),
174 DIS_ARMV8_SYSREG(ICC_HPPIR0_EL1),
175 DIS_ARMV8_SYSREG(ICC_BPR0_EL1),
176 DIS_ARMV8_SYSREG(ICC_AP0R0_EL1),
177 DIS_ARMV8_SYSREG(ICC_AP0R1_EL1),
178 DIS_ARMV8_SYSREG(ICC_AP0R2_EL1),
179 DIS_ARMV8_SYSREG(ICC_AP0R3_EL1),
180 DIS_ARMV8_SYSREG(ICC_AP1R0_EL1),
181 DIS_ARMV8_SYSREG(ICC_AP1R1_EL1),
182 DIS_ARMV8_SYSREG(ICC_AP1R2_EL1),
183 DIS_ARMV8_SYSREG(ICC_AP1R3_EL1),
184 DIS_ARMV8_SYSREG(ICC_NMIAR1_EL1),
185 DIS_ARMV8_SYSREG(ICC_DIR_EL1),
186 DIS_ARMV8_SYSREG(ICC_RPR_EL1),
187 DIS_ARMV8_SYSREG(ICC_SGI1R_EL1),
188 DIS_ARMV8_SYSREG(ICC_ASGI1R_EL1),
189 DIS_ARMV8_SYSREG(ICC_SGI0R_EL1),
190 DIS_ARMV8_SYSREG(ICC_IAR1_EL1),
191 DIS_ARMV8_SYSREG(ICC_EOIR1_EL1),
192 DIS_ARMV8_SYSREG(ICC_HPPIR1_EL1),
193 DIS_ARMV8_SYSREG(ICC_BPR1_EL1),
194 DIS_ARMV8_SYSREG(ICC_CTLR_EL1),
195 DIS_ARMV8_SYSREG(ICC_SRE_EL1),
196 DIS_ARMV8_SYSREG(ICC_IGRPEN0_EL1),
197 DIS_ARMV8_SYSREG(ICC_IGRPEN1_EL1),
198 DIS_ARMV8_SYSREG(CONTEXTIDR_EL1),
199 DIS_ARMV8_SYSREG(TPIDR_EL1),
200 DIS_ARMV8_SYSREG(CNTKCTL_EL1),
201 DIS_ARMV8_SYSREG(CSSELR_EL1),
202 DIS_ARMV8_SYSREG(NZCV),
203 DIS_ARMV8_SYSREG(DAIF),
204 DIS_ARMV8_SYSREG(SVCR),
205 DIS_ARMV8_SYSREG(DIT),
206 DIS_ARMV8_SYSREG(SSBS),
207 DIS_ARMV8_SYSREG(TCO),
208 DIS_ARMV8_SYSREG(FPCR),
209 DIS_ARMV8_SYSREG(FPSR),
210 DIS_ARMV8_SYSREG(ICC_SRE_EL2),
211 DIS_ARMV8_SYSREG(TPIDR_EL0),
212 DIS_ARMV8_SYSREG(TPIDRRO_EL0),
213 DIS_ARMV8_SYSREG(CNTFRQ_EL0),
214 DIS_ARMV8_SYSREG(CNTVCT_EL0),
215 DIS_ARMV8_SYSREG(CNTP_TVAL_EL0),
216 DIS_ARMV8_SYSREG(CNTP_CTL_EL0),
217 DIS_ARMV8_SYSREG(CNTP_CVAL_EL0),
218 DIS_ARMV8_SYSREG(CNTV_CTL_EL0),
219 DIS_ARMV8_SYSREG(VPIDR_EL2),
220 DIS_ARMV8_SYSREG(VMPIDR_EL2),
221 DIS_ARMV8_SYSREG(SCTLR_EL2),
222 DIS_ARMV8_SYSREG(ACTLR_EL2),
223 DIS_ARMV8_SYSREG(HCR_EL2),
224 DIS_ARMV8_SYSREG(MDCR_EL2),
225 DIS_ARMV8_SYSREG(CPTR_EL2),
226 DIS_ARMV8_SYSREG(HSTR_EL2),
227 DIS_ARMV8_SYSREG(HFGRTR_EL2),
228 DIS_ARMV8_SYSREG(HFGWTR_EL2),
229 DIS_ARMV8_SYSREG(HFGITR_EL2),
230 DIS_ARMV8_SYSREG(HACR_EL2),
231 DIS_ARMV8_SYSREG(ZCR_EL2),
232 DIS_ARMV8_SYSREG(TRFCR_EL2),
233 DIS_ARMV8_SYSREG(HCRX_EL2),
234 DIS_ARMV8_SYSREG(SDER32_EL2),
235 DIS_ARMV8_SYSREG(TTBR0_EL2),
236 DIS_ARMV8_SYSREG(TTBR1_EL2),
237 DIS_ARMV8_SYSREG(TCR_EL2),
238 DIS_ARMV8_SYSREG(VTTBR_EL2),
239 DIS_ARMV8_SYSREG(VTCR_EL2),
240 DIS_ARMV8_SYSREG(VNCR_EL2),
241 DIS_ARMV8_SYSREG(VSTTBR_EL2),
242 DIS_ARMV8_SYSREG(VSTCR_EL2),
243 DIS_ARMV8_SYSREG(DACR32_EL2),
244 DIS_ARMV8_SYSREG(HDFGRTR_EL2),
245 DIS_ARMV8_SYSREG(HDFGWTR_EL2),
246 DIS_ARMV8_SYSREG(HAFGRTR_EL2),
247 DIS_ARMV8_SYSREG(SPSR_EL2),
248 DIS_ARMV8_SYSREG(ELR_EL2),
249 DIS_ARMV8_SYSREG(SP_EL1),
250 DIS_ARMV8_SYSREG(IFSR32_EL2),
251 DIS_ARMV8_SYSREG(AFSR0_EL2),
252 DIS_ARMV8_SYSREG(AFSR1_EL2),
253 DIS_ARMV8_SYSREG(ESR_EL2),
254 DIS_ARMV8_SYSREG(VSESR_EL2),
255 DIS_ARMV8_SYSREG(FPEXC32_EL2),
256 DIS_ARMV8_SYSREG(TFSR_EL2),
257 DIS_ARMV8_SYSREG(FAR_EL2),
258 DIS_ARMV8_SYSREG(HPFAR_EL2),
259 DIS_ARMV8_SYSREG(PMSCR_EL2),
260 DIS_ARMV8_SYSREG(MAIR_EL2),
261 DIS_ARMV8_SYSREG(AMAIR_EL2),
262 DIS_ARMV8_SYSREG(MPAMHCR_EL2),
263 DIS_ARMV8_SYSREG(MPAMVPMV_EL2),
264 DIS_ARMV8_SYSREG(MPAM2_EL2),
265 DIS_ARMV8_SYSREG(MPAMVPM0_EL2),
266 DIS_ARMV8_SYSREG(MPAMVPM1_EL2),
267 DIS_ARMV8_SYSREG(MPAMVPM2_EL2),
268 DIS_ARMV8_SYSREG(MPAMVPM3_EL2),
269 DIS_ARMV8_SYSREG(MPAMVPM4_EL2),
270 DIS_ARMV8_SYSREG(MPAMVPM5_EL2),
271 DIS_ARMV8_SYSREG(MPAMVPM6_EL2),
272 DIS_ARMV8_SYSREG(MPAMVPM7_EL2),
273 DIS_ARMV8_SYSREG(VBAR_EL2),
274 DIS_ARMV8_SYSREG(RVBAR_EL2),
275 DIS_ARMV8_SYSREG(RMR_EL2),
276 DIS_ARMV8_SYSREG(VDISR_EL2),
277 DIS_ARMV8_SYSREG(CONTEXTIDR_EL2),
278 DIS_ARMV8_SYSREG(TPIDR_EL2),
279 DIS_ARMV8_SYSREG(SCXTNUM_EL2),
280 DIS_ARMV8_SYSREG(CNTVOFF_EL2),
281 DIS_ARMV8_SYSREG(CNTPOFF_EL2),
282 DIS_ARMV8_SYSREG(CNTHCTL_EL2),
283 DIS_ARMV8_SYSREG(CNTHP_TVAL_EL2),
284 DIS_ARMV8_SYSREG(CNTHP_CTL_EL2),
285 DIS_ARMV8_SYSREG(CNTHP_CVAL_EL2),
286 DIS_ARMV8_SYSREG(CNTHV_TVAL_EL2),
287 DIS_ARMV8_SYSREG(CNTHV_CTL_EL2),
288 DIS_ARMV8_SYSREG(CNTHV_CVAL_EL2),
289 DIS_ARMV8_SYSREG(CNTHVS_TVAL_EL2),
290 DIS_ARMV8_SYSREG(CNTHVS_CTL_EL2),
291 DIS_ARMV8_SYSREG(CNTHVS_CVAL_EL2),
292 DIS_ARMV8_SYSREG(CNTHPS_TVAL_EL2),
293 DIS_ARMV8_SYSREG(CNTHPS_CTL_EL2),
294 DIS_ARMV8_SYSREG(CNTHPS_CVAL_EL2),
295 DIS_ARMV8_SYSREG(SP_EL2)
296#undef DIS_ARMV8_SYSREG
297};
298
299
300/**
301 * Gets the base register name for the given parameter.
302 *
303 * @returns Pointer to the register name.
304 * @param pDis The disassembler state.
305 * @param pParam The parameter.
306 * @param pcchReg Where to store the length of the name.
307 */
308DECLINLINE(const char *) disasmFormatArmV8Reg(PCDISSTATE pDis, PCDISOPPARAMARMV8REG pReg, size_t *pcchReg)
309{
310 RT_NOREF_PV(pDis);
311
312 if (pReg->f32Bit)
313 {
314 Assert(pReg->idGpr < RT_ELEMENTS(g_aszArmV8RegGen32));
315 const char *psz = g_aszArmV8RegGen32[pReg->idGpr];
316 *pcchReg = 2 + !!psz[2];
317 return psz;
318 }
319
320 Assert(pReg->idGpr < RT_ELEMENTS(g_aszArmV8RegGen64));
321 const char *psz = g_aszArmV8RegGen64[pReg->idGpr];
322 *pcchReg = 2 + !!psz[2];
323 return psz;
324}
325
326
327/**
328 * Gets the base register name for the given parameter.
329 *
330 * @returns Pointer to the register name.
331 * @param pDis The disassembler state.
332 * @param pParam The parameter.
333 * @param pachTmp Pointer to temporary string storage when building
334 * the register name.
335 * @param pcchReg Where to store the length of the name.
336 */
337static const char *disasmFormatArmV8SysReg(PCDISSTATE pDis, PCDISOPPARAM pParam, char *pachTmp, size_t *pcchReg)
338{
339 RT_NOREF_PV(pDis);
340
341 /* Try to find the system register ID in the table. */
342 /** @todo Binary search (lazy). */
343 for (uint32_t i = 0; i < RT_ELEMENTS(g_aArmV8SysReg64); i++)
344 {
345 if (g_aArmV8SysReg64[i].idSysReg == pParam->armv8.Reg.idSysReg)
346 {
347 *pcchReg = g_aArmV8SysReg64[i].cchSysReg;
348 return g_aArmV8SysReg64[i].pszSysReg;
349 }
350 }
351
352 /* Generate S<op0>_<op1>_<Cn>_<Cm>_<op2> identifier. */
353 uint32_t const idSysReg = pParam->armv8.Reg.idSysReg;
354 uint8_t idx = 0;
355 pachTmp[idx++] = 'S';
356 pachTmp[idx++] = '2' + ((idSysReg >> 14) & 0x1);
357 pachTmp[idx++] = '_';
358 pachTmp[idx++] = '0' + ((idSysReg >> 11) & 0x7);
359 pachTmp[idx++] = '_';
360
361 uint8_t bTmp = (idSysReg >> 7) & 0xf;
362 if (bTmp >= 10)
363 {
364 pachTmp[idx++] = '1' + (bTmp - 10);
365 bTmp -= 10;
366 }
367 pachTmp[idx++] = '0' + bTmp;
368 pachTmp[idx++] = '_';
369
370 bTmp = (idSysReg >> 3) & 0xf;
371 if (bTmp >= 10)
372 {
373 pachTmp[idx++] = '1' + (bTmp - 10);
374 bTmp -= 10;
375 }
376 pachTmp[idx++] = '0' + bTmp;
377
378 pachTmp[idx++] = '_';
379 pachTmp[idx++] = '0' + (idSysReg & 0x7);
380 pachTmp[idx] = '\0';
381 *pcchReg = idx;
382 return pachTmp;
383}
384
385
386/**
387 * Formats the current instruction in Yasm (/ Nasm) style.
388 *
389 *
390 * @returns The number of output characters. If this is >= cchBuf, then the content
391 * of pszBuf will be truncated.
392 * @param pDis Pointer to the disassembler state.
393 * @param pszBuf The output buffer.
394 * @param cchBuf The size of the output buffer.
395 * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
396 * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
397 * @param pvUser User argument for pfnGetSymbol.
398 */
399DISDECL(size_t) DISFormatArmV8Ex(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags,
400 PFNDISGETSYMBOL pfnGetSymbol, void *pvUser)
401{
402 /*
403 * Input validation and massaging.
404 */
405 AssertPtr(pDis);
406 AssertPtrNull(pszBuf);
407 Assert(pszBuf || !cchBuf);
408 AssertPtrNull(pfnGetSymbol);
409 AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
410 if (fFlags & DIS_FMT_FLAGS_ADDR_COMMENT)
411 fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
412 if (fFlags & DIS_FMT_FLAGS_BYTES_COMMENT)
413 fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
414
415 PCDISOPCODE const pOp = pDis->pCurInstr;
416
417 /*
418 * Output macros
419 */
420 char *pszDst = pszBuf;
421 size_t cchDst = cchBuf;
422 size_t cchOutput = 0;
423#define PUT_C(ch) \
424 do { \
425 cchOutput++; \
426 if (cchDst > 1) \
427 { \
428 cchDst--; \
429 *pszDst++ = (ch); \
430 } \
431 } while (0)
432#define PUT_STR(pszSrc, cchSrc) \
433 do { \
434 cchOutput += (cchSrc); \
435 if (cchDst > (cchSrc)) \
436 { \
437 memcpy(pszDst, (pszSrc), (cchSrc)); \
438 pszDst += (cchSrc); \
439 cchDst -= (cchSrc); \
440 } \
441 else if (cchDst > 1) \
442 { \
443 memcpy(pszDst, (pszSrc), cchDst - 1); \
444 pszDst += cchDst - 1; \
445 cchDst = 1; \
446 } \
447 } while (0)
448#define PUT_SZ(sz) \
449 PUT_STR((sz), sizeof(sz) - 1)
450#define PUT_SZ_STRICT(szStrict, szRelaxed) \
451 do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0)
452#define PUT_PSZ(psz) \
453 do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
454#define PUT_NUM(cch, fmt, num) \
455 do { \
456 cchOutput += (cch); \
457 if (cchDst > 1) \
458 { \
459 const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \
460 pszDst += cchTmp; \
461 cchDst -= cchTmp; \
462 Assert(cchTmp == (cch) || cchDst == 1); \
463 } \
464 } while (0)
465/** @todo add two flags for choosing between %X / %x and h / 0x. */
466#define PUT_NUM_8(num) PUT_NUM(4, "0x%02x", (uint8_t)(num))
467#define PUT_NUM_16(num) PUT_NUM(6, "0x%04x", (uint16_t)(num))
468#define PUT_NUM_32(num) PUT_NUM(10, "0x%08x", (uint32_t)(num))
469#define PUT_NUM_64(num) PUT_NUM(18, "0x%016RX64", (uint64_t)(num))
470
471#define PUT_NUM_SIGN(cch, fmt, num, stype, utype) \
472 do { \
473 if ((stype)(num) >= 0) \
474 { \
475 PUT_C('+'); \
476 PUT_NUM(cch, fmt, (utype)(num)); \
477 } \
478 else \
479 { \
480 PUT_C('-'); \
481 PUT_NUM(cch, fmt, (utype)-(stype)(num)); \
482 } \
483 } while (0)
484#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0x%02x", num, int8_t, uint8_t)
485#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0x%04x", num, int16_t, uint16_t)
486#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0x%08x", num, int32_t, uint32_t)
487#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0x%016RX64", num, int64_t, uint64_t)
488
489#define PUT_SYMBOL_TWO(a_rcSym, a_szStart, a_chEnd) \
490 do { \
491 if (RT_SUCCESS(a_rcSym)) \
492 { \
493 PUT_SZ(a_szStart); \
494 PUT_PSZ(szSymbol); \
495 if (off != 0) \
496 { \
497 if ((int8_t)off == off) \
498 PUT_NUM_S8(off); \
499 else if ((int16_t)off == off) \
500 PUT_NUM_S16(off); \
501 else if ((int32_t)off == off) \
502 PUT_NUM_S32(off); \
503 else \
504 PUT_NUM_S64(off); \
505 } \
506 PUT_C(a_chEnd); \
507 } \
508 } while (0)
509
510#define PUT_SYMBOL(a_uSeg, a_uAddr, a_szStart, a_chEnd) \
511 do { \
512 if (pfnGetSymbol) \
513 { \
514 int rcSym = pfnGetSymbol(pDis, a_uSeg, a_uAddr, szSymbol, sizeof(szSymbol), &off, pvUser); \
515 PUT_SYMBOL_TWO(rcSym, a_szStart, a_chEnd); \
516 } \
517 } while (0)
518
519
520 /*
521 * The address?
522 */
523 if (fFlags & DIS_FMT_FLAGS_ADDR_LEFT)
524 {
525#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
526 if (pDis->uInstrAddr >= _4G)
527 PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32));
528#endif
529 PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr);
530 PUT_C(' ');
531 }
532
533 /*
534 * The opcode bytes?
535 */
536 if (fFlags & DIS_FMT_FLAGS_BYTES_LEFT)
537 {
538 size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags);
539 cchOutput += cchTmp;
540 if (cchDst > 1)
541 {
542 if (cchTmp <= cchDst)
543 {
544 cchDst -= cchTmp;
545 pszDst += cchTmp;
546 }
547 else
548 {
549 pszDst += cchDst - 1;
550 cchDst = 1;
551 }
552 }
553
554 /* Some padding to align the instruction. */
555 size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED)))
556 + !!(fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) * 2
557 + 2;
558 cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp;
559 PUT_STR(g_szSpaces, cchPadding);
560 }
561
562
563 /*
564 * Filter out invalid opcodes first as they need special
565 * treatment. UDF is an exception and should be handled normally.
566 */
567 size_t const offInstruction = cchOutput;
568 if (pOp->uOpcode == OP_INVALID)
569 PUT_SZ("Illegal opcode");
570 else
571 {
572 /* Start with the instruction. */
573 PUT_PSZ(pOp->pszOpcode);
574
575 /* Add any conditionals. */
576 if (pDis->armv8.enmCond != kDisArmv8InstrCond_Al)
577 {
578 PUT_C('.');
579 Assert((uint16_t)pDis->armv8.enmCond < RT_ELEMENTS(g_aszArmV8Cond));
580 PUT_STR(g_aszArmV8Cond[pDis->armv8.enmCond], sizeof(g_aszArmV8Cond[0]) - 1);
581 }
582
583 /*
584 * Format the parameters.
585 */
586 RTINTPTR off;
587 char szSymbol[128];
588 for (uint32_t i = 0; i < RT_ELEMENTS(pDis->aParams); i++)
589 {
590 PCDISOPPARAM pParam = &pDis->aParams[i];
591
592 /* First None parameter marks end of parameters. */
593 if (pParam->armv8.enmType == kDisArmv8OpParmNone)
594 break;
595
596 if (i > 0)
597 PUT_C(',');
598 PUT_C(' '); /** @todo Make the indenting configurable. */
599
600 switch (pParam->armv8.enmType)
601 {
602 case kDisArmv8OpParmImm:
603 {
604 PUT_C('#');
605 switch (pParam->fUse & ( DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64
606 | DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
607 {
608 case DISUSE_IMMEDIATE8:
609 PUT_NUM_8(pParam->uValue);
610 break;
611 case DISUSE_IMMEDIATE16:
612 PUT_NUM_16(pParam->uValue);
613 break;
614 case DISUSE_IMMEDIATE16_SX8:
615 PUT_NUM_16(pParam->uValue);
616 break;
617 case DISUSE_IMMEDIATE32:
618 PUT_NUM_32(pParam->uValue);
619 /** @todo Symbols */
620 break;
621 case DISUSE_IMMEDIATE32_SX8:
622 PUT_NUM_32(pParam->uValue);
623 break;
624 case DISUSE_IMMEDIATE64_SX8:
625 PUT_NUM_64(pParam->uValue);
626 break;
627 case DISUSE_IMMEDIATE64:
628 PUT_NUM_64(pParam->uValue);
629 /** @todo Symbols */
630 break;
631 default:
632 AssertFailed();
633 break;
634 }
635 break;
636 }
637 case kDisArmv8OpParmImmRel:
638 /*case kDisParmParseImmAdr:*/
639 {
640 int32_t offDisplacement;
641
642 PUT_C('#');
643 if (pParam->fUse & DISUSE_IMMEDIATE8_REL)
644 {
645 offDisplacement = (int8_t)pParam->uValue;
646 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
647 PUT_NUM_S8(offDisplacement * sizeof(uint32_t));
648 }
649 else if (pParam->fUse & DISUSE_IMMEDIATE16_REL)
650 {
651 offDisplacement = (int16_t)pParam->uValue;
652 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
653 PUT_NUM_S16(offDisplacement * sizeof(uint32_t));
654 }
655 else
656 {
657 offDisplacement = (int32_t)pParam->uValue;
658 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
659 PUT_NUM_S32(offDisplacement * sizeof(uint32_t));
660 }
661 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
662 PUT_SZ(" ; (");
663
664 RTUINTPTR uTrgAddr = pDis->uInstrAddr + (offDisplacement * sizeof(uint32_t));
665 if ( pDis->uCpuMode == DISCPUMODE_ARMV8_A32
666 || pDis->uCpuMode == DISCPUMODE_ARMV8_T32)
667 PUT_NUM_32(uTrgAddr);
668 else if (pDis->uCpuMode == DISCPUMODE_ARMV8_A64)
669 PUT_NUM_64(uTrgAddr);
670 else
671 AssertReleaseFailed();
672
673 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
674 {
675 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " = ", ' ');
676 PUT_C(')');
677 }
678 else
679 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " (", ')');
680 break;
681 }
682 case kDisArmv8OpParmGpr:
683 {
684 Assert(!(pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)));
685
686 size_t cchReg;
687 const char *pszReg = disasmFormatArmV8Reg(pDis, &pParam->armv8.Reg.Gpr, &cchReg);
688 PUT_STR(pszReg, cchReg);
689 break;
690 }
691 case kDisArmv8OpParmSysReg:
692 {
693 Assert(pParam->fUse == DISUSE_REG_SYSTEM);
694
695 size_t cchReg;
696 char achTmp[32];
697 const char *pszReg = disasmFormatArmV8SysReg(pDis, pParam, &achTmp[0], &cchReg);
698 PUT_STR(pszReg, cchReg);
699 break;
700 }
701 case kDisArmv8OpParmAddrInGpr:
702 {
703 Assert( (pParam->fUse & (DISUSE_PRE_INDEXED | DISUSE_POST_INDEXED))
704 != (DISUSE_PRE_INDEXED | DISUSE_POST_INDEXED));
705 Assert( ( RT_BOOL(pParam->fUse & (DISUSE_PRE_INDEXED | DISUSE_POST_INDEXED))
706 != RT_BOOL(pParam->fUse & DISUSE_INDEX))
707 || !(pParam->fUse & (DISUSE_PRE_INDEXED | DISUSE_POST_INDEXED | DISUSE_INDEX)));
708
709 PUT_C('[');
710
711 size_t cchReg;
712 const char *pszReg = disasmFormatArmV8Reg(pDis, &pParam->armv8.Reg.Gpr, &cchReg);
713 PUT_STR(pszReg, cchReg);
714
715 if (pParam->fUse & DISUSE_POST_INDEXED)
716 {
717 Assert(pParam->armv8.enmExtend == kDisArmv8OpParmExtendNone);
718 PUT_SZ("], #");
719 PUT_NUM_S16(pParam->armv8.u.offBase);
720 }
721 else
722 {
723 if (pParam->fUse & DISUSE_INDEX)
724 {
725 PUT_SZ(", ");
726
727 pszReg = disasmFormatArmV8Reg(pDis, &pParam->armv8.GprIndex, &cchReg);
728 PUT_STR(pszReg, cchReg);
729 }
730 else if (pParam->armv8.u.offBase)
731 {
732 PUT_SZ(", #");
733 PUT_NUM_S16(pParam->armv8.u.offBase);
734 }
735
736 if (pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone)
737 {
738 PUT_SZ(", ");
739 switch (pParam->armv8.enmExtend)
740 {
741 case kDisArmv8OpParmExtendUxtX: /* UXTX is same as LSL which is preferred by most disassemblers/assemblers. */
742 case kDisArmv8OpParmExtendLsl:
743 PUT_SZ("LSL #");
744 break;
745 case kDisArmv8OpParmExtendUxtB: PUT_SZ("UXTB #"); break;
746 case kDisArmv8OpParmExtendUxtH: PUT_SZ("UXTH #"); break;
747 case kDisArmv8OpParmExtendUxtW: PUT_SZ("UXTW #"); break;
748 case kDisArmv8OpParmExtendSxtB: PUT_SZ("SXTB #"); break;
749 case kDisArmv8OpParmExtendSxtH: PUT_SZ("SXTH #"); break;
750 case kDisArmv8OpParmExtendSxtW: PUT_SZ("SXTW #"); break;
751 case kDisArmv8OpParmExtendSxtX: PUT_SZ("SXTX #"); break;
752 default:
753 AssertFailed();
754 }
755 PUT_NUM_8(pParam->armv8.u.cExtend);
756 }
757
758 PUT_C(']');
759
760 if (pParam->fUse & DISUSE_PRE_INDEXED)
761 PUT_C('!');
762 }
763
764 break;
765 }
766 case kDisArmv8OpParmCond:
767 {
768 Assert((uint16_t)pParam->armv8.Reg.enmCond < RT_ELEMENTS(g_aszArmV8Cond));
769 PUT_STR(g_aszArmV8Cond[pParam->armv8.Reg.enmCond], sizeof(g_aszArmV8Cond[0]) - 1);
770 break;
771 }
772 default:
773 AssertFailed();
774 }
775
776 if ( pParam->armv8.enmType != kDisArmv8OpParmAddrInGpr
777 && pParam->armv8.enmExtend != kDisArmv8OpParmExtendNone)
778 {
779 Assert( pParam->armv8.enmType == kDisArmv8OpParmImm
780 || pParam->armv8.enmType == kDisArmv8OpParmGpr);
781 PUT_SZ(", ");
782 switch (pParam->armv8.enmExtend)
783 {
784 case kDisArmv8OpParmExtendLsl:
785 PUT_SZ("LSL #");
786 break;
787 case kDisArmv8OpParmExtendLsr:
788 PUT_SZ("LSR #");
789 break;
790 case kDisArmv8OpParmExtendAsr:
791 PUT_SZ("ASR #");
792 break;
793 case kDisArmv8OpParmExtendRor:
794 PUT_SZ("ROR #");
795 break;
796 default:
797 AssertFailed();
798 }
799 PUT_NUM_8(pParam->armv8.u.cExtend);
800 }
801 }
802 }
803
804 /*
805 * Any additional output to the right of the instruction?
806 */
807 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
808 {
809 /* some up front padding. */
810 size_t cchPadding = cchOutput - offInstruction;
811 cchPadding = cchPadding + 1 >= 42 ? 1 : 42 - cchPadding;
812 PUT_STR(g_szSpaces, cchPadding);
813
814 /* comment? */
815 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
816 PUT_SZ(";");
817
818 /*
819 * The address?
820 */
821 if (fFlags & DIS_FMT_FLAGS_ADDR_RIGHT)
822 {
823 PUT_C(' ');
824#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
825 if (pDis->uInstrAddr >= _4G)
826 PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32));
827#endif
828 PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr);
829 }
830
831 /*
832 * Opcode bytes?
833 */
834 if (fFlags & DIS_FMT_FLAGS_BYTES_RIGHT)
835 {
836 PUT_C(' ');
837 size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags);
838 cchOutput += cchTmp;
839 if (cchTmp >= cchDst)
840 cchTmp = cchDst - (cchDst != 0);
841 cchDst -= cchTmp;
842 pszDst += cchTmp;
843 }
844 }
845
846 /*
847 * Terminate it - on overflow we'll have reserved one byte for this.
848 */
849 if (cchDst > 0)
850 *pszDst = '\0';
851 else
852 Assert(!cchBuf);
853
854 /* clean up macros */
855#undef PUT_PSZ
856#undef PUT_SZ
857#undef PUT_STR
858#undef PUT_C
859 return cchOutput;
860}
861
862
863/**
864 * Formats the current instruction in Yasm (/ Nasm) style.
865 *
866 * This is a simplified version of DISFormatYasmEx() provided for your convenience.
867 *
868 *
869 * @returns The number of output characters. If this is >= cchBuf, then the content
870 * of pszBuf will be truncated.
871 * @param pDis Pointer to the disassembler state.
872 * @param pszBuf The output buffer.
873 * @param cchBuf The size of the output buffer.
874 */
875DISDECL(size_t) DISFormatArmV8(PCDISSTATE pDis, char *pszBuf, size_t cchBuf)
876{
877 return DISFormatArmV8Ex(pDis, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */);
878}
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