VirtualBox

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

Last change on this file since 53012 was 53007, checked in by vboxsync, 11 years ago

DIS: Fixed VMREAD/VMWRITE disassembling, added support for MOVBE, POPCNT, TZCNT, LZCNT, ADCX, ADOX and CRC32 (only CRC32 Gd, Eb & CRC32 Gd, Ey forms).

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