VirtualBox

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

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

More disassmbler updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.4 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};
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};
157
158/**
159 * Parses one instruction.
160 * The result is found in pCpu.
161 *
162 * @returns Success indicator.
163 * @param pCpu Pointer to cpu structure which has DISCPUSTATE::mode set correctly.
164 * @param InstructionAddr Pointer to the instruction to parse.
165 * @param pcbInstruction Where to store the size of the instruction.
166 * NULL is allowed.
167 */
168DISDECL(int) DISCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
169{
170 /*
171 * Reset instruction settings
172 */
173 pCpu->prefix = PREFIX_NONE;
174 pCpu->prefix_seg = 0;
175 pCpu->lastprefix = 0;
176 pCpu->addrmode = pCpu->mode;
177 pCpu->opmode = pCpu->mode;
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->prefix_seg = 0;
221 pCpu->lastprefix = 0;
222 pCpu->mode = enmCpuMode;
223 pCpu->addrmode = enmCpuMode;
224 pCpu->opmode = 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 /*
258 * Parse byte by byte.
259 */
260 unsigned iByte = 0;
261 unsigned cbInc;
262
263 while(1)
264 {
265 uint8_t codebyte = DISReadByte(pCpu, InstructionAddr+iByte);
266 uint8_t opcode = g_aOneByteMapX86[codebyte].opcode;
267
268 /* Hardcoded assumption about OP_* values!! */
269 if (opcode <= OP_LOCK)
270 {
271 pCpu->lastprefix = opcode;
272
273 /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
274 if (opcode != OP_REX)
275 pCpu->prefix &= ~PREFIX_REX;
276
277 switch (opcode)
278 {
279 case OP_INVALID:
280 AssertMsgFailed(("Invalid opcode!!\n"));
281 return VERR_GENERAL_FAILURE; /** @todo better error code. */
282
283 // segment override prefix byte
284 case OP_SEG:
285 pCpu->prefix_seg = g_aOneByteMapX86[codebyte].param1 - OP_PARM_REG_SEG_START;
286 pCpu->prefix |= PREFIX_SEG;
287 iByte += sizeof(uint8_t);
288 continue; //fetch the next byte
289
290 // lock prefix byte
291 case OP_LOCK:
292 pCpu->prefix |= PREFIX_LOCK;
293 iByte += sizeof(uint8_t);
294 continue; //fetch the next byte
295
296 // address size override prefix byte
297 case OP_ADRSIZE:
298 pCpu->prefix |= PREFIX_ADDRSIZE;
299 if (pCpu->mode == CPUMODE_16BIT)
300 pCpu->addrmode = CPUMODE_32BIT;
301 else pCpu->addrmode = CPUMODE_16BIT;
302 iByte += sizeof(uint8_t);
303 continue; //fetch the next byte
304
305 // operand size override prefix byte
306 case OP_OPSIZE:
307 pCpu->prefix |= PREFIX_OPSIZE;
308 if (pCpu->mode == CPUMODE_16BIT)
309 pCpu->opmode = CPUMODE_32BIT;
310 else pCpu->opmode = CPUMODE_16BIT;
311
312 iByte += sizeof(uint8_t);
313 continue; //fetch the next byte
314
315 // rep and repne are not really prefixes, but we'll treat them as such
316 case OP_REPE:
317 pCpu->prefix |= PREFIX_REP;
318 iByte += sizeof(uint8_t);
319 continue; //fetch the next byte
320
321 case OP_REPNE:
322 pCpu->prefix |= PREFIX_REPNE;
323 iByte += sizeof(uint8_t);
324 continue; //fetch the next byte
325
326 case OP_REX:
327 Assert(pCpu->mode == CPUMODE_64BIT);
328 /* REX prefix byte */
329 pCpu->prefix |= PREFIX_REX;
330 pCpu->prefix_rex = PREFIX_REX_OP_2_FLAGS(opcode);
331
332 if (pCpu->prefix_rex & PREFIX_REX_FLAGS_W)
333 pCpu->opmode = CPUMODE_64BIT; /* overrides size prefix byte */
334 break;
335 }
336 }
337
338 unsigned uIdx = iByte;
339 iByte += sizeof(uint8_t); //first opcode byte
340
341 pCpu->opaddr = InstructionAddr + uIdx;
342 pCpu->opcode = codebyte;
343
344 if (pCpu->mode == CPUMODE_64BIT)
345 cbInc = ParseInstruction(InstructionAddr + iByte, &g_aOneByteMapX64[pCpu->opcode], pCpu);
346 else
347 cbInc = ParseInstruction(InstructionAddr + iByte, &g_aOneByteMapX86[pCpu->opcode], pCpu);
348
349 iByte += cbInc;
350 break;
351 }
352
353 pCpu->opsize = iByte;
354 if (pcbInstruction)
355 *pcbInstruction = iByte;
356
357 return VINF_SUCCESS;
358}
359//*****************************************************************************
360//*****************************************************************************
361unsigned ParseInstruction(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, PDISCPUSTATE pCpu)
362{
363 int size = 0;
364 bool fFiltered = false;
365
366 // Store the opcode format string for disasmPrintf
367#ifndef DIS_CORE_ONLY
368 pCpu->pszOpcode = pOp->pszOpcode;
369#endif
370 pCpu->pCurInstr = pOp;
371
372 /*
373 * Apply filter to instruction type to determine if a full disassembly is required.
374 * @note Multibyte opcodes are always marked harmless until the final byte.
375 */
376 if ((pOp->optype & pCpu->uFilter) == 0)
377 {
378 fFiltered = true;
379 pCpu->pfnDisasmFnTable = pfnCalcSize;
380 }
381 else
382 {
383 /* Not filtered out -> full disassembly */
384 pCpu->pfnDisasmFnTable = pfnFullDisasm;
385 }
386
387 // Should contain the parameter type on input
388 pCpu->param1.param = pOp->param1;
389 pCpu->param2.param = pOp->param2;
390 pCpu->param3.param = pOp->param3;
391
392 if (pOp->idxParse1 != IDX_ParseNop)
393 {
394 size += pCpu->pfnDisasmFnTable[pOp->idxParse1](lpszCodeBlock, pOp, &pCpu->param1, pCpu);
395 if (fFiltered == false) pCpu->param1.size = DISGetParamSize(pCpu, &pCpu->param1);
396 }
397
398 if (pOp->idxParse2 != IDX_ParseNop)
399 {
400 size += pCpu->pfnDisasmFnTable[pOp->idxParse2](lpszCodeBlock+size, pOp, &pCpu->param2, pCpu);
401 if (fFiltered == false) pCpu->param2.size = DISGetParamSize(pCpu, &pCpu->param2);
402 }
403
404 if (pOp->idxParse3 != IDX_ParseNop)
405 {
406 size += pCpu->pfnDisasmFnTable[pOp->idxParse3](lpszCodeBlock+size, pOp, &pCpu->param3, pCpu);
407 if (fFiltered == false) pCpu->param3.size = DISGetParamSize(pCpu, &pCpu->param3);
408 }
409 // else simple one byte instruction
410
411 return size;
412}
413//*****************************************************************************
414/* Floating point opcode parsing */
415//*****************************************************************************
416unsigned ParseEscFP(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
417{
418 int index;
419 const OPCODE *fpop;
420 unsigned size = 0, ModRM;
421
422 ModRM = DISReadByte(pCpu, lpszCodeBlock);
423
424 index = pCpu->opcode - 0xD8;
425 if (ModRM <= 0xBF)
426 {
427 fpop = &(g_paMapX86_FP_Low[index])[MODRM_REG(ModRM)];
428 pCpu->pCurInstr = (PCOPCODE)fpop;
429
430 // Should contain the parameter type on input
431 pCpu->param1.parval = fpop->param1;
432 pCpu->param2.parval = fpop->param2;
433 }
434 else
435 {
436 fpop = &(g_paMapX86_FP_High[index])[ModRM - 0xC0];
437 pCpu->pCurInstr = (PCOPCODE)fpop;
438 }
439
440 /*
441 * Apply filter to instruction type to determine if a full disassembly is required.
442 * @note Multibyte opcodes are always marked harmless until the final byte.
443 */
444 if ((fpop->optype & pCpu->uFilter) == 0)
445 {
446 pCpu->pfnDisasmFnTable = pfnCalcSize;
447 }
448 else
449 {
450 /* Not filtered out -> full disassembly */
451 pCpu->pfnDisasmFnTable = pfnFullDisasm;
452 }
453
454 // Little hack to make sure the ModRM byte is included in the returned size
455 if (fpop->idxParse1 != IDX_ParseModRM && fpop->idxParse2 != IDX_ParseModRM)
456 size = sizeof(uint8_t); //ModRM byte
457
458 if (fpop->idxParse1 != IDX_ParseNop)
459 size += pCpu->pfnDisasmFnTable[fpop->idxParse1](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
460
461 if (fpop->idxParse2 != IDX_ParseNop)
462 size += pCpu->pfnDisasmFnTable[fpop->idxParse2](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
463
464 // Store the opcode format string for disasmPrintf
465#ifndef DIS_CORE_ONLY
466 pCpu->pszOpcode = fpop->pszOpcode;
467#endif
468
469 return size;
470}
471//*****************************************************************************
472// SIB byte: (32 bits mode only)
473// 7 - 6 5 - 3 2-0
474// Scale Index Base
475//*****************************************************************************
476const char *szSIBBaseReg[8] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
477const char *szSIBIndexReg[8] = {"EAX", "ECX", "EDX", "EBX", NULL, "EBP", "ESI", "EDI"};
478const char *szSIBScale[4] = {"", "*2", "*4", "*8"};
479
480//*****************************************************************************
481void UseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
482{
483 unsigned scale, base, index;
484 char szTemp[32];
485 szTemp[0] = '\0';
486
487 scale = pCpu->SIB.Bits.Scale;
488 base = pCpu->SIB.Bits.Base;
489 index = pCpu->SIB.Bits.Index;
490
491 if (szSIBIndexReg[index])
492 {
493 pParam->flags |= USE_INDEX;
494 pParam->index.reg_gen = index;
495
496 if (scale != 0)
497 {
498 pParam->flags |= USE_SCALE;
499 pParam->scale = (1<<scale);
500 }
501
502 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
503 disasmAddStringF(szTemp, sizeof(szTemp), "%s%s", szSIBIndexReg[index], szSIBScale[scale]);
504 else
505 disasmAddStringF(szTemp, sizeof(szTemp), "%s+%s%s", szSIBBaseReg[base], szSIBIndexReg[index], szSIBScale[scale]);
506 }
507 else
508 {
509 if (base != 5 || pCpu->ModRM.Bits.Mod != 0)
510 disasmAddStringF(szTemp, sizeof(szTemp), "%s", szSIBBaseReg[base]);
511 }
512
513 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
514 {
515 // [scaled index] + disp32
516 disasmAddString(pParam->szParam, &szTemp[0]);
517 pParam->flags |= USE_DISPLACEMENT32;
518 pParam->disp32 = pCpu->disp;
519 disasmAddChar(pParam->szParam, '+');
520 disasmPrintDisp32(pParam);
521 }
522 else
523 {
524 disasmAddString(pParam->szParam, szTemp);
525
526 pParam->flags |= USE_BASE | USE_REG_GEN32;
527 pParam->base.reg_gen = base;
528 }
529 return; /* Already fetched everything in ParseSIB; no size returned */
530}
531//*****************************************************************************
532//*****************************************************************************
533unsigned ParseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
534{
535 unsigned size = sizeof(uint8_t);
536 unsigned SIB;
537
538 SIB = DISReadByte(pCpu, lpszCodeBlock);
539 lpszCodeBlock += size;
540
541 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
542 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
543 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
544
545 if (pCpu->prefix & PREFIX_REX)
546 {
547 /* REX.B extends the Base field if not scaled index + disp32 */
548 if (!(pCpu->SIB.Bits.Base == 5 && pCpu->ModRM.Bits.Mod == 0))
549 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
550
551 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
552 }
553
554 if ( pCpu->SIB.Bits.Base == 5
555 && pCpu->ModRM.Bits.Mod == 0)
556 {
557 /* Additional 32 bits displacement. No change in long mode. */
558 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
559 size += sizeof(int32_t);
560 }
561 return size;
562}
563//*****************************************************************************
564//*****************************************************************************
565unsigned ParseSIB_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
566{
567 unsigned size = sizeof(uint8_t);
568 unsigned SIB;
569
570 SIB = DISReadByte(pCpu, lpszCodeBlock);
571 lpszCodeBlock += size;
572
573 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
574 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
575 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
576
577 if (pCpu->prefix & PREFIX_REX)
578 {
579 /* REX.B extends the Base field. */
580 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
581 /* REX.X extends the Index field. */
582 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
583 }
584
585 if ( pCpu->SIB.Bits.Base == 5
586 && pCpu->ModRM.Bits.Mod == 0)
587 {
588 /* Additional 32 bits displacement. No change in long mode. */
589 size += sizeof(int32_t);
590 }
591 return size;
592}
593//*****************************************************************************
594// ModR/M byte:
595// 7 - 6 5 - 3 2-0
596// Mod Reg/Opcode R/M
597//*****************************************************************************
598unsigned UseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
599{
600 int vtype = OP_PARM_VTYPE(pParam->param);
601 unsigned reg = pCpu->ModRM.Bits.Reg;
602 unsigned mod = pCpu->ModRM.Bits.Mod;
603 unsigned rm = pCpu->ModRM.Bits.Rm;
604
605 switch (vtype)
606 {
607 case OP_PARM_G: //general purpose register
608 disasmModRMReg(pCpu, pOp, reg, pParam, 0);
609 return 0;
610
611 default:
612 if (IS_OP_PARM_RARE(vtype))
613 {
614 switch (vtype)
615 {
616 case OP_PARM_C: //control register
617 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "CR%d", reg);
618 pParam->flags |= USE_REG_CR;
619 pParam->base.reg_ctrl = reg;
620 return 0;
621
622 case OP_PARM_D: //debug register
623 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "DR%d", reg);
624 pParam->flags |= USE_REG_DBG;
625 pParam->base.reg_dbg = reg;
626 return 0;
627
628 case OP_PARM_P: //MMX register
629 reg &= 7; /* REX.R has no effect here */
630 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "MM%d", reg);
631 pParam->flags |= USE_REG_MMX;
632 pParam->base.reg_mmx = reg;
633 return 0;
634
635 case OP_PARM_S: //segment register
636 reg &= 7; /* REX.R has no effect here */
637 disasmModRMSReg(pCpu, pOp, reg, pParam);
638 pParam->flags |= USE_REG_SEG;
639 return 0;
640
641 case OP_PARM_T: //test register
642 reg &= 7; /* REX.R has no effect here */
643 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "TR%d", reg);
644 pParam->flags |= USE_REG_TEST;
645 pParam->base.reg_test = reg;
646 return 0;
647
648 case OP_PARM_W: //XMM register or memory operand
649 if (mod != 3)
650 break; /* memory operand */
651 /* else no break */
652 case OP_PARM_V: //XMM register
653 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "XMM%d", reg);
654 pParam->flags |= USE_REG_XMM;
655 pParam->base.reg_xmm = reg;
656 return 0;
657 }
658 }
659 }
660
661 /* @todo bound */
662
663 if (pCpu->addrmode != CPUMODE_16BIT)
664 {
665 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
666
667 /*
668 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
669 */
670 switch (mod)
671 {
672 case 0: //effective address
673 disasmGetPtrString(pCpu, pOp, pParam);
674 disasmAddChar(pParam->szParam, '[');
675 if (rm == 4)
676 { /* SIB byte follows ModRM */
677 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
678 }
679 else
680 if (rm == 5)
681 {
682 /* 32 bits displacement */
683 if (pCpu->mode == CPUMODE_32BIT)
684 {
685 pParam->flags |= USE_DISPLACEMENT32;
686 pParam->disp32 = pCpu->disp;
687 disasmPrintDisp32(pParam);
688 }
689 else
690 {
691 pParam->flags |= USE_RIPDISPLACEMENT32;
692 pParam->disp32 = pCpu->disp;
693 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "RIP+");
694 disasmPrintDisp32(pParam);
695 }
696 }
697 else {//register address
698 pParam->flags |= USE_BASE;
699 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
700 }
701 disasmAddChar(pParam->szParam, ']');
702 break;
703
704 case 1: //effective address + 8 bits displacement
705 disasmGetPtrString(pCpu, pOp, pParam);
706 disasmAddChar(pParam->szParam, '[');
707 if (rm == 4) {//SIB byte follows ModRM
708 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
709 }
710 else
711 {
712 pParam->flags |= USE_BASE;
713 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
714 }
715 pParam->disp8 = pCpu->disp;
716 pParam->flags |= USE_DISPLACEMENT8;
717
718 if (pParam->disp8 != 0)
719 {
720 if (pParam->disp8 > 0)
721 disasmAddChar(pParam->szParam, '+');
722 disasmPrintDisp8(pParam);
723 }
724 disasmAddChar(pParam->szParam, ']');
725 break;
726
727 case 2: //effective address + 32 bits displacement
728 disasmGetPtrString(pCpu, pOp, pParam);
729 disasmAddChar(pParam->szParam, '[');
730 if (rm == 4) {//SIB byte follows ModRM
731 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
732 }
733 else
734 {
735 pParam->flags |= USE_BASE;
736 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
737 }
738 pParam->disp32 = pCpu->disp;
739 pParam->flags |= USE_DISPLACEMENT32;
740
741 if (pParam->disp32 != 0)
742 {
743 disasmAddChar(pParam->szParam, '+');
744 disasmPrintDisp32(pParam);
745 }
746 disasmAddChar(pParam->szParam, ']');
747 break;
748
749 case 3: //registers
750 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
751 break;
752 }
753 }
754 else
755 {//16 bits addressing mode
756 switch (mod)
757 {
758 case 0: //effective address
759 disasmGetPtrString(pCpu, pOp, pParam);
760 disasmAddChar(pParam->szParam, '[');
761 if (rm == 6)
762 {//16 bits displacement
763 pParam->disp16 = pCpu->disp;
764 pParam->flags |= USE_DISPLACEMENT16;
765 disasmPrintDisp16(pParam);
766 }
767 else
768 {
769 pParam->flags |= USE_BASE;
770 disasmModRMReg16(pCpu, pOp, rm, pParam);
771 }
772 disasmAddChar(pParam->szParam, ']');
773 break;
774
775 case 1: //effective address + 8 bits displacement
776 disasmGetPtrString(pCpu, pOp, pParam);
777 disasmAddChar(pParam->szParam, '[');
778 disasmModRMReg16(pCpu, pOp, rm, pParam);
779 pParam->disp8 = pCpu->disp;
780 pParam->flags |= USE_BASE | USE_DISPLACEMENT8;
781
782 if (pParam->disp8 != 0)
783 {
784 if (pParam->disp8 > 0)
785 disasmAddChar(pParam->szParam, '+');
786 disasmPrintDisp8(pParam);
787 }
788 disasmAddChar(pParam->szParam, ']');
789 break;
790
791 case 2: //effective address + 16 bits displacement
792 disasmGetPtrString(pCpu, pOp, pParam);
793 disasmAddChar(pParam->szParam, '[');
794 disasmModRMReg16(pCpu, pOp, rm, pParam);
795 pParam->disp16 = pCpu->disp;
796 pParam->flags |= USE_BASE | USE_DISPLACEMENT16;
797
798 if (pParam->disp16 != 0)
799 {
800 disasmAddChar(pParam->szParam, '+');
801 disasmPrintDisp16(pParam);
802 }
803 disasmAddChar(pParam->szParam, ']');
804 break;
805
806 case 3: //registers
807 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
808 break;
809 }
810 }
811 return 0; //everything was already fetched in ParseModRM
812}
813//*****************************************************************************
814// Query the size of the ModRM parameters and fetch the immediate data (if any)
815//*****************************************************************************
816unsigned QueryModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
817{
818 unsigned sibinc;
819 unsigned size = 0;
820 unsigned reg = pCpu->ModRM.Bits.Reg;
821 unsigned mod = pCpu->ModRM.Bits.Mod;
822 unsigned rm = pCpu->ModRM.Bits.Rm;
823
824 if (!pSibInc)
825 pSibInc = &sibinc;
826
827 *pSibInc = 0;
828
829 if (pCpu->addrmode != CPUMODE_16BIT)
830 {
831 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
832
833 /*
834 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
835 */
836 if (mod != 3 && rm == 4)
837 { /* SIB byte follows ModRM */
838 *pSibInc = ParseSIB(lpszCodeBlock, pOp, pParam, pCpu);
839 lpszCodeBlock += *pSibInc;
840 size += *pSibInc;
841 }
842
843 switch (mod)
844 {
845 case 0: /* Effective address */
846 if (rm == 5) { /* 32 bits displacement */
847 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
848 size += sizeof(int32_t);
849 }
850 /* else register address */
851 break;
852
853 case 1: /* Effective address + 8 bits displacement */
854 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
855 size += sizeof(char);
856 break;
857
858 case 2: /* Effective address + 32 bits displacement */
859 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
860 size += sizeof(int32_t);
861 break;
862
863 case 3: /* registers */
864 break;
865 }
866 }
867 else
868 {
869 /* 16 bits mode */
870 switch (mod)
871 {
872 case 0: /* Effective address */
873 if (rm == 6) {
874 pCpu->disp = DISReadWord(pCpu, lpszCodeBlock);
875 size += sizeof(uint16_t);
876 }
877 /* else register address */
878 break;
879
880 case 1: /* Effective address + 8 bits displacement */
881 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
882 size += sizeof(char);
883 break;
884
885 case 2: /* Effective address + 32 bits displacement */
886 pCpu->disp = (int16_t)DISReadWord(pCpu, lpszCodeBlock);
887 size += sizeof(uint16_t);
888 break;
889
890 case 3: /* registers */
891 break;
892 }
893 }
894 return size;
895}
896//*****************************************************************************
897// Query the size of the ModRM parameters and fetch the immediate data (if any)
898//*****************************************************************************
899unsigned QueryModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
900{
901 unsigned sibinc;
902 unsigned size = 0;
903 unsigned reg = pCpu->ModRM.Bits.Reg;
904 unsigned mod = pCpu->ModRM.Bits.Mod;
905 unsigned rm = pCpu->ModRM.Bits.Rm;
906
907 if (!pSibInc)
908 pSibInc = &sibinc;
909
910 *pSibInc = 0;
911
912 if (pCpu->addrmode != CPUMODE_16BIT)
913 {
914 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
915 /*
916 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
917 */
918 if (mod != 3 && rm == 4)
919 { /* SIB byte follows ModRM */
920 *pSibInc = ParseSIB_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu);
921 lpszCodeBlock += *pSibInc;
922 size += *pSibInc;
923 }
924
925 switch (mod)
926 {
927 case 0: //effective address
928 if (rm == 5) { /* 32 bits displacement */
929 size += sizeof(int32_t);
930 }
931 /* else register address */
932 break;
933
934 case 1: /* Effective address + 8 bits displacement */
935 size += sizeof(char);
936 break;
937
938 case 2: /* Effective address + 32 bits displacement */
939 size += sizeof(int32_t);
940 break;
941
942 case 3: /* registers */
943 break;
944 }
945 }
946 else
947 {
948 /* 16 bits mode */
949 switch (mod)
950 {
951 case 0: //effective address
952 if (rm == 6) {
953 size += sizeof(uint16_t);
954 }
955 /* else register address */
956 break;
957
958 case 1: /* Effective address + 8 bits displacement */
959 size += sizeof(char);
960 break;
961
962 case 2: /* Effective address + 32 bits displacement */
963 size += sizeof(uint16_t);
964 break;
965
966 case 3: /* registers */
967 break;
968 }
969 }
970 return size;
971}
972//*****************************************************************************
973//*****************************************************************************
974unsigned ParseIllegal(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
975{
976 AssertFailed();
977 return 0;
978}
979//*****************************************************************************
980//*****************************************************************************
981unsigned ParseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
982{
983 unsigned size = sizeof(uint8_t); //ModRM byte
984 unsigned sibinc, ModRM;
985
986 ModRM = DISReadByte(pCpu, lpszCodeBlock);
987 lpszCodeBlock += sizeof(uint8_t);
988
989 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
990 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
991 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
992
993 if (pCpu->prefix & PREFIX_REX)
994 {
995 Assert(pCpu->mode == CPUMODE_64BIT);
996
997 /* REX.R extends the Reg field. */
998 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
999
1000 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1001 if (!( pCpu->ModRM.Bits.Mod != 3
1002 && pCpu->ModRM.Bits.Rm == 4)
1003 &&
1004 !( pCpu->ModRM.Bits.Mod == 0
1005 && pCpu->ModRM.Bits.Rm == 5))
1006 {
1007 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1008 }
1009 }
1010 size += QueryModRM(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1011 lpszCodeBlock += sibinc;
1012
1013 UseModRM(lpszCodeBlock, pOp, pParam, pCpu);
1014 return size;
1015}
1016//*****************************************************************************
1017//*****************************************************************************
1018unsigned ParseModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1019{
1020 unsigned size = sizeof(uint8_t); //ModRM byte
1021 unsigned sibinc, ModRM;
1022
1023 ModRM = DISReadByte(pCpu, lpszCodeBlock);
1024 lpszCodeBlock += sizeof(uint8_t);
1025
1026 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1027 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1028 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1029
1030 if (pCpu->prefix & PREFIX_REX)
1031 {
1032 Assert(pCpu->mode == CPUMODE_64BIT);
1033
1034 /* REX.R extends the Reg field. */
1035 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
1036
1037 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1038 if (!( pCpu->ModRM.Bits.Mod != 3
1039 && pCpu->ModRM.Bits.Rm == 4)
1040 &&
1041 !( pCpu->ModRM.Bits.Mod == 0
1042 && pCpu->ModRM.Bits.Rm == 5))
1043 {
1044 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1045 }
1046 }
1047
1048 size += QueryModRM_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1049 lpszCodeBlock += sibinc;
1050
1051 /* UseModRM is not necessary here; we're only interested in the opcode size */
1052 return size;
1053}
1054//*****************************************************************************
1055//*****************************************************************************
1056unsigned ParseModFence(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1057{
1058 ////AssertMsgFailed(("??\n"));
1059 //nothing to do apparently
1060 return 0;
1061}
1062//*****************************************************************************
1063//*****************************************************************************
1064unsigned ParseImmByte(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1065{
1066 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1067 pParam->flags |= USE_IMMEDIATE8;
1068
1069 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%02Xh", (uint32_t)pParam->parval);
1070 return sizeof(uint8_t);
1071}
1072//*****************************************************************************
1073//*****************************************************************************
1074unsigned ParseImmByte_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1075{
1076 return sizeof(uint8_t);
1077}
1078//*****************************************************************************
1079//*****************************************************************************
1080unsigned ParseImmByteSX(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1081{
1082 if (pCpu->opmode == CPUMODE_32BIT)
1083 {
1084 pParam->parval = (uint32_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1085 pParam->flags |= USE_IMMEDIATE32_SX8;
1086 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1087 }
1088 else
1089 {
1090 pParam->parval = (uint16_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1091 pParam->flags |= USE_IMMEDIATE16_SX8;
1092 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1093 }
1094 return sizeof(uint8_t);
1095}
1096//*****************************************************************************
1097//*****************************************************************************
1098unsigned ParseImmByteSX_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1099{
1100 return sizeof(uint8_t);
1101}
1102//*****************************************************************************
1103//*****************************************************************************
1104unsigned ParseImmUshort(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1105{
1106 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1107 pParam->flags |= USE_IMMEDIATE16;
1108
1109 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1110 return sizeof(uint16_t);
1111}
1112//*****************************************************************************
1113//*****************************************************************************
1114unsigned ParseImmUshort_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1115{
1116 return sizeof(uint16_t);
1117}
1118//*****************************************************************************
1119//*****************************************************************************
1120unsigned ParseImmUlong(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1121{
1122 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1123 pParam->flags |= USE_IMMEDIATE32;
1124
1125 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1126 return sizeof(uint32_t);
1127}
1128//*****************************************************************************
1129//*****************************************************************************
1130unsigned ParseImmUlong_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1131{
1132 return sizeof(uint32_t);
1133}
1134//*****************************************************************************
1135//*****************************************************************************
1136unsigned ParseImmQword(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1137{
1138 pParam->parval = DISReadQWord(pCpu, lpszCodeBlock);
1139 pParam->flags |= USE_IMMEDIATE64;
1140
1141 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08X", (uint32_t)pParam->parval);
1142 disasmAddStringF(&pParam->szParam[9], sizeof(pParam->szParam)-9, "%08Xh", (uint32_t)(pParam->parval >> 32));
1143 return sizeof(uint64_t);
1144}
1145//*****************************************************************************
1146//*****************************************************************************
1147unsigned ParseImmQword_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1148{
1149 return sizeof(uint64_t);
1150}
1151//*****************************************************************************
1152//*****************************************************************************
1153unsigned ParseImmV(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1154{
1155 if (pCpu->opmode == CPUMODE_32BIT)
1156 {
1157 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1158 pParam->flags |= USE_IMMEDIATE32;
1159
1160 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1161 return sizeof(uint32_t);
1162 }
1163 else
1164 {
1165 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1166 pParam->flags |= USE_IMMEDIATE16;
1167
1168 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint32_t)pParam->parval);
1169 return sizeof(uint16_t);
1170 }
1171}
1172//*****************************************************************************
1173//*****************************************************************************
1174unsigned ParseImmV_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1175{
1176 if (pCpu->opmode == CPUMODE_32BIT)
1177 return sizeof(uint32_t);
1178 return sizeof(uint16_t);
1179}
1180//*****************************************************************************
1181// Relative displacement for branches (rel. to next instruction)
1182//*****************************************************************************
1183unsigned ParseImmBRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1184{
1185 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1186 pParam->flags |= USE_IMMEDIATE8_REL;
1187
1188 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%02Xh)", (uint32_t)pParam->parval);
1189 return sizeof(char);
1190}
1191//*****************************************************************************
1192// Relative displacement for branches (rel. to next instruction)
1193//*****************************************************************************
1194unsigned ParseImmBRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1195{
1196 return sizeof(char);
1197}
1198//*****************************************************************************
1199// Relative displacement for branches (rel. to next instruction)
1200//*****************************************************************************
1201unsigned ParseImmVRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1202{
1203 if (pCpu->opmode == CPUMODE_32BIT)
1204 {
1205 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1206 pParam->flags |= USE_IMMEDIATE32_REL;
1207
1208 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%08Xh)", (uint32_t)pParam->parval);
1209 return sizeof(int32_t);
1210 }
1211 else
1212 {
1213 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1214 pParam->flags |= USE_IMMEDIATE16_REL;
1215
1216 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%04Xh)", (uint32_t)pParam->parval);
1217 return sizeof(uint16_t);
1218 }
1219}
1220//*****************************************************************************
1221// Relative displacement for branches (rel. to next instruction)
1222//*****************************************************************************
1223unsigned ParseImmVRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1224{
1225 if (pCpu->opmode == CPUMODE_32BIT)
1226 return sizeof(int32_t);
1227 return sizeof(uint16_t);
1228}
1229//*****************************************************************************
1230//*****************************************************************************
1231unsigned ParseImmAddr(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1232{
1233 disasmGetPtrString(pCpu, pOp, pParam);
1234 if (pCpu->addrmode == CPUMODE_32BIT)
1235 {
1236 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1237 {// far 16:32 pointer
1238 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1239 *((uint32_t*)&pParam->parval+1) = DISReadWord(pCpu, lpszCodeBlock+sizeof(uint32_t));
1240 pParam->flags |= USE_IMMEDIATE_ADDR_16_32;
1241
1242 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%08Xh", (uint32_t)(pParam->parval>>32), (uint32_t)pParam->parval);
1243 return sizeof(uint32_t) + sizeof(uint16_t);
1244 }
1245 else
1246 {// near 32 bits pointer
1247 /*
1248 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1249 * so we treat it like displacement.
1250 */
1251 pParam->disp32 = DISReadDWord(pCpu, lpszCodeBlock);
1252 pParam->flags |= USE_DISPLACEMENT32;
1253
1254 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08Xh]", pParam->disp32);
1255 return sizeof(uint32_t);
1256 }
1257 }
1258 else
1259 if (pCpu->addrmode == CPUMODE_64BIT)
1260 {
1261 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1262 /* near 64 bits pointer */
1263 /*
1264 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1265 * so we treat it like displacement.
1266 */
1267 pParam->disp64 = DISReadQWord(pCpu, lpszCodeBlock);
1268 pParam->flags |= USE_DISPLACEMENT64;
1269
1270 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08X%08Xh]", (uint32_t)(pParam->disp64 >> 32), (uint32_t)pParam->disp64);
1271 return sizeof(uint64_t);
1272 }
1273 else
1274 {
1275 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1276 {// far 16:16 pointer
1277 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1278 pParam->flags |= USE_IMMEDIATE_ADDR_16_16;
1279
1280 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%04Xh", (uint32_t)(pParam->parval>>16), (uint16_t)pParam->parval );
1281 return sizeof(uint32_t);
1282 }
1283 else
1284 {// near 16 bits pointer
1285 /*
1286 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1287 * so we treat it like displacement.
1288 */
1289 pParam->disp16 = DISReadWord(pCpu, lpszCodeBlock);
1290 pParam->flags |= USE_DISPLACEMENT16;
1291
1292 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%04Xh]", (uint32_t)pParam->disp16);
1293 return sizeof(uint16_t);
1294 }
1295 }
1296}
1297//*****************************************************************************
1298//*****************************************************************************
1299unsigned ParseImmAddr_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1300{
1301 if (pCpu->addrmode == CPUMODE_32BIT)
1302 {
1303 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1304 {// far 16:32 pointer
1305 return sizeof(uint32_t) + sizeof(uint16_t);
1306 }
1307 else
1308 {// near 32 bits pointer
1309 return sizeof(uint32_t);
1310 }
1311 }
1312 if (pCpu->addrmode == CPUMODE_64BIT)
1313 {
1314 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1315 return sizeof(uint64_t);
1316 }
1317 else
1318 {
1319 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1320 {// far 16:16 pointer
1321 return sizeof(uint32_t);
1322 }
1323 else
1324 {// near 16 bits pointer
1325 return sizeof(uint16_t);
1326 }
1327 }
1328}
1329//*****************************************************************************
1330//*****************************************************************************
1331unsigned ParseFixedReg(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1332{
1333 /*
1334 * Sets up flags for stored in OPC fixed registers.
1335 */
1336
1337 if (pParam->param == OP_PARM_NONE)
1338 {
1339 /* No parameter at all. */
1340 return 0;
1341 }
1342
1343 AssertCompile(OP_PARM_REG_GEN32_END < OP_PARM_REG_SEG_END);
1344 AssertCompile(OP_PARM_REG_SEG_END < OP_PARM_REG_GEN16_END);
1345 AssertCompile(OP_PARM_REG_GEN16_END < OP_PARM_REG_GEN8_END);
1346 AssertCompile(OP_PARM_REG_GEN8_END < OP_PARM_REG_FP_END);
1347
1348 if (pParam->param <= OP_PARM_REG_GEN32_END)
1349 {
1350 /* 32-bit EAX..EDI registers. */
1351 if (pCpu->opmode == CPUMODE_32BIT)
1352 {
1353 /* Use 32-bit registers. */
1354 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1355 pParam->flags |= USE_REG_GEN32;
1356 pParam->size = 4;
1357 }
1358 else
1359 if (pCpu->opmode == CPUMODE_64BIT)
1360 {
1361 /* Use 64-bit registers. */
1362 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1363 if ( (pOp->optype & OPTYPE_REXB_EXTENDS_OPREG)
1364 && pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
1365 && (pCpu->prefix & PREFIX_REX)
1366 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1367 pParam->base.reg_gen += 8;
1368
1369 pParam->flags |= USE_REG_GEN64;
1370 pParam->size = 8;
1371 }
1372 else
1373 {
1374 /* Use 16-bit registers. */
1375 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1376 pParam->flags |= USE_REG_GEN16;
1377 pParam->size = 2;
1378 pParam->param = pParam->param - OP_PARM_REG_GEN32_START + OP_PARM_REG_GEN16_START;
1379 }
1380 }
1381 else
1382 if (pParam->param <= OP_PARM_REG_SEG_END)
1383 {
1384 /* Segment ES..GS registers. */
1385 pParam->base.reg_seg = pParam->param - OP_PARM_REG_SEG_START;
1386 pParam->flags |= USE_REG_SEG;
1387 pParam->size = 2;
1388 }
1389 else
1390 if (pParam->param <= OP_PARM_REG_GEN16_END)
1391 {
1392 /* 16-bit AX..DI registers. */
1393 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN16_START;
1394 pParam->flags |= USE_REG_GEN16;
1395 pParam->size = 2;
1396 }
1397 else
1398 if (pParam->param <= OP_PARM_REG_GEN8_END)
1399 {
1400 /* 8-bit AL..DL, AH..DH registers. */
1401 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN8_START;
1402 pParam->flags |= USE_REG_GEN8;
1403 pParam->size = 1;
1404
1405 if (pCpu->opmode == CPUMODE_64BIT)
1406 {
1407 if ( (pOp->optype & OPTYPE_REXB_EXTENDS_OPREG)
1408 && pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
1409 && (pCpu->prefix & PREFIX_REX)
1410 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1411 pParam->base.reg_gen += 8; /* least significant byte of R8-R15 */
1412 }
1413 }
1414 else
1415 if (pParam->param <= OP_PARM_REG_FP_END)
1416 {
1417 /* FPU registers. */
1418 pParam->base.reg_fp = pParam->param - OP_PARM_REG_FP_START;
1419 pParam->flags |= USE_REG_FP;
1420 pParam->size = 10;
1421 }
1422 Assert(!(pParam->param >= OP_PARM_REG_GEN64_START && pParam->param <= OP_PARM_REG_GEN64_END));
1423
1424 /* else - not supported for now registers. */
1425
1426 return 0;
1427}
1428//*****************************************************************************
1429//*****************************************************************************
1430unsigned ParseXv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1431{
1432 disasmGetPtrString(pCpu, pOp, pParam);
1433 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1434
1435 pParam->flags |= USE_POINTER_DS_BASED;
1436 if (pCpu->addrmode == CPUMODE_32BIT)
1437 {
1438 pParam->base.reg_gen = USE_REG_ESI;
1439 pParam->flags |= USE_REG_GEN32;
1440 }
1441 else
1442 if (pCpu->addrmode == CPUMODE_64BIT)
1443 {
1444 pParam->base.reg_gen = USE_REG_RSI;
1445 pParam->flags |= USE_REG_GEN64;
1446 }
1447 else
1448 {
1449 pParam->base.reg_gen = USE_REG_SI;
1450 pParam->flags |= USE_REG_GEN16;
1451 }
1452 return 0; //no additional opcode bytes
1453}
1454//*****************************************************************************
1455//*****************************************************************************
1456unsigned ParseXb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1457{
1458 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1459
1460 pParam->flags |= USE_POINTER_DS_BASED;
1461 if (pCpu->addrmode == CPUMODE_32BIT)
1462 {
1463 pParam->base.reg_gen = USE_REG_ESI;
1464 pParam->flags |= USE_REG_GEN32;
1465 }
1466 else
1467 if (pCpu->addrmode == CPUMODE_64BIT)
1468 {
1469 pParam->base.reg_gen = USE_REG_RSI;
1470 pParam->flags |= USE_REG_GEN64;
1471 }
1472 else
1473 {
1474 pParam->base.reg_gen = USE_REG_SI;
1475 pParam->flags |= USE_REG_GEN16;
1476 }
1477 return 0; //no additional opcode bytes
1478}
1479//*****************************************************************************
1480//*****************************************************************************
1481unsigned ParseYv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1482{
1483 disasmGetPtrString(pCpu, pOp, pParam);
1484 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1485
1486 pParam->flags |= USE_POINTER_ES_BASED;
1487 if (pCpu->addrmode == CPUMODE_32BIT)
1488 {
1489 pParam->base.reg_gen = USE_REG_EDI;
1490 pParam->flags |= USE_REG_GEN32;
1491 }
1492 else
1493 if (pCpu->addrmode == CPUMODE_64BIT)
1494 {
1495 pParam->base.reg_gen = USE_REG_RDI;
1496 pParam->flags |= USE_REG_GEN64;
1497 }
1498 else
1499 {
1500 pParam->base.reg_gen = USE_REG_DI;
1501 pParam->flags |= USE_REG_GEN16;
1502 }
1503 return 0; //no additional opcode bytes
1504}
1505//*****************************************************************************
1506//*****************************************************************************
1507unsigned ParseYb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1508{
1509 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1510
1511 pParam->flags |= USE_POINTER_ES_BASED;
1512 if (pCpu->addrmode == CPUMODE_32BIT)
1513 {
1514 pParam->base.reg_gen = USE_REG_EDI;
1515 pParam->flags |= USE_REG_GEN32;
1516 }
1517 else
1518 if (pCpu->addrmode == CPUMODE_64BIT)
1519 {
1520 pParam->base.reg_gen = USE_REG_RDI;
1521 pParam->flags |= USE_REG_GEN64;
1522 }
1523 else
1524 {
1525 pParam->base.reg_gen = USE_REG_DI;
1526 pParam->flags |= USE_REG_GEN16;
1527 }
1528 return 0; //no additional opcode bytes
1529}
1530//*****************************************************************************
1531//*****************************************************************************
1532unsigned ParseTwoByteEsc(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1533{
1534 const OPCODE *pOpcode;
1535 int size = sizeof(uint8_t);
1536
1537 //2nd byte
1538 pCpu->opcode = DISReadByte(pCpu, lpszCodeBlock);
1539 pOpcode = &g_aTwoByteMapX86[pCpu->opcode];
1540
1541 /* Handle opcode table extensions that rely on the address, repe or repne prefix byte. */
1542 /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
1543 if (pCpu->lastprefix)
1544 {
1545 switch (pCpu->lastprefix)
1546 {
1547 case OP_OPSIZE: /* 0x66 */
1548 if (g_aTwoByteMapX86_PF66[pCpu->opcode].opcode != OP_INVALID)
1549 {
1550 /* Table entry is valid, so use the extension table. */
1551 pOpcode = &g_aTwoByteMapX86_PF66[pCpu->opcode];
1552
1553 /* Cancel prefix changes. */
1554 pCpu->prefix &= ~PREFIX_OPSIZE;
1555 pCpu->opmode = pCpu->mode;
1556 }
1557 break;
1558
1559 case OP_REPNE: /* 0xF2 */
1560 if (g_aTwoByteMapX86_PFF2[pCpu->opcode].opcode != OP_INVALID)
1561 {
1562 /* Table entry is valid, so use the extension table. */
1563 pOpcode = &g_aTwoByteMapX86_PFF2[pCpu->opcode];
1564
1565 /* Cancel prefix changes. */
1566 pCpu->prefix &= ~PREFIX_REPNE;
1567 }
1568 break;
1569
1570 case OP_REPE: /* 0xF3 */
1571 if (g_aTwoByteMapX86_PFF3[pCpu->opcode].opcode != OP_INVALID)
1572 {
1573 /* Table entry is valid, so use the extension table. */
1574 pOpcode = &g_aTwoByteMapX86_PFF3[pCpu->opcode];
1575
1576 /* Cancel prefix changes. */
1577 pCpu->prefix &= ~PREFIX_REP;
1578 }
1579 break;
1580 }
1581 }
1582
1583 size += ParseInstruction(lpszCodeBlock+size, pOpcode, pCpu);
1584 return size;
1585}
1586//*****************************************************************************
1587//*****************************************************************************
1588unsigned ParseNopPause(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1589{
1590 unsigned size = 0;
1591
1592 if (pCpu->prefix & PREFIX_REP)
1593 {
1594 pOp = &g_aMapX86_NopPause[1]; /* PAUSE */
1595 pCpu->prefix &= ~PREFIX_REP;
1596 }
1597 else
1598 pOp = &g_aMapX86_NopPause[0]; /* NOP */
1599
1600 size += ParseInstruction(pu8CodeBlock, pOp, pCpu);
1601 return size;
1602}
1603//*****************************************************************************
1604//*****************************************************************************
1605unsigned ParseImmGrpl(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1606{
1607 int idx = (pCpu->opcode - 0x80) * 8;
1608 unsigned size = 0, modrm, reg;
1609
1610 modrm = DISReadByte(pCpu, lpszCodeBlock);
1611 reg = MODRM_REG(modrm);
1612
1613 pOp = (PCOPCODE)&g_aMapX86_Group1[idx+reg];
1614 //little hack to make sure the ModRM byte is included in the returned size
1615 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1616 size = sizeof(uint8_t); //ModRM byte
1617
1618 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1619
1620 return size;
1621}
1622//*****************************************************************************
1623//*****************************************************************************
1624unsigned ParseShiftGrp2(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1625{
1626 int idx;
1627 unsigned size = 0, modrm, reg;
1628
1629 switch (pCpu->opcode)
1630 {
1631 case 0xC0:
1632 case 0xC1:
1633 idx = (pCpu->opcode - 0xC0)*8;
1634 break;
1635
1636 case 0xD0:
1637 case 0xD1:
1638 case 0xD2:
1639 case 0xD3:
1640 idx = (pCpu->opcode - 0xD0 + 2)*8;
1641 break;
1642
1643 default:
1644 AssertMsgFailed(("Oops\n"));
1645 return sizeof(uint8_t);
1646 }
1647
1648 modrm = DISReadByte(pCpu, lpszCodeBlock);
1649 reg = MODRM_REG(modrm);
1650
1651 pOp = (PCOPCODE)&g_aMapX86_Group2[idx+reg];
1652
1653 //little hack to make sure the ModRM byte is included in the returned size
1654 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1655 size = sizeof(uint8_t); //ModRM byte
1656
1657 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1658
1659 return size;
1660}
1661//*****************************************************************************
1662//*****************************************************************************
1663unsigned ParseGrp3(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1664{
1665 int idx = (pCpu->opcode - 0xF6) * 8;
1666 unsigned size = 0, modrm, reg;
1667
1668 modrm = DISReadByte(pCpu, lpszCodeBlock);
1669 reg = MODRM_REG(modrm);
1670
1671 pOp = (PCOPCODE)&g_aMapX86_Group3[idx+reg];
1672
1673 //little hack to make sure the ModRM byte is included in the returned size
1674 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1675 size = sizeof(uint8_t); //ModRM byte
1676
1677 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1678
1679 return size;
1680}
1681//*****************************************************************************
1682//*****************************************************************************
1683unsigned ParseGrp4(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1684{
1685 unsigned size = 0, modrm, reg;
1686
1687 modrm = DISReadByte(pCpu, lpszCodeBlock);
1688 reg = MODRM_REG(modrm);
1689
1690 pOp = (PCOPCODE)&g_aMapX86_Group4[reg];
1691
1692 //little hack to make sure the ModRM byte is included in the returned size
1693 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1694 size = sizeof(uint8_t); //ModRM byte
1695
1696 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1697
1698 return size;
1699}
1700//*****************************************************************************
1701//*****************************************************************************
1702unsigned ParseGrp5(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1703{
1704 unsigned size = 0, modrm, reg;
1705
1706 modrm = DISReadByte(pCpu, lpszCodeBlock);
1707 reg = MODRM_REG(modrm);
1708
1709 pOp = (PCOPCODE)&g_aMapX86_Group5[reg];
1710
1711 //little hack to make sure the ModRM byte is included in the returned size
1712 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1713 size = sizeof(uint8_t); //ModRM byte
1714
1715 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1716
1717 return size;
1718}
1719//*****************************************************************************
1720// 0xF 0xF [ModRM] [SIB] [displacement] imm8_opcode
1721// It would appear the ModRM byte must always be present. How else can you
1722// determine the offset of the imm8_opcode byte otherwise?
1723//
1724//*****************************************************************************
1725unsigned Parse3DNow(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1726{
1727 unsigned size = 0, modrmsize;
1728
1729#ifdef DEBUG_Sander
1730 //needs testing
1731 AssertMsgFailed(("Test me\n"));
1732#endif
1733
1734 unsigned ModRM = DISReadByte(pCpu, lpszCodeBlock);
1735 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1736 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1737 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1738
1739 modrmsize = QueryModRM(lpszCodeBlock+sizeof(uint8_t), pOp, pParam, pCpu);
1740
1741 uint8_t opcode = DISReadByte(pCpu, lpszCodeBlock+sizeof(uint8_t)+modrmsize);
1742
1743 pOp = (PCOPCODE)&g_aTwoByteMapX86_3DNow[opcode];
1744
1745 //little hack to make sure the ModRM byte is included in the returned size
1746 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1747 {
1748#ifdef DEBUG_Sander /* bird, 2005-06-28: Alex is getting this during full installation of win2ksp4. */
1749 AssertMsgFailed(("Oops!\n")); //shouldn't happen!
1750#endif
1751 size = sizeof(uint8_t); //ModRM byte
1752 }
1753
1754 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1755 size += sizeof(uint8_t); //imm8_opcode uint8_t
1756
1757 return size;
1758}
1759//*****************************************************************************
1760//*****************************************************************************
1761unsigned ParseGrp6(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1762{
1763 unsigned size = 0, modrm, reg;
1764
1765 modrm = DISReadByte(pCpu, lpszCodeBlock);
1766 reg = MODRM_REG(modrm);
1767
1768 pOp = (PCOPCODE)&g_aMapX86_Group6[reg];
1769
1770 //little hack to make sure the ModRM byte is included in the returned size
1771 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1772 size = sizeof(uint8_t); //ModRM byte
1773
1774 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1775
1776 return size;
1777}
1778//*****************************************************************************
1779//*****************************************************************************
1780unsigned ParseGrp7(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1781{
1782 unsigned size = 0, modrm, reg, rm, mod;
1783
1784 modrm = DISReadByte(pCpu, lpszCodeBlock);
1785 mod = MODRM_MOD(modrm);
1786 reg = MODRM_REG(modrm);
1787 rm = MODRM_RM(modrm);
1788
1789 if (mod == 3 && rm == 0)
1790 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm000[reg];
1791 else
1792 if (mod == 3 && rm == 1)
1793 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm001[reg];
1794 else
1795 pOp = (PCOPCODE)&g_aMapX86_Group7_mem[reg];
1796
1797 //little hack to make sure the ModRM byte is included in the returned size
1798 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1799 size = sizeof(uint8_t); //ModRM byte
1800
1801 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1802
1803 return size;
1804}
1805//*****************************************************************************
1806//*****************************************************************************
1807unsigned ParseGrp8(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1808{
1809 unsigned size = 0, modrm, reg;
1810
1811 modrm = DISReadByte(pCpu, lpszCodeBlock);
1812 reg = MODRM_REG(modrm);
1813
1814 pOp = (PCOPCODE)&g_aMapX86_Group8[reg];
1815
1816 //little hack to make sure the ModRM byte is included in the returned size
1817 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1818 size = sizeof(uint8_t); //ModRM byte
1819
1820 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1821
1822 return size;
1823}
1824//*****************************************************************************
1825//*****************************************************************************
1826unsigned ParseGrp9(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1827{
1828 unsigned size = 0, modrm, reg;
1829
1830 modrm = DISReadByte(pCpu, lpszCodeBlock);
1831 reg = MODRM_REG(modrm);
1832
1833 pOp = (PCOPCODE)&g_aMapX86_Group9[reg];
1834
1835 //little hack to make sure the ModRM byte is included in the returned size
1836 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1837 size = sizeof(uint8_t); //ModRM byte
1838
1839 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1840
1841 return size;
1842}
1843//*****************************************************************************
1844//*****************************************************************************
1845unsigned ParseGrp10(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1846{
1847 unsigned size = 0, modrm, reg;
1848
1849 modrm = DISReadByte(pCpu, lpszCodeBlock);
1850 reg = MODRM_REG(modrm);
1851
1852 pOp = (PCOPCODE)&g_aMapX86_Group10[reg];
1853
1854 //little hack to make sure the ModRM byte is included in the returned size
1855 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1856 size = sizeof(uint8_t); //ModRM byte
1857
1858 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1859
1860 return size;
1861}
1862//*****************************************************************************
1863//*****************************************************************************
1864unsigned ParseGrp12(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1865{
1866 unsigned size = 0, modrm, reg;
1867
1868 modrm = DISReadByte(pCpu, lpszCodeBlock);
1869 reg = MODRM_REG(modrm);
1870
1871 if (pCpu->prefix & PREFIX_OPSIZE)
1872 reg += 8; //2nd table
1873
1874 pOp = (PCOPCODE)&g_aMapX86_Group12[reg];
1875
1876 //little hack to make sure the ModRM byte is included in the returned size
1877 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1878 size = sizeof(uint8_t); //ModRM byte
1879
1880 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1881 return size;
1882}
1883//*****************************************************************************
1884//*****************************************************************************
1885unsigned ParseGrp13(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1886{
1887 unsigned size = 0, modrm, reg;
1888
1889 modrm = DISReadByte(pCpu, lpszCodeBlock);
1890 reg = MODRM_REG(modrm);
1891 if (pCpu->prefix & PREFIX_OPSIZE)
1892 reg += 8; //2nd table
1893
1894 pOp = (PCOPCODE)&g_aMapX86_Group13[reg];
1895
1896 //little hack to make sure the ModRM byte is included in the returned size
1897 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1898 size = sizeof(uint8_t); //ModRM byte
1899
1900 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1901
1902 return size;
1903}
1904//*****************************************************************************
1905//*****************************************************************************
1906unsigned ParseGrp14(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1907{
1908 unsigned size = 0, modrm, reg;
1909
1910 modrm = DISReadByte(pCpu, lpszCodeBlock);
1911 reg = MODRM_REG(modrm);
1912 if (pCpu->prefix & PREFIX_OPSIZE)
1913 reg += 8; //2nd table
1914
1915 pOp = (PCOPCODE)&g_aMapX86_Group14[reg];
1916
1917 //little hack to make sure the ModRM byte is included in the returned size
1918 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1919 size = sizeof(uint8_t); //ModRM byte
1920
1921 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1922
1923 return size;
1924}
1925//*****************************************************************************
1926//*****************************************************************************
1927unsigned ParseGrp15(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1928{
1929 unsigned size = 0, modrm, reg, mod, rm;
1930
1931 modrm = DISReadByte(pCpu, lpszCodeBlock);
1932 mod = MODRM_MOD(modrm);
1933 reg = MODRM_REG(modrm);
1934 rm = MODRM_RM(modrm);
1935
1936 if (mod == 3 && rm == 0)
1937 pOp = (PCOPCODE)&g_aMapX86_Group15_mod11_rm000[reg];
1938 else
1939 pOp = (PCOPCODE)&g_aMapX86_Group15_mem[reg];
1940
1941 //little hack to make sure the ModRM byte is included in the returned size
1942 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1943 size = sizeof(uint8_t); //ModRM byte
1944
1945 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1946 return size;
1947}
1948//*****************************************************************************
1949//*****************************************************************************
1950unsigned ParseGrp16(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1951{
1952 unsigned size = 0, modrm, reg;
1953
1954 modrm = DISReadByte(pCpu, lpszCodeBlock);
1955 reg = MODRM_REG(modrm);
1956
1957 pOp = (PCOPCODE)&g_aMapX86_Group16[reg];
1958
1959 //little hack to make sure the ModRM byte is included in the returned size
1960 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1961 size = sizeof(uint8_t); //ModRM byte
1962
1963 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1964 return size;
1965}
1966//*****************************************************************************
1967#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
1968const char *szModRMReg8[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"};
1969const char *szModRMReg8_64[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8L", "R9L", "R10L", "R11L", "R12L", "R13L", "R14L", "R15L"};
1970const char *szModRMReg16[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"};
1971const char *szModRMReg32[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
1972const char *szModRMReg64[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
1973const char *szModRMReg1616[8] = {"BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX"};
1974#endif
1975const char *szModRMSegReg[6] = {"ES", "CS", "SS", "DS", "FS", "GS"};
1976const 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};
1977const int IndexModRMReg16[4] = { USE_REG_SI, USE_REG_DI, USE_REG_SI, USE_REG_DI};
1978//*****************************************************************************
1979void disasmModRMReg(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam, int fRegAddr)
1980{
1981 int subtype, type, mod;
1982
1983 mod = pCpu->ModRM.Bits.Mod;
1984
1985 type = OP_PARM_VTYPE(pParam->param);
1986 subtype = OP_PARM_VSUBTYPE(pParam->param);
1987 if (fRegAddr)
1988 subtype = OP_PARM_d;
1989 else
1990 if (subtype == OP_PARM_v || subtype == OP_PARM_NONE)
1991 {
1992 switch(pCpu->opmode)
1993 {
1994 case CPUMODE_32BIT:
1995 subtype = OP_PARM_d;
1996 break;
1997 case CPUMODE_64BIT:
1998 subtype = OP_PARM_q;
1999 break;
2000 case CPUMODE_16BIT:
2001 subtype = OP_PARM_w;
2002 break;
2003 }
2004 }
2005
2006 switch (subtype)
2007 {
2008 case OP_PARM_b:
2009#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2010 if (idx > RT_ELEMENTS(szModRMReg8))
2011 disasmAddString(pParam->szParam, szModRMReg8_64[idx]);
2012 else
2013 disasmAddString(pParam->szParam, szModRMReg8[idx]);
2014#endif
2015 pParam->flags |= USE_REG_GEN8;
2016 pParam->base.reg_gen = idx;
2017 break;
2018
2019 case OP_PARM_w:
2020 disasmAddString(pParam->szParam, szModRMReg16[idx]);
2021 pParam->flags |= USE_REG_GEN16;
2022 pParam->base.reg_gen = idx;
2023 break;
2024
2025 case OP_PARM_d:
2026 disasmAddString(pParam->szParam, szModRMReg32[idx]);
2027 pParam->flags |= USE_REG_GEN32;
2028 pParam->base.reg_gen = idx;
2029 break;
2030
2031 case OP_PARM_q:
2032 disasmAddString(pParam->szParam, szModRMReg64[idx]);
2033 pParam->flags |= USE_REG_GEN64;
2034 pParam->base.reg_gen = idx;
2035 break;
2036
2037 default:
2038#ifdef IN_RING3
2039 Log(("disasmModRMReg %x:%x failed!!\n", type, subtype));
2040 DIS_THROW(ExceptionInvalidModRM);
2041#else
2042 AssertMsgFailed(("Oops!\n"));
2043#endif
2044 break;
2045 }
2046}
2047//*****************************************************************************
2048//*****************************************************************************
2049void disasmModRMReg16(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam)
2050{
2051 disasmAddString(pParam->szParam, szModRMReg1616[idx]);
2052 pParam->flags |= USE_REG_GEN16;
2053 pParam->base.reg_gen = BaseModRMReg16[idx];
2054 if (idx < 4)
2055 {
2056 pParam->flags |= USE_INDEX;
2057 pParam->index.reg_gen = IndexModRMReg16[idx];
2058 }
2059}
2060//*****************************************************************************
2061//*****************************************************************************
2062void disasmModRMSReg(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam)
2063{
2064#if 0 //def DEBUG_Sander
2065 AssertMsg(idx < (int)ELEMENTS(szModRMSegReg), ("idx=%d\n", idx));
2066#endif
2067#ifdef IN_RING3
2068 if (idx >= (int)ELEMENTS(szModRMSegReg))
2069 {
2070 Log(("disasmModRMSReg %d failed!!\n", idx));
2071 DIS_THROW(ExceptionInvalidParameter);
2072 }
2073#endif
2074
2075 idx = RT_MIN(idx, (int)ELEMENTS(szModRMSegReg)-1);
2076 disasmAddString(pParam->szParam, szModRMSegReg[idx]);
2077 pParam->flags |= USE_REG_SEG;
2078 pParam->base.reg_seg = idx;
2079}
2080//*****************************************************************************
2081//*****************************************************************************
2082void disasmPrintAbs32(POP_PARAMETER pParam)
2083{
2084 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2085}
2086//*****************************************************************************
2087//*****************************************************************************
2088void disasmPrintDisp32(POP_PARAMETER pParam)
2089{
2090 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2091}
2092//*****************************************************************************
2093//*****************************************************************************
2094void disasmPrintDisp8(POP_PARAMETER pParam)
2095{
2096 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%d", pParam->disp8);
2097}
2098//*****************************************************************************
2099//*****************************************************************************
2100void disasmPrintDisp16(POP_PARAMETER pParam)
2101{
2102 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%04Xh", pParam->disp16);
2103}
2104//*****************************************************************************
2105//*****************************************************************************
2106void disasmGetPtrString(PDISCPUSTATE pCpu, PCOPCODE pOp, POP_PARAMETER pParam)
2107{
2108 int subtype = OP_PARM_VSUBTYPE(pParam->param);
2109
2110 if (subtype == OP_PARM_v)
2111 {
2112 subtype = (pCpu->opmode == CPUMODE_32BIT) ? OP_PARM_d : OP_PARM_w;
2113 }
2114
2115 switch (subtype)
2116 {
2117 case OP_PARM_a: //two words or dwords depending on operand size (bound only)
2118 break;
2119
2120 case OP_PARM_b:
2121 disasmAddString(pParam->szParam, "byte ptr ");
2122 break;
2123
2124 case OP_PARM_w:
2125 disasmAddString(pParam->szParam, "word ptr ");
2126 break;
2127
2128 case OP_PARM_d:
2129 disasmAddString(pParam->szParam, "dword ptr ");
2130 break;
2131
2132 case OP_PARM_q:
2133 case OP_PARM_dq:
2134 disasmAddString(pParam->szParam, "qword ptr ");
2135 break;
2136
2137 case OP_PARM_p:
2138 disasmAddString(pParam->szParam, "far ptr ");
2139 break;
2140
2141 case OP_PARM_s:
2142 break; //??
2143
2144 case OP_PARM_z:
2145 break;
2146 default:
2147 break; //no pointer type specified/necessary
2148 }
2149 if (pCpu->prefix & PREFIX_SEG)
2150 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%s:", szModRMSegReg[pCpu->prefix_seg]);
2151}
2152#ifndef IN_GC
2153//*****************************************************************************
2154/* Read functions for getting the opcode bytes */
2155//*****************************************************************************
2156uint8_t DISReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2157{
2158 if (pCpu->pfnReadBytes)
2159 {
2160 uint8_t temp = 0;
2161 int rc;
2162
2163 rc = pCpu->pfnReadBytes(pAddress, &temp, sizeof(temp), pCpu);
2164 if (VBOX_FAILURE(rc))
2165 {
2166 Log(("DISReadByte failed!!\n"));
2167 DIS_THROW(ExceptionMemRead);
2168 }
2169 return temp;
2170 }
2171#ifdef IN_RING0
2172 AssertMsgFailed(("DISReadByte with no read callback in ring 0!!\n"));
2173 return 0;
2174#else
2175 else return *(uint8_t *)pAddress;
2176#endif
2177}
2178//*****************************************************************************
2179//*****************************************************************************
2180uint16_t DISReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2181{
2182 if (pCpu->pfnReadBytes)
2183 {
2184 uint16_t temp = 0;
2185 int rc;
2186
2187 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2188 if (VBOX_FAILURE(rc))
2189 {
2190 Log(("DISReadWord failed!!\n"));
2191 DIS_THROW(ExceptionMemRead);
2192 }
2193 return temp;
2194 }
2195#ifdef IN_RING0
2196 AssertMsgFailed(("DISReadWord with no read callback in ring 0!!\n"));
2197 return 0;
2198#else
2199 else return *(uint16_t *)pAddress;
2200#endif
2201}
2202//*****************************************************************************
2203//*****************************************************************************
2204uint32_t DISReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2205{
2206 if (pCpu->pfnReadBytes)
2207 {
2208 uint32_t temp = 0;
2209 int rc;
2210
2211 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2212 if (VBOX_FAILURE(rc))
2213 {
2214 Log(("DISReadDWord failed!!\n"));
2215 DIS_THROW(ExceptionMemRead);
2216 }
2217 return temp;
2218 }
2219#ifdef IN_RING0
2220 AssertMsgFailed(("DISReadDWord with no read callback in ring 0!!\n"));
2221 return 0;
2222#else
2223 else return *(uint32_t *)pAddress;
2224#endif
2225}
2226//*****************************************************************************
2227//*****************************************************************************
2228uint64_t DISReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2229{
2230 if (pCpu->pfnReadBytes)
2231 {
2232 uint64_t temp = 0;
2233 int rc;
2234
2235 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2236 if (VBOX_FAILURE(rc))
2237 {
2238 Log(("DISReadQWord %x failed!!\n", pAddress));
2239 DIS_THROW(ExceptionMemRead);
2240 }
2241
2242 return temp;
2243 }
2244#ifdef IN_RING0
2245 AssertMsgFailed(("DISReadQWord with no read callback in ring 0!!\n"));
2246 return 0;
2247#else
2248 else return *(uint64_t *)pAddress;
2249#endif
2250}
2251#endif /* IN_GC */
2252
2253#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2254//*****************************************************************************
2255//*****************************************************************************
2256void disasmAddString(char *psz, const char *pszAdd)
2257{
2258 strcat(psz, pszAdd);
2259}
2260//*****************************************************************************
2261//*****************************************************************************
2262void disasmAddStringF(char *psz, uint32_t size, const char *pszFormat, ...)
2263{
2264 va_list args;
2265 va_start(args, pszFormat);
2266 RTStrPrintfV(psz + strlen(psz), size, pszFormat, args);
2267 va_end(args);
2268}
2269
2270//*****************************************************************************
2271//*****************************************************************************
2272void disasmAddChar(char *psz, char ch)
2273{
2274 char sz[2];
2275
2276 sz[0] = ch;
2277 sz[1] = '\0';
2278 strcat(psz, sz);
2279}
2280#endif /* !DIS_CORE_ONLY */
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