VirtualBox

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

Last change on this file since 38183 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

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

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