VirtualBox

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

Last change on this file since 25414 was 21187, checked in by vboxsync, 15 years ago

Deal with operand size and mod default values for certain instructions (mov crx, mov drx)

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

© 2023 Oracle
ContactPrivacy policyTerms of Use