VirtualBox

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

Last change on this file since 13762 was 13241, checked in by vboxsync, 16 years ago

Added support for three byte opcodes (not complete; just to test invept & invvpid)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 92.0 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 ParseImmZ,
116 ParseThreeByteEsc4,
117 ParseThreeByteEsc5
118};
119
120PFNDISPARSE pfnCalcSize[IDX_ParseMax] =
121{
122 ParseIllegal,
123 ParseModRM_SizeOnly,
124 UseModRM,
125 ParseImmByte_SizeOnly,
126 ParseImmBRel_SizeOnly,
127 ParseImmUshort_SizeOnly,
128 ParseImmV_SizeOnly,
129 ParseImmVRel_SizeOnly,
130 ParseImmAddr_SizeOnly,
131 ParseFixedReg,
132 ParseImmUlong_SizeOnly,
133 ParseImmQword_SizeOnly,
134 ParseTwoByteEsc,
135 ParseImmGrpl,
136 ParseShiftGrp2,
137 ParseGrp3,
138 ParseGrp4,
139 ParseGrp5,
140 Parse3DNow,
141 ParseGrp6,
142 ParseGrp7,
143 ParseGrp8,
144 ParseGrp9,
145 ParseGrp10,
146 ParseGrp12,
147 ParseGrp13,
148 ParseGrp14,
149 ParseGrp15,
150 ParseGrp16,
151 ParseModFence,
152 ParseYv,
153 ParseYb,
154 ParseXv,
155 ParseXb,
156 ParseEscFP,
157 ParseNopPause,
158 ParseImmByteSX_SizeOnly,
159 ParseImmZ_SizeOnly,
160 ParseThreeByteEsc4,
161 ParseThreeByteEsc5
162};
163
164/**
165 * Parses one instruction.
166 * The result is found in pCpu.
167 *
168 * @returns Success indicator.
169 * @param pCpu Pointer to cpu structure which has DISCPUSTATE::mode set correctly.
170 * @param InstructionAddr Pointer to the instruction to parse.
171 * @param pcbInstruction Where to store the size of the instruction.
172 * NULL is allowed.
173 */
174DISDECL(int) DISCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
175{
176 /*
177 * Reset instruction settings
178 */
179 pCpu->prefix = PREFIX_NONE;
180 pCpu->enmPrefixSeg = DIS_SELREG_DS;
181 pCpu->lastprefix = 0;
182 pCpu->ModRM.u = 0;
183 pCpu->SIB.u = 0;
184 pCpu->param1.parval = 0;
185 pCpu->param2.parval = 0;
186 pCpu->param3.parval = 0;
187 pCpu->param1.szParam[0] = '\0';
188 pCpu->param2.szParam[0] = '\0';
189 pCpu->param3.szParam[0] = '\0';
190 pCpu->param1.flags = 0;
191 pCpu->param2.flags = 0;
192 pCpu->param3.flags = 0;
193 pCpu->param1.size = 0;
194 pCpu->param2.size = 0;
195 pCpu->param3.size = 0;
196 pCpu->pfnReadBytes = 0;
197 pCpu->uFilter = OPTYPE_ALL;
198 pCpu->pfnDisasmFnTable = pfnFullDisasm;
199
200 return VBOX_SUCCESS(disCoreOne(pCpu, InstructionAddr, pcbInstruction));
201}
202
203/**
204 * Parses one guest instruction.
205 * The result is found in pCpu and pcbInstruction.
206 *
207 * @returns VBox status code.
208 * @param InstructionAddr Address of the instruction to decode. What this means
209 * is left to the pfnReadBytes function.
210 * @param enmCpuMode The CPU mode. CPUMODE_32BIT, CPUMODE_16BIT, or CPUMODE_64BIT.
211 * @param pfnReadBytes Callback for reading instruction bytes.
212 * @param pvUser User argument for the instruction reader. (Ends up in apvUserData[0].)
213 * @param pCpu Pointer to cpu structure. Will be initialized.
214 * @param pcbInstruction Where to store the size of the instruction.
215 * NULL is allowed.
216 */
217DISDECL(int) DISCoreOneEx(RTUINTPTR InstructionAddr, DISCPUMODE enmCpuMode, PFN_DIS_READBYTES pfnReadBytes, void *pvUser,
218 PDISCPUSTATE pCpu, unsigned *pcbInstruction)
219{
220 /*
221 * Reset instruction settings
222 */
223 pCpu->prefix = PREFIX_NONE;
224 pCpu->enmPrefixSeg = DIS_SELREG_DS;
225 pCpu->lastprefix = 0;
226 pCpu->mode = enmCpuMode;
227 pCpu->ModRM.u = 0;
228 pCpu->SIB.u = 0;
229 pCpu->param1.parval = 0;
230 pCpu->param2.parval = 0;
231 pCpu->param3.parval = 0;
232 pCpu->param1.szParam[0] = '\0';
233 pCpu->param2.szParam[0] = '\0';
234 pCpu->param3.szParam[0] = '\0';
235 pCpu->param1.flags = 0;
236 pCpu->param2.flags = 0;
237 pCpu->param3.flags = 0;
238 pCpu->param1.size = 0;
239 pCpu->param2.size = 0;
240 pCpu->param3.size = 0;
241 pCpu->pfnReadBytes = pfnReadBytes;
242 pCpu->apvUserData[0] = pvUser;
243 pCpu->uFilter = OPTYPE_ALL;
244 pCpu->pfnDisasmFnTable = pfnFullDisasm;
245
246 return disCoreOne(pCpu, InstructionAddr, pcbInstruction);
247}
248
249/**
250 * Internal worker for DISCoreOne and DISCoreOneEx.
251 *
252 * @returns VBox status code.
253 * @param pCpu Initialized cpu state.
254 * @param InstructionAddr Instruction address.
255 * @param pcbInstruction Where to store the instruction size. Can be NULL.
256 */
257static int disCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
258{
259 const OPCODE *paOneByteMap;
260
261 /*
262 * Parse byte by byte.
263 */
264 unsigned iByte = 0;
265 unsigned cbInc;
266
267 if (pCpu->mode == CPUMODE_64BIT)
268 {
269 paOneByteMap = g_aOneByteMapX64;
270 pCpu->addrmode = CPUMODE_64BIT;
271 pCpu->opmode = CPUMODE_32BIT;
272 }
273 else
274 {
275 paOneByteMap = g_aOneByteMapX86;
276 pCpu->addrmode = pCpu->mode;
277 pCpu->opmode = pCpu->mode;
278 }
279
280#ifdef IN_RING3
281# ifndef __L4ENV__ /* Unfortunately, we have no exception handling in l4env */
282 try
283# else
284 pCpu->pJumpBuffer = &jumpbuffer;
285 if (setjmp(jumpbuffer) == 0)
286# endif
287#endif
288 {
289 while(1)
290 {
291 uint8_t codebyte = DISReadByte(pCpu, InstructionAddr+iByte);
292 uint8_t opcode = paOneByteMap[codebyte].opcode;
293
294 /* Hardcoded assumption about OP_* values!! */
295 if (opcode <= OP_LAST_PREFIX)
296 {
297 /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
298 if (opcode != OP_REX)
299 {
300 /** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */
301 pCpu->lastprefix = opcode;
302 pCpu->prefix &= ~PREFIX_REX;
303 }
304
305 switch (opcode)
306 {
307 case OP_INVALID:
308 AssertMsgFailed(("Invalid opcode!!\n"));
309 return VERR_GENERAL_FAILURE; /** @todo better error code. */
310
311 // segment override prefix byte
312 case OP_SEG:
313 pCpu->enmPrefixSeg = (DIS_SELREG)(paOneByteMap[codebyte].param1 - OP_PARM_REG_SEG_START);
314 /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */
315 if ( pCpu->mode != CPUMODE_64BIT
316 || pCpu->enmPrefixSeg >= DIS_SELREG_FS)
317 {
318 pCpu->prefix |= PREFIX_SEG;
319 }
320 iByte += sizeof(uint8_t);
321 continue; //fetch the next byte
322
323 // lock prefix byte
324 case OP_LOCK:
325 pCpu->prefix |= PREFIX_LOCK;
326 iByte += sizeof(uint8_t);
327 continue; //fetch the next byte
328
329 // address size override prefix byte
330 case OP_ADDRSIZE:
331 pCpu->prefix |= PREFIX_ADDRSIZE;
332 if (pCpu->mode == CPUMODE_16BIT)
333 pCpu->addrmode = CPUMODE_32BIT;
334 else
335 if (pCpu->mode == CPUMODE_32BIT)
336 pCpu->addrmode = CPUMODE_16BIT;
337 else
338 pCpu->addrmode = CPUMODE_32BIT; /* 64 bits */
339
340 iByte += sizeof(uint8_t);
341 continue; //fetch the next byte
342
343 // operand size override prefix byte
344 case OP_OPSIZE:
345 pCpu->prefix |= PREFIX_OPSIZE;
346 if (pCpu->mode == CPUMODE_16BIT)
347 pCpu->opmode = CPUMODE_32BIT;
348 else
349 pCpu->opmode = CPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
350
351 iByte += sizeof(uint8_t);
352 continue; //fetch the next byte
353
354 // rep and repne are not really prefixes, but we'll treat them as such
355 case OP_REPE:
356 pCpu->prefix |= PREFIX_REP;
357 iByte += sizeof(uint8_t);
358 continue; //fetch the next byte
359
360 case OP_REPNE:
361 pCpu->prefix |= PREFIX_REPNE;
362 iByte += sizeof(uint8_t);
363 continue; //fetch the next byte
364
365 case OP_REX:
366 Assert(pCpu->mode == CPUMODE_64BIT);
367 /* REX prefix byte */
368 pCpu->prefix |= PREFIX_REX;
369 pCpu->prefix_rex = PREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].param1);
370 iByte += sizeof(uint8_t);
371
372 if (pCpu->prefix_rex & PREFIX_REX_FLAGS_W)
373 pCpu->opmode = CPUMODE_64BIT; /* overrides size prefix byte */
374 continue; //fetch the next byte
375 }
376 }
377
378 unsigned uIdx = iByte;
379 iByte += sizeof(uint8_t); //first opcode byte
380
381 pCpu->opaddr = InstructionAddr + uIdx;
382 pCpu->opcode = codebyte;
383
384 cbInc = ParseInstruction(InstructionAddr + iByte, &paOneByteMap[pCpu->opcode], pCpu);
385 iByte += cbInc;
386 break;
387 }
388 }
389#ifdef IN_RING3
390# ifndef __L4ENV__
391 catch(...)
392# else
393 else /* setjmp has returned a non-zero value: an exception occured */
394# endif
395 {
396 pCpu->opsize = 0;
397 return VERR_DIS_GEN_FAILURE;
398 }
399#endif
400
401 pCpu->opsize = iByte;
402 if (pcbInstruction)
403 *pcbInstruction = iByte;
404
405 if (pCpu->prefix & PREFIX_LOCK)
406 disValidateLockSequence(pCpu);
407
408 return VINF_SUCCESS;
409}
410//*****************************************************************************
411//*****************************************************************************
412unsigned ParseInstruction(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, PDISCPUSTATE pCpu)
413{
414 int size = 0;
415 bool fFiltered = false;
416
417 // Store the opcode format string for disasmPrintf
418#ifndef DIS_CORE_ONLY
419 pCpu->pszOpcode = pOp->pszOpcode;
420#endif
421 pCpu->pCurInstr = pOp;
422
423 /*
424 * Apply filter to instruction type to determine if a full disassembly is required.
425 * @note Multibyte opcodes are always marked harmless until the final byte.
426 */
427 if ((pOp->optype & pCpu->uFilter) == 0)
428 {
429 fFiltered = true;
430 pCpu->pfnDisasmFnTable = pfnCalcSize;
431 }
432 else
433 {
434 /* Not filtered out -> full disassembly */
435 pCpu->pfnDisasmFnTable = pfnFullDisasm;
436 }
437
438 // Should contain the parameter type on input
439 pCpu->param1.param = pOp->param1;
440 pCpu->param2.param = pOp->param2;
441 pCpu->param3.param = pOp->param3;
442
443 /* Correct the operand size if the instruction is marked as forced or default 64 bits */
444 if (pCpu->mode == CPUMODE_64BIT)
445 {
446 if (pOp->optype & OPTYPE_FORCED_64_OP_SIZE)
447 pCpu->opmode = CPUMODE_64BIT;
448 else
449 if ( (pOp->optype & OPTYPE_DEFAULT_64_OP_SIZE)
450 && !(pCpu->prefix & PREFIX_OPSIZE))
451 pCpu->opmode = CPUMODE_64BIT;
452 }
453
454 if (pOp->idxParse1 != IDX_ParseNop)
455 {
456 size += pCpu->pfnDisasmFnTable[pOp->idxParse1](lpszCodeBlock, pOp, &pCpu->param1, pCpu);
457 if (fFiltered == false) pCpu->param1.size = DISGetParamSize(pCpu, &pCpu->param1);
458 }
459
460 if (pOp->idxParse2 != IDX_ParseNop)
461 {
462 size += pCpu->pfnDisasmFnTable[pOp->idxParse2](lpszCodeBlock+size, pOp, &pCpu->param2, pCpu);
463 if (fFiltered == false) pCpu->param2.size = DISGetParamSize(pCpu, &pCpu->param2);
464 }
465
466 if (pOp->idxParse3 != IDX_ParseNop)
467 {
468 size += pCpu->pfnDisasmFnTable[pOp->idxParse3](lpszCodeBlock+size, pOp, &pCpu->param3, pCpu);
469 if (fFiltered == false) pCpu->param3.size = DISGetParamSize(pCpu, &pCpu->param3);
470 }
471 // else simple one byte instruction
472
473 return size;
474}
475//*****************************************************************************
476/* Floating point opcode parsing */
477//*****************************************************************************
478unsigned ParseEscFP(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
479{
480 int index;
481 const OPCODE *fpop;
482 unsigned size = 0, ModRM;
483
484 ModRM = DISReadByte(pCpu, lpszCodeBlock);
485
486 index = pCpu->opcode - 0xD8;
487 if (ModRM <= 0xBF)
488 {
489 fpop = &(g_paMapX86_FP_Low[index])[MODRM_REG(ModRM)];
490 pCpu->pCurInstr = (PCOPCODE)fpop;
491
492 // Should contain the parameter type on input
493 pCpu->param1.param = fpop->param1;
494 pCpu->param2.param = fpop->param2;
495 }
496 else
497 {
498 fpop = &(g_paMapX86_FP_High[index])[ModRM - 0xC0];
499 pCpu->pCurInstr = (PCOPCODE)fpop;
500 }
501
502 /*
503 * Apply filter to instruction type to determine if a full disassembly is required.
504 * @note Multibyte opcodes are always marked harmless until the final byte.
505 */
506 if ((fpop->optype & pCpu->uFilter) == 0)
507 {
508 pCpu->pfnDisasmFnTable = pfnCalcSize;
509 }
510 else
511 {
512 /* Not filtered out -> full disassembly */
513 pCpu->pfnDisasmFnTable = pfnFullDisasm;
514 }
515
516 /* Correct the operand size if the instruction is marked as forced or default 64 bits */
517 if (pCpu->mode == CPUMODE_64BIT)
518 {
519 /* Note: redundant, but just in case this ever changes */
520 if (fpop->optype & OPTYPE_FORCED_64_OP_SIZE)
521 pCpu->opmode = CPUMODE_64BIT;
522 else
523 if ( (fpop->optype & OPTYPE_DEFAULT_64_OP_SIZE)
524 && !(pCpu->prefix & PREFIX_OPSIZE))
525 pCpu->opmode = CPUMODE_64BIT;
526 }
527
528 // Little hack to make sure the ModRM byte is included in the returned size
529 if (fpop->idxParse1 != IDX_ParseModRM && fpop->idxParse2 != IDX_ParseModRM)
530 size = sizeof(uint8_t); //ModRM byte
531
532 if (fpop->idxParse1 != IDX_ParseNop)
533 size += pCpu->pfnDisasmFnTable[fpop->idxParse1](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
534
535 if (fpop->idxParse2 != IDX_ParseNop)
536 size += pCpu->pfnDisasmFnTable[fpop->idxParse2](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
537
538 // Store the opcode format string for disasmPrintf
539#ifndef DIS_CORE_ONLY
540 pCpu->pszOpcode = fpop->pszOpcode;
541#endif
542
543 return size;
544}
545//*****************************************************************************
546// SIB byte: (32 bits mode only)
547// 7 - 6 5 - 3 2-0
548// Scale Index Base
549//*****************************************************************************
550static const char *szSIBBaseReg[8] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
551static const char *szSIBIndexReg[8] = {"EAX", "ECX", "EDX", "EBX", NULL, "EBP", "ESI", "EDI"};
552static const char *szSIBBaseReg64[16] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
553static const char *szSIBIndexReg64[16]= {"RAX", "RCX", "RDX", "RBX", NULL, "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
554#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED) || defined(_MSC_VER)
555static const char *szSIBScale[4] = {"", "*2", "*4", "*8"};
556#endif
557//*****************************************************************************
558void UseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
559{
560 unsigned scale, base, index, regtype;
561 const char **ppszSIBIndexReg;
562 const char **ppszSIBBaseReg;
563 char szTemp[32];
564 szTemp[0] = '\0';
565
566 scale = pCpu->SIB.Bits.Scale;
567 base = pCpu->SIB.Bits.Base;
568 index = pCpu->SIB.Bits.Index;
569
570 if (pCpu->addrmode == CPUMODE_32BIT)
571 {
572 ppszSIBIndexReg = szSIBIndexReg;
573 ppszSIBBaseReg = szSIBBaseReg;
574 regtype = USE_REG_GEN32;
575 }
576 else
577 {
578 ppszSIBIndexReg = szSIBIndexReg64;
579 ppszSIBBaseReg = szSIBBaseReg64;
580 regtype = USE_REG_GEN64;
581 }
582
583 if (ppszSIBIndexReg[index])
584 {
585 pParam->flags |= USE_INDEX | regtype;
586 pParam->index.reg_gen = index;
587
588 if (scale != 0)
589 {
590 pParam->flags |= USE_SCALE;
591 pParam->scale = (1<<scale);
592 }
593
594 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
595 disasmAddStringF(szTemp, sizeof(szTemp), "%s%s", ppszSIBIndexReg[index], szSIBScale[scale]);
596 else
597 disasmAddStringF(szTemp, sizeof(szTemp), "%s+%s%s", ppszSIBBaseReg[base], ppszSIBIndexReg[index], szSIBScale[scale]);
598 }
599 else
600 {
601 if (base != 5 || pCpu->ModRM.Bits.Mod != 0)
602 disasmAddStringF(szTemp, sizeof(szTemp), "%s", ppszSIBBaseReg[base]);
603 }
604
605 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
606 {
607 // [scaled index] + disp32
608 disasmAddString(pParam->szParam, &szTemp[0]);
609 if (pCpu->addrmode == CPUMODE_32BIT)
610 {
611 pParam->flags |= USE_DISPLACEMENT32;
612 pParam->disp32 = pCpu->disp;
613 disasmAddChar(pParam->szParam, '+');
614 disasmPrintDisp32(pParam);
615 }
616 else
617 { /* sign-extend to 64 bits */
618 pParam->flags |= USE_DISPLACEMENT64;
619 pParam->disp64 = pCpu->disp;
620 disasmAddChar(pParam->szParam, '+');
621 disasmPrintDisp64(pParam);
622 }
623 }
624 else
625 {
626 disasmAddString(pParam->szParam, szTemp);
627
628 pParam->flags |= USE_BASE | regtype;
629 pParam->base.reg_gen = base;
630 }
631 return; /* Already fetched everything in ParseSIB; no size returned */
632}
633//*****************************************************************************
634//*****************************************************************************
635unsigned ParseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
636{
637 unsigned size = sizeof(uint8_t);
638 unsigned SIB;
639
640 SIB = DISReadByte(pCpu, lpszCodeBlock);
641 lpszCodeBlock += size;
642
643 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
644 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
645 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
646
647 if (pCpu->prefix & PREFIX_REX)
648 {
649 /* REX.B extends the Base field if not scaled index + disp32 */
650 if (!(pCpu->SIB.Bits.Base == 5 && pCpu->ModRM.Bits.Mod == 0))
651 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
652
653 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
654 }
655
656 if ( pCpu->SIB.Bits.Base == 5
657 && pCpu->ModRM.Bits.Mod == 0)
658 {
659 /* Additional 32 bits displacement. No change in long mode. */
660 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
661 size += sizeof(int32_t);
662 }
663 return size;
664}
665//*****************************************************************************
666//*****************************************************************************
667unsigned ParseSIB_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
668{
669 unsigned size = sizeof(uint8_t);
670 unsigned SIB;
671
672 SIB = DISReadByte(pCpu, lpszCodeBlock);
673 lpszCodeBlock += size;
674
675 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
676 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
677 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
678
679 if (pCpu->prefix & PREFIX_REX)
680 {
681 /* REX.B extends the Base field. */
682 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
683 /* REX.X extends the Index field. */
684 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
685 }
686
687 if ( pCpu->SIB.Bits.Base == 5
688 && pCpu->ModRM.Bits.Mod == 0)
689 {
690 /* Additional 32 bits displacement. No change in long mode. */
691 size += sizeof(int32_t);
692 }
693 return size;
694}
695//*****************************************************************************
696// ModR/M byte:
697// 7 - 6 5 - 3 2-0
698// Mod Reg/Opcode R/M
699//*****************************************************************************
700unsigned UseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
701{
702 int vtype = OP_PARM_VTYPE(pParam->param);
703 unsigned reg = pCpu->ModRM.Bits.Reg;
704 unsigned mod = pCpu->ModRM.Bits.Mod;
705 unsigned rm = pCpu->ModRM.Bits.Rm;
706
707 switch (vtype)
708 {
709 case OP_PARM_G: //general purpose register
710 disasmModRMReg(pCpu, pOp, reg, pParam, 0);
711 return 0;
712
713 default:
714 if (IS_OP_PARM_RARE(vtype))
715 {
716 switch (vtype)
717 {
718 case OP_PARM_C: //control register
719 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "CR%d", reg);
720 pParam->flags |= USE_REG_CR;
721 pParam->base.reg_ctrl = reg;
722 return 0;
723
724 case OP_PARM_D: //debug register
725 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "DR%d", reg);
726 pParam->flags |= USE_REG_DBG;
727 pParam->base.reg_dbg = reg;
728 return 0;
729
730 case OP_PARM_P: //MMX register
731 reg &= 7; /* REX.R has no effect here */
732 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "MM%d", reg);
733 pParam->flags |= USE_REG_MMX;
734 pParam->base.reg_mmx = reg;
735 return 0;
736
737 case OP_PARM_S: //segment register
738 reg &= 7; /* REX.R has no effect here */
739 disasmModRMSReg(pCpu, pOp, reg, pParam);
740 pParam->flags |= USE_REG_SEG;
741 return 0;
742
743 case OP_PARM_T: //test register
744 reg &= 7; /* REX.R has no effect here */
745 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "TR%d", reg);
746 pParam->flags |= USE_REG_TEST;
747 pParam->base.reg_test = reg;
748 return 0;
749
750 case OP_PARM_W: //XMM register or memory operand
751 if (mod != 3)
752 break; /* memory operand */
753 reg = rm; /* the RM field specifies the xmm register */
754 /* else no break */
755
756 case OP_PARM_V: //XMM register
757 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "XMM%d", reg);
758 pParam->flags |= USE_REG_XMM;
759 pParam->base.reg_xmm = reg;
760 return 0;
761 }
762 }
763 }
764
765 /* @todo bound */
766
767 if (pCpu->addrmode != CPUMODE_16BIT)
768 {
769 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
770
771 /*
772 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
773 */
774 switch (mod)
775 {
776 case 0: //effective address
777 disasmGetPtrString(pCpu, pOp, pParam);
778 disasmAddChar(pParam->szParam, '[');
779 if (rm == 4)
780 { /* SIB byte follows ModRM */
781 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
782 }
783 else
784 if (rm == 5)
785 {
786 /* 32 bits displacement */
787 if (pCpu->mode != CPUMODE_64BIT)
788 {
789 pParam->flags |= USE_DISPLACEMENT32;
790 pParam->disp32 = pCpu->disp;
791 disasmPrintDisp32(pParam);
792 }
793 else
794 {
795 pParam->flags |= USE_RIPDISPLACEMENT32;
796 pParam->disp32 = pCpu->disp;
797 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "RIP+");
798 disasmPrintDisp32(pParam);
799 }
800 }
801 else {//register address
802 pParam->flags |= USE_BASE;
803 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
804 }
805 disasmAddChar(pParam->szParam, ']');
806 break;
807
808 case 1: //effective address + 8 bits displacement
809 disasmGetPtrString(pCpu, pOp, pParam);
810 disasmAddChar(pParam->szParam, '[');
811 if (rm == 4) {//SIB byte follows ModRM
812 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
813 }
814 else
815 {
816 pParam->flags |= USE_BASE;
817 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
818 }
819 pParam->disp8 = pCpu->disp;
820 pParam->flags |= USE_DISPLACEMENT8;
821
822 if (pParam->disp8 != 0)
823 {
824 if (pParam->disp8 > 0)
825 disasmAddChar(pParam->szParam, '+');
826 disasmPrintDisp8(pParam);
827 }
828 disasmAddChar(pParam->szParam, ']');
829 break;
830
831 case 2: //effective address + 32 bits displacement
832 disasmGetPtrString(pCpu, pOp, pParam);
833 disasmAddChar(pParam->szParam, '[');
834 if (rm == 4) {//SIB byte follows ModRM
835 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
836 }
837 else
838 {
839 pParam->flags |= USE_BASE;
840 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
841 }
842 pParam->disp32 = pCpu->disp;
843 pParam->flags |= USE_DISPLACEMENT32;
844
845 if (pParam->disp32 != 0)
846 {
847 disasmAddChar(pParam->szParam, '+');
848 disasmPrintDisp32(pParam);
849 }
850 disasmAddChar(pParam->szParam, ']');
851 break;
852
853 case 3: //registers
854 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
855 break;
856 }
857 }
858 else
859 {//16 bits addressing mode
860 switch (mod)
861 {
862 case 0: //effective address
863 disasmGetPtrString(pCpu, pOp, pParam);
864 disasmAddChar(pParam->szParam, '[');
865 if (rm == 6)
866 {//16 bits displacement
867 pParam->disp16 = pCpu->disp;
868 pParam->flags |= USE_DISPLACEMENT16;
869 disasmPrintDisp16(pParam);
870 }
871 else
872 {
873 pParam->flags |= USE_BASE;
874 disasmModRMReg16(pCpu, pOp, rm, pParam);
875 }
876 disasmAddChar(pParam->szParam, ']');
877 break;
878
879 case 1: //effective address + 8 bits displacement
880 disasmGetPtrString(pCpu, pOp, pParam);
881 disasmAddChar(pParam->szParam, '[');
882 disasmModRMReg16(pCpu, pOp, rm, pParam);
883 pParam->disp8 = pCpu->disp;
884 pParam->flags |= USE_BASE | USE_DISPLACEMENT8;
885
886 if (pParam->disp8 != 0)
887 {
888 if (pParam->disp8 > 0)
889 disasmAddChar(pParam->szParam, '+');
890 disasmPrintDisp8(pParam);
891 }
892 disasmAddChar(pParam->szParam, ']');
893 break;
894
895 case 2: //effective address + 16 bits displacement
896 disasmGetPtrString(pCpu, pOp, pParam);
897 disasmAddChar(pParam->szParam, '[');
898 disasmModRMReg16(pCpu, pOp, rm, pParam);
899 pParam->disp16 = pCpu->disp;
900 pParam->flags |= USE_BASE | USE_DISPLACEMENT16;
901
902 if (pParam->disp16 != 0)
903 {
904 disasmAddChar(pParam->szParam, '+');
905 disasmPrintDisp16(pParam);
906 }
907 disasmAddChar(pParam->szParam, ']');
908 break;
909
910 case 3: //registers
911 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
912 break;
913 }
914 }
915 return 0; //everything was already fetched in ParseModRM
916}
917//*****************************************************************************
918// Query the size of the ModRM parameters and fetch the immediate data (if any)
919//*****************************************************************************
920unsigned QueryModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
921{
922 unsigned sibinc;
923 unsigned size = 0;
924 // unsigned reg = pCpu->ModRM.Bits.Reg;
925 unsigned mod = pCpu->ModRM.Bits.Mod;
926 unsigned rm = pCpu->ModRM.Bits.Rm;
927
928 if (!pSibInc)
929 pSibInc = &sibinc;
930
931 *pSibInc = 0;
932
933 if (pCpu->addrmode != CPUMODE_16BIT)
934 {
935 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
936
937 /*
938 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
939 */
940 if (mod != 3 && rm == 4)
941 { /* SIB byte follows ModRM */
942 *pSibInc = ParseSIB(lpszCodeBlock, pOp, pParam, pCpu);
943 lpszCodeBlock += *pSibInc;
944 size += *pSibInc;
945 }
946
947 switch (mod)
948 {
949 case 0: /* Effective address */
950 if (rm == 5) { /* 32 bits displacement */
951 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
952 size += sizeof(int32_t);
953 }
954 /* else register address */
955 break;
956
957 case 1: /* Effective address + 8 bits displacement */
958 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
959 size += sizeof(char);
960 break;
961
962 case 2: /* Effective address + 32 bits displacement */
963 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
964 size += sizeof(int32_t);
965 break;
966
967 case 3: /* registers */
968 break;
969 }
970 }
971 else
972 {
973 /* 16 bits mode */
974 switch (mod)
975 {
976 case 0: /* Effective address */
977 if (rm == 6) {
978 pCpu->disp = DISReadWord(pCpu, lpszCodeBlock);
979 size += sizeof(uint16_t);
980 }
981 /* else register address */
982 break;
983
984 case 1: /* Effective address + 8 bits displacement */
985 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
986 size += sizeof(char);
987 break;
988
989 case 2: /* Effective address + 32 bits displacement */
990 pCpu->disp = (int16_t)DISReadWord(pCpu, lpszCodeBlock);
991 size += sizeof(uint16_t);
992 break;
993
994 case 3: /* registers */
995 break;
996 }
997 }
998 return size;
999}
1000//*****************************************************************************
1001// Query the size of the ModRM parameters and fetch the immediate data (if any)
1002//*****************************************************************************
1003unsigned QueryModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
1004{
1005 unsigned sibinc;
1006 unsigned size = 0;
1007 // unsigned reg = pCpu->ModRM.Bits.Reg;
1008 unsigned mod = pCpu->ModRM.Bits.Mod;
1009 unsigned rm = pCpu->ModRM.Bits.Rm;
1010
1011 if (!pSibInc)
1012 pSibInc = &sibinc;
1013
1014 *pSibInc = 0;
1015
1016 if (pCpu->addrmode != CPUMODE_16BIT)
1017 {
1018 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
1019 /*
1020 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
1021 */
1022 if (mod != 3 && rm == 4)
1023 { /* SIB byte follows ModRM */
1024 *pSibInc = ParseSIB_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu);
1025 lpszCodeBlock += *pSibInc;
1026 size += *pSibInc;
1027 }
1028
1029 switch (mod)
1030 {
1031 case 0: //effective address
1032 if (rm == 5) { /* 32 bits displacement */
1033 size += sizeof(int32_t);
1034 }
1035 /* else register address */
1036 break;
1037
1038 case 1: /* Effective address + 8 bits displacement */
1039 size += sizeof(char);
1040 break;
1041
1042 case 2: /* Effective address + 32 bits displacement */
1043 size += sizeof(int32_t);
1044 break;
1045
1046 case 3: /* registers */
1047 break;
1048 }
1049 }
1050 else
1051 {
1052 /* 16 bits mode */
1053 switch (mod)
1054 {
1055 case 0: //effective address
1056 if (rm == 6) {
1057 size += sizeof(uint16_t);
1058 }
1059 /* else register address */
1060 break;
1061
1062 case 1: /* Effective address + 8 bits displacement */
1063 size += sizeof(char);
1064 break;
1065
1066 case 2: /* Effective address + 32 bits displacement */
1067 size += sizeof(uint16_t);
1068 break;
1069
1070 case 3: /* registers */
1071 break;
1072 }
1073 }
1074 return size;
1075}
1076//*****************************************************************************
1077//*****************************************************************************
1078unsigned ParseIllegal(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1079{
1080 AssertFailed();
1081 return 0;
1082}
1083//*****************************************************************************
1084//*****************************************************************************
1085unsigned ParseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1086{
1087 unsigned size = sizeof(uint8_t); //ModRM byte
1088 unsigned sibinc, ModRM;
1089
1090 ModRM = DISReadByte(pCpu, lpszCodeBlock);
1091 lpszCodeBlock += sizeof(uint8_t);
1092
1093 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1094 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1095 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1096
1097 if (pCpu->prefix & PREFIX_REX)
1098 {
1099 Assert(pCpu->mode == CPUMODE_64BIT);
1100
1101 /* REX.R extends the Reg field. */
1102 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
1103
1104 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1105 if (!( pCpu->ModRM.Bits.Mod != 3
1106 && pCpu->ModRM.Bits.Rm == 4)
1107 &&
1108 !( pCpu->ModRM.Bits.Mod == 0
1109 && pCpu->ModRM.Bits.Rm == 5))
1110 {
1111 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1112 }
1113 }
1114 size += QueryModRM(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1115 lpszCodeBlock += sibinc;
1116
1117 UseModRM(lpszCodeBlock, pOp, pParam, pCpu);
1118 return size;
1119}
1120//*****************************************************************************
1121//*****************************************************************************
1122unsigned ParseModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1123{
1124 unsigned size = sizeof(uint8_t); //ModRM byte
1125 unsigned sibinc, ModRM;
1126
1127 ModRM = DISReadByte(pCpu, lpszCodeBlock);
1128 lpszCodeBlock += sizeof(uint8_t);
1129
1130 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1131 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1132 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1133
1134 if (pCpu->prefix & PREFIX_REX)
1135 {
1136 Assert(pCpu->mode == CPUMODE_64BIT);
1137
1138 /* REX.R extends the Reg field. */
1139 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
1140
1141 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1142 if (!( pCpu->ModRM.Bits.Mod != 3
1143 && pCpu->ModRM.Bits.Rm == 4)
1144 &&
1145 !( pCpu->ModRM.Bits.Mod == 0
1146 && pCpu->ModRM.Bits.Rm == 5))
1147 {
1148 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1149 }
1150 }
1151
1152 size += QueryModRM_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1153 lpszCodeBlock += sibinc;
1154
1155 /* UseModRM is not necessary here; we're only interested in the opcode size */
1156 return size;
1157}
1158//*****************************************************************************
1159//*****************************************************************************
1160unsigned ParseModFence(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1161{
1162 ////AssertMsgFailed(("??\n"));
1163 //nothing to do apparently
1164 return 0;
1165}
1166//*****************************************************************************
1167//*****************************************************************************
1168unsigned ParseImmByte(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1169{
1170 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1171 pParam->flags |= USE_IMMEDIATE8;
1172 pParam->size = sizeof(uint8_t);
1173
1174 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%02Xh", (uint32_t)pParam->parval);
1175 return sizeof(uint8_t);
1176}
1177//*****************************************************************************
1178//*****************************************************************************
1179unsigned ParseImmByte_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1180{
1181 return sizeof(uint8_t);
1182}
1183//*****************************************************************************
1184//*****************************************************************************
1185unsigned ParseImmByteSX(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1186{
1187 if (pCpu->opmode == CPUMODE_32BIT)
1188 {
1189 pParam->parval = (uint32_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1190 pParam->flags |= USE_IMMEDIATE32_SX8;
1191 pParam->size = sizeof(uint32_t);
1192 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1193 }
1194 else
1195 if (pCpu->opmode == CPUMODE_64BIT)
1196 {
1197 pParam->parval = (uint64_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1198 pParam->flags |= USE_IMMEDIATE64_SX8;
1199 pParam->size = sizeof(uint64_t);
1200 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%016RX64h", pParam->parval);
1201 }
1202 else
1203 {
1204 pParam->parval = (uint16_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1205 pParam->flags |= USE_IMMEDIATE16_SX8;
1206 pParam->size = sizeof(uint16_t);
1207 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1208 }
1209 return sizeof(uint8_t);
1210}
1211//*****************************************************************************
1212//*****************************************************************************
1213unsigned ParseImmByteSX_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1214{
1215 return sizeof(uint8_t);
1216}
1217//*****************************************************************************
1218//*****************************************************************************
1219unsigned ParseImmUshort(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1220{
1221 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1222 pParam->flags |= USE_IMMEDIATE16;
1223 pParam->size = sizeof(uint16_t);
1224
1225 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1226 return sizeof(uint16_t);
1227}
1228//*****************************************************************************
1229//*****************************************************************************
1230unsigned ParseImmUshort_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1231{
1232 return sizeof(uint16_t);
1233}
1234//*****************************************************************************
1235//*****************************************************************************
1236unsigned ParseImmUlong(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1237{
1238 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1239 pParam->flags |= USE_IMMEDIATE32;
1240 pParam->size = sizeof(uint32_t);
1241
1242 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1243 return sizeof(uint32_t);
1244}
1245//*****************************************************************************
1246//*****************************************************************************
1247unsigned ParseImmUlong_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1248{
1249 return sizeof(uint32_t);
1250}
1251//*****************************************************************************
1252//*****************************************************************************
1253unsigned ParseImmQword(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1254{
1255 pParam->parval = DISReadQWord(pCpu, lpszCodeBlock);
1256 pParam->flags |= USE_IMMEDIATE64;
1257 pParam->size = sizeof(uint64_t);
1258
1259 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08X", (uint32_t)pParam->parval);
1260 disasmAddStringF(&pParam->szParam[9], sizeof(pParam->szParam)-9, "%08Xh", (uint32_t)(pParam->parval >> 32));
1261 return sizeof(uint64_t);
1262}
1263//*****************************************************************************
1264//*****************************************************************************
1265unsigned ParseImmQword_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1266{
1267 return sizeof(uint64_t);
1268}
1269//*****************************************************************************
1270//*****************************************************************************
1271unsigned ParseImmV(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1272{
1273 if (pCpu->opmode == CPUMODE_32BIT)
1274 {
1275 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1276 pParam->flags |= USE_IMMEDIATE32;
1277 pParam->size = sizeof(uint32_t);
1278
1279 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1280 return sizeof(uint32_t);
1281 }
1282 else
1283 if (pCpu->opmode == CPUMODE_64BIT)
1284 {
1285 pParam->parval = DISReadQWord(pCpu, lpszCodeBlock);
1286 pParam->flags |= USE_IMMEDIATE64;
1287 pParam->size = sizeof(uint64_t);
1288
1289 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%VX64h", pParam->parval);
1290 return sizeof(uint64_t);
1291 }
1292 else
1293 {
1294 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1295 pParam->flags |= USE_IMMEDIATE16;
1296 pParam->size = sizeof(uint16_t);
1297
1298 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint32_t)pParam->parval);
1299 return sizeof(uint16_t);
1300 }
1301}
1302//*****************************************************************************
1303//*****************************************************************************
1304unsigned ParseImmV_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1305{
1306 if (pCpu->opmode == CPUMODE_32BIT)
1307 return sizeof(uint32_t);
1308 else
1309 if (pCpu->opmode == CPUMODE_64BIT)
1310 return sizeof(uint64_t);
1311
1312 return sizeof(uint16_t);
1313}
1314//*****************************************************************************
1315//*****************************************************************************
1316unsigned ParseImmZ(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1317{
1318 /* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */
1319 if (pCpu->opmode == CPUMODE_16BIT)
1320 {
1321 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1322 pParam->flags |= USE_IMMEDIATE16;
1323 pParam->size = sizeof(uint16_t);
1324
1325 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint32_t)pParam->parval);
1326 return sizeof(uint16_t);
1327 }
1328 else
1329 {
1330 /* 64 bits op mode means *sign* extend to 64 bits. */
1331 if (pCpu->opmode == CPUMODE_64BIT)
1332 {
1333 pParam->parval = (uint64_t)(int32_t)DISReadDWord(pCpu, lpszCodeBlock);
1334 pParam->flags |= USE_IMMEDIATE64;
1335 pParam->size = sizeof(uint64_t);
1336 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%VX64h", pParam->parval);
1337 }
1338 else
1339 {
1340 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1341 pParam->flags |= USE_IMMEDIATE32;
1342 pParam->size = sizeof(uint32_t);
1343 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1344 }
1345 return sizeof(uint32_t);
1346 }
1347}
1348//*****************************************************************************
1349//*****************************************************************************
1350unsigned ParseImmZ_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1351{
1352 /* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */
1353 if (pCpu->opmode == CPUMODE_16BIT)
1354 return sizeof(uint16_t);
1355 return sizeof(uint32_t);
1356}
1357
1358//*****************************************************************************
1359// Relative displacement for branches (rel. to next instruction)
1360//*****************************************************************************
1361unsigned ParseImmBRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1362{
1363 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1364 pParam->flags |= USE_IMMEDIATE8_REL;
1365 pParam->size = sizeof(uint8_t);
1366
1367 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%02Xh)", (uint32_t)pParam->parval);
1368 return sizeof(char);
1369}
1370//*****************************************************************************
1371// Relative displacement for branches (rel. to next instruction)
1372//*****************************************************************************
1373unsigned ParseImmBRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1374{
1375 return sizeof(char);
1376}
1377//*****************************************************************************
1378// Relative displacement for branches (rel. to next instruction)
1379//*****************************************************************************
1380unsigned ParseImmVRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1381{
1382 if (pCpu->opmode == CPUMODE_32BIT)
1383 {
1384 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1385 pParam->flags |= USE_IMMEDIATE32_REL;
1386 pParam->size = sizeof(int32_t);
1387
1388 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%08Xh)", (uint32_t)pParam->parval);
1389 return sizeof(int32_t);
1390 }
1391 else
1392 if (pCpu->opmode == CPUMODE_64BIT)
1393 {
1394 /* 32 bits relative immediate sign extended to 64 bits. */
1395 pParam->parval = (uint64_t)(int32_t)DISReadDWord(pCpu, lpszCodeBlock);
1396 pParam->flags |= USE_IMMEDIATE64_REL;
1397 pParam->size = sizeof(int64_t);
1398
1399 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%VX64h)", pParam->parval);
1400 return sizeof(int32_t);
1401 }
1402 else
1403 {
1404 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1405 pParam->flags |= USE_IMMEDIATE16_REL;
1406 pParam->size = sizeof(int16_t);
1407
1408 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%04Xh)", (uint32_t)pParam->parval);
1409 return sizeof(int16_t);
1410 }
1411}
1412//*****************************************************************************
1413// Relative displacement for branches (rel. to next instruction)
1414//*****************************************************************************
1415unsigned ParseImmVRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1416{
1417 if (pCpu->opmode == CPUMODE_16BIT)
1418 return sizeof(int16_t);
1419 /* Both 32 & 64 bits mode use 32 bits relative immediates. */
1420 return sizeof(int32_t);
1421}
1422//*****************************************************************************
1423//*****************************************************************************
1424unsigned ParseImmAddr(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1425{
1426 disasmGetPtrString(pCpu, pOp, pParam);
1427 if (pCpu->addrmode == CPUMODE_32BIT)
1428 {
1429 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1430 {// far 16:32 pointer
1431 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1432 *((uint32_t*)&pParam->parval+1) = DISReadWord(pCpu, lpszCodeBlock+sizeof(uint32_t));
1433 pParam->flags |= USE_IMMEDIATE_ADDR_16_32;
1434 pParam->size = sizeof(uint16_t) + sizeof(uint32_t);
1435
1436 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%08Xh", (uint32_t)(pParam->parval>>32), (uint32_t)pParam->parval);
1437 return sizeof(uint32_t) + sizeof(uint16_t);
1438 }
1439 else
1440 {// near 32 bits pointer
1441 /*
1442 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1443 * so we treat it like displacement.
1444 */
1445 pParam->disp32 = DISReadDWord(pCpu, lpszCodeBlock);
1446 pParam->flags |= USE_DISPLACEMENT32;
1447 pParam->size = sizeof(uint32_t);
1448
1449 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08Xh]", pParam->disp32);
1450 return sizeof(uint32_t);
1451 }
1452 }
1453 else
1454 if (pCpu->addrmode == CPUMODE_64BIT)
1455 {
1456 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1457 /* near 64 bits pointer */
1458 /*
1459 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1460 * so we treat it like displacement.
1461 */
1462 pParam->disp64 = DISReadQWord(pCpu, lpszCodeBlock);
1463 pParam->flags |= USE_DISPLACEMENT64;
1464 pParam->size = sizeof(uint64_t);
1465
1466 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08X%08Xh]", (uint32_t)(pParam->disp64 >> 32), (uint32_t)pParam->disp64);
1467 return sizeof(uint64_t);
1468 }
1469 else
1470 {
1471 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1472 {// far 16:16 pointer
1473 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1474 pParam->flags |= USE_IMMEDIATE_ADDR_16_16;
1475 pParam->size = 2*sizeof(uint16_t);
1476
1477 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%04Xh", (uint32_t)(pParam->parval>>16), (uint16_t)pParam->parval );
1478 return sizeof(uint32_t);
1479 }
1480 else
1481 {// near 16 bits pointer
1482 /*
1483 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1484 * so we treat it like displacement.
1485 */
1486 pParam->disp16 = DISReadWord(pCpu, lpszCodeBlock);
1487 pParam->flags |= USE_DISPLACEMENT16;
1488 pParam->size = sizeof(uint16_t);
1489
1490 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%04Xh]", (uint32_t)pParam->disp16);
1491 return sizeof(uint16_t);
1492 }
1493 }
1494}
1495//*****************************************************************************
1496//*****************************************************************************
1497unsigned ParseImmAddr_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1498{
1499 if (pCpu->addrmode == CPUMODE_32BIT)
1500 {
1501 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1502 {// far 16:32 pointer
1503 return sizeof(uint32_t) + sizeof(uint16_t);
1504 }
1505 else
1506 {// near 32 bits pointer
1507 return sizeof(uint32_t);
1508 }
1509 }
1510 if (pCpu->addrmode == CPUMODE_64BIT)
1511 {
1512 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1513 return sizeof(uint64_t);
1514 }
1515 else
1516 {
1517 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1518 {// far 16:16 pointer
1519 return sizeof(uint32_t);
1520 }
1521 else
1522 {// near 16 bits pointer
1523 return sizeof(uint16_t);
1524 }
1525 }
1526}
1527//*****************************************************************************
1528//*****************************************************************************
1529unsigned ParseFixedReg(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1530{
1531 /*
1532 * Sets up flags for stored in OPC fixed registers.
1533 */
1534
1535 if (pParam->param == OP_PARM_NONE)
1536 {
1537 /* No parameter at all. */
1538 return 0;
1539 }
1540
1541 AssertCompile(OP_PARM_REG_GEN32_END < OP_PARM_REG_SEG_END);
1542 AssertCompile(OP_PARM_REG_SEG_END < OP_PARM_REG_GEN16_END);
1543 AssertCompile(OP_PARM_REG_GEN16_END < OP_PARM_REG_GEN8_END);
1544 AssertCompile(OP_PARM_REG_GEN8_END < OP_PARM_REG_FP_END);
1545
1546 if (pParam->param <= OP_PARM_REG_GEN32_END)
1547 {
1548 /* 32-bit EAX..EDI registers. */
1549 if (pCpu->opmode == CPUMODE_32BIT)
1550 {
1551 /* Use 32-bit registers. */
1552 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1553 pParam->flags |= USE_REG_GEN32;
1554 pParam->size = 4;
1555 }
1556 else
1557 if (pCpu->opmode == CPUMODE_64BIT)
1558 {
1559 /* Use 64-bit registers. */
1560 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1561 if ( (pOp->optype & OPTYPE_REXB_EXTENDS_OPREG)
1562 && pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
1563 && (pCpu->prefix & PREFIX_REX)
1564 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1565 pParam->base.reg_gen += 8;
1566
1567 pParam->flags |= USE_REG_GEN64;
1568 pParam->size = 8;
1569 }
1570 else
1571 {
1572 /* Use 16-bit registers. */
1573 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1574 pParam->flags |= USE_REG_GEN16;
1575 pParam->size = 2;
1576 pParam->param = pParam->param - OP_PARM_REG_GEN32_START + OP_PARM_REG_GEN16_START;
1577 }
1578 }
1579 else
1580 if (pParam->param <= OP_PARM_REG_SEG_END)
1581 {
1582 /* Segment ES..GS registers. */
1583 pParam->base.reg_seg = (DIS_SELREG)(pParam->param - OP_PARM_REG_SEG_START);
1584 pParam->flags |= USE_REG_SEG;
1585 pParam->size = 2;
1586 }
1587 else
1588 if (pParam->param <= OP_PARM_REG_GEN16_END)
1589 {
1590 /* 16-bit AX..DI registers. */
1591 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN16_START;
1592 pParam->flags |= USE_REG_GEN16;
1593 pParam->size = 2;
1594 }
1595 else
1596 if (pParam->param <= OP_PARM_REG_GEN8_END)
1597 {
1598 /* 8-bit AL..DL, AH..DH registers. */
1599 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN8_START;
1600 pParam->flags |= USE_REG_GEN8;
1601 pParam->size = 1;
1602
1603 if (pCpu->opmode == CPUMODE_64BIT)
1604 {
1605 if ( (pOp->optype & OPTYPE_REXB_EXTENDS_OPREG)
1606 && pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
1607 && (pCpu->prefix & PREFIX_REX)
1608 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1609 pParam->base.reg_gen += 8; /* least significant byte of R8-R15 */
1610 }
1611 }
1612 else
1613 if (pParam->param <= OP_PARM_REG_FP_END)
1614 {
1615 /* FPU registers. */
1616 pParam->base.reg_fp = pParam->param - OP_PARM_REG_FP_START;
1617 pParam->flags |= USE_REG_FP;
1618 pParam->size = 10;
1619 }
1620 Assert(!(pParam->param >= OP_PARM_REG_GEN64_START && pParam->param <= OP_PARM_REG_GEN64_END));
1621
1622 /* else - not supported for now registers. */
1623
1624 return 0;
1625}
1626//*****************************************************************************
1627//*****************************************************************************
1628unsigned ParseXv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1629{
1630 disasmGetPtrString(pCpu, pOp, pParam);
1631 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1632
1633 pParam->flags |= USE_POINTER_DS_BASED;
1634 if (pCpu->addrmode == CPUMODE_32BIT)
1635 {
1636 pParam->base.reg_gen = USE_REG_ESI;
1637 pParam->flags |= USE_REG_GEN32;
1638 }
1639 else
1640 if (pCpu->addrmode == CPUMODE_64BIT)
1641 {
1642 pParam->base.reg_gen = USE_REG_RSI;
1643 pParam->flags |= USE_REG_GEN64;
1644 }
1645 else
1646 {
1647 pParam->base.reg_gen = USE_REG_SI;
1648 pParam->flags |= USE_REG_GEN16;
1649 }
1650 return 0; //no additional opcode bytes
1651}
1652//*****************************************************************************
1653//*****************************************************************************
1654unsigned ParseXb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1655{
1656 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1657
1658 pParam->flags |= USE_POINTER_DS_BASED;
1659 if (pCpu->addrmode == CPUMODE_32BIT)
1660 {
1661 pParam->base.reg_gen = USE_REG_ESI;
1662 pParam->flags |= USE_REG_GEN32;
1663 }
1664 else
1665 if (pCpu->addrmode == CPUMODE_64BIT)
1666 {
1667 pParam->base.reg_gen = USE_REG_RSI;
1668 pParam->flags |= USE_REG_GEN64;
1669 }
1670 else
1671 {
1672 pParam->base.reg_gen = USE_REG_SI;
1673 pParam->flags |= USE_REG_GEN16;
1674 }
1675 return 0; //no additional opcode bytes
1676}
1677//*****************************************************************************
1678//*****************************************************************************
1679unsigned ParseYv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1680{
1681 disasmGetPtrString(pCpu, pOp, pParam);
1682 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1683
1684 pParam->flags |= USE_POINTER_ES_BASED;
1685 if (pCpu->addrmode == CPUMODE_32BIT)
1686 {
1687 pParam->base.reg_gen = USE_REG_EDI;
1688 pParam->flags |= USE_REG_GEN32;
1689 }
1690 else
1691 if (pCpu->addrmode == CPUMODE_64BIT)
1692 {
1693 pParam->base.reg_gen = USE_REG_RDI;
1694 pParam->flags |= USE_REG_GEN64;
1695 }
1696 else
1697 {
1698 pParam->base.reg_gen = USE_REG_DI;
1699 pParam->flags |= USE_REG_GEN16;
1700 }
1701 return 0; //no additional opcode bytes
1702}
1703//*****************************************************************************
1704//*****************************************************************************
1705unsigned ParseYb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1706{
1707 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1708
1709 pParam->flags |= USE_POINTER_ES_BASED;
1710 if (pCpu->addrmode == CPUMODE_32BIT)
1711 {
1712 pParam->base.reg_gen = USE_REG_EDI;
1713 pParam->flags |= USE_REG_GEN32;
1714 }
1715 else
1716 if (pCpu->addrmode == CPUMODE_64BIT)
1717 {
1718 pParam->base.reg_gen = USE_REG_RDI;
1719 pParam->flags |= USE_REG_GEN64;
1720 }
1721 else
1722 {
1723 pParam->base.reg_gen = USE_REG_DI;
1724 pParam->flags |= USE_REG_GEN16;
1725 }
1726 return 0; //no additional opcode bytes
1727}
1728//*****************************************************************************
1729//*****************************************************************************
1730unsigned ParseTwoByteEsc(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1731{
1732 const OPCODE *pOpcode;
1733 int size = sizeof(uint8_t);
1734
1735 /* 2nd byte */
1736 pCpu->opcode = DISReadByte(pCpu, lpszCodeBlock);
1737
1738 /* default to the non-prefixed table. */
1739 pOpcode = &g_aTwoByteMapX86[pCpu->opcode];
1740
1741 /* Handle opcode table extensions that rely on the address, repe or repne prefix byte. */
1742 /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
1743 if (pCpu->lastprefix)
1744 {
1745 switch (pCpu->lastprefix)
1746 {
1747 case OP_OPSIZE: /* 0x66 */
1748 if (g_aTwoByteMapX86_PF66[pCpu->opcode].opcode != OP_INVALID)
1749 {
1750 /* Table entry is valid, so use the extension table. */
1751 pOpcode = &g_aTwoByteMapX86_PF66[pCpu->opcode];
1752
1753 /* Cancel prefix changes. */
1754 pCpu->prefix &= ~PREFIX_OPSIZE;
1755 pCpu->opmode = pCpu->mode;
1756 }
1757 break;
1758
1759 case OP_REPNE: /* 0xF2 */
1760 if (g_aTwoByteMapX86_PFF2[pCpu->opcode].opcode != OP_INVALID)
1761 {
1762 /* Table entry is valid, so use the extension table. */
1763 pOpcode = &g_aTwoByteMapX86_PFF2[pCpu->opcode];
1764
1765 /* Cancel prefix changes. */
1766 pCpu->prefix &= ~PREFIX_REPNE;
1767 }
1768 break;
1769
1770 case OP_REPE: /* 0xF3 */
1771 if (g_aTwoByteMapX86_PFF3[pCpu->opcode].opcode != OP_INVALID)
1772 {
1773 /* Table entry is valid, so use the extension table. */
1774 pOpcode = &g_aTwoByteMapX86_PFF3[pCpu->opcode];
1775
1776 /* Cancel prefix changes. */
1777 pCpu->prefix &= ~PREFIX_REP;
1778 }
1779 break;
1780 }
1781 }
1782
1783 size += ParseInstruction(lpszCodeBlock+size, pOpcode, pCpu);
1784 return size;
1785}
1786//*****************************************************************************
1787//*****************************************************************************
1788unsigned ParseThreeByteEsc4(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1789{
1790 const OPCODE *pOpcode;
1791 int size = sizeof(uint8_t);
1792
1793 /* 3rd byte */
1794 pCpu->opcode = DISReadByte(pCpu, lpszCodeBlock);
1795
1796 /* default to the non-prefixed table. */
1797 if (g_apThreeByteMapX86_0F38[pCpu->opcode >> 4])
1798 {
1799 pOpcode = g_apThreeByteMapX86_0F38[pCpu->opcode >> 4];
1800 pOpcode = &pOpcode[pCpu->opcode & 0xf];
1801 }
1802 else
1803 pOpcode = &g_InvalidOpcode[0];
1804
1805 /* Handle opcode table extensions that rely on the address, repne prefix byte. */
1806 /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
1807 switch (pCpu->lastprefix)
1808 {
1809 case OP_OPSIZE: /* 0x66 */
1810 if (g_apThreeByteMapX86_660F38[pCpu->opcode >> 4])
1811 {
1812 pOpcode = g_apThreeByteMapX86_660F38[pCpu->opcode >> 4];
1813 pOpcode = &pOpcode[pCpu->opcode & 0xf];
1814
1815 if (pOpcode->opcode != OP_INVALID)
1816 {
1817 /* Table entry is valid, so use the extension table. */
1818
1819 /* Cancel prefix changes. */
1820 pCpu->prefix &= ~PREFIX_OPSIZE;
1821 pCpu->opmode = pCpu->mode;
1822 }
1823 }
1824 break;
1825
1826 case OP_REPNE: /* 0xF2 */
1827 if (g_apThreeByteMapX86_F20F38[pCpu->opcode >> 4])
1828 {
1829 pOpcode = g_apThreeByteMapX86_F20F38[pCpu->opcode >> 4];
1830 pOpcode = &pOpcode[pCpu->opcode & 0xf];
1831
1832 if (pOpcode->opcode != OP_INVALID)
1833 {
1834 /* Table entry is valid, so use the extension table. */
1835
1836 /* Cancel prefix changes. */
1837 pCpu->prefix &= ~PREFIX_REPNE;
1838 }
1839 }
1840 break;
1841 }
1842
1843 size += ParseInstruction(lpszCodeBlock+size, pOpcode, pCpu);
1844 return size;
1845}
1846//*****************************************************************************
1847//*****************************************************************************
1848unsigned ParseThreeByteEsc5(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1849{
1850 const OPCODE *pOpcode;
1851 int size = sizeof(uint8_t);
1852
1853 /* 3rd byte */
1854 pCpu->opcode = DISReadByte(pCpu, lpszCodeBlock);
1855
1856 /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
1857 Assert(pCpu->lastprefix == OP_OPSIZE);
1858
1859 /* default to the non-prefixed table. */
1860 if (g_apThreeByteMapX86_660F3A[pCpu->opcode >> 4])
1861 {
1862 pOpcode = g_apThreeByteMapX86_660F3A[pCpu->opcode >> 4];
1863 pOpcode = &pOpcode[pCpu->opcode & 0xf];
1864
1865 if (pOpcode->opcode != OP_INVALID)
1866 {
1867 /* Table entry is valid, so use the extension table. */
1868
1869 /* Cancel prefix changes. */
1870 pCpu->prefix &= ~PREFIX_OPSIZE;
1871 pCpu->opmode = pCpu->mode;
1872 }
1873 }
1874 else
1875 pOpcode = &g_InvalidOpcode[0];
1876
1877 size += ParseInstruction(lpszCodeBlock+size, pOpcode, pCpu);
1878 return size;
1879}
1880//*****************************************************************************
1881//*****************************************************************************
1882unsigned ParseNopPause(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1883{
1884 unsigned size = 0;
1885
1886 if (pCpu->prefix & PREFIX_REP)
1887 {
1888 pOp = &g_aMapX86_NopPause[1]; /* PAUSE */
1889 pCpu->prefix &= ~PREFIX_REP;
1890 }
1891 else
1892 pOp = &g_aMapX86_NopPause[0]; /* NOP */
1893
1894 size += ParseInstruction(pu8CodeBlock, pOp, pCpu);
1895 return size;
1896}
1897//*****************************************************************************
1898//*****************************************************************************
1899unsigned ParseImmGrpl(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1900{
1901 int idx = (pCpu->opcode - 0x80) * 8;
1902 unsigned size = 0, modrm, reg;
1903
1904 modrm = DISReadByte(pCpu, lpszCodeBlock);
1905 reg = MODRM_REG(modrm);
1906
1907 pOp = (PCOPCODE)&g_aMapX86_Group1[idx+reg];
1908 //little hack to make sure the ModRM byte is included in the returned size
1909 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1910 size = sizeof(uint8_t); //ModRM byte
1911
1912 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1913
1914 return size;
1915}
1916//*****************************************************************************
1917//*****************************************************************************
1918unsigned ParseShiftGrp2(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1919{
1920 int idx;
1921 unsigned size = 0, modrm, reg;
1922
1923 switch (pCpu->opcode)
1924 {
1925 case 0xC0:
1926 case 0xC1:
1927 idx = (pCpu->opcode - 0xC0)*8;
1928 break;
1929
1930 case 0xD0:
1931 case 0xD1:
1932 case 0xD2:
1933 case 0xD3:
1934 idx = (pCpu->opcode - 0xD0 + 2)*8;
1935 break;
1936
1937 default:
1938 AssertMsgFailed(("Oops\n"));
1939 return sizeof(uint8_t);
1940 }
1941
1942 modrm = DISReadByte(pCpu, lpszCodeBlock);
1943 reg = MODRM_REG(modrm);
1944
1945 pOp = (PCOPCODE)&g_aMapX86_Group2[idx+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
1953 return size;
1954}
1955//*****************************************************************************
1956//*****************************************************************************
1957unsigned ParseGrp3(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1958{
1959 int idx = (pCpu->opcode - 0xF6) * 8;
1960 unsigned size = 0, modrm, reg;
1961
1962 modrm = DISReadByte(pCpu, lpszCodeBlock);
1963 reg = MODRM_REG(modrm);
1964
1965 pOp = (PCOPCODE)&g_aMapX86_Group3[idx+reg];
1966
1967 //little hack to make sure the ModRM byte is included in the returned size
1968 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1969 size = sizeof(uint8_t); //ModRM byte
1970
1971 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1972
1973 return size;
1974}
1975//*****************************************************************************
1976//*****************************************************************************
1977unsigned ParseGrp4(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1978{
1979 unsigned size = 0, modrm, reg;
1980
1981 modrm = DISReadByte(pCpu, lpszCodeBlock);
1982 reg = MODRM_REG(modrm);
1983
1984 pOp = (PCOPCODE)&g_aMapX86_Group4[reg];
1985
1986 //little hack to make sure the ModRM byte is included in the returned size
1987 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1988 size = sizeof(uint8_t); //ModRM byte
1989
1990 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1991
1992 return size;
1993}
1994//*****************************************************************************
1995//*****************************************************************************
1996unsigned ParseGrp5(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1997{
1998 unsigned size = 0, modrm, reg;
1999
2000 modrm = DISReadByte(pCpu, lpszCodeBlock);
2001 reg = MODRM_REG(modrm);
2002
2003 pOp = (PCOPCODE)&g_aMapX86_Group5[reg];
2004
2005 //little hack to make sure the ModRM byte is included in the returned size
2006 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2007 size = sizeof(uint8_t); //ModRM byte
2008
2009 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2010
2011 return size;
2012}
2013//*****************************************************************************
2014// 0xF 0xF [ModRM] [SIB] [displacement] imm8_opcode
2015// It would appear the ModRM byte must always be present. How else can you
2016// determine the offset of the imm8_opcode byte otherwise?
2017//
2018//*****************************************************************************
2019unsigned Parse3DNow(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2020{
2021 unsigned size = 0, modrmsize;
2022
2023#ifdef DEBUG_Sander
2024 //needs testing
2025 AssertMsgFailed(("Test me\n"));
2026#endif
2027
2028 unsigned ModRM = DISReadByte(pCpu, lpszCodeBlock);
2029 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
2030 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
2031 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
2032
2033 modrmsize = QueryModRM(lpszCodeBlock+sizeof(uint8_t), pOp, pParam, pCpu);
2034
2035 uint8_t opcode = DISReadByte(pCpu, lpszCodeBlock+sizeof(uint8_t)+modrmsize);
2036
2037 pOp = (PCOPCODE)&g_aTwoByteMapX86_3DNow[opcode];
2038
2039 //little hack to make sure the ModRM byte is included in the returned size
2040 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2041 {
2042#ifdef DEBUG_Sander /* bird, 2005-06-28: Alex is getting this during full installation of win2ksp4. */
2043 AssertMsgFailed(("Oops!\n")); //shouldn't happen!
2044#endif
2045 size = sizeof(uint8_t); //ModRM byte
2046 }
2047
2048 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2049 size += sizeof(uint8_t); //imm8_opcode uint8_t
2050
2051 return size;
2052}
2053//*****************************************************************************
2054//*****************************************************************************
2055unsigned ParseGrp6(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2056{
2057 unsigned size = 0, modrm, reg;
2058
2059 modrm = DISReadByte(pCpu, lpszCodeBlock);
2060 reg = MODRM_REG(modrm);
2061
2062 pOp = (PCOPCODE)&g_aMapX86_Group6[reg];
2063
2064 //little hack to make sure the ModRM byte is included in the returned size
2065 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2066 size = sizeof(uint8_t); //ModRM byte
2067
2068 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2069
2070 return size;
2071}
2072//*****************************************************************************
2073//*****************************************************************************
2074unsigned ParseGrp7(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2075{
2076 unsigned size = 0, modrm, reg, rm, mod;
2077
2078 modrm = DISReadByte(pCpu, lpszCodeBlock);
2079 mod = MODRM_MOD(modrm);
2080 reg = MODRM_REG(modrm);
2081 rm = MODRM_RM(modrm);
2082
2083 if (mod == 3 && rm == 0)
2084 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm000[reg];
2085 else
2086 if (mod == 3 && rm == 1)
2087 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm001[reg];
2088 else
2089 pOp = (PCOPCODE)&g_aMapX86_Group7_mem[reg];
2090
2091 //little hack to make sure the ModRM byte is included in the returned size
2092 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2093 size = sizeof(uint8_t); //ModRM byte
2094
2095 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2096
2097 return size;
2098}
2099//*****************************************************************************
2100//*****************************************************************************
2101unsigned ParseGrp8(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2102{
2103 unsigned size = 0, modrm, reg;
2104
2105 modrm = DISReadByte(pCpu, lpszCodeBlock);
2106 reg = MODRM_REG(modrm);
2107
2108 pOp = (PCOPCODE)&g_aMapX86_Group8[reg];
2109
2110 //little hack to make sure the ModRM byte is included in the returned size
2111 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2112 size = sizeof(uint8_t); //ModRM byte
2113
2114 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2115
2116 return size;
2117}
2118//*****************************************************************************
2119//*****************************************************************************
2120unsigned ParseGrp9(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2121{
2122 unsigned size = 0, modrm, reg;
2123
2124 modrm = DISReadByte(pCpu, lpszCodeBlock);
2125 reg = MODRM_REG(modrm);
2126
2127 pOp = (PCOPCODE)&g_aMapX86_Group9[reg];
2128
2129 //little hack to make sure the ModRM byte is included in the returned size
2130 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2131 size = sizeof(uint8_t); //ModRM byte
2132
2133 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2134
2135 return size;
2136}
2137//*****************************************************************************
2138//*****************************************************************************
2139unsigned ParseGrp10(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2140{
2141 unsigned size = 0, modrm, reg;
2142
2143 modrm = DISReadByte(pCpu, lpszCodeBlock);
2144 reg = MODRM_REG(modrm);
2145
2146 pOp = (PCOPCODE)&g_aMapX86_Group10[reg];
2147
2148 //little hack to make sure the ModRM byte is included in the returned size
2149 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2150 size = sizeof(uint8_t); //ModRM byte
2151
2152 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2153
2154 return size;
2155}
2156//*****************************************************************************
2157//*****************************************************************************
2158unsigned ParseGrp12(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2159{
2160 unsigned size = 0, modrm, reg;
2161
2162 modrm = DISReadByte(pCpu, lpszCodeBlock);
2163 reg = MODRM_REG(modrm);
2164
2165 if (pCpu->prefix & PREFIX_OPSIZE)
2166 reg += 8; //2nd table
2167
2168 pOp = (PCOPCODE)&g_aMapX86_Group12[reg];
2169
2170 //little hack to make sure the ModRM byte is included in the returned size
2171 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2172 size = sizeof(uint8_t); //ModRM byte
2173
2174 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2175 return size;
2176}
2177//*****************************************************************************
2178//*****************************************************************************
2179unsigned ParseGrp13(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2180{
2181 unsigned size = 0, modrm, reg;
2182
2183 modrm = DISReadByte(pCpu, lpszCodeBlock);
2184 reg = MODRM_REG(modrm);
2185 if (pCpu->prefix & PREFIX_OPSIZE)
2186 reg += 8; //2nd table
2187
2188 pOp = (PCOPCODE)&g_aMapX86_Group13[reg];
2189
2190 //little hack to make sure the ModRM byte is included in the returned size
2191 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2192 size = sizeof(uint8_t); //ModRM byte
2193
2194 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2195
2196 return size;
2197}
2198//*****************************************************************************
2199//*****************************************************************************
2200unsigned ParseGrp14(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2201{
2202 unsigned size = 0, modrm, reg;
2203
2204 modrm = DISReadByte(pCpu, lpszCodeBlock);
2205 reg = MODRM_REG(modrm);
2206 if (pCpu->prefix & PREFIX_OPSIZE)
2207 reg += 8; //2nd table
2208
2209 pOp = (PCOPCODE)&g_aMapX86_Group14[reg];
2210
2211 //little hack to make sure the ModRM byte is included in the returned size
2212 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2213 size = sizeof(uint8_t); //ModRM byte
2214
2215 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2216
2217 return size;
2218}
2219//*****************************************************************************
2220//*****************************************************************************
2221unsigned ParseGrp15(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2222{
2223 unsigned size = 0, modrm, reg, mod, rm;
2224
2225 modrm = DISReadByte(pCpu, lpszCodeBlock);
2226 mod = MODRM_MOD(modrm);
2227 reg = MODRM_REG(modrm);
2228 rm = MODRM_RM(modrm);
2229
2230 if (mod == 3 && rm == 0)
2231 pOp = (PCOPCODE)&g_aMapX86_Group15_mod11_rm000[reg];
2232 else
2233 pOp = (PCOPCODE)&g_aMapX86_Group15_mem[reg];
2234
2235 //little hack to make sure the ModRM byte is included in the returned size
2236 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2237 size = sizeof(uint8_t); //ModRM byte
2238
2239 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2240 return size;
2241}
2242//*****************************************************************************
2243//*****************************************************************************
2244unsigned ParseGrp16(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
2245{
2246 unsigned size = 0, modrm, reg;
2247
2248 modrm = DISReadByte(pCpu, lpszCodeBlock);
2249 reg = MODRM_REG(modrm);
2250
2251 pOp = (PCOPCODE)&g_aMapX86_Group16[reg];
2252
2253 //little hack to make sure the ModRM byte is included in the returned size
2254 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2255 size = sizeof(uint8_t); //ModRM byte
2256
2257 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2258 return size;
2259}
2260//*****************************************************************************
2261#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2262static const char *szModRMReg8[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B", "SPL", "BPL", "SIL", "DIL"};
2263static const char *szModRMReg16[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", "R8W", "R9W", "R10W", "R11W", "R12W", "R13W", "R14W", "R15W"};
2264static const char *szModRMReg32[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", "R8D", "R9D", "R10D", "R11D", "R12D", "R13D", "R14D", "R15D"};
2265static const char *szModRMReg64[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
2266static const char *szModRMReg1616[8] = {"BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX"};
2267#endif
2268static const char *szModRMSegReg[6] = {"ES", "CS", "SS", "DS", "FS", "GS"};
2269static const 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};
2270static const int IndexModRMReg16[4] = { USE_REG_SI, USE_REG_DI, USE_REG_SI, USE_REG_DI};
2271//*****************************************************************************
2272void disasmModRMReg(PDISCPUSTATE pCpu, PCOPCODE pOp, unsigned idx, POP_PARAMETER pParam, int fRegAddr)
2273{
2274 int subtype, type, mod;
2275
2276 mod = pCpu->ModRM.Bits.Mod;
2277
2278 type = OP_PARM_VTYPE(pParam->param);
2279 subtype = OP_PARM_VSUBTYPE(pParam->param);
2280 if (fRegAddr)
2281 subtype = (pCpu->addrmode == CPUMODE_64BIT) ? OP_PARM_q : OP_PARM_d;
2282 else
2283 if (subtype == OP_PARM_v || subtype == OP_PARM_NONE)
2284 {
2285 switch(pCpu->opmode)
2286 {
2287 case CPUMODE_32BIT:
2288 subtype = OP_PARM_d;
2289 break;
2290 case CPUMODE_64BIT:
2291 subtype = OP_PARM_q;
2292 break;
2293 case CPUMODE_16BIT:
2294 subtype = OP_PARM_w;
2295 break;
2296 default:
2297 /* make gcc happy */
2298 break;
2299 }
2300 }
2301
2302 switch (subtype)
2303 {
2304 case OP_PARM_b:
2305 Assert(idx < (pCpu->prefix & PREFIX_REX) ? 16 : 8);
2306
2307 /* AH, BH, CH & DH map to DIL, SIL, EBL & SPL when a rex prefix is present. */
2308 /* Intel® 64 and IA-32 Architectures Software Developer’s Manual: 3.4.1.1 */
2309 if ( (pCpu->prefix & PREFIX_REX)
2310 && idx >= USE_REG_AH
2311 && idx <= USE_REG_BH)
2312 {
2313 idx += (USE_REG_SPL - USE_REG_AH);
2314 }
2315 disasmAddString(pParam->szParam, szModRMReg8[idx]);
2316
2317 pParam->flags |= USE_REG_GEN8;
2318 pParam->base.reg_gen = idx;
2319 break;
2320
2321 case OP_PARM_w:
2322 disasmAddString(pParam->szParam, szModRMReg16[idx]);
2323 Assert(idx < (pCpu->prefix & PREFIX_REX) ? 16 : 8);
2324
2325 pParam->flags |= USE_REG_GEN16;
2326 pParam->base.reg_gen = idx;
2327 break;
2328
2329 case OP_PARM_d:
2330 disasmAddString(pParam->szParam, szModRMReg32[idx]);
2331 Assert(idx < (pCpu->prefix & PREFIX_REX) ? 16 : 8);
2332
2333 pParam->flags |= USE_REG_GEN32;
2334 pParam->base.reg_gen = idx;
2335 break;
2336
2337 case OP_PARM_q:
2338 disasmAddString(pParam->szParam, szModRMReg64[idx]);
2339 pParam->flags |= USE_REG_GEN64;
2340 pParam->base.reg_gen = idx;
2341 break;
2342
2343 default:
2344#ifdef IN_RING3
2345 Log(("disasmModRMReg %x:%x failed!!\n", type, subtype));
2346 DIS_THROW(ExceptionInvalidModRM);
2347#else
2348 AssertMsgFailed(("Oops!\n"));
2349#endif
2350 break;
2351 }
2352}
2353//*****************************************************************************
2354//*****************************************************************************
2355void disasmModRMReg16(PDISCPUSTATE pCpu, PCOPCODE pOp, unsigned idx, POP_PARAMETER pParam)
2356{
2357 disasmAddString(pParam->szParam, szModRMReg1616[idx]);
2358 pParam->flags |= USE_REG_GEN16;
2359 pParam->base.reg_gen = BaseModRMReg16[idx];
2360 if (idx < 4)
2361 {
2362 pParam->flags |= USE_INDEX;
2363 pParam->index.reg_gen = IndexModRMReg16[idx];
2364 }
2365}
2366//*****************************************************************************
2367//*****************************************************************************
2368void disasmModRMSReg(PDISCPUSTATE pCpu, PCOPCODE pOp, unsigned idx, POP_PARAMETER pParam)
2369{
2370#if 0 //def DEBUG_Sander
2371 AssertMsg(idx < ELEMENTS(szModRMSegReg), ("idx=%d\n", idx));
2372#endif
2373#ifdef IN_RING3
2374 if (idx >= ELEMENTS(szModRMSegReg))
2375 {
2376 Log(("disasmModRMSReg %d failed!!\n", idx));
2377 DIS_THROW(ExceptionInvalidParameter);
2378 }
2379#endif
2380
2381 idx = RT_MIN(idx, ELEMENTS(szModRMSegReg)-1);
2382 disasmAddString(pParam->szParam, szModRMSegReg[idx]);
2383 pParam->flags |= USE_REG_SEG;
2384 pParam->base.reg_seg = (DIS_SELREG)idx;
2385}
2386//*****************************************************************************
2387//*****************************************************************************
2388void disasmPrintAbs32(POP_PARAMETER pParam)
2389{
2390 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2391}
2392//*****************************************************************************
2393//*****************************************************************************
2394void disasmPrintDisp32(POP_PARAMETER pParam)
2395{
2396 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2397}
2398//*****************************************************************************
2399//*****************************************************************************
2400void disasmPrintDisp64(POP_PARAMETER pParam)
2401{
2402 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%16RX64h", pParam->disp64);
2403}
2404//*****************************************************************************
2405//*****************************************************************************
2406void disasmPrintDisp8(POP_PARAMETER pParam)
2407{
2408 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%d", pParam->disp8);
2409}
2410//*****************************************************************************
2411//*****************************************************************************
2412void disasmPrintDisp16(POP_PARAMETER pParam)
2413{
2414 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%04Xh", pParam->disp16);
2415}
2416//*****************************************************************************
2417//*****************************************************************************
2418void disasmGetPtrString(PDISCPUSTATE pCpu, PCOPCODE pOp, POP_PARAMETER pParam)
2419{
2420 int subtype = OP_PARM_VSUBTYPE(pParam->param);
2421
2422 if (subtype == OP_PARM_v)
2423 {
2424 switch(pCpu->opmode)
2425 {
2426 case CPUMODE_32BIT:
2427 subtype = OP_PARM_d;
2428 break;
2429 case CPUMODE_64BIT:
2430 subtype = OP_PARM_q;
2431 break;
2432 case CPUMODE_16BIT:
2433 subtype = OP_PARM_w;
2434 break;
2435 default:
2436 /* make gcc happy */
2437 break;
2438 }
2439 }
2440
2441 switch (subtype)
2442 {
2443 case OP_PARM_a: //two words or dwords depending on operand size (bound only)
2444 break;
2445
2446 case OP_PARM_b:
2447 disasmAddString(pParam->szParam, "byte ptr ");
2448 break;
2449
2450 case OP_PARM_w:
2451 disasmAddString(pParam->szParam, "word ptr ");
2452 break;
2453
2454 case OP_PARM_d:
2455 disasmAddString(pParam->szParam, "dword ptr ");
2456 break;
2457
2458 case OP_PARM_q:
2459 case OP_PARM_dq:
2460 disasmAddString(pParam->szParam, "qword ptr ");
2461 break;
2462
2463 case OP_PARM_p:
2464 disasmAddString(pParam->szParam, "far ptr ");
2465 break;
2466
2467 case OP_PARM_s:
2468 break; //??
2469
2470 case OP_PARM_z:
2471 break;
2472 default:
2473 break; //no pointer type specified/necessary
2474 }
2475 if (pCpu->prefix & PREFIX_SEG)
2476 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%s:", szModRMSegReg[pCpu->enmPrefixSeg]);
2477}
2478#ifndef IN_GC
2479//*****************************************************************************
2480/* Read functions for getting the opcode bytes */
2481//*****************************************************************************
2482uint8_t DISReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2483{
2484 if (pCpu->pfnReadBytes)
2485 {
2486 uint8_t temp = 0;
2487 int rc;
2488
2489 rc = pCpu->pfnReadBytes(pAddress, &temp, sizeof(temp), pCpu);
2490 if (VBOX_FAILURE(rc))
2491 {
2492 Log(("DISReadByte failed!!\n"));
2493 DIS_THROW(ExceptionMemRead);
2494 }
2495 return temp;
2496 }
2497#ifdef IN_RING0
2498 AssertMsgFailed(("DISReadByte with no read callback in ring 0!!\n"));
2499 return 0;
2500#else
2501 else return *(uint8_t *)pAddress;
2502#endif
2503}
2504//*****************************************************************************
2505//*****************************************************************************
2506uint16_t DISReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2507{
2508 if (pCpu->pfnReadBytes)
2509 {
2510 uint16_t temp = 0;
2511 int rc;
2512
2513 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2514 if (VBOX_FAILURE(rc))
2515 {
2516 Log(("DISReadWord failed!!\n"));
2517 DIS_THROW(ExceptionMemRead);
2518 }
2519 return temp;
2520 }
2521#ifdef IN_RING0
2522 AssertMsgFailed(("DISReadWord with no read callback in ring 0!!\n"));
2523 return 0;
2524#else
2525 else return *(uint16_t *)pAddress;
2526#endif
2527}
2528//*****************************************************************************
2529//*****************************************************************************
2530uint32_t DISReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2531{
2532 if (pCpu->pfnReadBytes)
2533 {
2534 uint32_t temp = 0;
2535 int rc;
2536
2537 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2538 if (VBOX_FAILURE(rc))
2539 {
2540 Log(("DISReadDWord failed!!\n"));
2541 DIS_THROW(ExceptionMemRead);
2542 }
2543 return temp;
2544 }
2545#ifdef IN_RING0
2546 AssertMsgFailed(("DISReadDWord with no read callback in ring 0!!\n"));
2547 return 0;
2548#else
2549 else return *(uint32_t *)pAddress;
2550#endif
2551}
2552//*****************************************************************************
2553//*****************************************************************************
2554uint64_t DISReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2555{
2556 if (pCpu->pfnReadBytes)
2557 {
2558 uint64_t temp = 0;
2559 int rc;
2560
2561 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2562 if (VBOX_FAILURE(rc))
2563 {
2564 Log(("DISReadQWord %x failed!!\n", pAddress));
2565 DIS_THROW(ExceptionMemRead);
2566 }
2567
2568 return temp;
2569 }
2570#ifdef IN_RING0
2571 AssertMsgFailed(("DISReadQWord with no read callback in ring 0!!\n"));
2572 return 0;
2573#else
2574 else return *(uint64_t *)pAddress;
2575#endif
2576}
2577#endif /* IN_GC */
2578
2579#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2580//*****************************************************************************
2581//*****************************************************************************
2582void disasmAddString(char *psz, const char *pszAdd)
2583{
2584 strcat(psz, pszAdd);
2585}
2586//*****************************************************************************
2587//*****************************************************************************
2588void disasmAddStringF(char *psz, uint32_t size, const char *pszFormat, ...)
2589{
2590 va_list args;
2591 va_start(args, pszFormat);
2592 RTStrPrintfV(psz + strlen(psz), size, pszFormat, args);
2593 va_end(args);
2594}
2595
2596//*****************************************************************************
2597//*****************************************************************************
2598void disasmAddChar(char *psz, char ch)
2599{
2600 char sz[2];
2601
2602 sz[0] = ch;
2603 sz[1] = '\0';
2604 strcat(psz, sz);
2605}
2606#endif /* !DIS_CORE_ONLY */
2607
2608
2609/**
2610 * Validates the lock sequence.
2611 *
2612 * The AMD manual lists the following instructions:
2613 * ADC
2614 * ADD
2615 * AND
2616 * BTC
2617 * BTR
2618 * BTS
2619 * CMPXCHG
2620 * CMPXCHG8B
2621 * CMPXCHG16B
2622 * DEC
2623 * INC
2624 * NEG
2625 * NOT
2626 * OR
2627 * SBB
2628 * SUB
2629 * XADD
2630 * XCHG
2631 * XOR
2632 *
2633 * @param pCpu Fully dissassembled instruction.
2634 */
2635void disValidateLockSequence(PDISCPUSTATE pCpu)
2636{
2637 Assert(pCpu->prefix & PREFIX_LOCK);
2638
2639 /*
2640 * Filter out the valid lock sequences.
2641 */
2642 switch (pCpu->pCurInstr->opcode)
2643 {
2644 /* simple: no variations */
2645 case OP_CMPXCHG8B: /* == OP_CMPXCHG16B? */
2646 return;
2647
2648 /* simple: /r - reject register destination. */
2649 case OP_BTC:
2650 case OP_BTR:
2651 case OP_BTS:
2652 case OP_CMPXCHG:
2653 case OP_XADD:
2654 if (pCpu->ModRM.Bits.Mod == 3)
2655 break;
2656 return;
2657
2658 /*
2659 * Lots of variants but its sufficient to check that param 1
2660 * is a memory operand.
2661 */
2662 case OP_ADC:
2663 case OP_ADD:
2664 case OP_AND:
2665 case OP_DEC:
2666 case OP_INC:
2667 case OP_NEG:
2668 case OP_NOT:
2669 case OP_OR:
2670 case OP_SBB:
2671 case OP_SUB:
2672 case OP_XCHG:
2673 case OP_XOR:
2674 if (pCpu->param1.flags & (USE_BASE | USE_INDEX | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16 | USE_DISPLACEMENT8 | USE_RIPDISPLACEMENT32))
2675 return;
2676 break;
2677
2678 default:
2679 break;
2680 }
2681
2682 /*
2683 * Invalid lock sequence, make it a OP_ILLUD2.
2684 */
2685 pCpu->pCurInstr = &g_aTwoByteMapX86[11];
2686 Assert(pCpu->pCurInstr->opcode == OP_ILLUD2);
2687}
2688
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use