VirtualBox

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

Last change on this file since 8365 was 8365, checked in by vboxsync, 17 years ago

Missing occurances

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 79.7 KB
Line 
1/** @file
2 *
3 * VBox disassembler:
4 * Core components
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DIS
28#ifdef USING_VISUAL_STUDIO
29# include <stdafx.h>
30#endif
31
32#include <VBox/dis.h>
33#include <VBox/disopcode.h>
34#include <VBox/cpum.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/string.h>
39#include <iprt/stdarg.h>
40#include "DisasmInternal.h"
41#include "DisasmTables.h"
42
43#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
44# include <stdlib.h>
45# include <stdio.h>
46#endif
47
48
49/*******************************************************************************
50* Internal Functions *
51*******************************************************************************/
52static int disCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction);
53#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
54static void disasmAddString(char *psz, const char *pszString);
55static void disasmAddStringF(char *psz, uint32_t cbString, const char *pszFormat, ...);
56static void disasmAddChar(char *psz, char ch);
57#else
58# define disasmAddString(psz, pszString) do {} while (0)
59# ifdef _MSC_VER
60# define disasmAddStringF __noop
61# else
62# define disasmAddStringF(psz, cbString, pszFormat...) do {} while (0) /* Arg wanna get rid of that warning */
63# endif
64# define disasmAddChar(psz, ch) do {} while (0)
65#endif
66
67static unsigned QueryModRM(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
68static unsigned QueryModRM_SizeOnly(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
69static void UseSIB(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu);
70static unsigned ParseSIB_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu);
71
72/*******************************************************************************
73* Global Variables *
74*******************************************************************************/
75
76PFNDISPARSE pfnFullDisasm[IDX_ParseMax] =
77{
78 ParseIllegal,
79 ParseModRM,
80 UseModRM,
81 ParseImmByte,
82 ParseImmBRel,
83 ParseImmUshort,
84 ParseImmV,
85 ParseImmVRel,
86 ParseImmAddr,
87 ParseFixedReg,
88 ParseImmUlong,
89 ParseImmQword,
90 ParseTwoByteEsc,
91 ParseImmGrpl,
92 ParseShiftGrp2,
93 ParseGrp3,
94 ParseGrp4,
95 ParseGrp5,
96 Parse3DNow,
97 ParseGrp6,
98 ParseGrp7,
99 ParseGrp8,
100 ParseGrp9,
101 ParseGrp10,
102 ParseGrp12,
103 ParseGrp13,
104 ParseGrp14,
105 ParseGrp15,
106 ParseGrp16,
107 ParseModFence,
108 ParseYv,
109 ParseYb,
110 ParseXv,
111 ParseXb,
112 ParseEscFP,
113 ParseNopPause,
114 ParseImmByteSX
115};
116
117PFNDISPARSE pfnCalcSize[IDX_ParseMax] =
118{
119 ParseIllegal,
120 ParseModRM_SizeOnly,
121 UseModRM,
122 ParseImmByte_SizeOnly,
123 ParseImmBRel_SizeOnly,
124 ParseImmUshort_SizeOnly,
125 ParseImmV_SizeOnly,
126 ParseImmVRel_SizeOnly,
127 ParseImmAddr_SizeOnly,
128 ParseFixedReg,
129 ParseImmUlong_SizeOnly,
130 ParseImmQword_SizeOnly,
131 ParseTwoByteEsc,
132 ParseImmGrpl,
133 ParseShiftGrp2,
134 ParseGrp3,
135 ParseGrp4,
136 ParseGrp5,
137 Parse3DNow,
138 ParseGrp6,
139 ParseGrp7,
140 ParseGrp8,
141 ParseGrp9,
142 ParseGrp10,
143 ParseGrp12,
144 ParseGrp13,
145 ParseGrp14,
146 ParseGrp15,
147 ParseGrp16,
148 ParseModFence,
149 ParseYv,
150 ParseYb,
151 ParseXv,
152 ParseXb,
153 ParseEscFP,
154 ParseNopPause,
155 ParseImmByteSX_SizeOnly
156};
157
158/**
159 * Parses one instruction.
160 * The result is found in pCpu.
161 *
162 * @returns Success indicator.
163 * @param pCpu Pointer to cpu structure which has DISCPUSTATE::mode set correctly.
164 * @param InstructionAddr Pointer to the instruction to parse.
165 * @param pcbInstruction Where to store the size of the instruction.
166 * NULL is allowed.
167 */
168DISDECL(int) DISCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
169{
170 /*
171 * Reset instruction settings
172 */
173 pCpu->prefix = PREFIX_NONE;
174 pCpu->prefix_seg = 0;
175 pCpu->lastprefix = 0;
176 pCpu->ModRM.u = 0;
177 pCpu->SIB.u = 0;
178 pCpu->param1.parval = 0;
179 pCpu->param2.parval = 0;
180 pCpu->param3.parval = 0;
181 pCpu->param1.szParam[0] = '\0';
182 pCpu->param2.szParam[0] = '\0';
183 pCpu->param3.szParam[0] = '\0';
184 pCpu->param1.flags = 0;
185 pCpu->param2.flags = 0;
186 pCpu->param3.flags = 0;
187 pCpu->param1.size = 0;
188 pCpu->param2.size = 0;
189 pCpu->param3.size = 0;
190 pCpu->pfnReadBytes = 0;
191 pCpu->uFilter = OPTYPE_ALL;
192 pCpu->pfnDisasmFnTable = pfnFullDisasm;
193
194 return VBOX_SUCCESS(disCoreOne(pCpu, InstructionAddr, pcbInstruction));
195}
196
197/**
198 * Parses one guest instruction.
199 * The result is found in pCpu and pcbInstruction.
200 *
201 * @returns VBox status code.
202 * @param InstructionAddr Address of the instruction to decode. What this means
203 * is left to the pfnReadBytes function.
204 * @param enmCpuMode The CPU mode. CPUMODE_32BIT, CPUMODE_16BIT, or CPUMODE_64BIT.
205 * @param pfnReadBytes Callback for reading instruction bytes.
206 * @param pvUser User argument for the instruction reader. (Ends up in apvUserData[0].)
207 * @param pCpu Pointer to cpu structure. Will be initialized.
208 * @param pcbInstruction Where to store the size of the instruction.
209 * NULL is allowed.
210 */
211DISDECL(int) DISCoreOneEx(RTUINTPTR InstructionAddr, DISCPUMODE enmCpuMode, PFN_DIS_READBYTES pfnReadBytes, void *pvUser,
212 PDISCPUSTATE pCpu, unsigned *pcbInstruction)
213{
214 /*
215 * Reset instruction settings
216 */
217 pCpu->prefix = PREFIX_NONE;
218 pCpu->prefix_seg = 0;
219 pCpu->lastprefix = 0;
220 pCpu->mode = enmCpuMode;
221 pCpu->ModRM.u = 0;
222 pCpu->SIB.u = 0;
223 pCpu->param1.parval = 0;
224 pCpu->param2.parval = 0;
225 pCpu->param3.parval = 0;
226 pCpu->param1.szParam[0] = '\0';
227 pCpu->param2.szParam[0] = '\0';
228 pCpu->param3.szParam[0] = '\0';
229 pCpu->param1.flags = 0;
230 pCpu->param2.flags = 0;
231 pCpu->param3.flags = 0;
232 pCpu->param1.size = 0;
233 pCpu->param2.size = 0;
234 pCpu->param3.size = 0;
235 pCpu->pfnReadBytes = pfnReadBytes;
236 pCpu->apvUserData[0] = pvUser;
237 pCpu->uFilter = OPTYPE_ALL;
238 pCpu->pfnDisasmFnTable = pfnFullDisasm;
239
240 return disCoreOne(pCpu, InstructionAddr, pcbInstruction);
241}
242
243/**
244 * Internal worker for DISCoreOne and DISCoreOneEx.
245 *
246 * @returns VBox status code.
247 * @param pCpu Initialized cpu state.
248 * @param InstructionAddr Instruction address.
249 * @param pcbInstruction Where to store the instruction size. Can be NULL.
250 */
251static int disCoreOne(PDISCPUSTATE pCpu, RTUINTPTR InstructionAddr, unsigned *pcbInstruction)
252{
253 const OPCODE *paOneByteMap;
254
255 /*
256 * Parse byte by byte.
257 */
258 unsigned iByte = 0;
259 unsigned cbInc;
260
261 if (pCpu->mode == CPUMODE_64BIT)
262 {
263 paOneByteMap = g_aOneByteMapX64;
264 pCpu->addrmode = CPUMODE_64BIT;
265 pCpu->opmode = CPUMODE_32BIT;
266 }
267 else
268 {
269 paOneByteMap = g_aOneByteMapX86;
270 pCpu->addrmode = pCpu->mode;
271 pCpu->opmode = pCpu->mode;
272 }
273
274 while(1)
275 {
276 uint8_t codebyte = DISReadByte(pCpu, InstructionAddr+iByte);
277 uint8_t opcode = paOneByteMap[codebyte].opcode;
278
279 /* Hardcoded assumption about OP_* values!! */
280 if (opcode <= OP_LOCK)
281 {
282 pCpu->lastprefix = opcode;
283
284 /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
285 if (opcode != OP_REX)
286 pCpu->prefix &= ~PREFIX_REX;
287
288 switch (opcode)
289 {
290 case OP_INVALID:
291 AssertMsgFailed(("Invalid opcode!!\n"));
292 return VERR_GENERAL_FAILURE; /** @todo better error code. */
293
294 // segment override prefix byte
295 case OP_SEG:
296 pCpu->prefix_seg = paOneByteMap[codebyte].param1 - OP_PARM_REG_SEG_START;
297 /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */
298 if ( pCpu->mode != CPUMODE_64BIT
299 || pCpu->prefix_seg >= OP_PARM_REG_FS)
300 {
301 pCpu->prefix |= PREFIX_SEG;
302 }
303 iByte += sizeof(uint8_t);
304 continue; //fetch the next byte
305
306 // lock prefix byte
307 case OP_LOCK:
308 pCpu->prefix |= PREFIX_LOCK;
309 iByte += sizeof(uint8_t);
310 continue; //fetch the next byte
311
312 // address size override prefix byte
313 case OP_ADDRSIZE:
314 pCpu->prefix |= PREFIX_ADDRSIZE;
315 if (pCpu->mode == CPUMODE_16BIT)
316 pCpu->addrmode = CPUMODE_32BIT;
317 else
318 if (pCpu->mode == CPUMODE_32BIT)
319 pCpu->addrmode = CPUMODE_16BIT;
320 else
321 pCpu->addrmode = CPUMODE_32BIT; /* 64 bits */
322
323 iByte += sizeof(uint8_t);
324 continue; //fetch the next byte
325
326 // operand size override prefix byte
327 case OP_OPSIZE:
328 pCpu->prefix |= PREFIX_OPSIZE;
329 if (pCpu->mode == CPUMODE_16BIT)
330 pCpu->opmode = CPUMODE_32BIT;
331 else
332 pCpu->opmode = CPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
333
334 iByte += sizeof(uint8_t);
335 continue; //fetch the next byte
336
337 // rep and repne are not really prefixes, but we'll treat them as such
338 case OP_REPE:
339 pCpu->prefix |= PREFIX_REP;
340 iByte += sizeof(uint8_t);
341 continue; //fetch the next byte
342
343 case OP_REPNE:
344 pCpu->prefix |= PREFIX_REPNE;
345 iByte += sizeof(uint8_t);
346 continue; //fetch the next byte
347
348 case OP_REX:
349 Assert(pCpu->mode == CPUMODE_64BIT);
350 /* REX prefix byte */
351 pCpu->prefix |= PREFIX_REX;
352 pCpu->prefix_rex = PREFIX_REX_OP_2_FLAGS(opcode);
353
354 if (pCpu->prefix_rex & PREFIX_REX_FLAGS_W)
355 pCpu->opmode = CPUMODE_64BIT; /* overrides size prefix byte */
356 break;
357 }
358 }
359
360 unsigned uIdx = iByte;
361 iByte += sizeof(uint8_t); //first opcode byte
362
363 pCpu->opaddr = InstructionAddr + uIdx;
364 pCpu->opcode = codebyte;
365
366 cbInc = ParseInstruction(InstructionAddr + iByte, &paOneByteMap[pCpu->opcode], pCpu);
367 iByte += cbInc;
368 break;
369 }
370
371 pCpu->opsize = iByte;
372 if (pcbInstruction)
373 *pcbInstruction = iByte;
374
375 return VINF_SUCCESS;
376}
377//*****************************************************************************
378//*****************************************************************************
379unsigned ParseInstruction(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, PDISCPUSTATE pCpu)
380{
381 int size = 0;
382 bool fFiltered = false;
383
384 // Store the opcode format string for disasmPrintf
385#ifndef DIS_CORE_ONLY
386 pCpu->pszOpcode = pOp->pszOpcode;
387#endif
388 pCpu->pCurInstr = pOp;
389
390 /*
391 * Apply filter to instruction type to determine if a full disassembly is required.
392 * @note Multibyte opcodes are always marked harmless until the final byte.
393 */
394 if ((pOp->optype & pCpu->uFilter) == 0)
395 {
396 fFiltered = true;
397 pCpu->pfnDisasmFnTable = pfnCalcSize;
398 }
399 else
400 {
401 /* Not filtered out -> full disassembly */
402 pCpu->pfnDisasmFnTable = pfnFullDisasm;
403 }
404
405 // Should contain the parameter type on input
406 pCpu->param1.param = pOp->param1;
407 pCpu->param2.param = pOp->param2;
408 pCpu->param3.param = pOp->param3;
409
410 /* Correct the operand size if the instruction is marked as forced or default 64 bits */
411 if (pCpu->mode == CPUMODE_64BIT)
412 {
413 if (pOp->optype & OPTYPE_FORCED_64_OP_SIZE)
414 pCpu->opsize = CPUMODE_64BIT;
415 else
416 if ( (pOp->optype & OPTYPE_DEFAULT_64_OP_SIZE)
417 && !(pCpu->prefix & PREFIX_OPSIZE))
418 pCpu->opsize = CPUMODE_64BIT;
419 }
420
421 if (pOp->idxParse1 != IDX_ParseNop)
422 {
423 size += pCpu->pfnDisasmFnTable[pOp->idxParse1](lpszCodeBlock, pOp, &pCpu->param1, pCpu);
424 if (fFiltered == false) pCpu->param1.size = DISGetParamSize(pCpu, &pCpu->param1);
425 }
426
427 if (pOp->idxParse2 != IDX_ParseNop)
428 {
429 size += pCpu->pfnDisasmFnTable[pOp->idxParse2](lpszCodeBlock+size, pOp, &pCpu->param2, pCpu);
430 if (fFiltered == false) pCpu->param2.size = DISGetParamSize(pCpu, &pCpu->param2);
431 }
432
433 if (pOp->idxParse3 != IDX_ParseNop)
434 {
435 size += pCpu->pfnDisasmFnTable[pOp->idxParse3](lpszCodeBlock+size, pOp, &pCpu->param3, pCpu);
436 if (fFiltered == false) pCpu->param3.size = DISGetParamSize(pCpu, &pCpu->param3);
437 }
438 // else simple one byte instruction
439
440 return size;
441}
442//*****************************************************************************
443/* Floating point opcode parsing */
444//*****************************************************************************
445unsigned ParseEscFP(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
446{
447 int index;
448 const OPCODE *fpop;
449 unsigned size = 0, ModRM;
450
451 ModRM = DISReadByte(pCpu, lpszCodeBlock);
452
453 index = pCpu->opcode - 0xD8;
454 if (ModRM <= 0xBF)
455 {
456 fpop = &(g_paMapX86_FP_Low[index])[MODRM_REG(ModRM)];
457 pCpu->pCurInstr = (PCOPCODE)fpop;
458
459 // Should contain the parameter type on input
460 pCpu->param1.parval = fpop->param1;
461 pCpu->param2.parval = fpop->param2;
462 }
463 else
464 {
465 fpop = &(g_paMapX86_FP_High[index])[ModRM - 0xC0];
466 pCpu->pCurInstr = (PCOPCODE)fpop;
467 }
468
469 /*
470 * Apply filter to instruction type to determine if a full disassembly is required.
471 * @note Multibyte opcodes are always marked harmless until the final byte.
472 */
473 if ((fpop->optype & pCpu->uFilter) == 0)
474 {
475 pCpu->pfnDisasmFnTable = pfnCalcSize;
476 }
477 else
478 {
479 /* Not filtered out -> full disassembly */
480 pCpu->pfnDisasmFnTable = pfnFullDisasm;
481 }
482
483 /* Correct the operand size if the instruction is marked as forced or default 64 bits */
484 if (pCpu->mode == CPUMODE_64BIT)
485 {
486 /* Note: redundant, but just in case this ever changes */
487 if (fpop->optype & OPTYPE_FORCED_64_OP_SIZE)
488 pCpu->opsize = CPUMODE_64BIT;
489 else
490 if ( (fpop->optype & OPTYPE_DEFAULT_64_OP_SIZE)
491 && !(pCpu->prefix & PREFIX_OPSIZE))
492 pCpu->opsize = CPUMODE_64BIT;
493 }
494
495 // Little hack to make sure the ModRM byte is included in the returned size
496 if (fpop->idxParse1 != IDX_ParseModRM && fpop->idxParse2 != IDX_ParseModRM)
497 size = sizeof(uint8_t); //ModRM byte
498
499 if (fpop->idxParse1 != IDX_ParseNop)
500 size += pCpu->pfnDisasmFnTable[fpop->idxParse1](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
501
502 if (fpop->idxParse2 != IDX_ParseNop)
503 size += pCpu->pfnDisasmFnTable[fpop->idxParse2](lpszCodeBlock+size, (PCOPCODE)fpop, pParam, pCpu);
504
505 // Store the opcode format string for disasmPrintf
506#ifndef DIS_CORE_ONLY
507 pCpu->pszOpcode = fpop->pszOpcode;
508#endif
509
510 return size;
511}
512//*****************************************************************************
513// SIB byte: (32 bits mode only)
514// 7 - 6 5 - 3 2-0
515// Scale Index Base
516//*****************************************************************************
517const char *szSIBBaseReg[8] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
518const char *szSIBIndexReg[8] = {"EAX", "ECX", "EDX", "EBX", NULL, "EBP", "ESI", "EDI"};
519const char *szSIBScale[4] = {"", "*2", "*4", "*8"};
520
521//*****************************************************************************
522void UseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
523{
524 unsigned scale, base, index;
525 char szTemp[32];
526 szTemp[0] = '\0';
527
528 scale = pCpu->SIB.Bits.Scale;
529 base = pCpu->SIB.Bits.Base;
530 index = pCpu->SIB.Bits.Index;
531
532 if (szSIBIndexReg[index])
533 {
534 pParam->flags |= USE_INDEX;
535 pParam->index.reg_gen = index;
536
537 if (scale != 0)
538 {
539 pParam->flags |= USE_SCALE;
540 pParam->scale = (1<<scale);
541 }
542
543 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
544 disasmAddStringF(szTemp, sizeof(szTemp), "%s%s", szSIBIndexReg[index], szSIBScale[scale]);
545 else
546 disasmAddStringF(szTemp, sizeof(szTemp), "%s+%s%s", szSIBBaseReg[base], szSIBIndexReg[index], szSIBScale[scale]);
547 }
548 else
549 {
550 if (base != 5 || pCpu->ModRM.Bits.Mod != 0)
551 disasmAddStringF(szTemp, sizeof(szTemp), "%s", szSIBBaseReg[base]);
552 }
553
554 if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
555 {
556 // [scaled index] + disp32
557 disasmAddString(pParam->szParam, &szTemp[0]);
558 pParam->flags |= USE_DISPLACEMENT32;
559 pParam->disp32 = pCpu->disp;
560 disasmAddChar(pParam->szParam, '+');
561 disasmPrintDisp32(pParam);
562 }
563 else
564 {
565 disasmAddString(pParam->szParam, szTemp);
566
567 pParam->flags |= USE_BASE | USE_REG_GEN32;
568 pParam->base.reg_gen = base;
569 }
570 return; /* Already fetched everything in ParseSIB; no size returned */
571}
572//*****************************************************************************
573//*****************************************************************************
574unsigned ParseSIB(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
575{
576 unsigned size = sizeof(uint8_t);
577 unsigned SIB;
578
579 SIB = DISReadByte(pCpu, lpszCodeBlock);
580 lpszCodeBlock += size;
581
582 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
583 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
584 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
585
586 if (pCpu->prefix & PREFIX_REX)
587 {
588 /* REX.B extends the Base field if not scaled index + disp32 */
589 if (!(pCpu->SIB.Bits.Base == 5 && pCpu->ModRM.Bits.Mod == 0))
590 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
591
592 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
593 }
594
595 if ( pCpu->SIB.Bits.Base == 5
596 && pCpu->ModRM.Bits.Mod == 0)
597 {
598 /* Additional 32 bits displacement. No change in long mode. */
599 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
600 size += sizeof(int32_t);
601 }
602 return size;
603}
604//*****************************************************************************
605//*****************************************************************************
606unsigned ParseSIB_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
607{
608 unsigned size = sizeof(uint8_t);
609 unsigned SIB;
610
611 SIB = DISReadByte(pCpu, lpszCodeBlock);
612 lpszCodeBlock += size;
613
614 pCpu->SIB.Bits.Base = SIB_BASE(SIB);
615 pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
616 pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
617
618 if (pCpu->prefix & PREFIX_REX)
619 {
620 /* REX.B extends the Base field. */
621 pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
622 /* REX.X extends the Index field. */
623 pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_X)) << 3);
624 }
625
626 if ( pCpu->SIB.Bits.Base == 5
627 && pCpu->ModRM.Bits.Mod == 0)
628 {
629 /* Additional 32 bits displacement. No change in long mode. */
630 size += sizeof(int32_t);
631 }
632 return size;
633}
634//*****************************************************************************
635// ModR/M byte:
636// 7 - 6 5 - 3 2-0
637// Mod Reg/Opcode R/M
638//*****************************************************************************
639unsigned UseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
640{
641 int vtype = OP_PARM_VTYPE(pParam->param);
642 unsigned reg = pCpu->ModRM.Bits.Reg;
643 unsigned mod = pCpu->ModRM.Bits.Mod;
644 unsigned rm = pCpu->ModRM.Bits.Rm;
645
646 switch (vtype)
647 {
648 case OP_PARM_G: //general purpose register
649 disasmModRMReg(pCpu, pOp, reg, pParam, 0);
650 return 0;
651
652 default:
653 if (IS_OP_PARM_RARE(vtype))
654 {
655 switch (vtype)
656 {
657 case OP_PARM_C: //control register
658 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "CR%d", reg);
659 pParam->flags |= USE_REG_CR;
660 pParam->base.reg_ctrl = reg;
661 return 0;
662
663 case OP_PARM_D: //debug register
664 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "DR%d", reg);
665 pParam->flags |= USE_REG_DBG;
666 pParam->base.reg_dbg = reg;
667 return 0;
668
669 case OP_PARM_P: //MMX register
670 reg &= 7; /* REX.R has no effect here */
671 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "MM%d", reg);
672 pParam->flags |= USE_REG_MMX;
673 pParam->base.reg_mmx = reg;
674 return 0;
675
676 case OP_PARM_S: //segment register
677 reg &= 7; /* REX.R has no effect here */
678 disasmModRMSReg(pCpu, pOp, reg, pParam);
679 pParam->flags |= USE_REG_SEG;
680 return 0;
681
682 case OP_PARM_T: //test register
683 reg &= 7; /* REX.R has no effect here */
684 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "TR%d", reg);
685 pParam->flags |= USE_REG_TEST;
686 pParam->base.reg_test = reg;
687 return 0;
688
689 case OP_PARM_W: //XMM register or memory operand
690 if (mod != 3)
691 break; /* memory operand */
692 /* else no break */
693 case OP_PARM_V: //XMM register
694 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "XMM%d", reg);
695 pParam->flags |= USE_REG_XMM;
696 pParam->base.reg_xmm = reg;
697 return 0;
698 }
699 }
700 }
701
702 /* @todo bound */
703
704 if (pCpu->addrmode != CPUMODE_16BIT)
705 {
706 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
707
708 /*
709 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
710 */
711 switch (mod)
712 {
713 case 0: //effective address
714 disasmGetPtrString(pCpu, pOp, pParam);
715 disasmAddChar(pParam->szParam, '[');
716 if (rm == 4)
717 { /* SIB byte follows ModRM */
718 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
719 }
720 else
721 if (rm == 5)
722 {
723 /* 32 bits displacement */
724 if (pCpu->mode == CPUMODE_32BIT)
725 {
726 pParam->flags |= USE_DISPLACEMENT32;
727 pParam->disp32 = pCpu->disp;
728 disasmPrintDisp32(pParam);
729 }
730 else
731 {
732 pParam->flags |= USE_RIPDISPLACEMENT32;
733 pParam->disp32 = pCpu->disp;
734 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "RIP+");
735 disasmPrintDisp32(pParam);
736 }
737 }
738 else {//register address
739 pParam->flags |= USE_BASE;
740 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
741 }
742 disasmAddChar(pParam->szParam, ']');
743 break;
744
745 case 1: //effective address + 8 bits displacement
746 disasmGetPtrString(pCpu, pOp, pParam);
747 disasmAddChar(pParam->szParam, '[');
748 if (rm == 4) {//SIB byte follows ModRM
749 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
750 }
751 else
752 {
753 pParam->flags |= USE_BASE;
754 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
755 }
756 pParam->disp8 = pCpu->disp;
757 pParam->flags |= USE_DISPLACEMENT8;
758
759 if (pParam->disp8 != 0)
760 {
761 if (pParam->disp8 > 0)
762 disasmAddChar(pParam->szParam, '+');
763 disasmPrintDisp8(pParam);
764 }
765 disasmAddChar(pParam->szParam, ']');
766 break;
767
768 case 2: //effective address + 32 bits displacement
769 disasmGetPtrString(pCpu, pOp, pParam);
770 disasmAddChar(pParam->szParam, '[');
771 if (rm == 4) {//SIB byte follows ModRM
772 UseSIB(lpszCodeBlock, pOp, pParam, pCpu);
773 }
774 else
775 {
776 pParam->flags |= USE_BASE;
777 disasmModRMReg(pCpu, pOp, rm, pParam, 1);
778 }
779 pParam->disp32 = pCpu->disp;
780 pParam->flags |= USE_DISPLACEMENT32;
781
782 if (pParam->disp32 != 0)
783 {
784 disasmAddChar(pParam->szParam, '+');
785 disasmPrintDisp32(pParam);
786 }
787 disasmAddChar(pParam->szParam, ']');
788 break;
789
790 case 3: //registers
791 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
792 break;
793 }
794 }
795 else
796 {//16 bits addressing mode
797 switch (mod)
798 {
799 case 0: //effective address
800 disasmGetPtrString(pCpu, pOp, pParam);
801 disasmAddChar(pParam->szParam, '[');
802 if (rm == 6)
803 {//16 bits displacement
804 pParam->disp16 = pCpu->disp;
805 pParam->flags |= USE_DISPLACEMENT16;
806 disasmPrintDisp16(pParam);
807 }
808 else
809 {
810 pParam->flags |= USE_BASE;
811 disasmModRMReg16(pCpu, pOp, rm, pParam);
812 }
813 disasmAddChar(pParam->szParam, ']');
814 break;
815
816 case 1: //effective address + 8 bits displacement
817 disasmGetPtrString(pCpu, pOp, pParam);
818 disasmAddChar(pParam->szParam, '[');
819 disasmModRMReg16(pCpu, pOp, rm, pParam);
820 pParam->disp8 = pCpu->disp;
821 pParam->flags |= USE_BASE | USE_DISPLACEMENT8;
822
823 if (pParam->disp8 != 0)
824 {
825 if (pParam->disp8 > 0)
826 disasmAddChar(pParam->szParam, '+');
827 disasmPrintDisp8(pParam);
828 }
829 disasmAddChar(pParam->szParam, ']');
830 break;
831
832 case 2: //effective address + 16 bits displacement
833 disasmGetPtrString(pCpu, pOp, pParam);
834 disasmAddChar(pParam->szParam, '[');
835 disasmModRMReg16(pCpu, pOp, rm, pParam);
836 pParam->disp16 = pCpu->disp;
837 pParam->flags |= USE_BASE | USE_DISPLACEMENT16;
838
839 if (pParam->disp16 != 0)
840 {
841 disasmAddChar(pParam->szParam, '+');
842 disasmPrintDisp16(pParam);
843 }
844 disasmAddChar(pParam->szParam, ']');
845 break;
846
847 case 3: //registers
848 disasmModRMReg(pCpu, pOp, rm, pParam, 0);
849 break;
850 }
851 }
852 return 0; //everything was already fetched in ParseModRM
853}
854//*****************************************************************************
855// Query the size of the ModRM parameters and fetch the immediate data (if any)
856//*****************************************************************************
857unsigned QueryModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
858{
859 unsigned sibinc;
860 unsigned size = 0;
861 unsigned reg = pCpu->ModRM.Bits.Reg;
862 unsigned mod = pCpu->ModRM.Bits.Mod;
863 unsigned rm = pCpu->ModRM.Bits.Rm;
864
865 if (!pSibInc)
866 pSibInc = &sibinc;
867
868 *pSibInc = 0;
869
870 if (pCpu->addrmode != CPUMODE_16BIT)
871 {
872 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
873
874 /*
875 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
876 */
877 if (mod != 3 && rm == 4)
878 { /* SIB byte follows ModRM */
879 *pSibInc = ParseSIB(lpszCodeBlock, pOp, pParam, pCpu);
880 lpszCodeBlock += *pSibInc;
881 size += *pSibInc;
882 }
883
884 switch (mod)
885 {
886 case 0: /* Effective address */
887 if (rm == 5) { /* 32 bits displacement */
888 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
889 size += sizeof(int32_t);
890 }
891 /* else register address */
892 break;
893
894 case 1: /* Effective address + 8 bits displacement */
895 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
896 size += sizeof(char);
897 break;
898
899 case 2: /* Effective address + 32 bits displacement */
900 pCpu->disp = DISReadDWord(pCpu, lpszCodeBlock);
901 size += sizeof(int32_t);
902 break;
903
904 case 3: /* registers */
905 break;
906 }
907 }
908 else
909 {
910 /* 16 bits mode */
911 switch (mod)
912 {
913 case 0: /* Effective address */
914 if (rm == 6) {
915 pCpu->disp = DISReadWord(pCpu, lpszCodeBlock);
916 size += sizeof(uint16_t);
917 }
918 /* else register address */
919 break;
920
921 case 1: /* Effective address + 8 bits displacement */
922 pCpu->disp = (int8_t)DISReadByte(pCpu, lpszCodeBlock);
923 size += sizeof(char);
924 break;
925
926 case 2: /* Effective address + 32 bits displacement */
927 pCpu->disp = (int16_t)DISReadWord(pCpu, lpszCodeBlock);
928 size += sizeof(uint16_t);
929 break;
930
931 case 3: /* registers */
932 break;
933 }
934 }
935 return size;
936}
937//*****************************************************************************
938// Query the size of the ModRM parameters and fetch the immediate data (if any)
939//*****************************************************************************
940unsigned QueryModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
941{
942 unsigned sibinc;
943 unsigned size = 0;
944 unsigned reg = pCpu->ModRM.Bits.Reg;
945 unsigned mod = pCpu->ModRM.Bits.Mod;
946 unsigned rm = pCpu->ModRM.Bits.Rm;
947
948 if (!pSibInc)
949 pSibInc = &sibinc;
950
951 *pSibInc = 0;
952
953 if (pCpu->addrmode != CPUMODE_16BIT)
954 {
955 Assert(pCpu->addrmode == CPUMODE_32BIT || pCpu->addrmode == CPUMODE_64BIT);
956 /*
957 * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
958 */
959 if (mod != 3 && rm == 4)
960 { /* SIB byte follows ModRM */
961 *pSibInc = ParseSIB_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu);
962 lpszCodeBlock += *pSibInc;
963 size += *pSibInc;
964 }
965
966 switch (mod)
967 {
968 case 0: //effective address
969 if (rm == 5) { /* 32 bits displacement */
970 size += sizeof(int32_t);
971 }
972 /* else register address */
973 break;
974
975 case 1: /* Effective address + 8 bits displacement */
976 size += sizeof(char);
977 break;
978
979 case 2: /* Effective address + 32 bits displacement */
980 size += sizeof(int32_t);
981 break;
982
983 case 3: /* registers */
984 break;
985 }
986 }
987 else
988 {
989 /* 16 bits mode */
990 switch (mod)
991 {
992 case 0: //effective address
993 if (rm == 6) {
994 size += sizeof(uint16_t);
995 }
996 /* else register address */
997 break;
998
999 case 1: /* Effective address + 8 bits displacement */
1000 size += sizeof(char);
1001 break;
1002
1003 case 2: /* Effective address + 32 bits displacement */
1004 size += sizeof(uint16_t);
1005 break;
1006
1007 case 3: /* registers */
1008 break;
1009 }
1010 }
1011 return size;
1012}
1013//*****************************************************************************
1014//*****************************************************************************
1015unsigned ParseIllegal(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1016{
1017 AssertFailed();
1018 return 0;
1019}
1020//*****************************************************************************
1021//*****************************************************************************
1022unsigned ParseModRM(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1023{
1024 unsigned size = sizeof(uint8_t); //ModRM byte
1025 unsigned sibinc, ModRM;
1026
1027 ModRM = DISReadByte(pCpu, lpszCodeBlock);
1028 lpszCodeBlock += sizeof(uint8_t);
1029
1030 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1031 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1032 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1033
1034 if (pCpu->prefix & PREFIX_REX)
1035 {
1036 Assert(pCpu->mode == CPUMODE_64BIT);
1037
1038 /* REX.R extends the Reg field. */
1039 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
1040
1041 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1042 if (!( pCpu->ModRM.Bits.Mod != 3
1043 && pCpu->ModRM.Bits.Rm == 4)
1044 &&
1045 !( pCpu->ModRM.Bits.Mod == 0
1046 && pCpu->ModRM.Bits.Rm == 5))
1047 {
1048 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1049 }
1050 }
1051 size += QueryModRM(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1052 lpszCodeBlock += sibinc;
1053
1054 UseModRM(lpszCodeBlock, pOp, pParam, pCpu);
1055 return size;
1056}
1057//*****************************************************************************
1058//*****************************************************************************
1059unsigned ParseModRM_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1060{
1061 unsigned size = sizeof(uint8_t); //ModRM byte
1062 unsigned sibinc, ModRM;
1063
1064 ModRM = DISReadByte(pCpu, lpszCodeBlock);
1065 lpszCodeBlock += sizeof(uint8_t);
1066
1067 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1068 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1069 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1070
1071 if (pCpu->prefix & PREFIX_REX)
1072 {
1073 Assert(pCpu->mode == CPUMODE_64BIT);
1074
1075 /* REX.R extends the Reg field. */
1076 pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_R)) << 3);
1077
1078 /* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
1079 if (!( pCpu->ModRM.Bits.Mod != 3
1080 && pCpu->ModRM.Bits.Rm == 4)
1081 &&
1082 !( pCpu->ModRM.Bits.Mod == 0
1083 && pCpu->ModRM.Bits.Rm == 5))
1084 {
1085 pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & PREFIX_REX_FLAGS_B)) << 3);
1086 }
1087 }
1088
1089 size += QueryModRM_SizeOnly(lpszCodeBlock, pOp, pParam, pCpu, &sibinc);
1090 lpszCodeBlock += sibinc;
1091
1092 /* UseModRM is not necessary here; we're only interested in the opcode size */
1093 return size;
1094}
1095//*****************************************************************************
1096//*****************************************************************************
1097unsigned ParseModFence(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1098{
1099 ////AssertMsgFailed(("??\n"));
1100 //nothing to do apparently
1101 return 0;
1102}
1103//*****************************************************************************
1104//*****************************************************************************
1105unsigned ParseImmByte(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1106{
1107 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1108 pParam->flags |= USE_IMMEDIATE8;
1109
1110 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%02Xh", (uint32_t)pParam->parval);
1111 return sizeof(uint8_t);
1112}
1113//*****************************************************************************
1114//*****************************************************************************
1115unsigned ParseImmByte_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1116{
1117 return sizeof(uint8_t);
1118}
1119//*****************************************************************************
1120//*****************************************************************************
1121unsigned ParseImmByteSX(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1122{
1123 if (pCpu->opmode == CPUMODE_32BIT)
1124 {
1125 pParam->parval = (uint32_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1126 pParam->flags |= USE_IMMEDIATE32_SX8;
1127 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1128 }
1129 else
1130 {
1131 pParam->parval = (uint16_t)(int8_t)DISReadByte(pCpu, lpszCodeBlock);
1132 pParam->flags |= USE_IMMEDIATE16_SX8;
1133 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1134 }
1135 return sizeof(uint8_t);
1136}
1137//*****************************************************************************
1138//*****************************************************************************
1139unsigned ParseImmByteSX_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1140{
1141 return sizeof(uint8_t);
1142}
1143//*****************************************************************************
1144//*****************************************************************************
1145unsigned ParseImmUshort(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1146{
1147 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1148 pParam->flags |= USE_IMMEDIATE16;
1149
1150 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint16_t)pParam->parval);
1151 return sizeof(uint16_t);
1152}
1153//*****************************************************************************
1154//*****************************************************************************
1155unsigned ParseImmUshort_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1156{
1157 return sizeof(uint16_t);
1158}
1159//*****************************************************************************
1160//*****************************************************************************
1161unsigned ParseImmUlong(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1162{
1163 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1164 pParam->flags |= USE_IMMEDIATE32;
1165
1166 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1167 return sizeof(uint32_t);
1168}
1169//*****************************************************************************
1170//*****************************************************************************
1171unsigned ParseImmUlong_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1172{
1173 return sizeof(uint32_t);
1174}
1175//*****************************************************************************
1176//*****************************************************************************
1177unsigned ParseImmQword(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1178{
1179 pParam->parval = DISReadQWord(pCpu, lpszCodeBlock);
1180 pParam->flags |= USE_IMMEDIATE64;
1181
1182 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08X", (uint32_t)pParam->parval);
1183 disasmAddStringF(&pParam->szParam[9], sizeof(pParam->szParam)-9, "%08Xh", (uint32_t)(pParam->parval >> 32));
1184 return sizeof(uint64_t);
1185}
1186//*****************************************************************************
1187//*****************************************************************************
1188unsigned ParseImmQword_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1189{
1190 return sizeof(uint64_t);
1191}
1192//*****************************************************************************
1193//*****************************************************************************
1194unsigned ParseImmV(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1195{
1196 if (pCpu->opmode == CPUMODE_32BIT)
1197 {
1198 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1199 pParam->flags |= USE_IMMEDIATE32;
1200
1201 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%08Xh", (uint32_t)pParam->parval);
1202 return sizeof(uint32_t);
1203 }
1204 else
1205 {
1206 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1207 pParam->flags |= USE_IMMEDIATE16;
1208
1209 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04Xh", (uint32_t)pParam->parval);
1210 return sizeof(uint16_t);
1211 }
1212}
1213//*****************************************************************************
1214//*****************************************************************************
1215unsigned ParseImmV_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1216{
1217 if (pCpu->opmode == CPUMODE_32BIT)
1218 return sizeof(uint32_t);
1219 return sizeof(uint16_t);
1220}
1221//*****************************************************************************
1222// Relative displacement for branches (rel. to next instruction)
1223//*****************************************************************************
1224unsigned ParseImmBRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1225{
1226 pParam->parval = DISReadByte(pCpu, lpszCodeBlock);
1227 pParam->flags |= USE_IMMEDIATE8_REL;
1228
1229 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%02Xh)", (uint32_t)pParam->parval);
1230 return sizeof(char);
1231}
1232//*****************************************************************************
1233// Relative displacement for branches (rel. to next instruction)
1234//*****************************************************************************
1235unsigned ParseImmBRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1236{
1237 return sizeof(char);
1238}
1239//*****************************************************************************
1240// Relative displacement for branches (rel. to next instruction)
1241//*****************************************************************************
1242unsigned ParseImmVRel(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1243{
1244 if (pCpu->opmode == CPUMODE_32BIT)
1245 {
1246 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1247 pParam->flags |= USE_IMMEDIATE32_REL;
1248
1249 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%08Xh)", (uint32_t)pParam->parval);
1250 return sizeof(int32_t);
1251 }
1252 else
1253 {
1254 pParam->parval = DISReadWord(pCpu, lpszCodeBlock);
1255 pParam->flags |= USE_IMMEDIATE16_REL;
1256
1257 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), " (0%04Xh)", (uint32_t)pParam->parval);
1258 return sizeof(uint16_t);
1259 }
1260}
1261//*****************************************************************************
1262// Relative displacement for branches (rel. to next instruction)
1263//*****************************************************************************
1264unsigned ParseImmVRel_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1265{
1266 if (pCpu->opmode == CPUMODE_32BIT)
1267 return sizeof(int32_t);
1268 return sizeof(uint16_t);
1269}
1270//*****************************************************************************
1271//*****************************************************************************
1272unsigned ParseImmAddr(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1273{
1274 disasmGetPtrString(pCpu, pOp, pParam);
1275 if (pCpu->addrmode == CPUMODE_32BIT)
1276 {
1277 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1278 {// far 16:32 pointer
1279 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1280 *((uint32_t*)&pParam->parval+1) = DISReadWord(pCpu, lpszCodeBlock+sizeof(uint32_t));
1281 pParam->flags |= USE_IMMEDIATE_ADDR_16_32;
1282
1283 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%08Xh", (uint32_t)(pParam->parval>>32), (uint32_t)pParam->parval);
1284 return sizeof(uint32_t) + sizeof(uint16_t);
1285 }
1286 else
1287 {// near 32 bits pointer
1288 /*
1289 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1290 * so we treat it like displacement.
1291 */
1292 pParam->disp32 = DISReadDWord(pCpu, lpszCodeBlock);
1293 pParam->flags |= USE_DISPLACEMENT32;
1294
1295 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08Xh]", pParam->disp32);
1296 return sizeof(uint32_t);
1297 }
1298 }
1299 else
1300 if (pCpu->addrmode == CPUMODE_64BIT)
1301 {
1302 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1303 /* near 64 bits pointer */
1304 /*
1305 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1306 * so we treat it like displacement.
1307 */
1308 pParam->disp64 = DISReadQWord(pCpu, lpszCodeBlock);
1309 pParam->flags |= USE_DISPLACEMENT64;
1310
1311 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%08X%08Xh]", (uint32_t)(pParam->disp64 >> 32), (uint32_t)pParam->disp64);
1312 return sizeof(uint64_t);
1313 }
1314 else
1315 {
1316 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1317 {// far 16:16 pointer
1318 pParam->parval = DISReadDWord(pCpu, lpszCodeBlock);
1319 pParam->flags |= USE_IMMEDIATE_ADDR_16_16;
1320
1321 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "0%04X:0%04Xh", (uint32_t)(pParam->parval>>16), (uint16_t)pParam->parval );
1322 return sizeof(uint32_t);
1323 }
1324 else
1325 {// near 16 bits pointer
1326 /*
1327 * Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
1328 * so we treat it like displacement.
1329 */
1330 pParam->disp16 = DISReadWord(pCpu, lpszCodeBlock);
1331 pParam->flags |= USE_DISPLACEMENT16;
1332
1333 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "[0%04Xh]", (uint32_t)pParam->disp16);
1334 return sizeof(uint16_t);
1335 }
1336 }
1337}
1338//*****************************************************************************
1339//*****************************************************************************
1340unsigned ParseImmAddr_SizeOnly(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1341{
1342 if (pCpu->addrmode == CPUMODE_32BIT)
1343 {
1344 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1345 {// far 16:32 pointer
1346 return sizeof(uint32_t) + sizeof(uint16_t);
1347 }
1348 else
1349 {// near 32 bits pointer
1350 return sizeof(uint32_t);
1351 }
1352 }
1353 if (pCpu->addrmode == CPUMODE_64BIT)
1354 {
1355 Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
1356 return sizeof(uint64_t);
1357 }
1358 else
1359 {
1360 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
1361 {// far 16:16 pointer
1362 return sizeof(uint32_t);
1363 }
1364 else
1365 {// near 16 bits pointer
1366 return sizeof(uint16_t);
1367 }
1368 }
1369}
1370//*****************************************************************************
1371//*****************************************************************************
1372unsigned ParseFixedReg(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1373{
1374 /*
1375 * Sets up flags for stored in OPC fixed registers.
1376 */
1377
1378 if (pParam->param == OP_PARM_NONE)
1379 {
1380 /* No parameter at all. */
1381 return 0;
1382 }
1383
1384 AssertCompile(OP_PARM_REG_GEN32_END < OP_PARM_REG_SEG_END);
1385 AssertCompile(OP_PARM_REG_SEG_END < OP_PARM_REG_GEN16_END);
1386 AssertCompile(OP_PARM_REG_GEN16_END < OP_PARM_REG_GEN8_END);
1387 AssertCompile(OP_PARM_REG_GEN8_END < OP_PARM_REG_FP_END);
1388
1389 if (pParam->param <= OP_PARM_REG_GEN32_END)
1390 {
1391 /* 32-bit EAX..EDI registers. */
1392 if (pCpu->opmode == CPUMODE_32BIT)
1393 {
1394 /* Use 32-bit registers. */
1395 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1396 pParam->flags |= USE_REG_GEN32;
1397 pParam->size = 4;
1398 }
1399 else
1400 if (pCpu->opmode == CPUMODE_64BIT)
1401 {
1402 /* Use 64-bit registers. */
1403 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1404 if ( (pOp->optype & OPTYPE_REXB_EXTENDS_OPREG)
1405 && pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
1406 && (pCpu->prefix & PREFIX_REX)
1407 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1408 pParam->base.reg_gen += 8;
1409
1410 pParam->flags |= USE_REG_GEN64;
1411 pParam->size = 8;
1412 }
1413 else
1414 {
1415 /* Use 16-bit registers. */
1416 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
1417 pParam->flags |= USE_REG_GEN16;
1418 pParam->size = 2;
1419 pParam->param = pParam->param - OP_PARM_REG_GEN32_START + OP_PARM_REG_GEN16_START;
1420 }
1421 }
1422 else
1423 if (pParam->param <= OP_PARM_REG_SEG_END)
1424 {
1425 /* Segment ES..GS registers. */
1426 pParam->base.reg_seg = pParam->param - OP_PARM_REG_SEG_START;
1427 pParam->flags |= USE_REG_SEG;
1428 pParam->size = 2;
1429 }
1430 else
1431 if (pParam->param <= OP_PARM_REG_GEN16_END)
1432 {
1433 /* 16-bit AX..DI registers. */
1434 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN16_START;
1435 pParam->flags |= USE_REG_GEN16;
1436 pParam->size = 2;
1437 }
1438 else
1439 if (pParam->param <= OP_PARM_REG_GEN8_END)
1440 {
1441 /* 8-bit AL..DL, AH..DH registers. */
1442 pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN8_START;
1443 pParam->flags |= USE_REG_GEN8;
1444 pParam->size = 1;
1445
1446 if (pCpu->opmode == CPUMODE_64BIT)
1447 {
1448 if ( (pOp->optype & OPTYPE_REXB_EXTENDS_OPREG)
1449 && pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
1450 && (pCpu->prefix & PREFIX_REX)
1451 && (pCpu->prefix_rex & PREFIX_REX_FLAGS))
1452 pParam->base.reg_gen += 8; /* least significant byte of R8-R15 */
1453 }
1454 }
1455 else
1456 if (pParam->param <= OP_PARM_REG_FP_END)
1457 {
1458 /* FPU registers. */
1459 pParam->base.reg_fp = pParam->param - OP_PARM_REG_FP_START;
1460 pParam->flags |= USE_REG_FP;
1461 pParam->size = 10;
1462 }
1463 Assert(!(pParam->param >= OP_PARM_REG_GEN64_START && pParam->param <= OP_PARM_REG_GEN64_END));
1464
1465 /* else - not supported for now registers. */
1466
1467 return 0;
1468}
1469//*****************************************************************************
1470//*****************************************************************************
1471unsigned ParseXv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1472{
1473 disasmGetPtrString(pCpu, pOp, pParam);
1474 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1475
1476 pParam->flags |= USE_POINTER_DS_BASED;
1477 if (pCpu->addrmode == CPUMODE_32BIT)
1478 {
1479 pParam->base.reg_gen = USE_REG_ESI;
1480 pParam->flags |= USE_REG_GEN32;
1481 }
1482 else
1483 if (pCpu->addrmode == CPUMODE_64BIT)
1484 {
1485 pParam->base.reg_gen = USE_REG_RSI;
1486 pParam->flags |= USE_REG_GEN64;
1487 }
1488 else
1489 {
1490 pParam->base.reg_gen = USE_REG_SI;
1491 pParam->flags |= USE_REG_GEN16;
1492 }
1493 return 0; //no additional opcode bytes
1494}
1495//*****************************************************************************
1496//*****************************************************************************
1497unsigned ParseXb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1498{
1499 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "DS:ESI" : "DS:SI");
1500
1501 pParam->flags |= USE_POINTER_DS_BASED;
1502 if (pCpu->addrmode == CPUMODE_32BIT)
1503 {
1504 pParam->base.reg_gen = USE_REG_ESI;
1505 pParam->flags |= USE_REG_GEN32;
1506 }
1507 else
1508 if (pCpu->addrmode == CPUMODE_64BIT)
1509 {
1510 pParam->base.reg_gen = USE_REG_RSI;
1511 pParam->flags |= USE_REG_GEN64;
1512 }
1513 else
1514 {
1515 pParam->base.reg_gen = USE_REG_SI;
1516 pParam->flags |= USE_REG_GEN16;
1517 }
1518 return 0; //no additional opcode bytes
1519}
1520//*****************************************************************************
1521//*****************************************************************************
1522unsigned ParseYv(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1523{
1524 disasmGetPtrString(pCpu, pOp, pParam);
1525 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1526
1527 pParam->flags |= USE_POINTER_ES_BASED;
1528 if (pCpu->addrmode == CPUMODE_32BIT)
1529 {
1530 pParam->base.reg_gen = USE_REG_EDI;
1531 pParam->flags |= USE_REG_GEN32;
1532 }
1533 else
1534 if (pCpu->addrmode == CPUMODE_64BIT)
1535 {
1536 pParam->base.reg_gen = USE_REG_RDI;
1537 pParam->flags |= USE_REG_GEN64;
1538 }
1539 else
1540 {
1541 pParam->base.reg_gen = USE_REG_DI;
1542 pParam->flags |= USE_REG_GEN16;
1543 }
1544 return 0; //no additional opcode bytes
1545}
1546//*****************************************************************************
1547//*****************************************************************************
1548unsigned ParseYb(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1549{
1550 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), (pCpu->addrmode == CPUMODE_32BIT) ? "ES:EDI" : "ES:DI");
1551
1552 pParam->flags |= USE_POINTER_ES_BASED;
1553 if (pCpu->addrmode == CPUMODE_32BIT)
1554 {
1555 pParam->base.reg_gen = USE_REG_EDI;
1556 pParam->flags |= USE_REG_GEN32;
1557 }
1558 else
1559 if (pCpu->addrmode == CPUMODE_64BIT)
1560 {
1561 pParam->base.reg_gen = USE_REG_RDI;
1562 pParam->flags |= USE_REG_GEN64;
1563 }
1564 else
1565 {
1566 pParam->base.reg_gen = USE_REG_DI;
1567 pParam->flags |= USE_REG_GEN16;
1568 }
1569 return 0; //no additional opcode bytes
1570}
1571//*****************************************************************************
1572//*****************************************************************************
1573unsigned ParseTwoByteEsc(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1574{
1575 const OPCODE *pOpcode;
1576 int size = sizeof(uint8_t);
1577
1578 //2nd byte
1579 pCpu->opcode = DISReadByte(pCpu, lpszCodeBlock);
1580 pOpcode = &g_aTwoByteMapX86[pCpu->opcode];
1581
1582 /* Handle opcode table extensions that rely on the address, repe or repne prefix byte. */
1583 /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
1584 if (pCpu->lastprefix)
1585 {
1586 switch (pCpu->lastprefix)
1587 {
1588 case OP_OPSIZE: /* 0x66 */
1589 if (g_aTwoByteMapX86_PF66[pCpu->opcode].opcode != OP_INVALID)
1590 {
1591 /* Table entry is valid, so use the extension table. */
1592 pOpcode = &g_aTwoByteMapX86_PF66[pCpu->opcode];
1593
1594 /* Cancel prefix changes. */
1595 pCpu->prefix &= ~PREFIX_OPSIZE;
1596 pCpu->opmode = pCpu->mode;
1597 }
1598 break;
1599
1600 case OP_REPNE: /* 0xF2 */
1601 if (g_aTwoByteMapX86_PFF2[pCpu->opcode].opcode != OP_INVALID)
1602 {
1603 /* Table entry is valid, so use the extension table. */
1604 pOpcode = &g_aTwoByteMapX86_PFF2[pCpu->opcode];
1605
1606 /* Cancel prefix changes. */
1607 pCpu->prefix &= ~PREFIX_REPNE;
1608 }
1609 break;
1610
1611 case OP_REPE: /* 0xF3 */
1612 if (g_aTwoByteMapX86_PFF3[pCpu->opcode].opcode != OP_INVALID)
1613 {
1614 /* Table entry is valid, so use the extension table. */
1615 pOpcode = &g_aTwoByteMapX86_PFF3[pCpu->opcode];
1616
1617 /* Cancel prefix changes. */
1618 pCpu->prefix &= ~PREFIX_REP;
1619 }
1620 break;
1621 }
1622 }
1623
1624 size += ParseInstruction(lpszCodeBlock+size, pOpcode, pCpu);
1625 return size;
1626}
1627//*****************************************************************************
1628//*****************************************************************************
1629unsigned ParseNopPause(RTUINTPTR pu8CodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1630{
1631 unsigned size = 0;
1632
1633 if (pCpu->prefix & PREFIX_REP)
1634 {
1635 pOp = &g_aMapX86_NopPause[1]; /* PAUSE */
1636 pCpu->prefix &= ~PREFIX_REP;
1637 }
1638 else
1639 pOp = &g_aMapX86_NopPause[0]; /* NOP */
1640
1641 size += ParseInstruction(pu8CodeBlock, pOp, pCpu);
1642 return size;
1643}
1644//*****************************************************************************
1645//*****************************************************************************
1646unsigned ParseImmGrpl(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1647{
1648 int idx = (pCpu->opcode - 0x80) * 8;
1649 unsigned size = 0, modrm, reg;
1650
1651 modrm = DISReadByte(pCpu, lpszCodeBlock);
1652 reg = MODRM_REG(modrm);
1653
1654 pOp = (PCOPCODE)&g_aMapX86_Group1[idx+reg];
1655 //little hack to make sure the ModRM byte is included in the returned size
1656 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1657 size = sizeof(uint8_t); //ModRM byte
1658
1659 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1660
1661 return size;
1662}
1663//*****************************************************************************
1664//*****************************************************************************
1665unsigned ParseShiftGrp2(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1666{
1667 int idx;
1668 unsigned size = 0, modrm, reg;
1669
1670 switch (pCpu->opcode)
1671 {
1672 case 0xC0:
1673 case 0xC1:
1674 idx = (pCpu->opcode - 0xC0)*8;
1675 break;
1676
1677 case 0xD0:
1678 case 0xD1:
1679 case 0xD2:
1680 case 0xD3:
1681 idx = (pCpu->opcode - 0xD0 + 2)*8;
1682 break;
1683
1684 default:
1685 AssertMsgFailed(("Oops\n"));
1686 return sizeof(uint8_t);
1687 }
1688
1689 modrm = DISReadByte(pCpu, lpszCodeBlock);
1690 reg = MODRM_REG(modrm);
1691
1692 pOp = (PCOPCODE)&g_aMapX86_Group2[idx+reg];
1693
1694 //little hack to make sure the ModRM byte is included in the returned size
1695 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1696 size = sizeof(uint8_t); //ModRM byte
1697
1698 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1699
1700 return size;
1701}
1702//*****************************************************************************
1703//*****************************************************************************
1704unsigned ParseGrp3(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1705{
1706 int idx = (pCpu->opcode - 0xF6) * 8;
1707 unsigned size = 0, modrm, reg;
1708
1709 modrm = DISReadByte(pCpu, lpszCodeBlock);
1710 reg = MODRM_REG(modrm);
1711
1712 pOp = (PCOPCODE)&g_aMapX86_Group3[idx+reg];
1713
1714 //little hack to make sure the ModRM byte is included in the returned size
1715 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1716 size = sizeof(uint8_t); //ModRM byte
1717
1718 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1719
1720 return size;
1721}
1722//*****************************************************************************
1723//*****************************************************************************
1724unsigned ParseGrp4(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1725{
1726 unsigned size = 0, modrm, reg;
1727
1728 modrm = DISReadByte(pCpu, lpszCodeBlock);
1729 reg = MODRM_REG(modrm);
1730
1731 pOp = (PCOPCODE)&g_aMapX86_Group4[reg];
1732
1733 //little hack to make sure the ModRM byte is included in the returned size
1734 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1735 size = sizeof(uint8_t); //ModRM byte
1736
1737 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1738
1739 return size;
1740}
1741//*****************************************************************************
1742//*****************************************************************************
1743unsigned ParseGrp5(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1744{
1745 unsigned size = 0, modrm, reg;
1746
1747 modrm = DISReadByte(pCpu, lpszCodeBlock);
1748 reg = MODRM_REG(modrm);
1749
1750 pOp = (PCOPCODE)&g_aMapX86_Group5[reg];
1751
1752 //little hack to make sure the ModRM byte is included in the returned size
1753 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1754 size = sizeof(uint8_t); //ModRM byte
1755
1756 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1757
1758 return size;
1759}
1760//*****************************************************************************
1761// 0xF 0xF [ModRM] [SIB] [displacement] imm8_opcode
1762// It would appear the ModRM byte must always be present. How else can you
1763// determine the offset of the imm8_opcode byte otherwise?
1764//
1765//*****************************************************************************
1766unsigned Parse3DNow(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1767{
1768 unsigned size = 0, modrmsize;
1769
1770#ifdef DEBUG_Sander
1771 //needs testing
1772 AssertMsgFailed(("Test me\n"));
1773#endif
1774
1775 unsigned ModRM = DISReadByte(pCpu, lpszCodeBlock);
1776 pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
1777 pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
1778 pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
1779
1780 modrmsize = QueryModRM(lpszCodeBlock+sizeof(uint8_t), pOp, pParam, pCpu);
1781
1782 uint8_t opcode = DISReadByte(pCpu, lpszCodeBlock+sizeof(uint8_t)+modrmsize);
1783
1784 pOp = (PCOPCODE)&g_aTwoByteMapX86_3DNow[opcode];
1785
1786 //little hack to make sure the ModRM byte is included in the returned size
1787 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1788 {
1789#ifdef DEBUG_Sander /* bird, 2005-06-28: Alex is getting this during full installation of win2ksp4. */
1790 AssertMsgFailed(("Oops!\n")); //shouldn't happen!
1791#endif
1792 size = sizeof(uint8_t); //ModRM byte
1793 }
1794
1795 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1796 size += sizeof(uint8_t); //imm8_opcode uint8_t
1797
1798 return size;
1799}
1800//*****************************************************************************
1801//*****************************************************************************
1802unsigned ParseGrp6(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1803{
1804 unsigned size = 0, modrm, reg;
1805
1806 modrm = DISReadByte(pCpu, lpszCodeBlock);
1807 reg = MODRM_REG(modrm);
1808
1809 pOp = (PCOPCODE)&g_aMapX86_Group6[reg];
1810
1811 //little hack to make sure the ModRM byte is included in the returned size
1812 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1813 size = sizeof(uint8_t); //ModRM byte
1814
1815 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1816
1817 return size;
1818}
1819//*****************************************************************************
1820//*****************************************************************************
1821unsigned ParseGrp7(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1822{
1823 unsigned size = 0, modrm, reg, rm, mod;
1824
1825 modrm = DISReadByte(pCpu, lpszCodeBlock);
1826 mod = MODRM_MOD(modrm);
1827 reg = MODRM_REG(modrm);
1828 rm = MODRM_RM(modrm);
1829
1830 if (mod == 3 && rm == 0)
1831 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm000[reg];
1832 else
1833 if (mod == 3 && rm == 1)
1834 pOp = (PCOPCODE)&g_aMapX86_Group7_mod11_rm001[reg];
1835 else
1836 pOp = (PCOPCODE)&g_aMapX86_Group7_mem[reg];
1837
1838 //little hack to make sure the ModRM byte is included in the returned size
1839 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1840 size = sizeof(uint8_t); //ModRM byte
1841
1842 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1843
1844 return size;
1845}
1846//*****************************************************************************
1847//*****************************************************************************
1848unsigned ParseGrp8(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1849{
1850 unsigned size = 0, modrm, reg;
1851
1852 modrm = DISReadByte(pCpu, lpszCodeBlock);
1853 reg = MODRM_REG(modrm);
1854
1855 pOp = (PCOPCODE)&g_aMapX86_Group8[reg];
1856
1857 //little hack to make sure the ModRM byte is included in the returned size
1858 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1859 size = sizeof(uint8_t); //ModRM byte
1860
1861 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1862
1863 return size;
1864}
1865//*****************************************************************************
1866//*****************************************************************************
1867unsigned ParseGrp9(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1868{
1869 unsigned size = 0, modrm, reg;
1870
1871 modrm = DISReadByte(pCpu, lpszCodeBlock);
1872 reg = MODRM_REG(modrm);
1873
1874 pOp = (PCOPCODE)&g_aMapX86_Group9[reg];
1875
1876 //little hack to make sure the ModRM byte is included in the returned size
1877 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1878 size = sizeof(uint8_t); //ModRM byte
1879
1880 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1881
1882 return size;
1883}
1884//*****************************************************************************
1885//*****************************************************************************
1886unsigned ParseGrp10(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1887{
1888 unsigned size = 0, modrm, reg;
1889
1890 modrm = DISReadByte(pCpu, lpszCodeBlock);
1891 reg = MODRM_REG(modrm);
1892
1893 pOp = (PCOPCODE)&g_aMapX86_Group10[reg];
1894
1895 //little hack to make sure the ModRM byte is included in the returned size
1896 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1897 size = sizeof(uint8_t); //ModRM byte
1898
1899 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1900
1901 return size;
1902}
1903//*****************************************************************************
1904//*****************************************************************************
1905unsigned ParseGrp12(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1906{
1907 unsigned size = 0, modrm, reg;
1908
1909 modrm = DISReadByte(pCpu, lpszCodeBlock);
1910 reg = MODRM_REG(modrm);
1911
1912 if (pCpu->prefix & PREFIX_OPSIZE)
1913 reg += 8; //2nd table
1914
1915 pOp = (PCOPCODE)&g_aMapX86_Group12[reg];
1916
1917 //little hack to make sure the ModRM byte is included in the returned size
1918 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1919 size = sizeof(uint8_t); //ModRM byte
1920
1921 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1922 return size;
1923}
1924//*****************************************************************************
1925//*****************************************************************************
1926unsigned ParseGrp13(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1927{
1928 unsigned size = 0, modrm, reg;
1929
1930 modrm = DISReadByte(pCpu, lpszCodeBlock);
1931 reg = MODRM_REG(modrm);
1932 if (pCpu->prefix & PREFIX_OPSIZE)
1933 reg += 8; //2nd table
1934
1935 pOp = (PCOPCODE)&g_aMapX86_Group13[reg];
1936
1937 //little hack to make sure the ModRM byte is included in the returned size
1938 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1939 size = sizeof(uint8_t); //ModRM byte
1940
1941 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1942
1943 return size;
1944}
1945//*****************************************************************************
1946//*****************************************************************************
1947unsigned ParseGrp14(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1948{
1949 unsigned size = 0, modrm, reg;
1950
1951 modrm = DISReadByte(pCpu, lpszCodeBlock);
1952 reg = MODRM_REG(modrm);
1953 if (pCpu->prefix & PREFIX_OPSIZE)
1954 reg += 8; //2nd table
1955
1956 pOp = (PCOPCODE)&g_aMapX86_Group14[reg];
1957
1958 //little hack to make sure the ModRM byte is included in the returned size
1959 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1960 size = sizeof(uint8_t); //ModRM byte
1961
1962 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1963
1964 return size;
1965}
1966//*****************************************************************************
1967//*****************************************************************************
1968unsigned ParseGrp15(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1969{
1970 unsigned size = 0, modrm, reg, mod, rm;
1971
1972 modrm = DISReadByte(pCpu, lpszCodeBlock);
1973 mod = MODRM_MOD(modrm);
1974 reg = MODRM_REG(modrm);
1975 rm = MODRM_RM(modrm);
1976
1977 if (mod == 3 && rm == 0)
1978 pOp = (PCOPCODE)&g_aMapX86_Group15_mod11_rm000[reg];
1979 else
1980 pOp = (PCOPCODE)&g_aMapX86_Group15_mem[reg];
1981
1982 //little hack to make sure the ModRM byte is included in the returned size
1983 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
1984 size = sizeof(uint8_t); //ModRM byte
1985
1986 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
1987 return size;
1988}
1989//*****************************************************************************
1990//*****************************************************************************
1991unsigned ParseGrp16(RTUINTPTR lpszCodeBlock, PCOPCODE pOp, POP_PARAMETER pParam, PDISCPUSTATE pCpu)
1992{
1993 unsigned size = 0, modrm, reg;
1994
1995 modrm = DISReadByte(pCpu, lpszCodeBlock);
1996 reg = MODRM_REG(modrm);
1997
1998 pOp = (PCOPCODE)&g_aMapX86_Group16[reg];
1999
2000 //little hack to make sure the ModRM byte is included in the returned size
2001 if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
2002 size = sizeof(uint8_t); //ModRM byte
2003
2004 size += ParseInstruction(lpszCodeBlock, pOp, pCpu);
2005 return size;
2006}
2007//*****************************************************************************
2008#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2009const char *szModRMReg8[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"};
2010const char *szModRMReg8_64[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8L", "R9L", "R10L", "R11L", "R12L", "R13L", "R14L", "R15L"};
2011const char *szModRMReg16[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"};
2012const char *szModRMReg32[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
2013const char *szModRMReg64[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
2014const char *szModRMReg1616[8] = {"BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX"};
2015#endif
2016const char *szModRMSegReg[6] = {"ES", "CS", "SS", "DS", "FS", "GS"};
2017const int BaseModRMReg16[8] = { USE_REG_BX, USE_REG_BX, USE_REG_BP, USE_REG_BP, USE_REG_SI, USE_REG_DI, USE_REG_BP, USE_REG_BX};
2018const int IndexModRMReg16[4] = { USE_REG_SI, USE_REG_DI, USE_REG_SI, USE_REG_DI};
2019//*****************************************************************************
2020void disasmModRMReg(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam, int fRegAddr)
2021{
2022 int subtype, type, mod;
2023
2024 mod = pCpu->ModRM.Bits.Mod;
2025
2026 type = OP_PARM_VTYPE(pParam->param);
2027 subtype = OP_PARM_VSUBTYPE(pParam->param);
2028 if (fRegAddr)
2029 subtype = OP_PARM_d;
2030 else
2031 if (subtype == OP_PARM_v || subtype == OP_PARM_NONE)
2032 {
2033 switch(pCpu->opmode)
2034 {
2035 case CPUMODE_32BIT:
2036 subtype = OP_PARM_d;
2037 break;
2038 case CPUMODE_64BIT:
2039 subtype = OP_PARM_q;
2040 break;
2041 case CPUMODE_16BIT:
2042 subtype = OP_PARM_w;
2043 break;
2044 }
2045 }
2046
2047 switch (subtype)
2048 {
2049 case OP_PARM_b:
2050#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2051 if (idx > RT_ELEMENTS(szModRMReg8))
2052 disasmAddString(pParam->szParam, szModRMReg8_64[idx]);
2053 else
2054 disasmAddString(pParam->szParam, szModRMReg8[idx]);
2055#endif
2056 pParam->flags |= USE_REG_GEN8;
2057 pParam->base.reg_gen = idx;
2058 break;
2059
2060 case OP_PARM_w:
2061 disasmAddString(pParam->szParam, szModRMReg16[idx]);
2062 pParam->flags |= USE_REG_GEN16;
2063 pParam->base.reg_gen = idx;
2064 break;
2065
2066 case OP_PARM_d:
2067 disasmAddString(pParam->szParam, szModRMReg32[idx]);
2068 pParam->flags |= USE_REG_GEN32;
2069 pParam->base.reg_gen = idx;
2070 break;
2071
2072 case OP_PARM_q:
2073 disasmAddString(pParam->szParam, szModRMReg64[idx]);
2074 pParam->flags |= USE_REG_GEN64;
2075 pParam->base.reg_gen = idx;
2076 break;
2077
2078 default:
2079#ifdef IN_RING3
2080 Log(("disasmModRMReg %x:%x failed!!\n", type, subtype));
2081 DIS_THROW(ExceptionInvalidModRM);
2082#else
2083 AssertMsgFailed(("Oops!\n"));
2084#endif
2085 break;
2086 }
2087}
2088//*****************************************************************************
2089//*****************************************************************************
2090void disasmModRMReg16(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam)
2091{
2092 disasmAddString(pParam->szParam, szModRMReg1616[idx]);
2093 pParam->flags |= USE_REG_GEN16;
2094 pParam->base.reg_gen = BaseModRMReg16[idx];
2095 if (idx < 4)
2096 {
2097 pParam->flags |= USE_INDEX;
2098 pParam->index.reg_gen = IndexModRMReg16[idx];
2099 }
2100}
2101//*****************************************************************************
2102//*****************************************************************************
2103void disasmModRMSReg(PDISCPUSTATE pCpu, PCOPCODE pOp, int idx, POP_PARAMETER pParam)
2104{
2105#if 0 //def DEBUG_Sander
2106 AssertMsg(idx < (int)ELEMENTS(szModRMSegReg), ("idx=%d\n", idx));
2107#endif
2108#ifdef IN_RING3
2109 if (idx >= (int)ELEMENTS(szModRMSegReg))
2110 {
2111 Log(("disasmModRMSReg %d failed!!\n", idx));
2112 DIS_THROW(ExceptionInvalidParameter);
2113 }
2114#endif
2115
2116 idx = RT_MIN(idx, (int)ELEMENTS(szModRMSegReg)-1);
2117 disasmAddString(pParam->szParam, szModRMSegReg[idx]);
2118 pParam->flags |= USE_REG_SEG;
2119 pParam->base.reg_seg = idx;
2120}
2121//*****************************************************************************
2122//*****************************************************************************
2123void disasmPrintAbs32(POP_PARAMETER pParam)
2124{
2125 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2126}
2127//*****************************************************************************
2128//*****************************************************************************
2129void disasmPrintDisp32(POP_PARAMETER pParam)
2130{
2131 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%08Xh", pParam->disp32);
2132}
2133//*****************************************************************************
2134//*****************************************************************************
2135void disasmPrintDisp8(POP_PARAMETER pParam)
2136{
2137 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%d", pParam->disp8);
2138}
2139//*****************************************************************************
2140//*****************************************************************************
2141void disasmPrintDisp16(POP_PARAMETER pParam)
2142{
2143 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%04Xh", pParam->disp16);
2144}
2145//*****************************************************************************
2146//*****************************************************************************
2147void disasmGetPtrString(PDISCPUSTATE pCpu, PCOPCODE pOp, POP_PARAMETER pParam)
2148{
2149 int subtype = OP_PARM_VSUBTYPE(pParam->param);
2150
2151 if (subtype == OP_PARM_v)
2152 {
2153 subtype = (pCpu->opmode == CPUMODE_32BIT) ? OP_PARM_d : OP_PARM_w;
2154 }
2155
2156 switch (subtype)
2157 {
2158 case OP_PARM_a: //two words or dwords depending on operand size (bound only)
2159 break;
2160
2161 case OP_PARM_b:
2162 disasmAddString(pParam->szParam, "byte ptr ");
2163 break;
2164
2165 case OP_PARM_w:
2166 disasmAddString(pParam->szParam, "word ptr ");
2167 break;
2168
2169 case OP_PARM_d:
2170 disasmAddString(pParam->szParam, "dword ptr ");
2171 break;
2172
2173 case OP_PARM_q:
2174 case OP_PARM_dq:
2175 disasmAddString(pParam->szParam, "qword ptr ");
2176 break;
2177
2178 case OP_PARM_p:
2179 disasmAddString(pParam->szParam, "far ptr ");
2180 break;
2181
2182 case OP_PARM_s:
2183 break; //??
2184
2185 case OP_PARM_z:
2186 break;
2187 default:
2188 break; //no pointer type specified/necessary
2189 }
2190 if (pCpu->prefix & PREFIX_SEG)
2191 disasmAddStringF(pParam->szParam, sizeof(pParam->szParam), "%s:", szModRMSegReg[pCpu->prefix_seg]);
2192}
2193#ifndef IN_GC
2194//*****************************************************************************
2195/* Read functions for getting the opcode bytes */
2196//*****************************************************************************
2197uint8_t DISReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2198{
2199 if (pCpu->pfnReadBytes)
2200 {
2201 uint8_t temp = 0;
2202 int rc;
2203
2204 rc = pCpu->pfnReadBytes(pAddress, &temp, sizeof(temp), pCpu);
2205 if (VBOX_FAILURE(rc))
2206 {
2207 Log(("DISReadByte failed!!\n"));
2208 DIS_THROW(ExceptionMemRead);
2209 }
2210 return temp;
2211 }
2212#ifdef IN_RING0
2213 AssertMsgFailed(("DISReadByte with no read callback in ring 0!!\n"));
2214 return 0;
2215#else
2216 else return *(uint8_t *)pAddress;
2217#endif
2218}
2219//*****************************************************************************
2220//*****************************************************************************
2221uint16_t DISReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2222{
2223 if (pCpu->pfnReadBytes)
2224 {
2225 uint16_t temp = 0;
2226 int rc;
2227
2228 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2229 if (VBOX_FAILURE(rc))
2230 {
2231 Log(("DISReadWord failed!!\n"));
2232 DIS_THROW(ExceptionMemRead);
2233 }
2234 return temp;
2235 }
2236#ifdef IN_RING0
2237 AssertMsgFailed(("DISReadWord with no read callback in ring 0!!\n"));
2238 return 0;
2239#else
2240 else return *(uint16_t *)pAddress;
2241#endif
2242}
2243//*****************************************************************************
2244//*****************************************************************************
2245uint32_t DISReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2246{
2247 if (pCpu->pfnReadBytes)
2248 {
2249 uint32_t temp = 0;
2250 int rc;
2251
2252 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2253 if (VBOX_FAILURE(rc))
2254 {
2255 Log(("DISReadDWord failed!!\n"));
2256 DIS_THROW(ExceptionMemRead);
2257 }
2258 return temp;
2259 }
2260#ifdef IN_RING0
2261 AssertMsgFailed(("DISReadDWord with no read callback in ring 0!!\n"));
2262 return 0;
2263#else
2264 else return *(uint32_t *)pAddress;
2265#endif
2266}
2267//*****************************************************************************
2268//*****************************************************************************
2269uint64_t DISReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress)
2270{
2271 if (pCpu->pfnReadBytes)
2272 {
2273 uint64_t temp = 0;
2274 int rc;
2275
2276 rc = pCpu->pfnReadBytes(pAddress, (uint8_t*)&temp, sizeof(temp), pCpu);
2277 if (VBOX_FAILURE(rc))
2278 {
2279 Log(("DISReadQWord %x failed!!\n", pAddress));
2280 DIS_THROW(ExceptionMemRead);
2281 }
2282
2283 return temp;
2284 }
2285#ifdef IN_RING0
2286 AssertMsgFailed(("DISReadQWord with no read callback in ring 0!!\n"));
2287 return 0;
2288#else
2289 else return *(uint64_t *)pAddress;
2290#endif
2291}
2292#endif /* IN_GC */
2293
2294#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
2295//*****************************************************************************
2296//*****************************************************************************
2297void disasmAddString(char *psz, const char *pszAdd)
2298{
2299 strcat(psz, pszAdd);
2300}
2301//*****************************************************************************
2302//*****************************************************************************
2303void disasmAddStringF(char *psz, uint32_t size, const char *pszFormat, ...)
2304{
2305 va_list args;
2306 va_start(args, pszFormat);
2307 RTStrPrintfV(psz + strlen(psz), size, pszFormat, args);
2308 va_end(args);
2309}
2310
2311//*****************************************************************************
2312//*****************************************************************************
2313void disasmAddChar(char *psz, char ch)
2314{
2315 char sz[2];
2316
2317 sz[0] = ch;
2318 sz[1] = '\0';
2319 strcat(psz, sz);
2320}
2321#endif /* !DIS_CORE_ONLY */
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