VirtualBox

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

Last change on this file since 41796 was 41796, checked in by vboxsync, 12 years ago

DIS: Dropped most of the little hacks in the groups for dealing with instructions that doesn't actually parse modrm bytes. Only group 7 and the FPU instructions are left with this hack.

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

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