VirtualBox

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

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

Iz means sign extend to 64 bits, not zero extend.

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

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