VirtualBox

source: vbox/trunk/include/VBox/dis.h@ 96399

Last change on this file since 96399 was 95480, checked in by vboxsync, 2 years ago

DIS: DISOPTYPE_AVX. bugref:9898 bugref:6251

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.6 KB
Line 
1/** @file
2 * DIS - The VirtualBox Disassembler.
3 */
4
5/*
6 * Copyright (C) 2006-2022 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef VBOX_INCLUDED_dis_h
27#define VBOX_INCLUDED_dis_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <VBox/types.h>
33#include <VBox/disopcode.h>
34#include <iprt/assert.h>
35
36
37RT_C_DECLS_BEGIN
38
39/** @defgroup grp_dis VBox Disassembler
40 * @{ */
41
42/** @name Prefix byte flags (DISSTATE::fPrefix).
43 * @{
44 */
45#define DISPREFIX_NONE UINT8_C(0x00)
46/** non-default address size. */
47#define DISPREFIX_ADDRSIZE UINT8_C(0x01)
48/** non-default operand size. */
49#define DISPREFIX_OPSIZE UINT8_C(0x02)
50/** lock prefix. */
51#define DISPREFIX_LOCK UINT8_C(0x04)
52/** segment prefix. */
53#define DISPREFIX_SEG UINT8_C(0x08)
54/** rep(e) prefix (not a prefix, but we'll treat is as one). */
55#define DISPREFIX_REP UINT8_C(0x10)
56/** rep(e) prefix (not a prefix, but we'll treat is as one). */
57#define DISPREFIX_REPNE UINT8_C(0x20)
58/** REX prefix (64 bits) */
59#define DISPREFIX_REX UINT8_C(0x40)
60/** @} */
61
62/** @name VEX.Lvvvv prefix destination register flag.
63 * @{
64 */
65#define VEX_LEN256 UINT8_C(0x01)
66#define VEXREG_IS256B(x) ((x) & VEX_LEN256)
67/* Convert second byte of VEX prefix to internal format */
68#define VEX_2B2INT(x) ((((x) >> 2) & 0x1f))
69#define VEX_HAS_REX_R(x) (!((x) & 0x80))
70
71#define DISPREFIX_VEX_FLAG_W UINT8_C(0x01)
72 /** @} */
73
74/** @name 64 bits prefix byte flags (DISSTATE::fRexPrefix).
75 * Requires VBox/disopcode.h.
76 * @{
77 */
78#define DISPREFIX_REX_OP_2_FLAGS(a) (a - OP_PARM_REX_START)
79/*#define DISPREFIX_REX_FLAGS DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX) - 0, which is no flag */
80#define DISPREFIX_REX_FLAGS_B DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_B)
81#define DISPREFIX_REX_FLAGS_X DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_X)
82#define DISPREFIX_REX_FLAGS_XB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_XB)
83#define DISPREFIX_REX_FLAGS_R DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_R)
84#define DISPREFIX_REX_FLAGS_RB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RB)
85#define DISPREFIX_REX_FLAGS_RX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RX)
86#define DISPREFIX_REX_FLAGS_RXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RXB)
87#define DISPREFIX_REX_FLAGS_W DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_W)
88#define DISPREFIX_REX_FLAGS_WB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WB)
89#define DISPREFIX_REX_FLAGS_WX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WX)
90#define DISPREFIX_REX_FLAGS_WXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WXB)
91#define DISPREFIX_REX_FLAGS_WR DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WR)
92#define DISPREFIX_REX_FLAGS_WRB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRB)
93#define DISPREFIX_REX_FLAGS_WRX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRX)
94#define DISPREFIX_REX_FLAGS_WRXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRXB)
95/** @} */
96AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_B));
97AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_X));
98AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_W));
99AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_R));
100
101/** @name Operand type (DISOPCODE::fOpType).
102 * @{
103 */
104#define DISOPTYPE_INVALID RT_BIT_32(0)
105#define DISOPTYPE_HARMLESS RT_BIT_32(1)
106#define DISOPTYPE_CONTROLFLOW RT_BIT_32(2)
107#define DISOPTYPE_POTENTIALLY_DANGEROUS RT_BIT_32(3)
108#define DISOPTYPE_DANGEROUS RT_BIT_32(4)
109#define DISOPTYPE_PORTIO RT_BIT_32(5)
110#define DISOPTYPE_PRIVILEGED RT_BIT_32(6)
111#define DISOPTYPE_PRIVILEGED_NOTRAP RT_BIT_32(7)
112#define DISOPTYPE_UNCOND_CONTROLFLOW RT_BIT_32(8)
113#define DISOPTYPE_RELATIVE_CONTROLFLOW RT_BIT_32(9)
114#define DISOPTYPE_COND_CONTROLFLOW RT_BIT_32(10)
115#define DISOPTYPE_INTERRUPT RT_BIT_32(11)
116#define DISOPTYPE_ILLEGAL RT_BIT_32(12)
117#define DISOPTYPE_RRM_DANGEROUS RT_BIT_32(14) /**< Some additional dangerous ones when recompiling raw r0. */
118#define DISOPTYPE_RRM_DANGEROUS_16 RT_BIT_32(15) /**< Some additional dangerous ones when recompiling 16-bit raw r0. */
119#define DISOPTYPE_RRM_MASK (DISOPTYPE_RRM_DANGEROUS | DISOPTYPE_RRM_DANGEROUS_16)
120#define DISOPTYPE_INHIBIT_IRQS RT_BIT_32(16) /**< Will or can inhibit irqs (sti, pop ss, mov ss) */
121#define DISOPTYPE_PORTIO_READ RT_BIT_32(17)
122#define DISOPTYPE_PORTIO_WRITE RT_BIT_32(18)
123#define DISOPTYPE_INVALID_64 RT_BIT_32(19) /**< Invalid in 64 bits mode */
124#define DISOPTYPE_ONLY_64 RT_BIT_32(20) /**< Only valid in 64 bits mode */
125#define DISOPTYPE_DEFAULT_64_OP_SIZE RT_BIT_32(21) /**< Default 64 bits operand size */
126#define DISOPTYPE_FORCED_64_OP_SIZE RT_BIT_32(22) /**< Forced 64 bits operand size; regardless of prefix bytes */
127#define DISOPTYPE_REXB_EXTENDS_OPREG RT_BIT_32(23) /**< REX.B extends the register field in the opcode byte */
128#define DISOPTYPE_MOD_FIXED_11 RT_BIT_32(24) /**< modrm.mod is always 11b */
129#define DISOPTYPE_FORCED_32_OP_SIZE_X86 RT_BIT_32(25) /**< Forced 32 bits operand size; regardless of prefix bytes (only in 16 & 32 bits mode!) */
130#define DISOPTYPE_AVX RT_BIT_32(28) /**< AVX,AVX2,++ instruction. Not implemented yet! */
131#define DISOPTYPE_SSE RT_BIT_32(29) /**< SSE,SSE2,SSE3,SSE4,++ instruction. Not implemented yet! */
132#define DISOPTYPE_MMX RT_BIT_32(30) /**< MMX,MMXExt,3DNow,++ instruction. Not implemented yet! */
133#define DISOPTYPE_FPU RT_BIT_32(31) /**< FPU instruction. Not implemented yet! */
134#define DISOPTYPE_ALL UINT32_C(0xffffffff)
135/** @} */
136
137/** @name Parameter usage flags.
138 * @{
139 */
140#define DISUSE_BASE RT_BIT_64(0)
141#define DISUSE_INDEX RT_BIT_64(1)
142#define DISUSE_SCALE RT_BIT_64(2)
143#define DISUSE_REG_GEN8 RT_BIT_64(3)
144#define DISUSE_REG_GEN16 RT_BIT_64(4)
145#define DISUSE_REG_GEN32 RT_BIT_64(5)
146#define DISUSE_REG_GEN64 RT_BIT_64(6)
147#define DISUSE_REG_FP RT_BIT_64(7)
148#define DISUSE_REG_MMX RT_BIT_64(8)
149#define DISUSE_REG_XMM RT_BIT_64(9)
150#define DISUSE_REG_YMM RT_BIT_64(10)
151#define DISUSE_REG_CR RT_BIT_64(11)
152#define DISUSE_REG_DBG RT_BIT_64(12)
153#define DISUSE_REG_SEG RT_BIT_64(13)
154#define DISUSE_REG_TEST RT_BIT_64(14)
155#define DISUSE_DISPLACEMENT8 RT_BIT_64(15)
156#define DISUSE_DISPLACEMENT16 RT_BIT_64(16)
157#define DISUSE_DISPLACEMENT32 RT_BIT_64(17)
158#define DISUSE_DISPLACEMENT64 RT_BIT_64(18)
159#define DISUSE_RIPDISPLACEMENT32 RT_BIT_64(19)
160#define DISUSE_IMMEDIATE8 RT_BIT_64(20)
161#define DISUSE_IMMEDIATE8_REL RT_BIT_64(21)
162#define DISUSE_IMMEDIATE16 RT_BIT_64(22)
163#define DISUSE_IMMEDIATE16_REL RT_BIT_64(23)
164#define DISUSE_IMMEDIATE32 RT_BIT_64(24)
165#define DISUSE_IMMEDIATE32_REL RT_BIT_64(25)
166#define DISUSE_IMMEDIATE64 RT_BIT_64(26)
167#define DISUSE_IMMEDIATE64_REL RT_BIT_64(27)
168#define DISUSE_IMMEDIATE_ADDR_0_32 RT_BIT_64(28)
169#define DISUSE_IMMEDIATE_ADDR_16_32 RT_BIT_64(29)
170#define DISUSE_IMMEDIATE_ADDR_0_16 RT_BIT_64(30)
171#define DISUSE_IMMEDIATE_ADDR_16_16 RT_BIT_64(31)
172/** DS:ESI */
173#define DISUSE_POINTER_DS_BASED RT_BIT_64(32)
174/** ES:EDI */
175#define DISUSE_POINTER_ES_BASED RT_BIT_64(33)
176#define DISUSE_IMMEDIATE16_SX8 RT_BIT_64(34)
177#define DISUSE_IMMEDIATE32_SX8 RT_BIT_64(35)
178#define DISUSE_IMMEDIATE64_SX8 RT_BIT_64(36)
179
180/** Mask of immediate use flags. */
181#define DISUSE_IMMEDIATE ( DISUSE_IMMEDIATE8 \
182 | DISUSE_IMMEDIATE16 \
183 | DISUSE_IMMEDIATE32 \
184 | DISUSE_IMMEDIATE64 \
185 | DISUSE_IMMEDIATE8_REL \
186 | DISUSE_IMMEDIATE16_REL \
187 | DISUSE_IMMEDIATE32_REL \
188 | DISUSE_IMMEDIATE64_REL \
189 | DISUSE_IMMEDIATE_ADDR_0_32 \
190 | DISUSE_IMMEDIATE_ADDR_16_32 \
191 | DISUSE_IMMEDIATE_ADDR_0_16 \
192 | DISUSE_IMMEDIATE_ADDR_16_16 \
193 | DISUSE_IMMEDIATE16_SX8 \
194 | DISUSE_IMMEDIATE32_SX8 \
195 | DISUSE_IMMEDIATE64_SX8)
196/** Check if the use flags indicates an effective address. */
197#define DISUSE_IS_EFFECTIVE_ADDR(a_fUseFlags) (!!( (a_fUseFlags) \
198 & ( DISUSE_BASE \
199 | DISUSE_INDEX \
200 | DISUSE_DISPLACEMENT32 \
201 | DISUSE_DISPLACEMENT64 \
202 | DISUSE_DISPLACEMENT16 \
203 | DISUSE_DISPLACEMENT8 \
204 | DISUSE_RIPDISPLACEMENT32) ))
205/** @} */
206
207/** @name 64-bit general register indexes.
208 * This matches the AMD64 register encoding. It is found used in
209 * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg.
210 * @note Safe to assume same values as the 16-bit and 32-bit general registers.
211 * @{
212 */
213#define DISGREG_RAX UINT8_C(0)
214#define DISGREG_RCX UINT8_C(1)
215#define DISGREG_RDX UINT8_C(2)
216#define DISGREG_RBX UINT8_C(3)
217#define DISGREG_RSP UINT8_C(4)
218#define DISGREG_RBP UINT8_C(5)
219#define DISGREG_RSI UINT8_C(6)
220#define DISGREG_RDI UINT8_C(7)
221#define DISGREG_R8 UINT8_C(8)
222#define DISGREG_R9 UINT8_C(9)
223#define DISGREG_R10 UINT8_C(10)
224#define DISGREG_R11 UINT8_C(11)
225#define DISGREG_R12 UINT8_C(12)
226#define DISGREG_R13 UINT8_C(13)
227#define DISGREG_R14 UINT8_C(14)
228#define DISGREG_R15 UINT8_C(15)
229/** @} */
230
231/** @name 32-bit general register indexes.
232 * This matches the AMD64 register encoding. It is found used in
233 * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg.
234 * @note Safe to assume same values as the 16-bit and 64-bit general registers.
235 * @{
236 */
237#define DISGREG_EAX UINT8_C(0)
238#define DISGREG_ECX UINT8_C(1)
239#define DISGREG_EDX UINT8_C(2)
240#define DISGREG_EBX UINT8_C(3)
241#define DISGREG_ESP UINT8_C(4)
242#define DISGREG_EBP UINT8_C(5)
243#define DISGREG_ESI UINT8_C(6)
244#define DISGREG_EDI UINT8_C(7)
245#define DISGREG_R8D UINT8_C(8)
246#define DISGREG_R9D UINT8_C(9)
247#define DISGREG_R10D UINT8_C(10)
248#define DISGREG_R11D UINT8_C(11)
249#define DISGREG_R12D UINT8_C(12)
250#define DISGREG_R13D UINT8_C(13)
251#define DISGREG_R14D UINT8_C(14)
252#define DISGREG_R15D UINT8_C(15)
253/** @} */
254
255/** @name 16-bit general register indexes.
256 * This matches the AMD64 register encoding. It is found used in
257 * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg.
258 * @note Safe to assume same values as the 32-bit and 64-bit general registers.
259 * @{
260 */
261#define DISGREG_AX UINT8_C(0)
262#define DISGREG_CX UINT8_C(1)
263#define DISGREG_DX UINT8_C(2)
264#define DISGREG_BX UINT8_C(3)
265#define DISGREG_SP UINT8_C(4)
266#define DISGREG_BP UINT8_C(5)
267#define DISGREG_SI UINT8_C(6)
268#define DISGREG_DI UINT8_C(7)
269#define DISGREG_R8W UINT8_C(8)
270#define DISGREG_R9W UINT8_C(9)
271#define DISGREG_R10W UINT8_C(10)
272#define DISGREG_R11W UINT8_C(11)
273#define DISGREG_R12W UINT8_C(12)
274#define DISGREG_R13W UINT8_C(13)
275#define DISGREG_R14W UINT8_C(14)
276#define DISGREG_R15W UINT8_C(15)
277/** @} */
278
279/** @name 8-bit general register indexes.
280 * This mostly (?) matches the AMD64 register encoding. It is found used in
281 * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg.
282 * @{
283 */
284#define DISGREG_AL UINT8_C(0)
285#define DISGREG_CL UINT8_C(1)
286#define DISGREG_DL UINT8_C(2)
287#define DISGREG_BL UINT8_C(3)
288#define DISGREG_AH UINT8_C(4)
289#define DISGREG_CH UINT8_C(5)
290#define DISGREG_DH UINT8_C(6)
291#define DISGREG_BH UINT8_C(7)
292#define DISGREG_R8B UINT8_C(8)
293#define DISGREG_R9B UINT8_C(9)
294#define DISGREG_R10B UINT8_C(10)
295#define DISGREG_R11B UINT8_C(11)
296#define DISGREG_R12B UINT8_C(12)
297#define DISGREG_R13B UINT8_C(13)
298#define DISGREG_R14B UINT8_C(14)
299#define DISGREG_R15B UINT8_C(15)
300#define DISGREG_SPL UINT8_C(16)
301#define DISGREG_BPL UINT8_C(17)
302#define DISGREG_SIL UINT8_C(18)
303#define DISGREG_DIL UINT8_C(19)
304/** @} */
305
306/** @name Segment registerindexes.
307 * This matches the AMD64 register encoding. It is found used in
308 * DISOPPARAM::Base.idxSegReg.
309 * @{
310 */
311typedef enum
312{
313 DISSELREG_ES = 0,
314 DISSELREG_CS = 1,
315 DISSELREG_SS = 2,
316 DISSELREG_DS = 3,
317 DISSELREG_FS = 4,
318 DISSELREG_GS = 5,
319 /** End of the valid register index values. */
320 DISSELREG_END,
321 /** The usual 32-bit paranoia. */
322 DIS_SEGREG_32BIT_HACK = 0x7fffffff
323} DISSELREG;
324/** @} */
325
326/** @name FPU register indexes.
327 * This matches the AMD64 register encoding. It is found used in
328 * DISOPPARAM::Base.idxFpuReg.
329 * @{
330 */
331#define DISFPREG_ST0 UINT8_C(0)
332#define DISFPREG_ST1 UINT8_C(1)
333#define DISFPREG_ST2 UINT8_C(2)
334#define DISFPREG_ST3 UINT8_C(3)
335#define DISFPREG_ST4 UINT8_C(4)
336#define DISFPREG_ST5 UINT8_C(5)
337#define DISFPREG_ST6 UINT8_C(6)
338#define DISFPREG_ST7 UINT8_C(7)
339/** @} */
340
341/** @name Control register indexes.
342 * This matches the AMD64 register encoding. It is found used in
343 * DISOPPARAM::Base.idxCtrlReg.
344 * @{
345 */
346#define DISCREG_CR0 UINT8_C(0)
347#define DISCREG_CR1 UINT8_C(1)
348#define DISCREG_CR2 UINT8_C(2)
349#define DISCREG_CR3 UINT8_C(3)
350#define DISCREG_CR4 UINT8_C(4)
351#define DISCREG_CR8 UINT8_C(8)
352/** @} */
353
354/** @name Debug register indexes.
355 * This matches the AMD64 register encoding. It is found used in
356 * DISOPPARAM::Base.idxDbgReg.
357 * @{
358 */
359#define DISDREG_DR0 UINT8_C(0)
360#define DISDREG_DR1 UINT8_C(1)
361#define DISDREG_DR2 UINT8_C(2)
362#define DISDREG_DR3 UINT8_C(3)
363#define DISDREG_DR4 UINT8_C(4)
364#define DISDREG_DR5 UINT8_C(5)
365#define DISDREG_DR6 UINT8_C(6)
366#define DISDREG_DR7 UINT8_C(7)
367/** @} */
368
369/** @name MMX register indexes.
370 * This matches the AMD64 register encoding. It is found used in
371 * DISOPPARAM::Base.idxMmxReg.
372 * @{
373 */
374#define DISMREG_MMX0 UINT8_C(0)
375#define DISMREG_MMX1 UINT8_C(1)
376#define DISMREG_MMX2 UINT8_C(2)
377#define DISMREG_MMX3 UINT8_C(3)
378#define DISMREG_MMX4 UINT8_C(4)
379#define DISMREG_MMX5 UINT8_C(5)
380#define DISMREG_MMX6 UINT8_C(6)
381#define DISMREG_MMX7 UINT8_C(7)
382/** @} */
383
384/** @name SSE register indexes.
385 * This matches the AMD64 register encoding. It is found used in
386 * DISOPPARAM::Base.idxXmmReg.
387 * @{
388 */
389#define DISXREG_XMM0 UINT8_C(0)
390#define DISXREG_XMM1 UINT8_C(1)
391#define DISXREG_XMM2 UINT8_C(2)
392#define DISXREG_XMM3 UINT8_C(3)
393#define DISXREG_XMM4 UINT8_C(4)
394#define DISXREG_XMM5 UINT8_C(5)
395#define DISXREG_XMM6 UINT8_C(6)
396#define DISXREG_XMM7 UINT8_C(7)
397/** @} */
398
399
400/**
401 * Opcode parameter (operand) details.
402 */
403typedef struct DISOPPARAM
404{
405 /** A combination of DISUSE_XXX. */
406 uint64_t fUse;
407 /** Immediate value or address, applicable if any of the flags included in
408 * DISUSE_IMMEDIATE are set in fUse. */
409 uint64_t uValue;
410 /** Disposition. */
411 union
412 {
413 /** 64-bit displacement, applicable if DISUSE_DISPLACEMENT64 is set in fUse. */
414 int64_t i64;
415 uint64_t u64;
416 /** 32-bit displacement, applicable if DISUSE_DISPLACEMENT32 or
417 * DISUSE_RIPDISPLACEMENT32 is set in fUse. */
418 int32_t i32;
419 uint32_t u32;
420 /** 16-bit displacement, applicable if DISUSE_DISPLACEMENT16 is set in fUse. */
421 int32_t i16;
422 uint32_t u16;
423 /** 8-bit displacement, applicable if DISUSE_DISPLACEMENT8 is set in fUse. */
424 int32_t i8;
425 uint32_t u8;
426 } uDisp;
427 /** The base register from ModR/M or SIB, applicable if DISUSE_BASE is
428 * set in fUse. */
429 union
430 {
431 /** General register index (DISGREG_XXX), applicable if DISUSE_REG_GEN8,
432 * DISUSE_REG_GEN16, DISUSE_REG_GEN32 or DISUSE_REG_GEN64 is set in fUse. */
433 uint8_t idxGenReg;
434 /** FPU stack register index (DISFPREG_XXX), applicable if DISUSE_REG_FP is
435 * set in fUse. 1:1 indexes. */
436 uint8_t idxFpuReg;
437 /** MMX register index (DISMREG_XXX), applicable if DISUSE_REG_MMX is
438 * set in fUse. 1:1 indexes. */
439 uint8_t idxMmxReg;
440 /** SSE register index (DISXREG_XXX), applicable if DISUSE_REG_XMM is
441 * set in fUse. 1:1 indexes. */
442 uint8_t idxXmmReg;
443 /** SSE2 register index (DISYREG_XXX), applicable if DISUSE_REG_YMM is
444 * set in fUse. 1:1 indexes. */
445 uint8_t idxYmmReg;
446 /** Segment register index (DISSELREG_XXX), applicable if DISUSE_REG_SEG is
447 * set in fUse. */
448 uint8_t idxSegReg;
449 /** Test register, TR0-TR7, present on early IA32 CPUs, applicable if
450 * DISUSE_REG_TEST is set in fUse. No index defines for these. */
451 uint8_t idxTestReg;
452 /** Control register index (DISCREG_XXX), applicable if DISUSE_REG_CR is
453 * set in fUse. 1:1 indexes. */
454 uint8_t idxCtrlReg;
455 /** Debug register index (DISDREG_XXX), applicable if DISUSE_REG_DBG is
456 * set in fUse. 1:1 indexes. */
457 uint8_t idxDbgReg;
458 } Base;
459 /** The SIB index register meaning, applicable if DISUSE_INDEX is
460 * set in fUse. */
461 union
462 {
463 /** General register index (DISGREG_XXX), applicable if DISUSE_REG_GEN8,
464 * DISUSE_REG_GEN16, DISUSE_REG_GEN32 or DISUSE_REG_GEN64 is set in fUse. */
465 uint8_t idxGenReg;
466 /** XMM register index (DISXREG_XXX), applicable if DISUSE_REG_XMM
467 * is set in fUse. */
468 uint8_t idxXmmReg;
469 /** YMM register index (DISXREG_XXX), applicable if DISUSE_REG_YMM
470 * is set in fUse. */
471 uint8_t idxYmmReg;
472 } Index;
473 /** 2, 4 or 8, if DISUSE_SCALE is set in fUse. */
474 uint8_t uScale;
475 /** Parameter size. */
476 uint8_t cb;
477 /** Copy of the corresponding DISOPCODE::fParam1 / DISOPCODE::fParam2 /
478 * DISOPCODE::fParam3. */
479 uint32_t fParam;
480} DISOPPARAM;
481AssertCompileSize(DISOPPARAM, 32);
482/** Pointer to opcode parameter. */
483typedef DISOPPARAM *PDISOPPARAM;
484/** Pointer to opcode parameter. */
485typedef const DISOPPARAM *PCDISOPPARAM;
486
487
488#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && defined(DIS_CORE_ONLY)
489# define DISOPCODE_BITFIELD(a_cBits) : a_cBits
490#else
491# define DISOPCODE_BITFIELD(a_cBits)
492#endif
493
494/**
495 * Opcode descriptor.
496 */
497#if !defined(DIS_CORE_ONLY) || defined(DOXYGEN_RUNNING)
498typedef struct DISOPCODE
499{
500# define DISOPCODE_FORMAT 0
501 /** Mnemonic and operand formatting. */
502 const char *pszOpcode;
503 /** Parameter \#1 parser index. */
504 uint8_t idxParse1;
505 /** Parameter \#2 parser index. */
506 uint8_t idxParse2;
507 /** Parameter \#3 parser index. */
508 uint8_t idxParse3;
509 /** Parameter \#4 parser index. */
510 uint8_t idxParse4;
511 /** The opcode identifier. This DIS specific, @see grp_dis_opcodes and
512 * VBox/disopcode.h. */
513 uint16_t uOpcode;
514 /** Parameter \#1 info, @see grp_dis_opparam. */
515 uint16_t fParam1;
516 /** Parameter \#2 info, @see grp_dis_opparam. */
517 uint16_t fParam2;
518 /** Parameter \#3 info, @see grp_dis_opparam. */
519 uint16_t fParam3;
520 /** Parameter \#4 info, @see grp_dis_opparam. */
521 uint16_t fParam4;
522 /** padding unused */
523 uint16_t uPadding;
524 /** Operand type flags, DISOPTYPE_XXX. */
525 uint32_t fOpType;
526} DISOPCODE;
527#else
528# pragma pack(1)
529typedef struct DISOPCODE
530{
531#if 1 /*!defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64) - probably not worth it for ~4K, costs 2-3% speed. */
532 /* 16 bytes (trick is to make sure the bitfields doesn't cross dwords): */
533# define DISOPCODE_FORMAT 16
534 uint32_t fOpType;
535 uint16_t uOpcode;
536 uint8_t idxParse1;
537 uint8_t idxParse2;
538 uint32_t fParam1 : 12; /* 1st dword: 12+12+8 = 0x20 (32) */
539 uint32_t fParam2 : 12;
540 uint32_t idxParse3 : 8;
541 uint32_t fParam3 : 12; /* 2nd dword: 12+12+8 = 0x20 (32) */
542 uint32_t fParam4 : 12;
543 uint32_t idxParse4 : 8;
544#else /* 15 bytes: */
545# define DISOPCODE_FORMAT 15
546 uint64_t uOpcode : 10; /* 1st qword: 10+12+12+12+6+6+6 = 0x40 (64) */
547 uint64_t idxParse1 : 6;
548 uint64_t idxParse2 : 6;
549 uint64_t idxParse3 : 6;
550 uint64_t fParam1 : 12;
551 uint64_t fParam2 : 12;
552 uint64_t fParam3 : 12;
553 uint32_t fOpType;
554 uint16_t fParam4;
555 uint8_t idxParse4;
556#endif
557} DISOPCODE;
558# pragma pack()
559AssertCompile(sizeof(DISOPCODE) == DISOPCODE_FORMAT);
560#endif
561/** Pointer to const opcode. */
562typedef const struct DISOPCODE *PCDISOPCODE;
563
564
565/**
566 * Callback for reading instruction bytes.
567 *
568 * @returns VBox status code, bytes in DISSTATE::abInstr and byte count in
569 * DISSTATE::cbCachedInstr.
570 * @param pDis Pointer to the disassembler state. The user
571 * argument can be found in DISSTATE::pvUser if needed.
572 * @param offInstr The offset relative to the start of the instruction.
573 *
574 * To get the source address, add this to
575 * DISSTATE::uInstrAddr.
576 *
577 * To calculate the destination buffer address, use it
578 * as an index into DISSTATE::abInstr.
579 *
580 * @param cbMinRead The minimum number of bytes to read.
581 * @param cbMaxRead The maximum number of bytes that may be read.
582 */
583typedef DECLCALLBACKTYPE(int, FNDISREADBYTES,(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead));
584/** Pointer to a opcode byte reader. */
585typedef FNDISREADBYTES *PFNDISREADBYTES;
586
587/** Parser callback.
588 * @remark no DECLCALLBACK() here because it's considered to be internal and
589 * there is no point in enforcing CDECL. */
590typedef size_t FNDISPARSE(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam);
591/** Pointer to a disassembler parser function. */
592typedef FNDISPARSE *PFNDISPARSE;
593/** Pointer to a const disassembler parser function pointer. */
594typedef PFNDISPARSE const *PCPFNDISPARSE;
595
596/**
597 * The diassembler state and result.
598 */
599typedef struct DISSTATE
600{
601 /** The number of valid bytes in abInstr. */
602 uint8_t cbCachedInstr;
603 /** SIB fields. */
604 union
605 {
606 /** Bitfield view */
607 struct
608 {
609 uint8_t Base;
610 uint8_t Index;
611 uint8_t Scale;
612 } Bits;
613 } SIB;
614 /** ModRM fields. */
615 union
616 {
617 /** Bitfield view */
618 struct
619 {
620 uint8_t Rm;
621 uint8_t Reg;
622 uint8_t Mod;
623 } Bits;
624 } ModRM;
625 /** The CPU mode (DISCPUMODE). */
626 uint8_t uCpuMode;
627 /** The addressing mode (DISCPUMODE). */
628 uint8_t uAddrMode;
629 /** The operand mode (DISCPUMODE). */
630 uint8_t uOpMode;
631 /** Per instruction prefix settings. */
632 uint8_t fPrefix;
633 /** REX prefix value (64 bits only). */
634 uint8_t fRexPrefix;
635 /** Segment prefix value (DISSELREG). */
636 uint8_t idxSegPrefix;
637 /** Last prefix byte (for SSE2 extension tables). */
638 uint8_t bLastPrefix;
639 /** Last significant opcode byte of instruction. */
640 uint8_t bOpCode;
641 /** The size of the prefix bytes. */
642 uint8_t cbPrefix;
643 /** The instruction size. */
644 uint8_t cbInstr;
645 /** VEX presence flag, destination register and size
646 * @todo r=bird: There is no VEX presence flage here, just ~vvvv and L. */
647 uint8_t bVexDestReg;
648 /** VEX.W flag */
649 uint8_t bVexWFlag;
650 /** Unused bytes. */
651 uint8_t abUnused[1];
652 /** Internal: instruction filter */
653 uint32_t fFilter;
654 /** Internal: pointer to disassembly function table */
655 PCPFNDISPARSE pfnDisasmFnTable;
656#if ARCH_BITS == 32
657 uint32_t uPtrPadding1;
658#endif
659 /** Pointer to the current instruction. */
660 PCDISOPCODE pCurInstr;
661#if ARCH_BITS == 32
662 uint32_t uPtrPadding2;
663#endif
664 /** The instruction bytes. */
665 uint8_t abInstr[16];
666 /** SIB displacment. */
667 int32_t i32SibDisp;
668
669 /** Return code set by a worker function like the opcode bytes readers. */
670 int32_t rc;
671 /** The address of the instruction. */
672 RTUINTPTR uInstrAddr;
673 /** Optional read function */
674 PFNDISREADBYTES pfnReadBytes;
675#if ARCH_BITS == 32
676 uint32_t uPadding3;
677#endif
678 /** User data supplied as an argument to the APIs. */
679 void *pvUser;
680#if ARCH_BITS == 32
681 uint32_t uPadding4;
682#endif
683 /** Parameters. */
684 DISOPPARAM Param1;
685 DISOPPARAM Param2;
686 DISOPPARAM Param3;
687 DISOPPARAM Param4;
688} DISSTATE;
689AssertCompileSize(DISSTATE, 0xd8);
690
691/** @deprecated Use DISSTATE and change Cpu and DisState to Dis. */
692typedef DISSTATE DISCPUSTATE;
693
694
695
696DISDECL(int) DISInstrToStr(void const *pvInstr, DISCPUMODE enmCpuMode,
697 PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput);
698DISDECL(int) DISInstrToStrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
699 PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput);
700DISDECL(int) DISInstrToStrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode,
701 PFNDISREADBYTES pfnReadBytes, void *pvUser, uint32_t uFilter,
702 PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput);
703
704DISDECL(int) DISInstr(void const *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr);
705DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
706 PDISSTATE pDis, uint32_t *pcbInstr);
707DISDECL(int) DISInstrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t uFilter,
708 PFNDISREADBYTES pfnReadBytes, void *pvUser,
709 PDISSTATE pDis, uint32_t *pcbInstr);
710DISDECL(int) DISInstrWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
711 void const *pvPrefetched, size_t cbPretched,
712 PFNDISREADBYTES pfnReadBytes, void *pvUser,
713 PDISSTATE pDis, uint32_t *pcbInstr);
714
715DISDECL(uint8_t) DISGetParamSize(PCDISSTATE pDis, PCDISOPPARAM pParam);
716DISDECL(DISSELREG) DISDetectSegReg(PCDISSTATE pDis, PCDISOPPARAM pParam);
717DISDECL(uint8_t) DISQuerySegPrefixByte(PCDISSTATE pDis);
718
719
720
721/** @name Flags returned by DISQueryParamVal (DISQPVPARAMVAL::flags).
722 * @{
723 */
724#define DISQPV_FLAG_8 UINT8_C(0x01)
725#define DISQPV_FLAG_16 UINT8_C(0x02)
726#define DISQPV_FLAG_32 UINT8_C(0x04)
727#define DISQPV_FLAG_64 UINT8_C(0x08)
728#define DISQPV_FLAG_FARPTR16 UINT8_C(0x10)
729#define DISQPV_FLAG_FARPTR32 UINT8_C(0x20)
730/** @} */
731
732/** @name Types returned by DISQueryParamVal (DISQPVPARAMVAL::flags).
733 * @{ */
734#define DISQPV_TYPE_REGISTER UINT8_C(1)
735#define DISQPV_TYPE_ADDRESS UINT8_C(2)
736#define DISQPV_TYPE_IMMEDIATE UINT8_C(3)
737/** @} */
738
739typedef struct
740{
741 union
742 {
743 uint8_t val8;
744 uint16_t val16;
745 uint32_t val32;
746 uint64_t val64;
747
748 int8_t i8;
749 int16_t i16;
750 int32_t i32;
751 int64_t i64;
752
753 struct
754 {
755 uint16_t sel;
756 uint32_t offset;
757 } farptr;
758 } val;
759
760 uint8_t type;
761 uint8_t size;
762 uint8_t flags;
763} DISQPVPARAMVAL;
764/** Pointer to opcode parameter value. */
765typedef DISQPVPARAMVAL *PDISQPVPARAMVAL;
766
767/** Indicates which parameter DISQueryParamVal should operate on. */
768typedef enum DISQPVWHICH
769{
770 DISQPVWHICH_DST = 1,
771 DISQPVWHICH_SRC,
772 DISQPVWHAT_32_BIT_HACK = 0x7fffffff
773} DISQPVWHICH;
774DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype);
775DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, void **ppReg, size_t *pcbSize);
776
777DISDECL(int) DISFetchReg8(PCCPUMCTXCORE pCtx, unsigned reg8, uint8_t *pVal);
778DISDECL(int) DISFetchReg16(PCCPUMCTXCORE pCtx, unsigned reg16, uint16_t *pVal);
779DISDECL(int) DISFetchReg32(PCCPUMCTXCORE pCtx, unsigned reg32, uint32_t *pVal);
780DISDECL(int) DISFetchReg64(PCCPUMCTXCORE pCtx, unsigned reg64, uint64_t *pVal);
781DISDECL(int) DISFetchRegSeg(PCCPUMCTXCORE pCtx, DISSELREG sel, RTSEL *pVal);
782DISDECL(int) DISFetchRegSegEx(PCPUMCTXCORE pCtx, DISSELREG sel, PCPUMSELREG *ppSelReg);
783DISDECL(int) DISWriteReg8(PCPUMCTXCORE pRegFrame, unsigned reg8, uint8_t val8);
784DISDECL(int) DISWriteReg16(PCPUMCTXCORE pRegFrame, unsigned reg32, uint16_t val16);
785DISDECL(int) DISWriteReg32(PCPUMCTXCORE pRegFrame, unsigned reg32, uint32_t val32);
786DISDECL(int) DISWriteReg64(PCPUMCTXCORE pRegFrame, unsigned reg64, uint64_t val64);
787DISDECL(int) DISWriteRegSeg(PCPUMCTXCORE pCtx, DISSELREG sel, RTSEL val);
788DISDECL(int) DISPtrReg8(PCPUMCTXCORE pCtx, unsigned reg8, uint8_t **ppReg);
789DISDECL(int) DISPtrReg16(PCPUMCTXCORE pCtx, unsigned reg16, uint16_t **ppReg);
790DISDECL(int) DISPtrReg32(PCPUMCTXCORE pCtx, unsigned reg32, uint32_t **ppReg);
791DISDECL(int) DISPtrReg64(PCPUMCTXCORE pCtx, unsigned reg64, uint64_t **ppReg);
792
793
794/**
795 * Try resolve an address into a symbol name.
796 *
797 * For use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx().
798 *
799 * @returns VBox status code.
800 * @retval VINF_SUCCESS on success, pszBuf contains the full symbol name.
801 * @retval VINF_BUFFER_OVERFLOW if pszBuf is too small the symbol name. The
802 * content of pszBuf is truncated and zero terminated.
803 * @retval VERR_SYMBOL_NOT_FOUND if no matching symbol was found for the address.
804 *
805 * @param pDis Pointer to the disassembler CPU state.
806 * @param u32Sel The selector value. Use DIS_FMT_SEL_IS_REG, DIS_FMT_SEL_GET_VALUE,
807 * DIS_FMT_SEL_GET_REG to access this.
808 * @param uAddress The segment address.
809 * @param pszBuf Where to store the symbol name
810 * @param cchBuf The size of the buffer.
811 * @param poff If not a perfect match, then this is where the offset from the return
812 * symbol to the specified address is returned.
813 * @param pvUser The user argument.
814 */
815typedef DECLCALLBACKTYPE(int, FNDISGETSYMBOL,(PCDISSTATE pDis, uint32_t u32Sel, RTUINTPTR uAddress, char *pszBuf, size_t cchBuf,
816 RTINTPTR *poff, void *pvUser));
817/** Pointer to a FNDISGETSYMBOL(). */
818typedef FNDISGETSYMBOL *PFNDISGETSYMBOL;
819
820/**
821 * Checks if the FNDISGETSYMBOL argument u32Sel is a register or not.
822 */
823#define DIS_FMT_SEL_IS_REG(u32Sel) ( !!((u32Sel) & RT_BIT(31)) )
824
825/**
826 * Extracts the selector value from the FNDISGETSYMBOL argument u32Sel.
827 * @returns Selector value.
828 */
829#define DIS_FMT_SEL_GET_VALUE(u32Sel) ( (RTSEL)(u32Sel) )
830
831/**
832 * Extracts the register number from the FNDISGETSYMBOL argument u32Sel.
833 * @returns USE_REG_CS, USE_REG_SS, USE_REG_DS, USE_REG_ES, USE_REG_FS or USE_REG_FS.
834 */
835#define DIS_FMT_SEL_GET_REG(u32Sel) ( ((u32Sel) >> 16) & 0xf )
836
837/** @internal */
838#define DIS_FMT_SEL_FROM_REG(uReg) ( ((uReg) << 16) | RT_BIT(31) | 0xffff )
839/** @internal */
840#define DIS_FMT_SEL_FROM_VALUE(Sel) ( (Sel) & 0xffff )
841
842
843/** @name Flags for use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx().
844 * @{
845 */
846/** Put the address to the right. */
847#define DIS_FMT_FLAGS_ADDR_RIGHT RT_BIT_32(0)
848/** Put the address to the left. */
849#define DIS_FMT_FLAGS_ADDR_LEFT RT_BIT_32(1)
850/** Put the address in comments.
851 * For some assemblers this implies placing it to the right. */
852#define DIS_FMT_FLAGS_ADDR_COMMENT RT_BIT_32(2)
853/** Put the instruction bytes to the right of the disassembly. */
854#define DIS_FMT_FLAGS_BYTES_RIGHT RT_BIT_32(3)
855/** Put the instruction bytes to the left of the disassembly. */
856#define DIS_FMT_FLAGS_BYTES_LEFT RT_BIT_32(4)
857/** Put the instruction bytes in comments.
858 * For some assemblers this implies placing the bytes to the right. */
859#define DIS_FMT_FLAGS_BYTES_COMMENT RT_BIT_32(5)
860/** Put the bytes in square brackets. */
861#define DIS_FMT_FLAGS_BYTES_BRACKETS RT_BIT_32(6)
862/** Put spaces between the bytes. */
863#define DIS_FMT_FLAGS_BYTES_SPACED RT_BIT_32(7)
864/** Display the relative +/- offset of branch instructions that uses relative addresses,
865 * and put the target address in parenthesis. */
866#define DIS_FMT_FLAGS_RELATIVE_BRANCH RT_BIT_32(8)
867/** Strict assembly. The assembly should, when ever possible, make the
868 * assembler reproduce the exact same binary. (Refers to the yasm
869 * strict keyword.) */
870#define DIS_FMT_FLAGS_STRICT RT_BIT_32(9)
871/** Checks if the given flags are a valid combination. */
872#define DIS_FMT_FLAGS_IS_VALID(fFlags) \
873 ( !((fFlags) & ~UINT32_C(0x000003ff)) \
874 && ((fFlags) & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) != (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT) \
875 && ( !((fFlags) & DIS_FMT_FLAGS_ADDR_COMMENT) \
876 || (fFlags & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) ) \
877 && ((fFlags) & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) != (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT) \
878 && ( !((fFlags) & (DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_BRACKETS)) \
879 || (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) ) \
880 )
881/** @} */
882
883DISDECL(size_t) DISFormatYasm( PCDISSTATE pDis, char *pszBuf, size_t cchBuf);
884DISDECL(size_t) DISFormatYasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser);
885DISDECL(size_t) DISFormatMasm( PCDISSTATE pDis, char *pszBuf, size_t cchBuf);
886DISDECL(size_t) DISFormatMasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser);
887DISDECL(size_t) DISFormatGas( PCDISSTATE pDis, char *pszBuf, size_t cchBuf);
888DISDECL(size_t) DISFormatGasEx( PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser);
889
890/** @todo DISAnnotate(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, register
891 * reader, memory reader); */
892
893DISDECL(bool) DISFormatYasmIsOddEncoding(PDISSTATE pDis);
894
895/** @} */
896
897RT_C_DECLS_END
898
899#endif /* !VBOX_INCLUDED_dis_h */
900
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