VirtualBox

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

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

scm copyright and license note update

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