VirtualBox

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

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

DIS: Prefetch instruction bytes before starting to disassemble, inline all fetchers. Poison the state a bit in strict builds.

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