VirtualBox

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

Last change on this file since 59077 was 57372, checked in by vboxsync, 9 years ago

scm: fixes in previous cleanup run.

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