VirtualBox

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

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

DIS: pCpu -> pDis.

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