VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmReg.cpp@ 94521

Last change on this file since 94521 was 93746, checked in by vboxsync, 2 years ago

Disasm,iprt/cdefs.h: clang and arm64 adjustments. [scm] bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
  • Property svn:sync_process set to export
File size: 30.4 KB
Line 
1/* $Id: DisasmReg.cpp 93746 2022-02-14 21:04:50Z vboxsync $ */
2/** @file
3 * VBox disassembler- Register Info Helpers.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DIS
23#include <VBox/dis.h>
24#include <VBox/disopcode.h>
25#include <iprt/errcore.h>
26#include <VBox/log.h>
27#include <VBox/vmm/cpum.h>
28#include <iprt/assert.h>
29#include <iprt/string.h>
30#include <iprt/stdarg.h>
31#include "DisasmInternal.h"
32
33
34/*********************************************************************************************************************************
35* Global Variables *
36*********************************************************************************************************************************/
37/**
38 * Array for accessing 64-bit general registers in VMMREGFRAME structure
39 * by register's index from disasm.
40 */
41static const unsigned g_aReg64Index[] =
42{
43 RT_OFFSETOF(CPUMCTXCORE, rax), /* DISGREG_RAX */
44 RT_OFFSETOF(CPUMCTXCORE, rcx), /* DISGREG_RCX */
45 RT_OFFSETOF(CPUMCTXCORE, rdx), /* DISGREG_RDX */
46 RT_OFFSETOF(CPUMCTXCORE, rbx), /* DISGREG_RBX */
47 RT_OFFSETOF(CPUMCTXCORE, rsp), /* DISGREG_RSP */
48 RT_OFFSETOF(CPUMCTXCORE, rbp), /* DISGREG_RBP */
49 RT_OFFSETOF(CPUMCTXCORE, rsi), /* DISGREG_RSI */
50 RT_OFFSETOF(CPUMCTXCORE, rdi), /* DISGREG_RDI */
51 RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8 */
52 RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9 */
53 RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R10 */
54 RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11 */
55 RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12 */
56 RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13 */
57 RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14 */
58 RT_OFFSETOF(CPUMCTXCORE, r15) /* DISGREG_R15 */
59};
60
61/**
62 * Macro for accessing 64-bit general purpose registers in CPUMCTXCORE structure.
63 */
64#define DIS_READ_REG64(p, idx) (*(uint64_t *)((char *)(p) + g_aReg64Index[idx]))
65#define DIS_WRITE_REG64(p, idx, val) (*(uint64_t *)((char *)(p) + g_aReg64Index[idx]) = val)
66#define DIS_PTR_REG64(p, idx) ( (uint64_t *)((char *)(p) + g_aReg64Index[idx]))
67
68/**
69 * Array for accessing 32-bit general registers in VMMREGFRAME structure
70 * by register's index from disasm.
71 */
72static const unsigned g_aReg32Index[] =
73{
74 RT_OFFSETOF(CPUMCTXCORE, eax), /* DISGREG_EAX */
75 RT_OFFSETOF(CPUMCTXCORE, ecx), /* DISGREG_ECX */
76 RT_OFFSETOF(CPUMCTXCORE, edx), /* DISGREG_EDX */
77 RT_OFFSETOF(CPUMCTXCORE, ebx), /* DISGREG_EBX */
78 RT_OFFSETOF(CPUMCTXCORE, esp), /* DISGREG_ESP */
79 RT_OFFSETOF(CPUMCTXCORE, ebp), /* DISGREG_EBP */
80 RT_OFFSETOF(CPUMCTXCORE, esi), /* DISGREG_ESI */
81 RT_OFFSETOF(CPUMCTXCORE, edi), /* DISGREG_EDI */
82 RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8D */
83 RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9D */
84 RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R1D */
85 RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11D */
86 RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12D */
87 RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13D */
88 RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14D */
89 RT_OFFSETOF(CPUMCTXCORE, r15) /* DISGREG_R15D */
90};
91
92/**
93 * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure.
94 */
95#define DIS_READ_REG32(p, idx) (*(uint32_t *)((char *)(p) + g_aReg32Index[idx]))
96/* From http://www.cs.cmu.edu/~fp/courses/15213-s06/misc/asm64-handout.pdf:
97 * ``Perhaps unexpectedly, instructions that move or generate 32-bit register
98 * values also set the upper 32 bits of the register to zero. Consequently
99 * there is no need for an instruction movzlq.''
100 */
101#define DIS_WRITE_REG32(p, idx, val) (*(uint64_t *)((char *)(p) + g_aReg32Index[idx]) = (uint32_t)val)
102#define DIS_PTR_REG32(p, idx) ( (uint32_t *)((char *)(p) + g_aReg32Index[idx]))
103
104/**
105 * Array for accessing 16-bit general registers in CPUMCTXCORE structure
106 * by register's index from disasm.
107 */
108static const unsigned g_aReg16Index[] =
109{
110 RT_OFFSETOF(CPUMCTXCORE, eax), /* DISGREG_AX */
111 RT_OFFSETOF(CPUMCTXCORE, ecx), /* DISGREG_CX */
112 RT_OFFSETOF(CPUMCTXCORE, edx), /* DISGREG_DX */
113 RT_OFFSETOF(CPUMCTXCORE, ebx), /* DISGREG_BX */
114 RT_OFFSETOF(CPUMCTXCORE, esp), /* DISGREG_SP */
115 RT_OFFSETOF(CPUMCTXCORE, ebp), /* DISGREG_BP */
116 RT_OFFSETOF(CPUMCTXCORE, esi), /* DISGREG_SI */
117 RT_OFFSETOF(CPUMCTXCORE, edi), /* DISGREG_DI */
118 RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8W */
119 RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9W */
120 RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R10W */
121 RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11W */
122 RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12W */
123 RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13W */
124 RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14W */
125 RT_OFFSETOF(CPUMCTXCORE, r15) /* DISGREG_R15W */
126};
127
128/**
129 * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure.
130 */
131#define DIS_READ_REG16(p, idx) (*(uint16_t *)((char *)(p) + g_aReg16Index[idx]))
132#define DIS_WRITE_REG16(p, idx, val) (*(uint16_t *)((char *)(p) + g_aReg16Index[idx]) = val)
133#define DIS_PTR_REG16(p, idx) ( (uint16_t *)((char *)(p) + g_aReg16Index[idx]))
134
135/**
136 * Array for accessing 8-bit general registers in CPUMCTXCORE structure
137 * by register's index from disasm.
138 */
139static const unsigned g_aReg8Index[] =
140{
141 RT_OFFSETOF(CPUMCTXCORE, eax), /* DISGREG_AL */
142 RT_OFFSETOF(CPUMCTXCORE, ecx), /* DISGREG_CL */
143 RT_OFFSETOF(CPUMCTXCORE, edx), /* DISGREG_DL */
144 RT_OFFSETOF(CPUMCTXCORE, ebx), /* DISGREG_BL */
145 RT_OFFSETOF_ADD(CPUMCTXCORE, eax, 1), /* DISGREG_AH */
146 RT_OFFSETOF_ADD(CPUMCTXCORE, ecx, 1), /* DISGREG_CH */
147 RT_OFFSETOF_ADD(CPUMCTXCORE, edx, 1), /* DISGREG_DH */
148 RT_OFFSETOF_ADD(CPUMCTXCORE, ebx, 1), /* DISGREG_BH */
149 RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8B */
150 RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9B */
151 RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R10B*/
152 RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11B */
153 RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12B */
154 RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13B */
155 RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14B */
156 RT_OFFSETOF(CPUMCTXCORE, r15), /* DISGREG_R15B */
157 RT_OFFSETOF(CPUMCTXCORE, esp), /* DISGREG_SPL; with REX prefix only */
158 RT_OFFSETOF(CPUMCTXCORE, ebp), /* DISGREG_BPL; with REX prefix only */
159 RT_OFFSETOF(CPUMCTXCORE, esi), /* DISGREG_SIL; with REX prefix only */
160 RT_OFFSETOF(CPUMCTXCORE, edi) /* DISGREG_DIL; with REX prefix only */
161};
162
163/**
164 * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure.
165 */
166#define DIS_READ_REG8(p, idx) (*(uint8_t *)((char *)(p) + g_aReg8Index[idx]))
167#define DIS_WRITE_REG8(p, idx, val) (*(uint8_t *)((char *)(p) + g_aReg8Index[idx]) = val)
168#define DIS_PTR_REG8(p, idx) ( (uint8_t *)((char *)(p) + g_aReg8Index[idx]))
169
170/**
171 * Array for accessing segment registers in CPUMCTXCORE structure
172 * by register's index from disasm.
173 */
174static const unsigned g_aRegSegIndex[] =
175{
176 RT_OFFSETOF(CPUMCTXCORE, es), /* DISSELREG_ES */
177 RT_OFFSETOF(CPUMCTXCORE, cs), /* DISSELREG_CS */
178 RT_OFFSETOF(CPUMCTXCORE, ss), /* DISSELREG_SS */
179 RT_OFFSETOF(CPUMCTXCORE, ds), /* DISSELREG_DS */
180 RT_OFFSETOF(CPUMCTXCORE, fs), /* DISSELREG_FS */
181 RT_OFFSETOF(CPUMCTXCORE, gs) /* DISSELREG_GS */
182};
183
184static const unsigned g_aRegHidSegIndex[] =
185{
186 RT_OFFSETOF(CPUMCTXCORE, es), /* DISSELREG_ES */
187 RT_OFFSETOF(CPUMCTXCORE, cs), /* DISSELREG_CS */
188 RT_OFFSETOF(CPUMCTXCORE, ss), /* DISSELREG_SS */
189 RT_OFFSETOF(CPUMCTXCORE, ds), /* DISSELREG_DS */
190 RT_OFFSETOF(CPUMCTXCORE, fs), /* DISSELREG_FS */
191 RT_OFFSETOF(CPUMCTXCORE, gs) /* DISSELREG_GS */
192};
193
194/**
195 * Macro for accessing segment registers in CPUMCTXCORE structure.
196 */
197#define DIS_READ_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])))
198#define DIS_WRITE_REGSEG(p, idx, val) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])) = val)
199
200
201//*****************************************************************************
202//*****************************************************************************
203DISDECL(uint8_t) DISGetParamSize(PCDISSTATE pDis, PCDISOPPARAM pParam)
204{
205 unsigned subtype = OP_PARM_VSUBTYPE(pParam->fParam);
206 switch (subtype)
207 {
208 case OP_PARM_v:
209 switch (pDis->uOpMode)
210 {
211 case DISCPUMODE_32BIT:
212 return 4;
213 case DISCPUMODE_64BIT:
214 return 8;
215 case DISCPUMODE_16BIT:
216 return 2;
217 default: AssertFailed(); /* make gcc happy */ return 4;
218 }
219 break;
220
221 case OP_PARM_b:
222 return 1;
223
224 case OP_PARM_w:
225 return 2;
226
227 case OP_PARM_d:
228 return 4;
229
230 case OP_PARM_q:
231 return 8;
232
233 case OP_PARM_dq:
234 return 16;
235
236 case OP_PARM_qq:
237 return 32;
238
239 case 0: /* nop, pause, lea, wrmsr, rdmsr, etc. Most of these due to DISOPPARAM::cb being initialized in the wrong place
240 (disParseInstruction) where it will be called on intermediate stuff like IDX_ParseTwoByteEsc. The parameter
241 parsers should do it instead, though I see the potential filtering issue. */
242 //Assert( pDis->pCurInstr
243 // && ( pDis->pCurInstr->uOpcode == OP_NOP
244 // || pDis->pCurInstr->uOpcode == OP_LEA ));
245 return 0;
246
247 case OP_PARM_p: /* far pointer */
248 if (pDis->uAddrMode == DISCPUMODE_32BIT)
249 return 6; /* 16:32 */
250 if (pDis->uAddrMode == DISCPUMODE_64BIT)
251 return 12; /* 16:64 */
252 return 4; /* 16:16 */
253
254 case OP_PARM_s: /* lgdt, sgdt, lidt, sidt */
255 return pDis->uCpuMode == DISCPUMODE_64BIT ? 2 + 8 : 2 + 4;
256
257 case OP_PARM_a:
258 return pDis->uOpMode == DISCPUMODE_16BIT ? 2 + 2 : 4 + 4;
259
260 case OP_PARM_pi:
261 return 8;
262
263 case OP_PARM_sd:
264 case OP_PARM_ss:
265 return 16;
266
267 case OP_PARM_x:
268 case OP_PARM_pd:
269 case OP_PARM_ps:
270 return VEXREG_IS256B(pDis->bVexDestReg) ? 32 : 16; //??
271
272 case OP_PARM_y:
273 return pDis->uOpMode == DISCPUMODE_64BIT ? 4 : 8; //??
274
275 case OP_PARM_z:
276 if (pParam->cb)
277 return pParam->cb;
278 return pDis->uOpMode == DISCPUMODE_16BIT ? 2 : 4; //??
279
280 default:
281 if (pParam->cb)
282 return pParam->cb;
283 /// @todo dangerous!!!
284 AssertMsgFailed(("subtype=%#x fParam=%#x fUse=%#RX64 op=%#x\n", subtype, pParam->fParam, pParam->fUse,
285 pDis->pCurInstr ? pDis->pCurInstr->uOpcode : 0));
286 return 4;
287 }
288}
289//*****************************************************************************
290//*****************************************************************************
291DISDECL(DISSELREG) DISDetectSegReg(PCDISSTATE pDis, PCDISOPPARAM pParam)
292{
293 if (pDis->fPrefix & DISPREFIX_SEG)
294 /* Use specified SEG: prefix. */
295 return (DISSELREG)pDis->idxSegPrefix;
296
297 /* Guess segment register by parameter type. */
298 if (pParam->fUse & (DISUSE_REG_GEN32|DISUSE_REG_GEN64|DISUSE_REG_GEN16))
299 {
300 AssertCompile(DISGREG_ESP == DISGREG_RSP);
301 AssertCompile(DISGREG_EBP == DISGREG_RBP);
302 AssertCompile(DISGREG_ESP == DISGREG_SP);
303 AssertCompile(DISGREG_EBP == DISGREG_BP);
304 if (pParam->Base.idxGenReg == DISGREG_ESP || pParam->Base.idxGenReg == DISGREG_EBP)
305 return DISSELREG_SS;
306 }
307 /* Default is use DS: for data access. */
308 return DISSELREG_DS;
309}
310//*****************************************************************************
311//*****************************************************************************
312DISDECL(uint8_t) DISQuerySegPrefixByte(PCDISSTATE pDis)
313{
314 Assert(pDis->fPrefix & DISPREFIX_SEG);
315 switch (pDis->idxSegPrefix)
316 {
317 case DISSELREG_ES:
318 return 0x26;
319 case DISSELREG_CS:
320 return 0x2E;
321 case DISSELREG_SS:
322 return 0x36;
323 case DISSELREG_DS:
324 return 0x3E;
325 case DISSELREG_FS:
326 return 0x64;
327 case DISSELREG_GS:
328 return 0x65;
329 default:
330 AssertFailed();
331 return 0;
332 }
333}
334
335
336
337/**
338 * Returns the value of the specified 8 bits general purpose register
339 *
340 */
341DISDECL(int) DISFetchReg8(PCCPUMCTXCORE pCtx, unsigned reg8, uint8_t *pVal)
342{
343 AssertReturnStmt(reg8 < RT_ELEMENTS(g_aReg8Index), *pVal = 0, VERR_INVALID_PARAMETER);
344
345 *pVal = DIS_READ_REG8(pCtx, reg8);
346 return VINF_SUCCESS;
347}
348
349/**
350 * Returns the value of the specified 16 bits general purpose register
351 *
352 */
353DISDECL(int) DISFetchReg16(PCCPUMCTXCORE pCtx, unsigned reg16, uint16_t *pVal)
354{
355 AssertReturnStmt(reg16 < RT_ELEMENTS(g_aReg16Index), *pVal = 0, VERR_INVALID_PARAMETER);
356
357 *pVal = DIS_READ_REG16(pCtx, reg16);
358 return VINF_SUCCESS;
359}
360
361/**
362 * Returns the value of the specified 32 bits general purpose register
363 *
364 */
365DISDECL(int) DISFetchReg32(PCCPUMCTXCORE pCtx, unsigned reg32, uint32_t *pVal)
366{
367 AssertReturnStmt(reg32 < RT_ELEMENTS(g_aReg32Index), *pVal = 0, VERR_INVALID_PARAMETER);
368
369 *pVal = DIS_READ_REG32(pCtx, reg32);
370 return VINF_SUCCESS;
371}
372
373/**
374 * Returns the value of the specified 64 bits general purpose register
375 *
376 */
377DISDECL(int) DISFetchReg64(PCCPUMCTXCORE pCtx, unsigned reg64, uint64_t *pVal)
378{
379 AssertReturnStmt(reg64 < RT_ELEMENTS(g_aReg64Index), *pVal = 0, VERR_INVALID_PARAMETER);
380
381 *pVal = DIS_READ_REG64(pCtx, reg64);
382 return VINF_SUCCESS;
383}
384
385/**
386 * Returns the pointer to the specified 8 bits general purpose register
387 *
388 */
389DISDECL(int) DISPtrReg8(PCPUMCTXCORE pCtx, unsigned reg8, uint8_t **ppReg)
390{
391 AssertReturnStmt(reg8 < RT_ELEMENTS(g_aReg8Index), *ppReg = NULL, VERR_INVALID_PARAMETER);
392
393 *ppReg = DIS_PTR_REG8(pCtx, reg8);
394 return VINF_SUCCESS;
395}
396
397/**
398 * Returns the pointer to the specified 16 bits general purpose register
399 *
400 */
401DISDECL(int) DISPtrReg16(PCPUMCTXCORE pCtx, unsigned reg16, uint16_t **ppReg)
402{
403 AssertReturnStmt(reg16 < RT_ELEMENTS(g_aReg16Index), *ppReg = NULL, VERR_INVALID_PARAMETER);
404
405 *ppReg = DIS_PTR_REG16(pCtx, reg16);
406 return VINF_SUCCESS;
407}
408
409/**
410 * Returns the pointer to the specified 32 bits general purpose register
411 */
412DISDECL(int) DISPtrReg32(PCPUMCTXCORE pCtx, unsigned reg32, uint32_t **ppReg)
413{
414 AssertReturnStmt(reg32 < RT_ELEMENTS(g_aReg32Index), *ppReg = NULL, VERR_INVALID_PARAMETER);
415
416 *ppReg = DIS_PTR_REG32(pCtx, reg32);
417 return VINF_SUCCESS;
418}
419
420/**
421 * Returns the pointer to the specified 64 bits general purpose register
422 */
423DISDECL(int) DISPtrReg64(PCPUMCTXCORE pCtx, unsigned reg64, uint64_t **ppReg)
424{
425 AssertReturnStmt(reg64 < RT_ELEMENTS(g_aReg64Index), *ppReg = NULL, VERR_INVALID_PARAMETER);
426
427 *ppReg = DIS_PTR_REG64(pCtx, reg64);
428 return VINF_SUCCESS;
429}
430
431/**
432 * Returns the value of the specified segment register
433 */
434DISDECL(int) DISFetchRegSeg(PCCPUMCTXCORE pCtx, DISSELREG sel, RTSEL *pVal)
435{
436 AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER);
437
438 AssertCompile(sizeof(uint16_t) == sizeof(RTSEL));
439 *pVal = DIS_READ_REGSEG(pCtx, sel);
440 return VINF_SUCCESS;
441}
442
443/**
444 * Returns the value of the specified segment register including a pointer to the hidden register in the supplied cpu context
445 *
446 */
447DISDECL(int) DISFetchRegSegEx(PCPUMCTXCORE pCtx, DISSELREG sel, PCPUMSELREG *ppSelReg)
448{
449 AssertReturnStmt((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), *ppSelReg = NULL, VERR_INVALID_PARAMETER);
450 *ppSelReg = (CPUMSELREG *)((uintptr_t)pCtx + g_aRegHidSegIndex[sel]);
451 return VINF_SUCCESS;
452}
453
454/**
455 * Updates the value of the specified 64 bits general purpose register
456 *
457 */
458DISDECL(int) DISWriteReg64(PCPUMCTXCORE pRegFrame, unsigned reg64, uint64_t val64)
459{
460 AssertReturn(reg64 < RT_ELEMENTS(g_aReg64Index), VERR_INVALID_PARAMETER);
461
462 DIS_WRITE_REG64(pRegFrame, reg64, val64);
463 return VINF_SUCCESS;
464}
465
466/**
467 * Updates the value of the specified 32 bits general purpose register
468 *
469 */
470DISDECL(int) DISWriteReg32(PCPUMCTXCORE pRegFrame, unsigned reg32, uint32_t val32)
471{
472 AssertReturn(reg32 < RT_ELEMENTS(g_aReg32Index), VERR_INVALID_PARAMETER);
473
474 DIS_WRITE_REG32(pRegFrame, reg32, val32);
475 return VINF_SUCCESS;
476}
477
478/**
479 * Updates the value of the specified 16 bits general purpose register
480 *
481 */
482DISDECL(int) DISWriteReg16(PCPUMCTXCORE pRegFrame, unsigned reg16, uint16_t val16)
483{
484 AssertReturn(reg16 < RT_ELEMENTS(g_aReg16Index), VERR_INVALID_PARAMETER);
485
486 DIS_WRITE_REG16(pRegFrame, reg16, val16);
487 return VINF_SUCCESS;
488}
489
490/**
491 * Updates the specified 8 bits general purpose register
492 *
493 */
494DISDECL(int) DISWriteReg8(PCPUMCTXCORE pRegFrame, unsigned reg8, uint8_t val8)
495{
496 AssertReturn(reg8 < RT_ELEMENTS(g_aReg8Index), VERR_INVALID_PARAMETER);
497
498 DIS_WRITE_REG8(pRegFrame, reg8, val8);
499 return VINF_SUCCESS;
500}
501
502/**
503 * Updates the specified segment register
504 *
505 */
506DISDECL(int) DISWriteRegSeg(PCPUMCTXCORE pCtx, DISSELREG sel, RTSEL val)
507{
508 AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER);
509
510 AssertCompile(sizeof(uint16_t) == sizeof(RTSEL));
511 DIS_WRITE_REGSEG(pCtx, sel, val);
512 return VINF_SUCCESS;
513}
514
515/**
516 * Returns the value of the parameter in pParam
517 *
518 * @returns VBox error code
519 * @param pCtx CPU context structure pointer
520 * @param pDis Pointer to the disassembler state.
521 * @param pParam Pointer to the parameter to parse
522 * @param pParamVal Pointer to parameter value (OUT)
523 * @param parmtype Parameter type
524 *
525 * @note Currently doesn't handle FPU/XMM/MMX/3DNow! parameters correctly!!
526 *
527 */
528DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype)
529{
530 memset(pParamVal, 0, sizeof(*pParamVal));
531
532 if (DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse))
533 {
534 // Effective address
535 pParamVal->type = DISQPV_TYPE_ADDRESS;
536 pParamVal->size = pParam->cb;
537
538 if (pParam->fUse & DISUSE_BASE)
539 {
540 if (pParam->fUse & DISUSE_REG_GEN8)
541 {
542 pParamVal->flags |= DISQPV_FLAG_8;
543 if (RT_FAILURE(DISFetchReg8(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER;
544 }
545 else
546 if (pParam->fUse & DISUSE_REG_GEN16)
547 {
548 pParamVal->flags |= DISQPV_FLAG_16;
549 if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER;
550 }
551 else
552 if (pParam->fUse & DISUSE_REG_GEN32)
553 {
554 pParamVal->flags |= DISQPV_FLAG_32;
555 if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER;
556 }
557 else
558 if (pParam->fUse & DISUSE_REG_GEN64)
559 {
560 pParamVal->flags |= DISQPV_FLAG_64;
561 if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER;
562 }
563 else
564 {
565 AssertFailed();
566 return VERR_INVALID_PARAMETER;
567 }
568 }
569 // Note that scale implies index (SIB byte)
570 if (pParam->fUse & DISUSE_INDEX)
571 {
572 if (pParam->fUse & DISUSE_REG_GEN16)
573 {
574 uint16_t val16;
575
576 pParamVal->flags |= DISQPV_FLAG_16;
577 if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Index.idxGenReg, &val16))) return VERR_INVALID_PARAMETER;
578
579 Assert(!(pParam->fUse & DISUSE_SCALE)); /* shouldn't be possible in 16 bits mode */
580
581 pParamVal->val.val16 += val16;
582 }
583 else
584 if (pParam->fUse & DISUSE_REG_GEN32)
585 {
586 uint32_t val32;
587
588 pParamVal->flags |= DISQPV_FLAG_32;
589 if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Index.idxGenReg, &val32))) return VERR_INVALID_PARAMETER;
590
591 if (pParam->fUse & DISUSE_SCALE)
592 val32 *= pParam->uScale;
593
594 pParamVal->val.val32 += val32;
595 }
596 else
597 if (pParam->fUse & DISUSE_REG_GEN64)
598 {
599 uint64_t val64;
600
601 pParamVal->flags |= DISQPV_FLAG_64;
602 if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Index.idxGenReg, &val64))) return VERR_INVALID_PARAMETER;
603
604 if (pParam->fUse & DISUSE_SCALE)
605 val64 *= pParam->uScale;
606
607 pParamVal->val.val64 += val64;
608 }
609 else
610 AssertFailed();
611 }
612
613 if (pParam->fUse & DISUSE_DISPLACEMENT8)
614 {
615 if (pDis->uCpuMode == DISCPUMODE_32BIT)
616 pParamVal->val.i32 += (int32_t)pParam->uDisp.i8;
617 else if (pDis->uCpuMode == DISCPUMODE_64BIT)
618 pParamVal->val.i64 += (int64_t)pParam->uDisp.i8;
619 else
620 pParamVal->val.i16 += (int16_t)pParam->uDisp.i8;
621 }
622 else if (pParam->fUse & DISUSE_DISPLACEMENT16)
623 {
624 if (pDis->uCpuMode == DISCPUMODE_32BIT)
625 pParamVal->val.i32 += (int32_t)pParam->uDisp.i16;
626 else if (pDis->uCpuMode == DISCPUMODE_64BIT)
627 pParamVal->val.i64 += (int64_t)pParam->uDisp.i16;
628 else
629 pParamVal->val.i16 += pParam->uDisp.i16;
630 }
631 else if (pParam->fUse & DISUSE_DISPLACEMENT32)
632 {
633 if (pDis->uCpuMode == DISCPUMODE_32BIT)
634 pParamVal->val.i32 += pParam->uDisp.i32;
635 else
636 pParamVal->val.i64 += pParam->uDisp.i32;
637 }
638 else if (pParam->fUse & DISUSE_DISPLACEMENT64)
639 {
640 Assert(pDis->uCpuMode == DISCPUMODE_64BIT);
641 pParamVal->val.i64 += pParam->uDisp.i64;
642 }
643 else if (pParam->fUse & DISUSE_RIPDISPLACEMENT32)
644 {
645 Assert(pDis->uCpuMode == DISCPUMODE_64BIT);
646 /* Relative to the RIP of the next instruction. */
647 pParamVal->val.i64 += pParam->uDisp.i32 + pCtx->rip + pDis->cbInstr;
648 }
649 return VINF_SUCCESS;
650 }
651
652 if (pParam->fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32|DISUSE_REG_GEN64|DISUSE_REG_FP|DISUSE_REG_MMX|DISUSE_REG_XMM|DISUSE_REG_CR|DISUSE_REG_DBG|DISUSE_REG_SEG|DISUSE_REG_TEST))
653 {
654 if (parmtype == DISQPVWHICH_DST)
655 {
656 // Caller needs to interpret the register according to the instruction (source/target, special value etc)
657 pParamVal->type = DISQPV_TYPE_REGISTER;
658 pParamVal->size = pParam->cb;
659 return VINF_SUCCESS;
660 }
661 //else DISQPVWHICH_SRC
662
663 pParamVal->type = DISQPV_TYPE_IMMEDIATE;
664
665 if (pParam->fUse & DISUSE_REG_GEN8)
666 {
667 pParamVal->flags |= DISQPV_FLAG_8;
668 pParamVal->size = sizeof(uint8_t);
669 if (RT_FAILURE(DISFetchReg8(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER;
670 }
671 else
672 if (pParam->fUse & DISUSE_REG_GEN16)
673 {
674 pParamVal->flags |= DISQPV_FLAG_16;
675 pParamVal->size = sizeof(uint16_t);
676 if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER;
677 }
678 else
679 if (pParam->fUse & DISUSE_REG_GEN32)
680 {
681 pParamVal->flags |= DISQPV_FLAG_32;
682 pParamVal->size = sizeof(uint32_t);
683 if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER;
684 }
685 else
686 if (pParam->fUse & DISUSE_REG_GEN64)
687 {
688 pParamVal->flags |= DISQPV_FLAG_64;
689 pParamVal->size = sizeof(uint64_t);
690 if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER;
691 }
692 else
693 {
694 // Caller needs to interpret the register according to the instruction (source/target, special value etc)
695 pParamVal->type = DISQPV_TYPE_REGISTER;
696 }
697 Assert(!(pParam->fUse & DISUSE_IMMEDIATE));
698 return VINF_SUCCESS;
699 }
700
701 if (pParam->fUse & DISUSE_IMMEDIATE)
702 {
703 pParamVal->type = DISQPV_TYPE_IMMEDIATE;
704 if (pParam->fUse & (DISUSE_IMMEDIATE8|DISUSE_IMMEDIATE8_REL))
705 {
706 pParamVal->flags |= DISQPV_FLAG_8;
707 if (pParam->cb == 2)
708 {
709 pParamVal->size = sizeof(uint16_t);
710 pParamVal->val.val16 = (uint8_t)pParam->uValue;
711 }
712 else
713 {
714 pParamVal->size = sizeof(uint8_t);
715 pParamVal->val.val8 = (uint8_t)pParam->uValue;
716 }
717 }
718 else
719 if (pParam->fUse & (DISUSE_IMMEDIATE16|DISUSE_IMMEDIATE16_REL|DISUSE_IMMEDIATE_ADDR_0_16|DISUSE_IMMEDIATE16_SX8))
720 {
721 pParamVal->flags |= DISQPV_FLAG_16;
722 pParamVal->size = sizeof(uint16_t);
723 pParamVal->val.val16 = (uint16_t)pParam->uValue;
724 AssertMsg(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE16_SX8)), ("pParamVal->size %d vs %d EIP=%RX32\n", pParamVal->size, pParam->cb, pCtx->eip) );
725 }
726 else
727 if (pParam->fUse & (DISUSE_IMMEDIATE32|DISUSE_IMMEDIATE32_REL|DISUSE_IMMEDIATE_ADDR_0_32|DISUSE_IMMEDIATE32_SX8))
728 {
729 pParamVal->flags |= DISQPV_FLAG_32;
730 pParamVal->size = sizeof(uint32_t);
731 pParamVal->val.val32 = (uint32_t)pParam->uValue;
732 Assert(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE32_SX8)) );
733 }
734 else
735 if (pParam->fUse & (DISUSE_IMMEDIATE64 | DISUSE_IMMEDIATE64_REL | DISUSE_IMMEDIATE64_SX8))
736 {
737 pParamVal->flags |= DISQPV_FLAG_64;
738 pParamVal->size = sizeof(uint64_t);
739 pParamVal->val.val64 = pParam->uValue;
740 Assert(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE64_SX8)) );
741 }
742 else
743 if (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16))
744 {
745 pParamVal->flags |= DISQPV_FLAG_FARPTR16;
746 pParamVal->size = sizeof(uint16_t)*2;
747 pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->uValue >> 16);
748 pParamVal->val.farptr.offset = (uint32_t)RT_LOWORD(pParam->uValue);
749 Assert(pParamVal->size == pParam->cb);
750 }
751 else
752 if (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_32))
753 {
754 pParamVal->flags |= DISQPV_FLAG_FARPTR32;
755 pParamVal->size = sizeof(uint16_t) + sizeof(uint32_t);
756 pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->uValue >> 32);
757 pParamVal->val.farptr.offset = (uint32_t)(pParam->uValue & 0xFFFFFFFF);
758 Assert(pParam->cb == 8);
759 }
760 }
761 return VINF_SUCCESS;
762}
763
764/**
765 * Returns the pointer to a register of the parameter in pParam. We need this
766 * pointer when an interpreted instruction updates a register as a side effect.
767 * In CMPXCHG we know that only [r/e]ax is updated, but with XADD this could
768 * be every register.
769 *
770 * @returns VBox error code
771 * @param pCtx CPU context structure pointer
772 * @param pDis Pointer to the disassembler state.
773 * @param pParam Pointer to the parameter to parse
774 * @param pReg Pointer to parameter value (OUT)
775 * @param cbsize Parameter size (OUT)
776 *
777 * @note Currently doesn't handle FPU/XMM/MMX/3DNow! parameters correctly!!
778 *
779 */
780DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, void **ppReg, size_t *pcbSize)
781{
782 NOREF(pDis);
783 if (pParam->fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32|DISUSE_REG_FP|DISUSE_REG_MMX|DISUSE_REG_XMM|DISUSE_REG_CR|DISUSE_REG_DBG|DISUSE_REG_SEG|DISUSE_REG_TEST))
784 {
785 if (pParam->fUse & DISUSE_REG_GEN8)
786 {
787 uint8_t *pu8Reg;
788 if (RT_SUCCESS(DISPtrReg8(pCtx, pParam->Base.idxGenReg, &pu8Reg)))
789 {
790 *pcbSize = sizeof(uint8_t);
791 *ppReg = (void *)pu8Reg;
792 return VINF_SUCCESS;
793 }
794 }
795 else
796 if (pParam->fUse & DISUSE_REG_GEN16)
797 {
798 uint16_t *pu16Reg;
799 if (RT_SUCCESS(DISPtrReg16(pCtx, pParam->Base.idxGenReg, &pu16Reg)))
800 {
801 *pcbSize = sizeof(uint16_t);
802 *ppReg = (void *)pu16Reg;
803 return VINF_SUCCESS;
804 }
805 }
806 else
807 if (pParam->fUse & DISUSE_REG_GEN32)
808 {
809 uint32_t *pu32Reg;
810 if (RT_SUCCESS(DISPtrReg32(pCtx, pParam->Base.idxGenReg, &pu32Reg)))
811 {
812 *pcbSize = sizeof(uint32_t);
813 *ppReg = (void *)pu32Reg;
814 return VINF_SUCCESS;
815 }
816 }
817 else
818 if (pParam->fUse & DISUSE_REG_GEN64)
819 {
820 uint64_t *pu64Reg;
821 if (RT_SUCCESS(DISPtrReg64(pCtx, pParam->Base.idxGenReg, &pu64Reg)))
822 {
823 *pcbSize = sizeof(uint64_t);
824 *ppReg = (void *)pu64Reg;
825 return VINF_SUCCESS;
826 }
827 }
828 }
829 return VERR_INVALID_PARAMETER;
830}
831
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use