VirtualBox

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

Last change on this file since 95167 was 95167, checked in by vboxsync, 2 years ago

VMM/IEM,DIS: Refreshed my memory on generating disassembler tables from IEM, making some related VEX table+code optimizations (saves a few Ks of data and some code bytes too). bugref:6251

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