VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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