VirtualBox

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

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

scm copyright and license note update

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

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