VirtualBox

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

Last change on this file since 76678 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use