VirtualBox

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

Last change on this file since 98110 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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