VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmCore.cpp@ 8355

Last change on this file since 8355 was 8355, checked in by vboxsync, 17 years ago

Fixes for REX.R

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.5 KB
Line 
1/** @file
2 *
3 * VBox disassembler:
4 * Core components
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DIS
28#ifdef USING_VISUAL_STUDIO
29# include <stdafx.h>
30#endif
31
32#include <VBox/dis.h>
33#include <VBox/disopcode.h>
34#include <VBox/cpum.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/string.h>
39#include <iprt/stdarg.h>
40#include "DisasmInternal.h"
41#include "DisasmTables.h"
42
43#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
44# include <stdlib.h>
45# include <stdio.h>
46#endif
47
48
49/*******************************************************************************
50* Internal Functions *
51*******************************************************************************/
52static int disCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction);
53#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
54static void disasmAddString(char *psz, const char *pszString);
55static void disasmAddStringF(char *psz, uint32_t cbString, const char *pszFormat, ...);
56static void disasmAddChar(char *psz, char ch);
57#else
58# define disasmAddString(psz, pszString) do {} while (0)
59# ifdef _MSC_VER
60# define disasmAddStringF __noop
61# else
62# define disasmAddStringF(psz, cbString, pszFormat...) do {} while (0) /* Arg wanna get rid of that warning */
63# endif
64# define disasmAddChar(psz, ch) do {} while (0)
65#endif
66
67static unsigned QueryModRM(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
68static unsigned QueryModRM_SizeOnly(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
69static void UseSIB(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu);
70static unsigned ParseSIB_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu);
71
72/*******************************************************************************
73* Global Variables *
74*******************************************************************************/
75
76PFNDISPARSE pfnFullDisasm[IDX_ParseMax] =
77{
78 ParseIllegal,
79 ParseModRM,
80 UseModRM,
81 ParseImmByte,
82 ParseImmBRel,
83 ParseImmUshort,
84 ParseImmV,
85 ParseImmVRel,
86 ParseImmAddr,
87 ParseFixedReg,
88 ParseImmUlong,
89 ParseImmQword,
90 ParseTwoByteEsc,
91 ParseImmGrpl,
92 ParseShiftGrp2,
93 ParseGrp3,
94 ParseGrp4,
95 ParseGrp5,
96 Parse3DNow,
97 ParseGrp6,
98 ParseGrp7,
99 ParseGrp8,
100 ParseGrp9,
101 ParseGrp10,
102 ParseGrp12,
103 ParseGrp13,
104 ParseGrp14,
105 ParseGrp15,
106 ParseGrp16,
107 ParseModFence,
108 ParseYv,
109 ParseYb,
110 ParseXv,
111 ParseXb,
112 ParseEscFP,
113 ParseNopPause,
114 ParseImmByteSX
115};
116
117PFNDISPARSE pfnCalcSize[IDX_ParseMax] =
118{
119 ParseIllegal,
120 ParseModRM_SizeOnly,
121 UseModRM,
122 ParseImmByte_SizeOnly,
123 ParseImmBRel_SizeOnly,
124 ParseImmUshort_SizeOnly,
125 ParseImmV_SizeOnly,
126 ParseImmVRel_SizeOnly,
127 ParseImmAddr_SizeOnly,
128 ParseFixedReg,
129 ParseImmUlong_SizeOnly,
130 ParseImmQword_SizeOnly,
131 ParseTwoByteEsc,
132 ParseImmGrpl,
133 ParseShiftGrp2,
134 ParseGrp3,
135 ParseGrp4,
136 ParseGrp5,
137 Parse3DNow,
138 ParseGrp6,
139 ParseGrp7,
140 ParseGrp8,
141 ParseGrp9,
142 ParseGrp10,
143 ParseGrp12,
144 ParseGrp13,
145 ParseGrp14,
146 ParseGrp15,
147 ParseGrp16,
148 ParseModFence,
149 ParseYv,
150 ParseYb,
151 ParseXv,
152 ParseXb,
153 ParseEscFP,
154 ParseNopPause,
155 ParseImmByteSX_SizeOnly
156};
157
158/**
159 * Parses one instruction.
160 * The result is found in pCpu.
161 *
162 * @returns Success indicator.
163 * @param pCpu Pointer to cpu structure which has DISCPUSTATE::mode set correctly.
164 * @param InstructionAddr Pointer to the instruction to parse.
165 * @param pcbInstruction Where to store the size of the instruction.
166 * NULL is allowed.
167 */
168DISDECL(int) DISCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
169{
170 /*
171 * Reset instruction settings
172 */
173 pCpu->prefix = PREFIX_NONE;
174 pCpu->prefix_seg = 0;
175 pCpu->lastprefix = 0;
176 pCpu->addrmode = pCpu->mode;
177 pCpu->opmode = pCpu->mode;
178 pCpu->ModRM.u = 0;
179 pCpu->SIB.u = 0;
180 pCpu->param1.parval = 0;
181 pCpu->param2.parval = 0;
182 pCpu->param3.parval = 0;
183 pCpu->param1.szParam[0] = '\0';
184 pCpu->param2.szParam[0] = '\0';
185 pCpu->param3.szParam[0] = '\0';
186 pCpu->param1.flags = 0;
187 pCpu->param2.flags = 0;
188 pCpu->param3.flags = 0;
189 pCpu->param1.size = 0;
190 pCpu->param2.size = 0;
191 pCpu->param3.size = 0;
192 pCpu->pfnReadBytes = 0;
193 pCpu->uFilter = OPTYPE_ALL;
194 pCpu->pfnDisasmFnTable = pfnFullDisasm;
195
196 return VBOX_SUCCESS(disCoreOne(pCpu, InstructionAddr, pcbInstruction));
197}
198
199/**
200 * Parses one guest instruction.
201 * The result is found in pCpu and pcbInstruction.
202 *
203 * @returns VBox status code.
204 * @param InstructionAddr Address of the instruction to decode. What this means
205 * is left to the pfnReadBytes function.
206 * @param enmCpuMode The CPU mode. CPUMODE_32BIT, CPUMODE_16BIT, or CPUMODE_64BIT.
207 * @param pfnReadBytes Callback for reading instruction bytes.
208 * @param pvUser User argument for the instruction reader. (Ends up in apvUserData[0].)
209 * @param pCpu Pointer to cpu structure. Will be initialized.
210 * @param pcbInstruction Where to store the size of the instruction.
211 * NULL is allowed.
212 */
213DISDECL(int) DISCoreOneEx(RTUINTPTR InstructionAddr, DISCPUMODE enmCpuMode, PFN_DIS_READBYTES pfnReadBytes, void *pvUser,
214 PDISCPUSTATE pCpu, unsigned *pcbInstruction)
215{
216 /*
217 * Reset instruction settings
218 */
219 pCpu->prefix = PREFIX_NONE;
220 pCpu->prefix_seg = 0;
221 pCpu->lastprefix = 0;
222 pCpu->mode = enmCpuMode;
223 pCpu->addrmode = enmCpuMode;
224 pCpu->opmode = enmCpuMode;
225 pCpu->ModRM.u = 0;
226 pCpu->SIB.u = 0;
227 pCpu->param1.parval = 0;
228 pCpu->param2.parval = 0;
229 pCpu->param3.parval = 0;
230 pCpu->param1.szParam[0] = '\0';
231 pCpu->param2.szParam[0] = '\0';
232 pCpu->param3.szParam[0] = '\0';
233 pCpu->param1.flags = 0;
234 pCpu->param2.flags = 0;
235 pCpu->param3.flags = 0;
236 pCpu->param1.size = 0;
237 pCpu->param2.size = 0;
238 pCpu->param3.size = 0;
239 pCpu->pfnReadBytes = pfnReadBytes;
240 pCpu->apvUserData[0] = pvUser;
241 pCpu->uFilter = OPTYPE_ALL;
242 pCpu->pfnDisasmFnTable = pfnFullDisasm;
243
244 return disCoreOne(pCpu, InstructionAddr, pcbInstruction);
245}
246
247/**
248 * Internal worker for DISCoreOne and DISCoreOneEx.
249 *
250 * @returns VBox status code.
251 * @param pCpu Initialized cpu state.
252 * @param InstructionAddr Instruction address.
253 * @param pcbInstruction Where to store the instruction size. Can be NULL.
254 */
255static int disCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
256{
257 /*
258 * Parse byte by byte.
259 */
260 unsigned iByte = 0;
261 unsigned cbInc;
262
263 while(1)
264 {
265 uint8_t codebyte = DISReadByte(pCpu, InstructionAddr+iByte);
266 uint8_t opcode = g_aOneByteMapX86[codebyte].opcode;
267
268 /* Hardcoded assumption about OP_* values!! */
269 if (opcode <= OP_LOCK)
270 {
271 pCpu->lastprefix = opcode;
272
273 /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
274 if (opcode != OP_REX)
275 pCpu->prefix &= ~PREFIX_REX;
276
277 switch (opcode)
278 {
279 case OP_INVALID:
280 AssertMsgFailed(("Invalid opcode!!\n"));
281 return VERR_GENERAL_FAILURE; /** @todo better error code. */
282
283 // segment override prefix byte
284 case OP_SEG:
285 pCpu->prefix_seg = g_aOneByteMapX86[codebyte].param1 - OP_PARM_REG_SEG_START;
286 pCpu->prefix |= PREFIX_SEG;
287 iByte += sizeof(uint8_t);
288 continue; //fetch the next byte
289
290 // lock prefix byte
291 case OP_LOCK:
292 pCpu->prefix |= PREFIX_LOCK;
293 iByte += sizeof(uint8_t);
294 continue; //fetch the next byte
295
296 // address size override prefix byte
297 case OP_ADRSIZE:
298 pCpu->prefix |= PREFIX_ADDRSIZE;
299 if (pCpu->mode == CPUMODE_16BIT)
300 pCpu->addrmode = CPUMODE_32BIT;
301 else pCpu->addrmode = CPUMODE_16BIT;
302 iByte += sizeof(uint8_t);
303 continue; //fetch the next byte
304
305 // operand size override prefix byte
306 case OP_OPSIZE:
307 pCpu->prefix |= PREFIX_OPSIZE;
308 if (pCpu->mode == CPUMODE_16BIT)
309 pCpu->opmode = CPUMODE_32BIT;
310 else pCpu->opmode = CPUMODE_16BIT;
311
312 iByte += sizeof(uint8_t);
313 continue; //fetch the next byte
314
315 // rep and repne are not really prefixes, but we'll treat them as such
316 case OP_REPE:
317 pCpu->prefix |= PREFIX_REP;
318 iByte += sizeof(uint8_t);
319 continue; //fetch the next byte
320
321 case OP_REPNE:
322 pCpu->prefix |= PREFIX_REPNE;
323 iByte += sizeof(uint8_t);
324 continue; //fetch the next byte
325
326 case OP_REX:
327 Assert(pCpu->mode == CPUMODE_64BIT);
328 /* REX prefix byte */
329 pCpu->prefix |= PREFIX_REX;
330 pCpu->prefix_rex = PREFIX_REX_OP_2_FLAGS(opcode);
331
332 if (pCpu->prefix_rex & PREFIX_REX_FLAGS_W)
333 pCpu->opmode = CPUMODE_64BIT; /* overrides size prefix byte */
334 break;
335 }
336 }
337
338 unsigned uIdx = iByte;
339 iByte += sizeof(uint8_t); //first opcode byte
340
341 pCpu->opaddr = InstructionAddr + uIdx;
342 pCpu->opcode = codebyte;
343
344 if (pCpu->mode == CPUMODE_64BIT)
345 cbInc = ParseInstruction(InstructionAddr + iByte, &g_aOneByteMapX64[pCpu->opcode], pCpu);
346 else
347 cbInc = ParseInstruction(InstructionAddr + iByte, &g_aOneByteMapX86[pCpu->opcode], pCpu);
348
349 iByte += cbInc;
350 break;
351 }
352
353 pCpu->opsize = iByte;
354 if (pcbInstruction)
355 *pcbInstruction = iByte;
356
357 return VINF_SUCCESS;
358}
359//*****************************************************************************
360//*****************************************************************************
361unsigned ParseInstruction(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, PDISCPUSTATE pCpu)
362{
363 int size = 0;
364 bool fFiltered = false;
365
366 // Store the opcode format string for disasmPrintf
367#ifndef DIS_CORE_ONLY
368 pCpu->pszOpcode = pOp->pszOpcode;
369#endif
370 pCpu->pCurInstr = pOp;
371
372 /*
373 * Apply filter to instruction type to determine if a full disassembly is required.
374 * @note Multibyte opcodes are always marked harmless until the final byte.
375 */
376 if ((pOp->optype & pCpu->uFilter) == 0)
377 {
378 fFiltered = true;
379 pCpu->pfnDisasmFnTable = pfnCalcSize;
380 }
381 else
382 {
383 /* Not filtered out -> full disassembly */
384 pCpu->pfnDisasmFnTable = pfnFullDisasm;
385 }
386
387 // Should contain the parameter type on input
388 pCpu->param1.param = pOp->param1;
389 pCpu->param2.param = pOp->param2;
390 pCpu->param3.param = pOp->param3;
391
392 if (pOp->idxParse1 != IDX_ParseNop)
393 {
394 size += pCpu->pfnDisasmFnTable[pOp->idxParse1](lpszCodeBlock, pOp, &pCpu->param1, pCpu);
395 if (fFiltered == false) pCpu->param1.size = DISGetParamSize(pCpu, &pCpu->param1);
396 }
397
398 if (pOp->idxParse2 != IDX_ParseNop)
399 {
400 size += pCpu->pfnDisasmFnTable[pOp->idxParse2](lpszCodeBlock+size, pOp, &pCpu->param2, pCpu);
401 if (fFiltered == false) pCpu->param2.size = DISGetParamSize(pCpu, &pCpu->param2);
402 }
403
404 if (pOp->idxParse3 != IDX_ParseNop)
405 {
406 size += pCpu->pfnDisasmFnTable[pOp->idxParse3](lpszCodeBlock+size, pOp, &pCpu->param3, pCpu);
407 if (fFiltered == false) pCpu->param3.size = DISGetParamSize(pCpu, &pCpu->param3);
408 }
409 // else simple one byte instruction
410
411 return size;
412}
413//*****************************************************************************
414/* Floating point opcode parsing */
415//*****************************************************************************
416unsigned ParseEscFP(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
417{
418 int index;
419 const OPCODE *fpop;
420 unsigned size = 0, ModRM;
421
422 ModRM = DISReadByte(pCpu, lpszCodeBlock);
423
424 index = pCpu->opcode - 0xD8;
425 if (ModRM <= 0xBF)
426 {
427 fpop = &(g_paMapX86_FP_Low[index])[MODRM_REG(ModRM)];
428 pCpu->pCurInstr = (PCOPCODE)fpop;
429
430 // Should contain the parameter type on input
431 pCpu->param1.parval = fpop->param1;
432 pCpu->param2.parval = fpop->param2;
433 }
434 else
435 {
436 fpop = &(g_paMapX86_FP_High[index])[ModRM - 0xC0];
437 pCpu->pCurInstr = (PCOPCODE)fpop;
438 }
439
440 /*
441 * Apply filter to instruction type to determine if a full disassembly is required.
442 * @note Multibyte opcodes are always marked harmless until the final byte.
443 */
444 if ((fpop->optype & pCpu->uFilter) == 0)
445 {
446 pCpu->pfnDisasmFnTable = pfnCalcSize;
447 }
448 else
449 {
450 /* Not filtered out -> full disassembly */
451 pCpu->pfnDisasmFnTable = pfnFullDisasm;
452 }
453
454 // Little hack to make sure the ModRM byte is included in the returned size
455 if (fpop->idxParse1 != IDX_ParseModRM && fpop->idxParse2 != IDX_ParseModRM)
456 size = sizeof(uint8_t); //ModRM byte
457
458 if (fpop->idxParse1 != IDX_ParseNop)
459 size += pCpu->pfnDisasmFnTable[fpop->idxParse1](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
460
461 if (fpop->idxParse2 != IDX_ParseNop)
462 size += pCpu->pfnDisasmFnTable[fpop->idxParse2](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
463
464 // Store the opcode format string for disasmPrintf
465#ifndef DIS_CORE_ONLY
466 pCpu->pszOpcode = fpop->pszOpcode;
467#endif
468
469 return size;
470}
471//*****************************************************************************
472// SIB byte: (32 bits mode only)
473// 7 - 6 5 - 3 2-0
474// Scale Index Base
475//*****************************************************************************
476const char *szSIBBaseReg[8] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
477const char *szSIBIndexReg[8] = {"EAX", "ECX", "EDX", "EBX", NULL, "EBP", "ESI", "EDI"};
478const char *szSIBScale[4] = {"", "*2", "*4", "*8"};
479
480//*****************************************************************************
481void UseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
482{
483 unsigned scale, base, index;
484 char szTemp[32];
485 szTemp[0] = '\0';
486
487 scale = pCpu->SIB.Bits.Scale;
488 base = pCpu->SIB.Bits.Base;
489 index = pCpu->SIB.Bits.Index;
490
491 if (szSIBIndexReg[index])
492 {
493 pParam->flags |= USE_INDEX;
494 pParam->index.reg_gen = index;
495
496 if (scale != 0)
497 {
498 pParam->flags |= USE_SCALE;
499 pParam->scale = (1<<scale);
500 }
501
502 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
503 disasmAddStringF(szTemp, sizeof(szTemp), "%s%s", szSIBIndexReg[index], szSIBScale[scale]);
504 else
505 disasmAddStringF(szTemp, sizeof(szTemp), "%s+%s%s", szSIBBaseReg[base], szSIBIndexReg[index], szSIBScale[scale]);
506 }
507 else
508 {
509 if (base != 5 || pCpu->ModRM.Bits.Mod != 0)
510 disasmAddStringF(szTemp, sizeof(szTemp), "%s", szSIBBaseReg[base]);
511 }
512
513 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
514 {
515 // [scaled index] + disp32
516 disasmAddString(pParam->szParam, &szTemp[0]);
517 pParam->flags |= USE_DISPLACEMENT32;
518 pParam->disp32 = pCpu->disp;
519 disasmAddChar(pParam->szParam, '+');
520 disasmPrintDisp32(pParam);
521 }
522 else
523 {
524 disasmAddString(pParam->szParam, szTemp);
525
526 pParam->flags |= USE_BASE | USE_REG_GEN32;
527 pParam->base.reg_gen = base;
528 }
529 return; /* Already fetched everything in ParseSIB; no size returned */
530}
531//*****************************************************************************
532//*****************************************************************************
533unsigned ParseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
534{
535 unsigned size = sizeof(uint8_t);
536 unsigned SIB;
537
538 SIB = DISReadByte(pCpu, lpszCodeBlock);
539 lpszCodeBlock += size;
540
541 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
542 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
543 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
544
545 if (pCpu->prefix & PREFIX_REX)
546 {
547 /* REX.B extends the Base field if not scaled index + disp32 */
548 if (!(pCpu->SIB.Bits.Base == 5 && pCpu->ModRM.Bits.Mod == 0))
549 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
550
551 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
552 }
553
554 if ( pCpu->SIB.Bits.Base == 5
555 && pCpu->ModRM.Bits.Mod == 0)
556 {
557 /* Additional 32 bits displacement. No change in long mode. */
558 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
559 size += sizeof(int32_t);
560 }
561 return size;
562}
563//*****************************************************************************
564//*****************************************************************************
565unsigned ParseSIB_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
566{
567 unsigned size = sizeof(uint8_t);
568 unsigned SIB;
569
570 SIB = DISReadByte(pCpu, lpszCodeBlock);
571 lpszCodeBlock += size;
572
573 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
574 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
575 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
576
577 if (pCpu->prefix & PREFIX_REX)
578 {
579 /* REX.B extends the Base field. */
580 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
581 /* REX.X extends the Index field. */
582 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
583 }
584
585 if ( pCpu->SIB.Bits.Base == 5
586 && pCpu->ModRM.Bits.Mod == 0)
587 {
588 /* Additional 32 bits displacement. No change in long mode. */
589 size += sizeof(int32_t);
590 }
591 return size;
592}
593//*****************************************************************************
594// ModR/M byte:
595// 7 - 6 5 - 3 2-0
596// Mod Reg/Opcode R/M
597//*****************************************************************************
598unsigned UseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
599{
600 int vtype = OP_PARM_VTYPE(pParam->param);
601 unsigned reg = pCpu->ModRM.Bits.Reg;
602 unsigned mod = pCpu->ModRM.Bits.Mod;
603 unsigned rm = pCpu->ModRM.Bits.Rm;
604
605 switch (vtype)
606 {
607 case OP_PARM_G: //general purpose register
608 disasmModRMReg(pCpu, pOp, reg, pParam, 0);
609 return 0;
610
611 default:
612 if (IS_OP_PARM_RARE(vtype))
613 {
614 switch (vtype)
615 {
616 case OP_PARM_C: //control register
617 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "CR%d", reg);
618 pParam->flags |= USE_REG_CR;
619 pParam->base.reg_ctrl = reg;
620 return 0;
621
622 case OP_PARM_D: //debug register
623 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "DR%d", reg);
624 pParam->flags |= USE_REG_DBG;
625 pParam->base.reg_dbg = reg;
626 return 0;
627
628 case OP_PARM_P: //MMX register
629 reg &= 7; /* REX.R has no effect here */
630 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "MM%d", reg);
631 pParam->flags |= USE_REG_MMX;
632 pParam->base.reg_mmx = reg;
633 return 0;
634
635 case OP_PARM_S: //segment register
636 reg &= 7; /* REX.R has no effect here */
637 disasmModRMSReg(pCpu, pOp, reg, pParam);
638 pParam->flags |= USE_REG_SEG;
639 return 0;
640
641 case OP_PARM_T: //test register
642 reg &= 7; /* REX.R has no effect here */
643 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "TR%d", reg);
644 pParam->flags |= USE_REG_TEST;
645 pParam->base.reg_test = reg;
646 return 0;
647
648 case OP_PARM_W: //XMM register or memory operand
649 if (mod != 3)
650 break; /* memory operand */
651 /* else no break */
652 case OP_PARM_V: //XMM register
653 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "XMM%d", reg);
654 pParam->flags |= USE_REG_XMM;
655 pParam->base.reg_xmm = reg;
656 return 0;
657 }
658 }
659 }
660
661 /* @todo bound */
662
663 if (pCpu->addrmode != CPUMODE_16BIT)
664 {
665 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
666
667 /*
668 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
669 */
670 switch (mod)
671 {
672 case 0: //effective address
673 disasmGetPtrString(pCpu, pOp, pParam);
674 disasmAddChar(pParam->szParam, '[');
675 if (rm == 4)
676 { /* SIB byte follows ModRM */
677 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
678 }
679 else
680 if (rm == 5)
681 {
682 /* 32 bits displacement */
683 if (pCpu->mode == CPUMODE_32BIT)
684 {
685 pParam->flags |= USE_DISPLACEMENT32;
686 pParam->disp32 = pCpu->disp;
687 disasmPrintDisp32(pParam);
688 }
689 else
690 {
691 pParam->flags |= USE_RIPDISPLACEMENT32;
692 pParam->disp32 = pCpu->disp;
693 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "RIP+");
694 disasmPrintDisp32(pParam);
695 }
696 }
697 else {//register address
698 pParam->flags |= USE_BASE;
699 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
700 }
701 disasmAddChar(pParam->szParam, ']');
702 break;
703
704 case 1: //effective address + 8 bits displacement
705 disasmGetPtrString(pCpu, pOp, pParam);
706 disasmAddChar(pParam->szParam, '[');
707 if (rm == 4) {//SIB byte follows ModRM
708 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
709 }
710 else
711 {
712 pParam->flags |= USE_BASE;
713 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
714 }
715 pParam->disp8 = pCpu->disp;
716 pParam->flags |= USE_DISPLACEMENT8;
717
718 if (pParam->disp8 != 0)
719 {
720 if (pParam->disp8 > 0)
721 disasmAddChar(pParam->szParam, '+');
722 disasmPrintDisp8(pParam);
723 }
724 disasmAddChar(pParam->szParam, ']');
725 break;
726
727 case 2: //effective address + 32 bits displacement
728 disasmGetPtrString(pCpu, pOp, pParam);
729 disasmAddChar(pParam->szParam, '[');
730 if (rm == 4) {//SIB byte follows ModRM
731 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
732 }
733 else
734 {
735 pParam->flags |= USE_BASE;
736 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
737 }
738 pParam->disp32 = pCpu->disp;
739 pParam->flags |= USE_DISPLACEMENT32;
740
741 if (pParam->disp32 != 0)
742 {
743 disasmAddChar(pParam->szParam, '+');
744 disasmPrintDisp32(pParam);
745 }
746 disasmAddChar(pParam->szParam, ']');
747 break;
748
749 case 3: //registers
750 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
751 break;
752 }
753 }
754 else
755 {//16 bits addressing mode
756 switch (mod)
757 {
758 case 0: //effective address
759 disasmGetPtrString(pCpu, pOp, pParam);
760 disasmAddChar(pParam->szParam, '[');
761 if (rm == 6)
762 {//16 bits displacement
763 pParam->disp16 = pCpu->disp;
764 pParam->flags |= USE_DISPLACEMENT16;
765 disasmPrintDisp16(pParam);
766 }
767 else
768 {
769 pParam->flags |= USE_BASE;
770 disasmModRMReg16(pCpu, pOp, rm, pParam);
771 }
772 disasmAddChar(pParam->szParam, ']');
773 break;
774
775 case 1: //effective address + 8 bits displacement
776 disasmGetPtrString(pCpu, pOp, pParam);
777 disasmAddChar(pParam->szParam, '[');
778 disasmModRMReg16(pCpu, pOp, rm, pParam);
779 pParam->disp8 = pCpu->disp;
780 pParam->flags |= USE_BASE | USE_DISPLACEMENT8;
781
782 if (pParam->disp8 != 0)
783 {
784 if (pParam->disp8 > 0)
785 disasmAddChar(pParam->szParam, '+');
786 disasmPrintDisp8(pParam);
787 }
788 disasmAddChar(pParam->szParam, ']');
789 break;
790
791 case 2: //effective address + 16 bits displacement
792 disasmGetPtrString(pCpu, pOp, pParam);
793 disasmAddChar(pParam->szParam, '[');
794 disasmModRMReg16(pCpu, pOp, rm, pParam);
795 pParam->disp16 = pCpu->disp;
796 pParam->flags |= USE_BASE | USE_DISPLACEMENT16;
797
798 if (pParam->disp16 != 0)
799 {
800 disasmAddChar(pParam->szParam, '+');
801 disasmPrintDisp16(pParam);
802 }
803 disasmAddChar(pParam->szParam, ']');
804 break;
805
806 case 3: //registers
807 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
808 break;
809 }
810 }
811 return 0; //everything was already fetched in ParseModRM
812}
813//*****************************************************************************
814// Query the size of the ModRM parameters and fetch the immediate data (if any)
815//*****************************************************************************
816unsigned QueryModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
817{
818 unsigned sibinc;
819 unsigned size = 0;
820 unsigned reg = pCpu->ModRM.Bits.Reg;
821 unsigned mod = pCpu->ModRM.Bits.Mod;
822 unsigned rm = pCpu->ModRM.Bits.Rm;
823
824 if (!pSibInc)
825 pSibInc = &sibinc;
826
827 *pSibInc = 0;
828
829 if (pCpu->addrmode != CPUMODE_16BIT)
830 {
831 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
832
833 /*
834 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
835 */
836 if (mod != 3 && rm == 4)
837 { /* SIB byte follows ModRM */
838 *pSibInc = ParseSIB(lpszCodeBlock, pOp, pParam, pCpu);
839 lpszCodeBlock += *pSibInc;
840 size += *pSibInc;
841 }
842
843 switch (mod)
844 {
845 case 0: /* Effective address */
846 if (rm == 5) { /* 32 bits displacement */
847 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
848 size += sizeof(int32_t);
849 }
850 /* else register address */
851 break;
852
853 case 1: /* Effective address + 8 bits displacement */
854 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
855 size += sizeof(char);
856 break;
857
858 case 2: /* Effective address + 32 bits displacement */
859 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
860 size += sizeof(int32_t);
861 break;
862
863 case 3: /* registers */
864 break;
865 }
866 }
867 else
868 {
869 /* 16 bits mode */
870 switch (mod)
871 {
872 case 0: /* Effective address */
873 if (rm == 6) {
874 pCpu->disp = DISReadWord(pCpu, lpszCodeBlock);
875 size += sizeof(uint16_t);
876 }
877 /* else register address */
878 break;
879
880 case 1: /* Effective address + 8 bits displacement */
881 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
882 size += sizeof(char);
883 break;
884
885 case 2: /* Effective address + 32 bits displacement */
886 pCpu->disp = (int16_t)DISReadWord(pCpu, lpszCodeBlock);
887 size += sizeof(uint16_t);
888 break;
889
890 case 3: /* registers */
891 break;
892 }
893 }
894 return size;
895}
896//*****************************************************************************
897// Query the size of the ModRM parameters and fetch the immediate data (if any)
898//*****************************************************************************
899unsigned QueryModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
900{
901 unsigned sibinc;
902 unsigned size = 0;
903 unsigned reg = pCpu->ModRM.Bits.Reg;
904 unsigned mod = pCpu->ModRM.Bits.Mod;
905 unsigned rm = pCpu->ModRM.Bits.Rm;
906
907 if (!pSibInc)
908 pSibInc = &sibinc;
909
910 *pSibInc = 0;
911
912 if (pCpu->addrmode != CPUMODE_16BIT)
913 {
914 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
915 /*
916 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
917 */
918 if (mod != 3 && rm == 4)
919 { /* SIB byte follows ModRM */
920 *pSibInc = ParseSIB_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu);
921 lpszCodeBlock += *pSibInc;
922 size += *pSibInc;
923 }
924
925 switch (mod)
926 {
927 case 0: //effective address
928 if (rm == 5) { /* 32 bits displacement */
929 size += sizeof(int32_t);
930 }
931 /* else register address */
932 break;
933
934 case 1: /* Effective address + 8 bits displacement */
935 size += sizeof(char);
936 break;
937
938 case 2: /* Effective address + 32 bits displacement */
939 size += sizeof(int32_t);
940 break;
941
942 case 3: /* registers */
943 break;
944 }
945 }
946 else
947 {
948 /* 16 bits mode */
949 switch (mod)
950 {
951 case 0: //effective address
952 if (rm == 6) {
953 size += sizeof(uint16_t);
954 }
955 /* else register address */
956 break;
957
958 case 1: /* Effective address + 8 bits displacement */
959 size += sizeof(char);
960 break;
961
962 case 2: /* Effective address + 32 bits displacement */
963 size += sizeof(uint16_t);
964 break;
965
966 case 3: /* registers */
967 break;
968 }
969 }
970 return size;
971}
972//*****************************************************************************
973//*****************************************************************************
974unsigned ParseIllegal(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
975{
976 AssertFailed();
977 return 0;
978}
979//*****************************************************************************
980//*****************************************************************************
981unsigned ParseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
982{
983 unsigned size = sizeof(uint8_t); //ModRM byte
984 unsigned sibinc, ModRM;
985
986 ModRM = DISReadByte(pCpu, lpszCodeBlock);
987 lpszCodeBlock += sizeof(uint8_t);
988
989 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
990 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
991 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
992
993 if (pCpu->prefix & PREFIX_REX)
994 {
995 Assert(pCpu->mode == CPUMODE_64BIT);
996
997 /* REX.R extends the Reg field. */
998 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
999
1000 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1001 if (!( pCpu->ModRM.Bits.Mod != 3
1002 && pCpu->ModRM.Bits.Rm == 4)
1003 &&
1004 !( pCpu->ModRM.Bits.Mod == 0
1005 && pCpu->ModRM.Bits.Rm == 5))
1006 {
1007 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1008 }
1009 }
1010 size += QueryModRM(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1011 lpszCodeBlock += sibinc;
1012
1013 UseModRM(lpszCodeBlock, pOp, pParam, pCpu);
1014 return size;
1015}
1016//*****************************************************************************
1017//*****************************************************************************
1018unsigned ParseModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1019{
1020 unsigned size = sizeof(uint8_t); //ModRM byte
1021 unsigned sibinc, ModRM;
1022
1023 ModRM = DISReadByte(pCpu, lpszCodeBlock);
1024 lpszCodeBlock += sizeof(uint8_t);
1025
1026 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1027 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1028 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1029
1030 if (pCpu->prefix & PREFIX_REX)
1031 {
1032 Assert(pCpu->mode == CPUMODE_64BIT);
1033
1034 /* REX.R extends the Reg field. */
1035 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
1036
1037 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1038 if (!( pCpu->ModRM.Bits.Mod != 3
1039 && pCpu->ModRM.Bits.Rm == 4)
1040 &&
1041 !( pCpu->ModRM.Bits.Mod == 0
1042 && pCpu->ModRM.Bits.Rm == 5))
1043 {
1044 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1045 }
1046 }
1047
1048 size += QueryModRM_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1049 lpszCodeBlock += sibinc;
1050
1051 /* UseModRM is not necessary here; we're only interested in the opcode size */
1052 return size;
1053}
1054//*****************************************************************************
1055//*****************************************************************************
1056unsigned ParseModFence(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1057{
1058 ////AssertMsgFailed(("??\n"));
1059 //nothing to do apparently
1060 return 0;
1061}
1062//*****************************************************************************
1063//*****************************************************************************
1064unsigned ParseImmByte(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1065{
1066 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1067 pParam->flags |= USE_IMMEDIATE8;
1068
1069 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%02Xh", (uint32_t)pParam->parval);
1070 return sizeof(uint8_t);
1071}
1072//*****************************************************************************
1073//*****************************************************************************
1074unsigned ParseImmByte_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1075{
1076 return sizeof(uint8_t);
1077}
1078//*****************************************************************************
1079//*****************************************************************************
1080unsigned ParseImmByteSX(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1081{
1082 if (pCpu->opmode == CPUMODE_32BIT)
1083 {
1084 pParam->parval = (uint32_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1085 pParam->flags |= USE_IMMEDIATE32_SX8;
1086 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1087 }
1088 else
1089 {
1090 pParam->parval = (uint16_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1091 pParam->flags |= USE_IMMEDIATE16_SX8;
1092 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1093 }
1094 return sizeof(uint8_t);
1095}
1096//*****************************************************************************
1097//*****************************************************************************
1098unsigned ParseImmByteSX_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1099{
1100 return sizeof(uint8_t);
1101}
1102//*****************************************************************************
1103//*****************************************************************************
1104unsigned ParseImmUshort(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1105{
1106 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1107 pParam->flags |= USE_IMMEDIATE16;
1108
1109 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1110 return sizeof(uint16_t);
1111}
1112//*****************************************************************************
1113//*****************************************************************************
1114unsigned ParseImmUshort_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1115{
1116 return sizeof(uint16_t);
1117}
1118//*****************************************************************************
1119//*****************************************************************************
1120unsigned ParseImmUlong(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1121{
1122 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1123 pParam->flags |= USE_IMMEDIATE32;
1124
1125 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1126 return sizeof(uint32_t);
1127}
1128//*****************************************************************************
1129//*****************************************************************************
1130unsigned ParseImmUlong_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1131{
1132 return sizeof(uint32_t);
1133}
1134//*****************************************************************************
1135//*****************************************************************************
1136unsigned ParseImmQword(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1137{
1138 pParam->parval = DISReadQWord(pCpu, lpszCodeBlock);
1139 pParam->flags |= USE_IMMEDIATE64;
1140
1141 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08X", (uint32_t)pParam->parval);
1142 disasmAddStringF(&pParam->szParam[9], sizeof(pParam->szParam)-9, "%08Xh", (uint32_t)(pParam->parval >> 32));
1143 return sizeof(uint64_t);
1144}
1145//*****************************************************************************
1146//*****************************************************************************
1147unsigned ParseImmQword_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1148{
1149 return sizeof(uint64_t);
1150}
1151//*****************************************************************************
1152//*****************************************************************************
1153unsigned ParseImmV(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1154{
1155 if (pCpu->opmode == CPUMODE_32BIT)
1156 {
1157 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1158 pParam->flags |= USE_IMMEDIATE32;
1159
1160 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1161 return sizeof(uint32_t);
1162 }
1163 else
1164 {
1165 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1166 pParam->flags |= USE_IMMEDIATE16;
1167
1168 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint32_t)pParam->parval);
1169 return sizeof(uint16_t);
1170 }
1171}
1172//*****************************************************************************
1173//*****************************************************************************
1174unsigned ParseImmV_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1175{
1176 if (pCpu->opmode == CPUMODE_32BIT)
1177 return sizeof(uint32_t);
1178 return sizeof(uint16_t);
1179}
1180//*****************************************************************************
1181// Relative displacement for branches (rel. to next instruction)
1182//*****************************************************************************
1183unsigned ParseImmBRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1184{
1185 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1186 pParam->flags |= USE_IMMEDIATE8_REL;
1187
1188 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%02Xh)", (uint32_t)pParam->parval);
1189 return sizeof(char);
1190}
1191//*****************************************************************************
1192// Relative displacement for branches (rel. to next instruction)
1193//*****************************************************************************
1194unsigned ParseImmBRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1195{
1196 return sizeof(char);
1197}
1198//*****************************************************************************
1199// Relative displacement for branches (rel. to next instruction)
1200//*****************************************************************************
1201unsigned ParseImmVRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1202{
1203 if (pCpu->opmode == CPUMODE_32BIT)
1204 {
1205 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1206 pParam->flags |= USE_IMMEDIATE32_REL;
1207
1208 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%08Xh)", (uint32_t)pParam->parval);
1209 return sizeof(int32_t);
1210 }
1211 else
1212 {
1213 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1214 pParam->flags |= USE_IMMEDIATE16_REL;
1215
1216 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%04Xh)", (uint32_t)pParam->parval);
1217 return sizeof(uint16_t);
1218 }
1219}
1220//*****************************************************************************
1221// Relative displacement for branches (rel. to next instruction)
1222//*****************************************************************************
1223unsigned ParseImmVRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1224{
1225 if (pCpu->opmode == CPUMODE_32BIT)
1226 return sizeof(int32_t);
1227 return sizeof(uint16_t);
1228}
1229//*****************************************************************************
1230//*****************************************************************************
1231unsigned ParseImmAddr(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1232{
1233 disasmGetPtrString(pCpu, pOp, pParam);
1234 if (pCpu->addrmode == CPUMODE_32BIT)
1235 {
1236 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1237 {// far 16:32 pointer
1238 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1239 *((uint32_t*)&pParam->parval+1) = DISReadWord(pCpu, lpszCodeBlock+sizeof(uint32_t));
1240 pParam->flags |= USE_IMMEDIATE_ADDR_16_32;
1241
1242 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%08Xh", (uint32_t)(pParam->parval>>32), (uint32_t)pParam->parval);
1243 return sizeof(uint32_t) + sizeof(uint16_t);
1244 }
1245 else
1246 {// near 32 bits pointer
1247 /*
1248 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1249 * so we treat it like displacement.
1250 */
1251 pParam->disp32 = DISReadDWord(pCpu, lpszCodeBlock);
1252 pParam->flags |= USE_DISPLACEMENT32;
1253
1254 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08Xh]", pParam->disp32);
1255 return sizeof(uint32_t);
1256 }
1257 }
1258 else
1259 if (pCpu->addrmode == CPUMODE_64BIT)
1260 {
1261 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1262 /* near 64 bits pointer */
1263 /*
1264 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1265 * so we treat it like displacement.
1266 */
1267 pParam->disp64 = DISReadQWord(pCpu, lpszCodeBlock);
1268 pParam->flags |= USE_DISPLACEMENT64;
1269
1270 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08X%08Xh]", (uint32_t)(pParam->disp64 >> 32), (uint32_t)pParam->disp64);
1271 return sizeof(uint32_t);
1272 }
1273 else
1274 {
1275 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1276 {// far 16:16 pointer
1277 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1278 pParam->flags |= USE_IMMEDIATE_ADDR_16_16;
1279
1280 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%04Xh", (uint32_t)(pParam->parval>>16), (uint16_t)pParam->parval );
1281 return sizeof(uint32_t);
1282 }
1283 else
1284 {// near 16 bits pointer
1285 /*
1286 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1287 * so we treat it like displacement.
1288 */
1289 pParam->disp16 = DISReadWord(pCpu, lpszCodeBlock);
1290 pParam->flags |= USE_DISPLACEMENT16;
1291
1292 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%04Xh]", (uint32_t)pParam->disp16);
1293 return sizeof(uint16_t);
1294 }
1295 }
1296}
1297//*****************************************************************************
1298//*****************************************************************************
1299unsigned ParseImmAddr_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1300{
1301 if (pCpu->addrmode == CPUMODE_32BIT)
1302 {
1303 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1304 {// far 16:32 pointer
1305 return sizeof(uint32_t) + sizeof(uint16_t);
1306 }
1307 else
1308 {// near 32 bits pointer
1309 return sizeof(uint32_t);
1310 }
1311 }
1312 if (pCpu->addrmode == CPUMODE_64BIT)
1313 {
1314 return sizeof(uint64_t);
1315 }
1316 else
1317 {
1318 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1319 {// far 16:16 pointer
1320 return sizeof(uint32_t);
1321 }
1322 else
1323 {// near 16 bits pointer
1324 return sizeof(uint16_t);
1325 }
1326 }
1327}
1328//*****************************************************************************
1329//*****************************************************************************
1330unsigned ParseFixedReg(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1331{
1332 /*
1333 * Sets up flags for stored in OPC fixed registers.
1334 */
1335
1336 if (pParam->param == OP_PARM_NONE)
1337 {
1338 /* No parameter at all. */
1339 return 0;
1340 }
1341
1342 AssertCompile(OP_PARM_REG_GEN32_END < OP_PARM_REG_SEG_END);
1343 AssertCompile(OP_PARM_REG_SEG_END < OP_PARM_REG_GEN16_END);
1344 AssertCompile(OP_PARM_REG_GEN16_END < OP_PARM_REG_GEN8_END);
1345 AssertCompile(OP_PARM_REG_GEN8_END < OP_PARM_REG_FP_END);
1346
1347 if (pParam->param <= OP_PARM_REG_GEN32_END)
1348 {
1349 /* 32-bit EAX..EDI registers. */
1350 if (pCpu->opmode == CPUMODE_32BIT)
1351 {
1352 /* Use 32-bit registers. */
1353 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1354 pParam->flags |= USE_REG_GEN32;
1355 pParam->size = 4;
1356 }
1357 else
1358 if (pCpu->opmode == CPUMODE_64BIT)
1359 {
1360 /* Use 64-bit registers. */
1361 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1362 if ( (pCpu->prefix & PREFIX_REX)
1363 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1364 pParam->base.reg_gen += 8;
1365
1366 pParam->flags |= USE_REG_GEN64;
1367 pParam->size = 8;
1368 }
1369 else
1370 {
1371 /* Use 16-bit registers. */
1372 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1373 pParam->flags |= USE_REG_GEN16;
1374 pParam->size = 2;
1375 pParam->param = pParam->param - OP_PARM_REG_GEN32_START + OP_PARM_REG_GEN16_START;
1376 }
1377 }
1378 else
1379 if (pParam->param <= OP_PARM_REG_SEG_END)
1380 {
1381 /* Segment ES..GS registers. */
1382 pParam->base.reg_seg = pParam->param - OP_PARM_REG_SEG_START;
1383 pParam->flags |= USE_REG_SEG;
1384 pParam->size = 2;
1385 }
1386 else
1387 if (pParam->param <= OP_PARM_REG_GEN16_END)
1388 {
1389 /* 16-bit AX..DI registers. */
1390 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN16_START;
1391 pParam->flags |= USE_REG_GEN16;
1392 pParam->size = 2;
1393 }
1394 else
1395 if (pParam->param <= OP_PARM_REG_GEN8_END)
1396 {
1397 /* 8-bit AL..DL, AH..DH registers. */
1398 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN8_START;
1399 pParam->flags |= USE_REG_GEN8;
1400 pParam->size = 1;
1401 }
1402 else
1403 if (pParam->param <= OP_PARM_REG_FP_END)
1404 {
1405 /* FPU registers. */
1406 pParam->base.reg_fp = pParam->param - OP_PARM_REG_FP_START;
1407 pParam->flags |= USE_REG_FP;
1408 pParam->size = 10;
1409 }
1410 Assert(!(pParam->param >= OP_PARM_REG_GEN64_START && pParam->param <= OP_PARM_REG_GEN64_END));
1411
1412 /* else - not supported for now registers. */
1413
1414 return 0;
1415}
1416//*****************************************************************************
1417//*****************************************************************************
1418unsigned ParseXv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1419{
1420 disasmGetPtrString(pCpu, pOp, pParam);
1421 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1422
1423 pParam->flags |= USE_POINTER_DS_BASED;
1424 if (pCpu->addrmode == CPUMODE_32BIT)
1425 {
1426 pParam->base.reg_gen = USE_REG_ESI;
1427 pParam->flags |= USE_REG_GEN32;
1428 }
1429 else
1430 if (pCpu->addrmode == CPUMODE_64BIT)
1431 {
1432 pParam->base.reg_gen = USE_REG_RSI;
1433 pParam->flags |= USE_REG_GEN64;
1434 }
1435 else
1436 {
1437 pParam->base.reg_gen = USE_REG_SI;
1438 pParam->flags |= USE_REG_GEN16;
1439 }
1440 return 0; //no additional opcode bytes
1441}
1442//*****************************************************************************
1443//*****************************************************************************
1444unsigned ParseXb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1445{
1446 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1447
1448 pParam->flags |= USE_POINTER_DS_BASED;
1449 if (pCpu->addrmode == CPUMODE_32BIT)
1450 {
1451 pParam->base.reg_gen = USE_REG_ESI;
1452 pParam->flags |= USE_REG_GEN32;
1453 }
1454 else
1455 if (pCpu->addrmode == CPUMODE_64BIT)
1456 {
1457 pParam->base.reg_gen = USE_REG_RSI;
1458 pParam->flags |= USE_REG_GEN64;
1459 }
1460 else
1461 {
1462 pParam->base.reg_gen = USE_REG_SI;
1463 pParam->flags |= USE_REG_GEN16;
1464 }
1465 return 0; //no additional opcode bytes
1466}
1467//*****************************************************************************
1468//*****************************************************************************
1469unsigned ParseYv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1470{
1471 disasmGetPtrString(pCpu, pOp, pParam);
1472 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1473
1474 pParam->flags |= USE_POINTER_ES_BASED;
1475 if (pCpu->addrmode == CPUMODE_32BIT)
1476 {
1477 pParam->base.reg_gen = USE_REG_EDI;
1478 pParam->flags |= USE_REG_GEN32;
1479 }
1480 else
1481 if (pCpu->addrmode == CPUMODE_64BIT)
1482 {
1483 pParam->base.reg_gen = USE_REG_RDI;
1484 pParam->flags |= USE_REG_GEN64;
1485 }
1486 else
1487 {
1488 pParam->base.reg_gen = USE_REG_DI;
1489 pParam->flags |= USE_REG_GEN16;
1490 }
1491 return 0; //no additional opcode bytes
1492}
1493//*****************************************************************************
1494//*****************************************************************************
1495unsigned ParseYb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1496{
1497 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1498
1499 pParam->flags |= USE_POINTER_ES_BASED;
1500 if (pCpu->addrmode == CPUMODE_32BIT)
1501 {
1502 pParam->base.reg_gen = USE_REG_EDI;
1503 pParam->flags |= USE_REG_GEN32;
1504 }
1505 else
1506 if (pCpu->addrmode == CPUMODE_64BIT)
1507 {
1508 pParam->base.reg_gen = USE_REG_RDI;
1509 pParam->flags |= USE_REG_GEN64;
1510 }
1511 else
1512 {
1513 pParam->base.reg_gen = USE_REG_DI;
1514 pParam->flags |= USE_REG_GEN16;
1515 }
1516 return 0; //no additional opcode bytes
1517}
1518//*****************************************************************************
1519//*****************************************************************************
1520unsigned ParseTwoByteEsc(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1521{
1522 const OPCODE *pOpcode;
1523 int size = sizeof(uint8_t);
1524
1525 //2nd byte
1526 pCpu->opcode = DISReadByte(pCpu, lpszCodeBlock);
1527 pOpcode = &g_aTwoByteMapX86[pCpu->opcode];
1528
1529 /* Handle opcode table extensions that rely on the address, repe or repne prefix byte. */
1530 /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
1531 if (pCpu->lastprefix)
1532 {
1533 switch (pCpu->lastprefix)
1534 {
1535 case OP_OPSIZE: /* 0x66 */
1536 if (g_aTwoByteMapX86_PF66[pCpu->opcode].opcode != OP_INVALID)
1537 {
1538 /* Table entry is valid, so use the extension table. */
1539 pOpcode = &g_aTwoByteMapX86_PF66[pCpu->opcode];
1540
1541 /* Cancel prefix changes. */
1542 pCpu->prefix &= ~PREFIX_OPSIZE;
1543 pCpu->opmode = pCpu->mode;
1544 }
1545 break;
1546
1547 case OP_REPNE: /* 0xF2 */
1548 if (g_aTwoByteMapX86_PFF2[pCpu->opcode].opcode != OP_INVALID)
1549 {
1550 /* Table entry is valid, so use the extension table. */
1551 pOpcode = &g_aTwoByteMapX86_PFF2[pCpu->opcode];
1552
1553 /* Cancel prefix changes. */
1554 pCpu->prefix &= ~PREFIX_REPNE;
1555 }
1556 break;
1557
1558 case OP_REPE: /* 0xF3 */
1559 if (g_aTwoByteMapX86_PFF3[pCpu->opcode].opcode != OP_INVALID)
1560 {
1561 /* Table entry is valid, so use the extension table. */
1562 pOpcode = &g_aTwoByteMapX86_PFF3[pCpu->opcode];
1563
1564 /* Cancel prefix changes. */
1565 pCpu->prefix &= ~PREFIX_REP;
1566 }
1567 break;
1568 }
1569 }
1570
1571 size += ParseInstruction(lpszCodeBlock+size, pOpcode, pCpu);
1572 return size;
1573}
1574//*****************************************************************************
1575//*****************************************************************************
1576unsigned ParseNopPause(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1577{
1578 unsigned size = 0;
1579
1580 if (pCpu->prefix & PREFIX_REP)
1581 {
1582 pOp = &g_aMapX86_NopPause[1]; /* PAUSE */
1583 pCpu->prefix &= ~PREFIX_REP;
1584 }
1585 else
1586 pOp = &g_aMapX86_NopPause[0]; /* NOP */
1587
1588 size += ParseInstruction(pu8CodeBlock, pOp, pCpu);
1589 return size;
1590}
1591//*****************************************************************************
1592//*****************************************************************************
1593unsigned ParseImmGrpl(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1594{
1595 int idx = (pCpu->opcode - 0x80) * 8;
1596 unsigned size = 0, modrm, reg;
1597
1598 modrm = DISReadByte(pCpu, lpszCodeBlock);
1599 reg = MODRM_REG(modrm);
1600
1601 pOp = (PCOPCODE)&g_aMapX86_Group1[idx+reg];
1602 //little hack to make sure the ModRM byte is included in the returned size
1603 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1604 size = sizeof(uint8_t); //ModRM byte
1605
1606 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1607
1608 return size;
1609}
1610//*****************************************************************************
1611//*****************************************************************************
1612unsigned ParseShiftGrp2(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1613{
1614 int idx;
1615 unsigned size = 0, modrm, reg;
1616
1617 switch (pCpu->opcode)
1618 {
1619 case 0xC0:
1620 case 0xC1:
1621 idx = (pCpu->opcode - 0xC0)*8;
1622 break;
1623
1624 case 0xD0:
1625 case 0xD1:
1626 case 0xD2:
1627 case 0xD3:
1628 idx = (pCpu->opcode - 0xD0 + 2)*8;
1629 break;
1630
1631 default:
1632 AssertMsgFailed(("Oops\n"));
1633 return sizeof(uint8_t);
1634 }
1635
1636 modrm = DISReadByte(pCpu, lpszCodeBlock);
1637 reg = MODRM_REG(modrm);
1638
1639 pOp = (PCOPCODE)&g_aMapX86_Group2[idx+reg];
1640
1641 //little hack to make sure the ModRM byte is included in the returned size
1642 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1643 size = sizeof(uint8_t); //ModRM byte
1644
1645 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1646
1647 return size;
1648}
1649//*****************************************************************************
1650//*****************************************************************************
1651unsigned ParseGrp3(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1652{
1653 int idx = (pCpu->opcode - 0xF6) * 8;
1654 unsigned size = 0, modrm, reg;
1655
1656 modrm = DISReadByte(pCpu, lpszCodeBlock);
1657 reg = MODRM_REG(modrm);
1658
1659 pOp = (PCOPCODE)&g_aMapX86_Group3[idx+reg];
1660
1661 //little hack to make sure the ModRM byte is included in the returned size
1662 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1663 size = sizeof(uint8_t); //ModRM byte
1664
1665 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1666
1667 return size;
1668}
1669//*****************************************************************************
1670//*****************************************************************************
1671unsigned ParseGrp4(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1672{
1673 unsigned size = 0, modrm, reg;
1674
1675 modrm = DISReadByte(pCpu, lpszCodeBlock);
1676 reg = MODRM_REG(modrm);
1677
1678 pOp = (PCOPCODE)&g_aMapX86_Group4[reg];
1679
1680 //little hack to make sure the ModRM byte is included in the returned size
1681 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1682 size = sizeof(uint8_t); //ModRM byte
1683
1684 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1685
1686 return size;
1687}
1688//*****************************************************************************
1689//*****************************************************************************
1690unsigned ParseGrp5(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1691{
1692 unsigned size = 0, modrm, reg;
1693
1694 modrm = DISReadByte(pCpu, lpszCodeBlock);
1695 reg = MODRM_REG(modrm);
1696
1697 pOp = (PCOPCODE)&g_aMapX86_Group5[reg];
1698
1699 //little hack to make sure the ModRM byte is included in the returned size
1700 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1701 size = sizeof(uint8_t); //ModRM byte
1702
1703 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1704
1705 return size;
1706}
1707//*****************************************************************************
1708// 0xF 0xF [ModRM] [SIB] [displacement] imm8_opcode
1709// It would appear the ModRM byte must always be present. How else can you
1710// determine the offset of the imm8_opcode byte otherwise?
1711//
1712//*****************************************************************************
1713unsigned Parse3DNow(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1714{
1715 unsigned size = 0, modrmsize;
1716
1717#ifdef DEBUG_Sander
1718 //needs testing
1719 AssertMsgFailed(("Test me\n"));
1720#endif
1721
1722 unsigned ModRM = DISReadByte(pCpu, lpszCodeBlock);
1723 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1724 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1725 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1726
1727 modrmsize = QueryModRM(lpszCodeBlock+sizeof(uint8_t), pOp, pParam, pCpu);
1728
1729 uint8_t opcode = DISReadByte(pCpu, lpszCodeBlock+sizeof(uint8_t)+modrmsize);
1730
1731 pOp = (PCOPCODE)&g_aTwoByteMapX86_3DNow[opcode];
1732
1733 //little hack to make sure the ModRM byte is included in the returned size
1734 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1735 {
1736#ifdef DEBUG_Sander /* bird, 2005-06-28: Alex is getting this during full installation of win2ksp4. */
1737 AssertMsgFailed(("Oops!\n")); //shouldn't happen!
1738#endif
1739 size = sizeof(uint8_t); //ModRM byte
1740 }
1741
1742 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1743 size += sizeof(uint8_t); //imm8_opcode uint8_t
1744
1745 return size;
1746}
1747//*****************************************************************************
1748//*****************************************************************************
1749unsigned ParseGrp6(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1750{
1751 unsigned size = 0, modrm, reg;
1752
1753 modrm = DISReadByte(pCpu, lpszCodeBlock);
1754 reg = MODRM_REG(modrm);
1755
1756 pOp = (PCOPCODE)&g_aMapX86_Group6[reg];
1757
1758 //little hack to make sure the ModRM byte is included in the returned size
1759 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1760 size = sizeof(uint8_t); //ModRM byte
1761
1762 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1763
1764 return size;
1765}
1766//*****************************************************************************
1767//*****************************************************************************
1768unsigned ParseGrp7(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1769{
1770 unsigned size = 0, modrm, reg, rm, mod;
1771
1772 modrm = DISReadByte(pCpu, lpszCodeBlock);
1773 mod = MODRM_MOD(modrm);
1774 reg = MODRM_REG(modrm);
1775 rm = MODRM_RM(modrm);
1776
1777 if (mod == 3 && rm == 0)
1778 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm000[reg];
1779 else
1780 if (mod == 3 && rm == 1)
1781 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm001[reg];
1782 else
1783 pOp = (PCOPCODE)&g_aMapX86_Group7_mem[reg];
1784
1785 //little hack to make sure the ModRM byte is included in the returned size
1786 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1787 size = sizeof(uint8_t); //ModRM byte
1788
1789 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1790
1791 return size;
1792}
1793//*****************************************************************************
1794//*****************************************************************************
1795unsigned ParseGrp8(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1796{
1797 unsigned size = 0, modrm, reg;
1798
1799 modrm = DISReadByte(pCpu, lpszCodeBlock);
1800 reg = MODRM_REG(modrm);
1801
1802 pOp = (PCOPCODE)&g_aMapX86_Group8[reg];
1803
1804 //little hack to make sure the ModRM byte is included in the returned size
1805 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1806 size = sizeof(uint8_t); //ModRM byte
1807
1808 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1809
1810 return size;
1811}
1812//*****************************************************************************
1813//*****************************************************************************
1814unsigned ParseGrp9(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1815{
1816 unsigned size = 0, modrm, reg;
1817
1818 modrm = DISReadByte(pCpu, lpszCodeBlock);
1819 reg = MODRM_REG(modrm);
1820
1821 pOp = (PCOPCODE)&g_aMapX86_Group9[reg];
1822
1823 //little hack to make sure the ModRM byte is included in the returned size
1824 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1825 size = sizeof(uint8_t); //ModRM byte
1826
1827 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1828
1829 return size;
1830}
1831//*****************************************************************************
1832//*****************************************************************************
1833unsigned ParseGrp10(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1834{
1835 unsigned size = 0, modrm, reg;
1836
1837 modrm = DISReadByte(pCpu, lpszCodeBlock);
1838 reg = MODRM_REG(modrm);
1839
1840 pOp = (PCOPCODE)&g_aMapX86_Group10[reg];
1841
1842 //little hack to make sure the ModRM byte is included in the returned size
1843 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1844 size = sizeof(uint8_t); //ModRM byte
1845
1846 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1847
1848 return size;
1849}
1850//*****************************************************************************
1851//*****************************************************************************
1852unsigned ParseGrp12(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1853{
1854 unsigned size = 0, modrm, reg;
1855
1856 modrm = DISReadByte(pCpu, lpszCodeBlock);
1857 reg = MODRM_REG(modrm);
1858
1859 if (pCpu->prefix & PREFIX_OPSIZE)
1860 reg += 8; //2nd table
1861
1862 pOp = (PCOPCODE)&g_aMapX86_Group12[reg];
1863
1864 //little hack to make sure the ModRM byte is included in the returned size
1865 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1866 size = sizeof(uint8_t); //ModRM byte
1867
1868 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1869 return size;
1870}
1871//*****************************************************************************
1872//*****************************************************************************
1873unsigned ParseGrp13(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1874{
1875 unsigned size = 0, modrm, reg;
1876
1877 modrm = DISReadByte(pCpu, lpszCodeBlock);
1878 reg = MODRM_REG(modrm);
1879 if (pCpu->prefix & PREFIX_OPSIZE)
1880 reg += 8; //2nd table
1881
1882 pOp = (PCOPCODE)&g_aMapX86_Group13[reg];
1883
1884 //little hack to make sure the ModRM byte is included in the returned size
1885 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1886 size = sizeof(uint8_t); //ModRM byte
1887
1888 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1889
1890 return size;
1891}
1892//*****************************************************************************
1893//*****************************************************************************
1894unsigned ParseGrp14(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1895{
1896 unsigned size = 0, modrm, reg;
1897
1898 modrm = DISReadByte(pCpu, lpszCodeBlock);
1899 reg = MODRM_REG(modrm);
1900 if (pCpu->prefix & PREFIX_OPSIZE)
1901 reg += 8; //2nd table
1902
1903 pOp = (PCOPCODE)&g_aMapX86_Group14[reg];
1904
1905 //little hack to make sure the ModRM byte is included in the returned size
1906 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1907 size = sizeof(uint8_t); //ModRM byte
1908
1909 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1910
1911 return size;
1912}
1913//*****************************************************************************
1914//*****************************************************************************
1915unsigned ParseGrp15(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1916{
1917 unsigned size = 0, modrm, reg, mod, rm;
1918
1919 modrm = DISReadByte(pCpu, lpszCodeBlock);
1920 mod = MODRM_MOD(modrm);
1921 reg = MODRM_REG(modrm);
1922 rm = MODRM_RM(modrm);
1923
1924 if (mod == 3 && rm == 0)
1925 pOp = (PCOPCODE)&g_aMapX86_Group15_mod11_rm000[reg];
1926 else
1927 pOp = (PCOPCODE)&g_aMapX86_Group15_mem[reg];
1928
1929 //little hack to make sure the ModRM byte is included in the returned size
1930 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1931 size = sizeof(uint8_t); //ModRM byte
1932
1933 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1934 return size;
1935}
1936//*****************************************************************************
1937//*****************************************************************************
1938unsigned ParseGrp16(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1939{
1940 unsigned size = 0, modrm, reg;
1941
1942 modrm = DISReadByte(pCpu, lpszCodeBlock);
1943 reg = MODRM_REG(modrm);
1944
1945 pOp = (PCOPCODE)&g_aMapX86_Group16[reg];
1946
1947 //little hack to make sure the ModRM byte is included in the returned size
1948 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1949 size = sizeof(uint8_t); //ModRM byte
1950
1951 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1952 return size;
1953}
1954//*****************************************************************************
1955#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
1956const char *szModRMReg8[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"};
1957const char *szModRMReg8_64[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8L", "R9L", "R10L", "R11L", "R12L", "R13L", "R14L", "R15L"};
1958const char *szModRMReg16[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"};
1959const char *szModRMReg32[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
1960const char *szModRMReg64[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
1961const char *szModRMReg1616[8] = {"BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX"};
1962#endif
1963const char *szModRMSegReg[6] = {"ES", "CS", "SS", "DS", "FS", "GS"};
1964const int BaseModRMReg16[8] = { USE_REG_BX, USE_REG_BX, USE_REG_BP, USE_REG_BP, USE_REG_SI, USE_REG_DI, USE_REG_BP, USE_REG_BX};
1965const int IndexModRMReg16[4] = { USE_REG_SI, USE_REG_DI, USE_REG_SI, USE_REG_DI};
1966//*****************************************************************************
1967void disasmModRMReg(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam, int fRegAddr)
1968{
1969 int subtype, type, mod;
1970
1971 mod = pCpu->ModRM.Bits.Mod;
1972
1973 type = OP_PARM_VTYPE(pParam->param);
1974 subtype = OP_PARM_VSUBTYPE(pParam->param);
1975 if (fRegAddr)
1976 subtype = OP_PARM_d;
1977 else
1978 if (subtype == OP_PARM_v || subtype == OP_PARM_NONE)
1979 {
1980 switch(pCpu->opmode)
1981 {
1982 case CPUMODE_32BIT:
1983 subtype = OP_PARM_d;
1984 break;
1985 case CPUMODE_64BIT:
1986 subtype = OP_PARM_q;
1987 break;
1988 case CPUMODE_16BIT:
1989 subtype = OP_PARM_w;
1990 break;
1991 }
1992 }
1993
1994 switch (subtype)
1995 {
1996 case OP_PARM_b:
1997 disasmAddString(pParam->szParam, szModRMReg8[idx]);
1998 pParam->flags |= USE_REG_GEN8;
1999 pParam->base.reg_gen = idx;
2000 break;
2001
2002 case OP_PARM_w:
2003 disasmAddString(pParam->szParam, szModRMReg16[idx]);
2004 pParam->flags |= USE_REG_GEN16;
2005 pParam->base.reg_gen = idx;
2006 break;
2007
2008 case OP_PARM_d:
2009 disasmAddString(pParam->szParam, szModRMReg32[idx]);
2010 pParam->flags |= USE_REG_GEN32;
2011 pParam->base.reg_gen = idx;
2012 break;
2013
2014 case OP_PARM_q:
2015 disasmAddString(pParam->szParam, szModRMReg64[idx]);
2016 pParam->flags |= USE_REG_GEN64;
2017 pParam->base.reg_gen = idx;
2018 break;
2019
2020 default:
2021#ifdef IN_RING3
2022 Log(("disasmModRMReg %x:%x failed!!\n", type, subtype));
2023 DIS_THROW(ExceptionInvalidModRM);
2024#else
2025 AssertMsgFailed(("Oops!\n"));
2026#endif
2027 break;
2028 }
2029}
2030//*****************************************************************************
2031//*****************************************************************************
2032void disasmModRMReg16(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam)
2033{
2034 disasmAddString(pParam->szParam, szModRMReg1616[idx]);
2035 pParam->flags |= USE_REG_GEN16;
2036 pParam->base.reg_gen = BaseModRMReg16[idx];
2037 if (idx < 4)
2038 {
2039 pParam->flags |= USE_INDEX;
2040 pParam->index.reg_gen = IndexModRMReg16[idx];
2041 }
2042}
2043//*****************************************************************************
2044//*****************************************************************************
2045void disasmModRMSReg(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam)
2046{
2047#if 0 //def DEBUG_Sander
2048 AssertMsg(idx < (int)ELEMENTS(szModRMSegReg), ("idx=%d\n", idx));
2049#endif
2050#ifdef IN_RING3
2051 if (idx >= (int)ELEMENTS(szModRMSegReg))
2052 {
2053 Log(("disasmModRMSReg %d failed!!\n", idx));
2054 DIS_THROW(ExceptionInvalidParameter);
2055 }
2056#endif
2057
2058 idx = RT_MIN(idx, (int)ELEMENTS(szModRMSegReg)-1);
2059 disasmAddString(pParam->szParam, szModRMSegReg[idx]);
2060 pParam->flags |= USE_REG_SEG;
2061 pParam->base.reg_seg = idx;
2062}
2063//*****************************************************************************
2064//*****************************************************************************
2065void disasmPrintAbs32(POP_PARAMETER pParam)
2066{
2067 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2068}
2069//*****************************************************************************
2070//*****************************************************************************
2071void disasmPrintDisp32(POP_PARAMETER pParam)
2072{
2073 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2074}
2075//*****************************************************************************
2076//*****************************************************************************
2077void disasmPrintDisp8(POP_PARAMETER pParam)
2078{
2079 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%d", pParam->disp8);
2080}
2081//*****************************************************************************
2082//*****************************************************************************
2083void disasmPrintDisp16(POP_PARAMETER pParam)
2084{
2085 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%04Xh", pParam->disp16);
2086}
2087//*****************************************************************************
2088//*****************************************************************************
2089void disasmGetPtrString(PDISCPUSTATE pCpu, PCOPCODE pOp, POP_PARAMETER pParam)
2090{
2091 int subtype = OP_PARM_VSUBTYPE(pParam->param);
2092
2093 if (subtype == OP_PARM_v)
2094 {
2095 subtype = (pCpu->opmode == CPUMODE_32BIT) ? OP_PARM_d : OP_PARM_w;
2096 }
2097
2098 switch (subtype)
2099 {
2100 case OP_PARM_a: //two words or dwords depending on operand size (bound only)
2101 break;
2102
2103 case OP_PARM_b:
2104 disasmAddString(pParam->szParam, "byte ptr ");
2105 break;
2106
2107 case OP_PARM_w:
2108 disasmAddString(pParam->szParam, "word ptr ");
2109 break;
2110
2111 case OP_PARM_d:
2112 disasmAddString(pParam->szParam, "dword ptr ");
2113 break;
2114
2115 case OP_PARM_q:
2116 case OP_PARM_dq:
2117 disasmAddString(pParam->szParam, "qword ptr ");
2118 break;
2119
2120 case OP_PARM_p:
2121 disasmAddString(pParam->szParam, "far ptr ");
2122 break;
2123
2124 case OP_PARM_s:
2125 break; //??
2126
2127 case OP_PARM_z:
2128 break;
2129 default:
2130 break; //no pointer type specified/necessary
2131 }
2132 if (pCpu->prefix & PREFIX_SEG)
2133 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%s:", szModRMSegReg[pCpu->prefix_seg]);
2134}
2135#ifndef IN_GC
2136//*****************************************************************************
2137/* Read functions for getting the opcode bytes */
2138//*****************************************************************************
2139uint8_t DISReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2140{
2141 if (pCpu->pfnReadBytes)
2142 {
2143 uint8_t temp = 0;
2144 int rc;
2145
2146 rc = pCpu->pfnReadBytes(pAddress, &temp, sizeof(temp), pCpu);
2147 if (VBOX_FAILURE(rc))
2148 {
2149 Log(("DISReadByte failed!!\n"));
2150 DIS_THROW(ExceptionMemRead);
2151 }
2152 return temp;
2153 }
2154#ifdef IN_RING0
2155 AssertMsgFailed(("DISReadByte with no read callback in ring 0!!\n"));
2156 return 0;
2157#else
2158 else return *(uint8_t *)pAddress;
2159#endif
2160}
2161//*****************************************************************************
2162//*****************************************************************************
2163uint16_t DISReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2164{
2165 if (pCpu->pfnReadBytes)
2166 {
2167 uint16_t temp = 0;
2168 int rc;
2169
2170 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2171 if (VBOX_FAILURE(rc))
2172 {
2173 Log(("DISReadWord failed!!\n"));
2174 DIS_THROW(ExceptionMemRead);
2175 }
2176 return temp;
2177 }
2178#ifdef IN_RING0
2179 AssertMsgFailed(("DISReadWord with no read callback in ring 0!!\n"));
2180 return 0;
2181#else
2182 else return *(uint16_t *)pAddress;
2183#endif
2184}
2185//*****************************************************************************
2186//*****************************************************************************
2187uint32_t DISReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2188{
2189 if (pCpu->pfnReadBytes)
2190 {
2191 uint32_t temp = 0;
2192 int rc;
2193
2194 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2195 if (VBOX_FAILURE(rc))
2196 {
2197 Log(("DISReadDWord failed!!\n"));
2198 DIS_THROW(ExceptionMemRead);
2199 }
2200 return temp;
2201 }
2202#ifdef IN_RING0
2203 AssertMsgFailed(("DISReadDWord with no read callback in ring 0!!\n"));
2204 return 0;
2205#else
2206 else return *(uint32_t *)pAddress;
2207#endif
2208}
2209//*****************************************************************************
2210//*****************************************************************************
2211uint64_t DISReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2212{
2213 if (pCpu->pfnReadBytes)
2214 {
2215 uint64_t temp = 0;
2216 int rc;
2217
2218 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2219 if (VBOX_FAILURE(rc))
2220 {
2221 Log(("DISReadQWord %x failed!!\n", pAddress));
2222 DIS_THROW(ExceptionMemRead);
2223 }
2224
2225 return temp;
2226 }
2227#ifdef IN_RING0
2228 AssertMsgFailed(("DISReadQWord with no read callback in ring 0!!\n"));
2229 return 0;
2230#else
2231 else return *(uint64_t *)pAddress;
2232#endif
2233}
2234#endif /* IN_GC */
2235
2236#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2237//*****************************************************************************
2238//*****************************************************************************
2239void disasmAddString(char *psz, const char *pszAdd)
2240{
2241 strcat(psz, pszAdd);
2242}
2243//*****************************************************************************
2244//*****************************************************************************
2245void disasmAddStringF(char *psz, uint32_t size, const char *pszFormat, ...)
2246{
2247 va_list args;
2248 va_start(args, pszFormat);
2249 RTStrPrintfV(psz + strlen(psz), size, pszFormat, args);
2250 va_end(args);
2251}
2252
2253//*****************************************************************************
2254//*****************************************************************************
2255void disasmAddChar(char *psz, char ch)
2256{
2257 char sz[2];
2258
2259 sz[0] = ch;
2260 sz[1] = '\0';
2261 strcat(psz, sz);
2262}
2263#endif /* !DIS_CORE_ONLY */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette