VirtualBox

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

Last change on this file since 41049 was 40580, checked in by vboxsync, 13 years ago

The instruction address (opaddr) should include prefixes.

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