VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmFormatYasm.cpp@ 41692

Last change on this file since 41692 was 41692, checked in by vboxsync, 12 years ago

DIS: Reducing the DISCPUMODE even more (200 bytes now) and making it have the same layout in all contexts. This is useful since it's used several places in the VM structure. Also a bunch of other cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 59.7 KB
Line 
1/* $Id: DisasmFormatYasm.cpp 41692 2012-06-13 19:32:54Z vboxsync $ */
2/** @file
3 * VBox Disassembler - Yasm(/Nasm) Style Formatter.
4 */
5
6/*
7 * Copyright (C) 2008-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <VBox/dis.h>
23#include "DisasmInternal.h"
24#include <iprt/string.h>
25#include <iprt/assert.h>
26#include <iprt/ctype.h>
27
28
29/*******************************************************************************
30* Global Variables *
31*******************************************************************************/
32static const char g_szSpaces[] =
33" ";
34static const char g_aszYasmRegGen8[20][5] =
35{
36 "al\0\0", "cl\0\0", "dl\0\0", "bl\0\0", "ah\0\0", "ch\0\0", "dh\0\0", "bh\0\0", "r8b\0", "r9b\0", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", "spl\0", "bpl\0", "sil\0", "dil\0"
37};
38static const char g_aszYasmRegGen16[16][5] =
39{
40 "ax\0\0", "cx\0\0", "dx\0\0", "bx\0\0", "sp\0\0", "bp\0\0", "si\0\0", "di\0\0", "r8w\0", "r9w\0", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
41};
42static const char g_aszYasmRegGen1616[8][6] =
43{
44 "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0"
45};
46static const char g_aszYasmRegGen32[16][5] =
47{
48 "eax\0", "ecx\0", "edx\0", "ebx\0", "esp\0", "ebp\0", "esi\0", "edi\0", "r8d\0", "r9d\0", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
49};
50static const char g_aszYasmRegGen64[16][4] =
51{
52 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8\0", "r9\0", "r10", "r11", "r12", "r13", "r14", "r15"
53};
54static const char g_aszYasmRegSeg[6][3] =
55{
56 "es", "cs", "ss", "ds", "fs", "gs"
57};
58static const char g_aszYasmRegFP[8][4] =
59{
60 "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
61};
62static const char g_aszYasmRegMMX[8][4] =
63{
64 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"
65};
66static const char g_aszYasmRegXMM[16][6] =
67{
68 "xmm0\0", "xmm1\0", "xmm2\0", "xmm3\0", "xmm4\0", "xmm5\0", "xmm6\0", "xmm7\0", "xmm8\0", "xmm9\0", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
69};
70static const char g_aszYasmRegCRx[16][5] =
71{
72 "cr0\0", "cr1\0", "cr2\0", "cr3\0", "cr4\0", "cr5\0", "cr6\0", "cr7\0", "cr8\0", "cr9\0", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15"
73};
74static const char g_aszYasmRegDRx[16][5] =
75{
76 "dr0\0", "dr1\0", "dr2\0", "dr3\0", "dr4\0", "dr5\0", "dr6\0", "dr7\0", "dr8\0", "dr9\0", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15"
77};
78static const char g_aszYasmRegTRx[16][5] =
79{
80 "tr0\0", "tr1\0", "tr2\0", "tr3\0", "tr4\0", "tr5\0", "tr6\0", "tr7\0", "tr8\0", "tr9\0", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15"
81};
82
83
84
85/**
86 * Gets the base register name for the given parameter.
87 *
88 * @returns Pointer to the register name.
89 * @param pCpu The disassembler cpu state.
90 * @param pParam The parameter.
91 * @param pcchReg Where to store the length of the name.
92 */
93static const char *disasmFormatYasmBaseReg(PCDISCPUSTATE pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
94{
95 switch (pParam->fUse & ( DISUSE_REG_GEN8 | DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64
96 | DISUSE_REG_FP | DISUSE_REG_MMX | DISUSE_REG_XMM | DISUSE_REG_CR
97 | DISUSE_REG_DBG | DISUSE_REG_SEG | DISUSE_REG_TEST))
98
99 {
100 case DISUSE_REG_GEN8:
101 {
102 Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen8));
103 const char *psz = g_aszYasmRegGen8[pParam->base.reg_gen];
104 *pcchReg = 2 + !!psz[2] + !!psz[3];
105 return psz;
106 }
107
108 case DISUSE_REG_GEN16:
109 {
110 Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
111 const char *psz = g_aszYasmRegGen16[pParam->base.reg_gen];
112 *pcchReg = 2 + !!psz[2] + !!psz[3];
113 return psz;
114 }
115
116 case DISUSE_REG_GEN32:
117 {
118 Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
119 const char *psz = g_aszYasmRegGen32[pParam->base.reg_gen];
120 *pcchReg = 2 + !!psz[2] + !!psz[3];
121 return psz;
122 }
123
124 case DISUSE_REG_GEN64:
125 {
126 Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
127 const char *psz = g_aszYasmRegGen64[pParam->base.reg_gen];
128 *pcchReg = 2 + !!psz[2] + !!psz[3];
129 return psz;
130 }
131
132 case DISUSE_REG_FP:
133 {
134 Assert(pParam->base.reg_fp < RT_ELEMENTS(g_aszYasmRegFP));
135 const char *psz = g_aszYasmRegFP[pParam->base.reg_fp];
136 *pcchReg = 3;
137 return psz;
138 }
139
140 case DISUSE_REG_MMX:
141 {
142 Assert(pParam->base.reg_mmx < RT_ELEMENTS(g_aszYasmRegMMX));
143 const char *psz = g_aszYasmRegMMX[pParam->base.reg_mmx];
144 *pcchReg = 3;
145 return psz;
146 }
147
148 case DISUSE_REG_XMM:
149 {
150 Assert(pParam->base.reg_xmm < RT_ELEMENTS(g_aszYasmRegXMM));
151 const char *psz = g_aszYasmRegXMM[pParam->base.reg_mmx];
152 *pcchReg = 4 + !!psz[4];
153 return psz;
154 }
155
156 case DISUSE_REG_CR:
157 {
158 Assert(pParam->base.reg_ctrl < RT_ELEMENTS(g_aszYasmRegCRx));
159 const char *psz = g_aszYasmRegCRx[pParam->base.reg_ctrl];
160 *pcchReg = 3;
161 return psz;
162 }
163
164 case DISUSE_REG_DBG:
165 {
166 Assert(pParam->base.reg_dbg < RT_ELEMENTS(g_aszYasmRegDRx));
167 const char *psz = g_aszYasmRegDRx[pParam->base.reg_dbg];
168 *pcchReg = 3;
169 return psz;
170 }
171
172 case DISUSE_REG_SEG:
173 {
174 Assert(pParam->base.reg_seg < RT_ELEMENTS(g_aszYasmRegCRx));
175 const char *psz = g_aszYasmRegSeg[pParam->base.reg_seg];
176 *pcchReg = 2;
177 return psz;
178 }
179
180 case DISUSE_REG_TEST:
181 {
182 Assert(pParam->base.reg_test < RT_ELEMENTS(g_aszYasmRegTRx));
183 const char *psz = g_aszYasmRegTRx[pParam->base.reg_test];
184 *pcchReg = 3;
185 return psz;
186 }
187
188 default:
189 AssertMsgFailed(("%#x\n", pParam->fUse));
190 *pcchReg = 3;
191 return "r??";
192 }
193}
194
195
196/**
197 * Gets the index register name for the given parameter.
198 *
199 * @returns The index register name.
200 * @param pCpu The disassembler cpu state.
201 * @param pParam The parameter.
202 * @param pcchReg Where to store the length of the name.
203 */
204static const char *disasmFormatYasmIndexReg(PCDISCPUSTATE pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
205{
206 switch (pCpu->addrmode)
207 {
208 case DISCPUMODE_16BIT:
209 {
210 Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
211 const char *psz = g_aszYasmRegGen16[pParam->index.reg_gen];
212 *pcchReg = 2 + !!psz[2] + !!psz[3];
213 return psz;
214 }
215
216 case DISCPUMODE_32BIT:
217 {
218 Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
219 const char *psz = g_aszYasmRegGen32[pParam->index.reg_gen];
220 *pcchReg = 2 + !!psz[2] + !!psz[3];
221 return psz;
222 }
223
224 case DISCPUMODE_64BIT:
225 {
226 Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
227 const char *psz = g_aszYasmRegGen64[pParam->index.reg_gen];
228 *pcchReg = 2 + !!psz[2] + !!psz[3];
229 return psz;
230 }
231
232 default:
233 AssertMsgFailed(("%#x %#x\n", pParam->fUse, pCpu->addrmode));
234 *pcchReg = 3;
235 return "r??";
236 }
237}
238
239
240/**
241 * Formats the current instruction in Yasm (/ Nasm) style.
242 *
243 *
244 * @returns The number of output characters. If this is >= cchBuf, then the content
245 * of pszBuf will be truncated.
246 * @param pCpu Pointer to the disassembler CPU state.
247 * @param pszBuf The output buffer.
248 * @param cchBuf The size of the output buffer.
249 * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
250 * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
251 * @param pvUser User argument for pfnGetSymbol.
252 */
253DISDECL(size_t) DISFormatYasmEx(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags,
254 PFNDISGETSYMBOL pfnGetSymbol, void *pvUser)
255{
256 /*
257 * Input validation and massaging.
258 */
259 AssertPtr(pCpu);
260 AssertPtrNull(pszBuf);
261 Assert(pszBuf || !cchBuf);
262 AssertPtrNull(pfnGetSymbol);
263 AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
264 if (fFlags & DIS_FMT_FLAGS_ADDR_COMMENT)
265 fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
266 if (fFlags & DIS_FMT_FLAGS_BYTES_COMMENT)
267 fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
268
269 PCDISOPCODE const pOp = pCpu->pCurInstr;
270
271 /*
272 * Output macros
273 */
274 char *pszDst = pszBuf;
275 size_t cchDst = cchBuf;
276 size_t cchOutput = 0;
277#define PUT_C(ch) \
278 do { \
279 cchOutput++; \
280 if (cchDst > 1) \
281 { \
282 cchDst--; \
283 *pszDst++ = (ch); \
284 } \
285 } while (0)
286#define PUT_STR(pszSrc, cchSrc) \
287 do { \
288 cchOutput += (cchSrc); \
289 if (cchDst > (cchSrc)) \
290 { \
291 memcpy(pszDst, (pszSrc), (cchSrc)); \
292 pszDst += (cchSrc); \
293 cchDst -= (cchSrc); \
294 } \
295 else if (cchDst > 1) \
296 { \
297 memcpy(pszDst, (pszSrc), cchDst - 1); \
298 pszDst += cchDst - 1; \
299 cchDst = 1; \
300 } \
301 } while (0)
302#define PUT_SZ(sz) \
303 PUT_STR((sz), sizeof(sz) - 1)
304#define PUT_SZ_STRICT(szStrict, szRelaxed) \
305 do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0)
306#define PUT_PSZ(psz) \
307 do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
308#define PUT_NUM(cch, fmt, num) \
309 do { \
310 cchOutput += (cch); \
311 if (cchDst > 1) \
312 { \
313 const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \
314 pszDst += cchTmp; \
315 cchDst -= cchTmp; \
316 Assert(cchTmp == (cch) || cchDst == 1); \
317 } \
318 } while (0)
319/** @todo add two flags for choosing between %X / %x and h / 0x. */
320#define PUT_NUM_8(num) PUT_NUM(4, "0%02xh", (uint8_t)(num))
321#define PUT_NUM_16(num) PUT_NUM(6, "0%04xh", (uint16_t)(num))
322#define PUT_NUM_32(num) PUT_NUM(10, "0%08xh", (uint32_t)(num))
323#define PUT_NUM_64(num) PUT_NUM(18, "0%016RX64h", (uint64_t)(num))
324
325#define PUT_NUM_SIGN(cch, fmt, num, stype, utype) \
326 do { \
327 if ((stype)(num) >= 0) \
328 { \
329 PUT_C('+'); \
330 PUT_NUM(cch, fmt, (utype)(num)); \
331 } \
332 else \
333 { \
334 PUT_C('-'); \
335 PUT_NUM(cch, fmt, (utype)-(stype)(num)); \
336 } \
337 } while (0)
338#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0%02xh", num, int8_t, uint8_t)
339#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0%04xh", num, int16_t, uint16_t)
340#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0%08xh", num, int32_t, uint32_t)
341#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0%016RX64h", num, int64_t, uint64_t)
342
343
344 /*
345 * The address?
346 */
347 if (fFlags & DIS_FMT_FLAGS_ADDR_LEFT)
348 {
349#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
350 if (pCpu->uInstrAddr >= _4G)
351 PUT_NUM(9, "%08x`", (uint32_t)(pCpu->uInstrAddr >> 32));
352#endif
353 PUT_NUM(8, "%08x", (uint32_t)pCpu->uInstrAddr);
354 PUT_C(' ');
355 }
356
357 /*
358 * The opcode bytes?
359 */
360 if (fFlags & DIS_FMT_FLAGS_BYTES_LEFT)
361 {
362 size_t cchTmp = disFormatBytes(pCpu, pszDst, cchDst, fFlags);
363 cchOutput += cchTmp;
364 if (cchDst > 1)
365 {
366 if (cchTmp <= cchDst)
367 {
368 cchDst -= cchTmp;
369 pszDst += cchTmp;
370 }
371 else
372 {
373 pszDst += cchDst - 1;
374 cchDst = 1;
375 }
376 }
377
378 /* Some padding to align the instruction. */
379 size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED)))
380 + !!(fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) * 2
381 + 2;
382 cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp;
383 PUT_STR(g_szSpaces, cchPadding);
384 }
385
386
387 /*
388 * Filter out invalid opcodes first as they need special
389 * treatment. UD2 is an exception and should be handled normally.
390 */
391 size_t const offInstruction = cchOutput;
392 if ( pOp->opcode == OP_INVALID
393 || ( pOp->opcode == OP_ILLUD2
394 && (pCpu->prefix & DISPREFIX_LOCK)))
395 {
396
397 }
398 else
399 {
400 /*
401 * Prefixes
402 */
403 if (pCpu->prefix & DISPREFIX_LOCK)
404 PUT_SZ("lock ");
405 if(pCpu->prefix & DISPREFIX_REP)
406 PUT_SZ("rep ");
407 else if(pCpu->prefix & DISPREFIX_REPNE)
408 PUT_SZ("repne ");
409
410 /*
411 * Adjust the format string to the correct mnemonic
412 * or to avoid things the assembler cannot handle correctly.
413 */
414 char szTmpFmt[48];
415 const char *pszFmt = pOp->pszOpcode;
416 switch (pOp->opcode)
417 {
418 case OP_JECXZ:
419 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "jcxz %Jb" : pCpu->opmode == DISCPUMODE_32BIT ? "jecxz %Jb" : "jrcxz %Jb";
420 break;
421 case OP_PUSHF:
422 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "pushfw" : pCpu->opmode == DISCPUMODE_32BIT ? "pushfd" : "pushfq";
423 break;
424 case OP_POPF:
425 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "popfw" : pCpu->opmode == DISCPUMODE_32BIT ? "popfd" : "popfq";
426 break;
427 case OP_PUSHA:
428 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "pushaw" : "pushad";
429 break;
430 case OP_POPA:
431 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "popaw" : "popad";
432 break;
433 case OP_INSB:
434 pszFmt = "insb";
435 break;
436 case OP_INSWD:
437 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "insw" : pCpu->opmode == DISCPUMODE_32BIT ? "insd" : "insq";
438 break;
439 case OP_OUTSB:
440 pszFmt = "outsb";
441 break;
442 case OP_OUTSWD:
443 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "outsw" : pCpu->opmode == DISCPUMODE_32BIT ? "outsd" : "outsq";
444 break;
445 case OP_MOVSB:
446 pszFmt = "movsb";
447 break;
448 case OP_MOVSWD:
449 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "movsw" : pCpu->opmode == DISCPUMODE_32BIT ? "movsd" : "movsq";
450 break;
451 case OP_CMPSB:
452 pszFmt = "cmpsb";
453 break;
454 case OP_CMPWD:
455 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "cmpsw" : pCpu->opmode == DISCPUMODE_32BIT ? "cmpsd" : "cmpsq";
456 break;
457 case OP_SCASB:
458 pszFmt = "scasb";
459 break;
460 case OP_SCASWD:
461 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "scasw" : pCpu->opmode == DISCPUMODE_32BIT ? "scasd" : "scasq";
462 break;
463 case OP_LODSB:
464 pszFmt = "lodsb";
465 break;
466 case OP_LODSWD:
467 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "lodsw" : pCpu->opmode == DISCPUMODE_32BIT ? "lodsd" : "lodsq";
468 break;
469 case OP_STOSB:
470 pszFmt = "stosb";
471 break;
472 case OP_STOSWD:
473 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "stosw" : pCpu->opmode == DISCPUMODE_32BIT ? "stosd" : "stosq";
474 break;
475 case OP_CBW:
476 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "cbw" : pCpu->opmode == DISCPUMODE_32BIT ? "cwde" : "cdqe";
477 break;
478 case OP_CWD:
479 pszFmt = pCpu->opmode == DISCPUMODE_16BIT ? "cwd" : pCpu->opmode == DISCPUMODE_32BIT ? "cdq" : "cqo";
480 break;
481 case OP_SHL:
482 Assert(pszFmt[3] == '/');
483 pszFmt += 4;
484 break;
485 case OP_XLAT:
486 pszFmt = "xlatb";
487 break;
488 case OP_INT3:
489 pszFmt = "int3";
490 break;
491
492 /*
493 * Don't know how to tell yasm to generate complicated nop stuff, so 'db' it.
494 */
495 case OP_NOP:
496 if (pCpu->opcode == 0x90)
497 /* fine, fine */;
498 else if (pszFmt[sizeof("nop %Ev") - 1] == '/' && pszFmt[sizeof("nop %Ev")] == 'p')
499 pszFmt = "prefetch %Eb";
500 else if (pCpu->opcode == 0x1f)
501 {
502 Assert(pCpu->opsize >= 3);
503 PUT_SZ("db 00fh, 01fh,");
504 PUT_NUM_8(pCpu->ModRM.u);
505 for (unsigned i = 3; i < pCpu->opsize; i++)
506 {
507 PUT_C(',');
508 PUT_NUM_8(0x90); ///@todo fixme.
509 }
510 pszFmt = "";
511 }
512 break;
513
514 default:
515 /* ST(X) -> stX (floating point) */
516 if (*pszFmt == 'f' && strchr(pszFmt, '('))
517 {
518 char *pszFmtDst = szTmpFmt;
519 char ch;
520 do
521 {
522 ch = *pszFmt++;
523 if (ch == 'S' && pszFmt[0] == 'T' && pszFmt[1] == '(')
524 {
525 *pszFmtDst++ = 's';
526 *pszFmtDst++ = 't';
527 pszFmt += 2;
528 ch = *pszFmt;
529 Assert(pszFmt[1] == ')');
530 pszFmt += 2;
531 *pszFmtDst++ = ch;
532 }
533 else
534 *pszFmtDst++ = ch;
535 } while (ch != '\0');
536 pszFmt = szTmpFmt;
537 }
538 break;
539
540 /*
541 * Horrible hacks.
542 */
543 case OP_FLD:
544 if (pCpu->opcode == 0xdb) /* m80fp workaround. */
545 *(int *)&pCpu->param1.param &= ~0x1f; /* make it pure OP_PARM_M */
546 break;
547 case OP_LAR: /* hack w -> v, probably not correct. */
548 *(int *)&pCpu->param2.param &= ~0x1f;
549 *(int *)&pCpu->param2.param |= OP_PARM_v;
550 break;
551 }
552
553 /*
554 * Formatting context and associated macros.
555 */
556 PCOP_PARAMETER pParam = &pCpu->param1;
557 int iParam = 1;
558
559#define PUT_FAR() \
560 do { \
561 if ( OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p \
562 && pOp->opcode != OP_LDS /* table bugs? */ \
563 && pOp->opcode != OP_LES \
564 && pOp->opcode != OP_LFS \
565 && pOp->opcode != OP_LGS \
566 && pOp->opcode != OP_LSS ) \
567 PUT_SZ("far "); \
568 } while (0)
569 /** @todo mov ah,ch ends up with a byte 'override'... - check if this wasn't fixed. */
570 /** @todo drop the work/dword/qword override when the src/dst is a register (except for movsx/movzx). */
571#define PUT_SIZE_OVERRIDE() \
572 do { \
573 switch (OP_PARM_VSUBTYPE(pParam->param)) \
574 { \
575 case OP_PARM_v: \
576 switch (pCpu->opmode) \
577 { \
578 case DISCPUMODE_16BIT: PUT_SZ("word "); break; \
579 case DISCPUMODE_32BIT: PUT_SZ("dword "); break; \
580 case DISCPUMODE_64BIT: PUT_SZ("qword "); break; \
581 default: break; \
582 } \
583 break; \
584 case OP_PARM_b: PUT_SZ("byte "); break; \
585 case OP_PARM_w: PUT_SZ("word "); break; \
586 case OP_PARM_d: PUT_SZ("dword "); break; \
587 case OP_PARM_q: PUT_SZ("qword "); break; \
588 case OP_PARM_dq: \
589 if (OP_PARM_VTYPE(pParam->param) != OP_PARM_W) /* these are 128 bit, pray they are all unambiguous.. */ \
590 PUT_SZ("qword "); \
591 break; \
592 case OP_PARM_p: break; /* see PUT_FAR */ \
593 case OP_PARM_s: if (pParam->fUse & DISUSE_REG_FP) PUT_SZ("tword "); break; /* ?? */ \
594 case OP_PARM_z: break; \
595 case OP_PARM_NONE: \
596 if ( OP_PARM_VTYPE(pParam->param) == OP_PARM_M \
597 && ((pParam->fUse & DISUSE_REG_FP) || pOp->opcode == OP_FLD)) \
598 PUT_SZ("tword "); \
599 break; \
600 default: break; /*no pointer type specified/necessary*/ \
601 } \
602 } while (0)
603 static const char s_szSegPrefix[6][4] = { "es:", "cs:", "ss:", "ds:", "fs:", "gs:" };
604#define PUT_SEGMENT_OVERRIDE() \
605 do { \
606 if (pCpu->prefix & DISPREFIX_SEG) \
607 PUT_STR(s_szSegPrefix[pCpu->idxSegPrefix], 3); \
608 } while (0)
609
610
611 /*
612 * Segment prefixing for instructions that doesn't do memory access.
613 */
614 if ( (pCpu->prefix & DISPREFIX_SEG)
615 && !DISUSE_IS_EFFECTIVE_ADDR(pCpu->param1.fUse)
616 && !DISUSE_IS_EFFECTIVE_ADDR(pCpu->param2.fUse)
617 && !DISUSE_IS_EFFECTIVE_ADDR(pCpu->param3.fUse))
618 {
619 PUT_STR(s_szSegPrefix[pCpu->idxSegPrefix], 2);
620 PUT_C(' ');
621 }
622
623
624 /*
625 * The formatting loop.
626 */
627 RTINTPTR off;
628 char szSymbol[128];
629 char ch;
630 while ((ch = *pszFmt++) != '\0')
631 {
632 if (ch == '%')
633 {
634 ch = *pszFmt++;
635 switch (ch)
636 {
637 /*
638 * ModRM - Register only.
639 */
640 case 'C': /* Control register (ParseModRM / UseModRM). */
641 case 'D': /* Debug register (ParseModRM / UseModRM). */
642 case 'G': /* ModRM selects general register (ParseModRM / UseModRM). */
643 case 'S': /* ModRM byte selects a segment register (ParseModRM / UseModRM). */
644 case 'T': /* ModRM byte selects a test register (ParseModRM / UseModRM). */
645 case 'V': /* ModRM byte selects an XMM/SSE register (ParseModRM / UseModRM). */
646 case 'P': /* ModRM byte selects MMX register (ParseModRM / UseModRM). */
647 {
648 pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
649 Assert(!(pParam->fUse & (DISUSE_INDEX | DISUSE_SCALE) /* No SIB here... */));
650 Assert(!(pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)));
651
652 size_t cchReg;
653 const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
654 PUT_STR(pszReg, cchReg);
655 break;
656 }
657
658 /*
659 * ModRM - Register or memory.
660 */
661 case 'E': /* ModRM specifies parameter (ParseModRM / UseModRM / UseSIB). */
662 case 'Q': /* ModRM byte selects MMX register or memory address (ParseModRM / UseModRM). */
663 case 'R': /* ModRM byte may only refer to a general register (ParseModRM / UseModRM). */
664 case 'W': /* ModRM byte selects an XMM/SSE register or a memory address (ParseModRM / UseModRM). */
665 case 'M': /* ModRM may only refer to memory (ParseModRM / UseModRM). */
666 {
667 pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
668
669 PUT_FAR();
670 if (DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse))
671 {
672 /* Work around mov seg,[mem16] and mov [mem16],seg as these always make a 16-bit mem
673 while the register variants deals with 16, 32 & 64 in the normal fashion. */
674 if ( pParam->param != OP_PARM_Ev
675 || pOp->opcode != OP_MOV
676 || ( pOp->param1 != OP_PARM_Sw
677 && pOp->param2 != OP_PARM_Sw))
678 PUT_SIZE_OVERRIDE();
679 PUT_C('[');
680 }
681 if ( (fFlags & DIS_FMT_FLAGS_STRICT)
682 && (pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)))
683 {
684 if ( (pParam->fUse & DISUSE_DISPLACEMENT8)
685 && !pParam->uDisp.i8)
686 PUT_SZ("byte ");
687 else if ( (pParam->fUse & DISUSE_DISPLACEMENT16)
688 && (int8_t)pParam->uDisp.i16 == (int16_t)pParam->uDisp.i16)
689 PUT_SZ("word ");
690 else if ( (pParam->fUse & DISUSE_DISPLACEMENT32)
691 && (int16_t)pParam->uDisp.i32 == (int32_t)pParam->uDisp.i32) //??
692 PUT_SZ("dword ");
693 else if ( (pParam->fUse & DISUSE_DISPLACEMENT64)
694 && (pCpu->SIB.Bits.Base != 5 || pCpu->ModRM.Bits.Mod != 0)
695 && (int32_t)pParam->uDisp.i64 == (int64_t)pParam->uDisp.i64) //??
696 PUT_SZ("qword ");
697 }
698 if (DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse))
699 PUT_SEGMENT_OVERRIDE();
700
701 bool fBase = (pParam->fUse & DISUSE_BASE) /* When exactly is DISUSE_BASE supposed to be set? disasmModRMReg doesn't set it. */
702 || ( (pParam->fUse & (DISUSE_REG_GEN8 | DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64))
703 && !DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse));
704 if (fBase)
705 {
706 size_t cchReg;
707 const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
708 PUT_STR(pszReg, cchReg);
709 }
710
711 if (pParam->fUse & DISUSE_INDEX)
712 {
713 if (fBase)
714 PUT_C('+');
715
716 size_t cchReg;
717 const char *pszReg = disasmFormatYasmIndexReg(pCpu, pParam, &cchReg);
718 PUT_STR(pszReg, cchReg);
719
720 if (pParam->fUse & DISUSE_SCALE)
721 {
722 PUT_C('*');
723 PUT_C('0' + pParam->scale);
724 }
725 }
726 else
727 Assert(!(pParam->fUse & DISUSE_SCALE));
728
729 if (pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32))
730 {
731 int64_t off2;
732 if (pParam->fUse & DISUSE_DISPLACEMENT8)
733 off2 = pParam->uDisp.i8;
734 else if (pParam->fUse & DISUSE_DISPLACEMENT16)
735 off2 = pParam->uDisp.i16;
736 else if (pParam->fUse & (DISUSE_DISPLACEMENT32 | DISUSE_RIPDISPLACEMENT32))
737 off2 = pParam->uDisp.i32;
738 else if (pParam->fUse & DISUSE_DISPLACEMENT64)
739 off2 = pParam->uDisp.i64;
740 else
741 {
742 AssertFailed();
743 off2 = 0;
744 }
745
746 if (fBase || (pParam->fUse & DISUSE_INDEX))
747 {
748 PUT_C(off2 >= 0 ? '+' : '-');
749 if (off2 < 0)
750 off2 = -off2;
751 }
752 if (pParam->fUse & DISUSE_DISPLACEMENT8)
753 PUT_NUM_8( off2);
754 else if (pParam->fUse & DISUSE_DISPLACEMENT16)
755 PUT_NUM_16(off2);
756 else if (pParam->fUse & DISUSE_DISPLACEMENT32)
757 PUT_NUM_32(off2);
758 else if (pParam->fUse & DISUSE_DISPLACEMENT64)
759 PUT_NUM_64(off2);
760 else
761 {
762 PUT_NUM_32(off2);
763 PUT_SZ(" wrt rip"); //??
764 }
765 }
766
767 if (DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse))
768 PUT_C(']');
769 break;
770 }
771
772 case 'F': /* Eflags register (0 - popf/pushf only, avoided in adjustments above). */
773 AssertFailed();
774 break;
775
776 case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */
777 Assert(*pszFmt == 'b' || *pszFmt == 'v' || *pszFmt == 'w' || *pszFmt == 'z'); pszFmt++;
778 switch (pParam->fUse & ( DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64
779 | DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
780 {
781 case DISUSE_IMMEDIATE8:
782 if ( (fFlags & DIS_FMT_FLAGS_STRICT)
783 && ( (pOp->param1 >= OP_PARM_REG_GEN8_START && pOp->param1 <= OP_PARM_REG_GEN8_END)
784 || (pOp->param2 >= OP_PARM_REG_GEN8_START && pOp->param2 <= OP_PARM_REG_GEN8_END))
785 )
786 PUT_SZ("strict byte ");
787 PUT_NUM_8(pParam->parval);
788 break;
789
790 case DISUSE_IMMEDIATE16:
791 if ( pCpu->mode != pCpu->opmode
792 || ( (fFlags & DIS_FMT_FLAGS_STRICT)
793 && ( (int8_t)pParam->parval == (int16_t)pParam->parval
794 || (pOp->param1 >= OP_PARM_REG_GEN16_START && pOp->param1 <= OP_PARM_REG_GEN16_END)
795 || (pOp->param2 >= OP_PARM_REG_GEN16_START && pOp->param2 <= OP_PARM_REG_GEN16_END))
796 )
797 )
798 {
799 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_b)
800 PUT_SZ_STRICT("strict byte ", "byte ");
801 else if ( OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_v
802 || OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_z)
803 PUT_SZ_STRICT("strict word ", "word ");
804 }
805 PUT_NUM_16(pParam->parval);
806 break;
807
808 case DISUSE_IMMEDIATE16_SX8:
809 PUT_SZ_STRICT("strict byte ", "byte ");
810 PUT_NUM_16(pParam->parval);
811 break;
812
813 case DISUSE_IMMEDIATE32:
814 if ( pCpu->opmode != (pCpu->mode == DISCPUMODE_16BIT ? DISCPUMODE_16BIT : DISCPUMODE_32BIT) /* not perfect */
815 || ( (fFlags & DIS_FMT_FLAGS_STRICT)
816 && ( (int8_t)pParam->parval == (int32_t)pParam->parval
817 || (pOp->param1 >= OP_PARM_REG_GEN32_START && pOp->param1 <= OP_PARM_REG_GEN32_END)
818 || (pOp->param2 >= OP_PARM_REG_GEN32_START && pOp->param2 <= OP_PARM_REG_GEN32_END))
819 )
820 )
821 {
822 if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_b)
823 PUT_SZ_STRICT("strict byte ", "byte ");
824 else if ( OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_v
825 || OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_z)
826 PUT_SZ_STRICT("strict dword ", "dword ");
827 }
828 PUT_NUM_32(pParam->parval);
829 break;
830
831 case DISUSE_IMMEDIATE32_SX8:
832 PUT_SZ_STRICT("strict byte ", "byte ");
833 PUT_NUM_32(pParam->parval);
834 break;
835
836 case DISUSE_IMMEDIATE64_SX8:
837 PUT_SZ_STRICT("strict byte ", "byte ");
838 PUT_NUM_64(pParam->parval);
839 break;
840
841 case DISUSE_IMMEDIATE64:
842 PUT_NUM_64(pParam->parval);
843 break;
844
845 default:
846 AssertFailed();
847 break;
848 }
849 break;
850
851 case 'J': /* Relative jump offset (ParseImmBRel + ParseImmVRel). */
852 {
853 int32_t offDisplacement;
854 Assert(iParam == 1);
855 bool fPrefix = (fFlags & DIS_FMT_FLAGS_STRICT)
856 && pOp->opcode != OP_CALL
857 && pOp->opcode != OP_LOOP
858 && pOp->opcode != OP_LOOPE
859 && pOp->opcode != OP_LOOPNE
860 && pOp->opcode != OP_JECXZ;
861 if (pOp->opcode == OP_CALL)
862 fFlags &= ~DIS_FMT_FLAGS_RELATIVE_BRANCH;
863
864 if (pParam->fUse & DISUSE_IMMEDIATE8_REL)
865 {
866 if (fPrefix)
867 PUT_SZ("short ");
868 offDisplacement = (int8_t)pParam->parval;
869 Assert(*pszFmt == 'b'); pszFmt++;
870
871 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
872 PUT_NUM_S8(offDisplacement);
873 }
874 else if (pParam->fUse & DISUSE_IMMEDIATE16_REL)
875 {
876 if (fPrefix)
877 PUT_SZ("near ");
878 offDisplacement = (int16_t)pParam->parval;
879 Assert(*pszFmt == 'v'); pszFmt++;
880
881 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
882 PUT_NUM_S16(offDisplacement);
883 }
884 else
885 {
886 if (fPrefix)
887 PUT_SZ("near ");
888 offDisplacement = (int32_t)pParam->parval;
889 Assert(pParam->fUse & (DISUSE_IMMEDIATE32_REL|DISUSE_IMMEDIATE64_REL));
890 Assert(*pszFmt == 'v'); pszFmt++;
891
892 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
893 PUT_NUM_S32(offDisplacement);
894 }
895 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
896 PUT_SZ(" (");
897
898 RTUINTPTR uTrgAddr = pCpu->uInstrAddr + pCpu->opsize + offDisplacement;
899 if (pCpu->mode == DISCPUMODE_16BIT)
900 PUT_NUM_16(uTrgAddr);
901 else if (pCpu->mode == DISCPUMODE_32BIT)
902 PUT_NUM_32(uTrgAddr);
903 else
904 PUT_NUM_64(uTrgAddr);
905
906 if (pfnGetSymbol)
907 {
908 int rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), uTrgAddr, szSymbol, sizeof(szSymbol), &off, pvUser);
909 if (RT_SUCCESS(rc))
910 {
911 PUT_SZ(" [");
912 PUT_PSZ(szSymbol);
913 if (off != 0)
914 {
915 if ((int8_t)off == off)
916 PUT_NUM_S8(off);
917 else if ((int16_t)off == off)
918 PUT_NUM_S16(off);
919 else if ((int32_t)off == off)
920 PUT_NUM_S32(off);
921 else
922 PUT_NUM_S64(off);
923 }
924 PUT_C(']');
925 }
926 }
927
928 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
929 PUT_C(')');
930 break;
931 }
932
933 case 'A': /* Direct (jump/call) address (ParseImmAddr). */
934 {
935 Assert(*pszFmt == 'p'); pszFmt++;
936 PUT_FAR();
937 PUT_SIZE_OVERRIDE();
938 PUT_SEGMENT_OVERRIDE();
939 int rc = VERR_SYMBOL_NOT_FOUND;
940 switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16))
941 {
942 case DISUSE_IMMEDIATE_ADDR_16_16:
943 PUT_NUM_16(pParam->parval >> 16);
944 PUT_C(':');
945 PUT_NUM_16(pParam->parval);
946 if (pfnGetSymbol)
947 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
948 break;
949 case DISUSE_IMMEDIATE_ADDR_16_32:
950 PUT_NUM_16(pParam->parval >> 32);
951 PUT_C(':');
952 PUT_NUM_32(pParam->parval);
953 if (pfnGetSymbol)
954 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
955 break;
956 case DISUSE_DISPLACEMENT16:
957 PUT_NUM_16(pParam->parval);
958 if (pfnGetSymbol)
959 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
960 break;
961 case DISUSE_DISPLACEMENT32:
962 PUT_NUM_32(pParam->parval);
963 if (pfnGetSymbol)
964 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
965 break;
966 case DISUSE_DISPLACEMENT64:
967 PUT_NUM_64(pParam->parval);
968 if (pfnGetSymbol)
969 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint64_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
970 break;
971 default:
972 AssertFailed();
973 break;
974 }
975
976 if (RT_SUCCESS(rc))
977 {
978 PUT_SZ(" [");
979 PUT_PSZ(szSymbol);
980 if (off != 0)
981 {
982 if ((int8_t)off == off)
983 PUT_NUM_S8(off);
984 else if ((int16_t)off == off)
985 PUT_NUM_S16(off);
986 else if ((int32_t)off == off)
987 PUT_NUM_S32(off);
988 else
989 PUT_NUM_S64(off);
990 }
991 PUT_C(']');
992 }
993 break;
994 }
995
996 case 'O': /* No ModRM byte (ParseImmAddr). */
997 {
998 Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
999 PUT_FAR();
1000 PUT_SIZE_OVERRIDE();
1001 PUT_C('[');
1002 PUT_SEGMENT_OVERRIDE();
1003 int rc = VERR_SYMBOL_NOT_FOUND;
1004 switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16))
1005 {
1006 case DISUSE_IMMEDIATE_ADDR_16_16:
1007 PUT_NUM_16(pParam->parval >> 16);
1008 PUT_C(':');
1009 PUT_NUM_16(pParam->parval);
1010 if (pfnGetSymbol)
1011 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1012 break;
1013 case DISUSE_IMMEDIATE_ADDR_16_32:
1014 PUT_NUM_16(pParam->parval >> 32);
1015 PUT_C(':');
1016 PUT_NUM_32(pParam->parval);
1017 if (pfnGetSymbol)
1018 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1019 break;
1020 case DISUSE_DISPLACEMENT16:
1021 PUT_NUM_16(pParam->uDisp.i16);
1022 if (pfnGetSymbol)
1023 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), pParam->uDisp.u16, szSymbol, sizeof(szSymbol), &off, pvUser);
1024 break;
1025 case DISUSE_DISPLACEMENT32:
1026 PUT_NUM_32(pParam->uDisp.i32);
1027 if (pfnGetSymbol)
1028 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), pParam->uDisp.u32, szSymbol, sizeof(szSymbol), &off, pvUser);
1029 break;
1030 case DISUSE_DISPLACEMENT64:
1031 PUT_NUM_64(pParam->uDisp.i64);
1032 if (pfnGetSymbol)
1033 rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), pParam->uDisp.u64, szSymbol, sizeof(szSymbol), &off, pvUser);
1034 break;
1035 default:
1036 AssertFailed();
1037 break;
1038 }
1039 PUT_C(']');
1040
1041 if (RT_SUCCESS(rc))
1042 {
1043 PUT_SZ(" (");
1044 PUT_PSZ(szSymbol);
1045 if (off != 0)
1046 {
1047 if ((int8_t)off == off)
1048 PUT_NUM_S8(off);
1049 else if ((int16_t)off == off)
1050 PUT_NUM_S16(off);
1051 else if ((int32_t)off == off)
1052 PUT_NUM_S32(off);
1053 else
1054 PUT_NUM_S64(off);
1055 }
1056 PUT_C(')');
1057 }
1058 break;
1059 }
1060
1061 case 'X': /* DS:SI (ParseXb, ParseXv). */
1062 case 'Y': /* ES:DI (ParseYb, ParseYv). */
1063 {
1064 Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
1065 PUT_FAR();
1066 PUT_SIZE_OVERRIDE();
1067 PUT_C('[');
1068 if (pParam->fUse & DISUSE_POINTER_DS_BASED)
1069 PUT_SZ("ds:");
1070 else
1071 PUT_SZ("es:");
1072
1073 size_t cchReg;
1074 const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
1075 PUT_STR(pszReg, cchReg);
1076 PUT_C(']');
1077 break;
1078 }
1079
1080 case 'e': /* Register based on operand size (e.g. %eAX) (ParseFixedReg). */
1081 {
1082 Assert(RT_C_IS_ALPHA(pszFmt[0]) && RT_C_IS_ALPHA(pszFmt[1]) && !RT_C_IS_ALPHA(pszFmt[2])); pszFmt += 2;
1083 size_t cchReg;
1084 const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
1085 PUT_STR(pszReg, cchReg);
1086 break;
1087 }
1088
1089 default:
1090 AssertMsgFailed(("%c%s!\n", ch, pszFmt));
1091 break;
1092 }
1093 AssertMsg(*pszFmt == ',' || *pszFmt == '\0', ("%c%s\n", ch, pszFmt));
1094 }
1095 else
1096 {
1097 PUT_C(ch);
1098 if (ch == ',')
1099 {
1100 Assert(*pszFmt != ' ');
1101 PUT_C(' ');
1102 switch (++iParam)
1103 {
1104 case 2: pParam = &pCpu->param2; break;
1105 case 3: pParam = &pCpu->param3; break;
1106 default: pParam = NULL; break;
1107 }
1108 }
1109 }
1110 } /* while more to format */
1111 }
1112
1113 /*
1114 * Any additional output to the right of the instruction?
1115 */
1116 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
1117 {
1118 /* some up front padding. */
1119 size_t cchPadding = cchOutput - offInstruction;
1120 cchPadding = cchPadding + 1 >= 42 ? 1 : 42 - cchPadding;
1121 PUT_STR(g_szSpaces, cchPadding);
1122
1123 /* comment? */
1124 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
1125 PUT_SZ(";");
1126
1127 /*
1128 * The address?
1129 */
1130 if (fFlags & DIS_FMT_FLAGS_ADDR_RIGHT)
1131 {
1132 PUT_C(' ');
1133#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
1134 if (pCpu->uInstrAddr >= _4G)
1135 PUT_NUM(9, "%08x`", (uint32_t)(pCpu->uInstrAddr >> 32));
1136#endif
1137 PUT_NUM(8, "%08x", (uint32_t)pCpu->uInstrAddr);
1138 }
1139
1140 /*
1141 * Opcode bytes?
1142 */
1143 if (fFlags & DIS_FMT_FLAGS_BYTES_RIGHT)
1144 {
1145 PUT_C(' ');
1146 size_t cchTmp = disFormatBytes(pCpu, pszDst, cchDst, fFlags);
1147 cchOutput += cchTmp;
1148 if (cchTmp >= cchDst)
1149 cchTmp = cchDst - (cchDst != 0);
1150 cchDst -= cchTmp;
1151 pszDst += cchTmp;
1152 }
1153 }
1154
1155 /*
1156 * Terminate it - on overflow we'll have reserved one byte for this.
1157 */
1158 if (cchDst > 0)
1159 *pszDst = '\0';
1160 else
1161 Assert(!cchBuf);
1162
1163 /* clean up macros */
1164#undef PUT_PSZ
1165#undef PUT_SZ
1166#undef PUT_STR
1167#undef PUT_C
1168 return cchOutput;
1169}
1170
1171
1172/**
1173 * Formats the current instruction in Yasm (/ Nasm) style.
1174 *
1175 * This is a simplified version of DISFormatYasmEx() provided for your convenience.
1176 *
1177 *
1178 * @returns The number of output characters. If this is >= cchBuf, then the content
1179 * of pszBuf will be truncated.
1180 * @param pCpu Pointer to the disassembler CPU state.
1181 * @param pszBuf The output buffer.
1182 * @param cchBuf The size of the output buffer.
1183 */
1184DISDECL(size_t) DISFormatYasm(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf)
1185{
1186 return DISFormatYasmEx(pCpu, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */);
1187}
1188
1189
1190/**
1191 * Checks if the encoding of the given disassembled instruction is something we
1192 * can never get YASM to produce.
1193 *
1194 * @returns true if it's odd, false if it isn't.
1195 * @param pCpu The disassembler output. The byte fetcher callback will
1196 * be used if present as we might need to fetch opcode
1197 * bytes.
1198 */
1199DISDECL(bool) DISFormatYasmIsOddEncoding(PDISCPUSTATE pCpu)
1200{
1201 /*
1202 * Mod rm + SIB: Check for duplicate EBP encodings that yasm won't use for very good reasons.
1203 */
1204 if ( pCpu->addrmode != DISCPUMODE_16BIT ///@todo correct?
1205 && pCpu->ModRM.Bits.Rm == 4
1206 && pCpu->ModRM.Bits.Mod != 3)
1207 {
1208 /* No scaled index SIB (index=4), except for ESP. */
1209 if ( pCpu->SIB.Bits.Index == 4
1210 && pCpu->SIB.Bits.Base != 4)
1211 return true;
1212
1213 /* EBP + displacement */
1214 if ( pCpu->ModRM.Bits.Mod != 0
1215 && pCpu->SIB.Bits.Base == 5
1216 && pCpu->SIB.Bits.Scale == 0)
1217 return true;
1218 }
1219
1220 /*
1221 * Seems to be an instruction alias here, but I cannot find any docs on it... hrmpf!
1222 */
1223 if ( pCpu->pCurInstr->opcode == OP_SHL
1224 && pCpu->ModRM.Bits.Reg == 6)
1225 return true;
1226
1227 /*
1228 * Check for multiple prefixes of the same kind.
1229 */
1230 uint32_t fPrefixes = 0;
1231 for (uint32_t offOpcode = 0; offOpcode < RT_ELEMENTS(pCpu->abInstr); offOpcode++)
1232 {
1233 uint32_t f;
1234 switch (pCpu->abInstr[offOpcode])
1235 {
1236 case 0xf0:
1237 f = DISPREFIX_LOCK;
1238 break;
1239
1240 case 0xf2:
1241 case 0xf3:
1242 f = DISPREFIX_REP; /* yes, both */
1243 break;
1244
1245 case 0x2e:
1246 case 0x3e:
1247 case 0x26:
1248 case 0x36:
1249 case 0x64:
1250 case 0x65:
1251 f = DISPREFIX_SEG;
1252 break;
1253
1254 case 0x66:
1255 f = DISPREFIX_OPSIZE;
1256 break;
1257
1258 case 0x67:
1259 f = DISPREFIX_ADDRSIZE;
1260 break;
1261
1262 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
1263 case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
1264 f = pCpu->mode == DISCPUMODE_64BIT ? DISPREFIX_REX : 0;
1265 break;
1266
1267 default:
1268 f = 0;
1269 break;
1270 }
1271 if (!f)
1272 break; /* done */
1273 if (fPrefixes & f)
1274 return true;
1275 fPrefixes |= f;
1276 }
1277
1278 /* segment overrides are fun */
1279 if (fPrefixes & DISPREFIX_SEG)
1280 {
1281 /* no effective address which it may apply to. */
1282 Assert((pCpu->prefix & DISPREFIX_SEG) || pCpu->mode == DISCPUMODE_64BIT);
1283 if ( !DISUSE_IS_EFFECTIVE_ADDR(pCpu->param1.fUse)
1284 && !DISUSE_IS_EFFECTIVE_ADDR(pCpu->param2.fUse)
1285 && !DISUSE_IS_EFFECTIVE_ADDR(pCpu->param3.fUse))
1286 return true;
1287 }
1288
1289 /* fixed register + addr override doesn't go down all that well. */
1290 if (fPrefixes & DISPREFIX_ADDRSIZE)
1291 {
1292 Assert(pCpu->prefix & DISPREFIX_ADDRSIZE);
1293 if ( pCpu->pCurInstr->param3 == OP_PARM_NONE
1294 && pCpu->pCurInstr->param2 == OP_PARM_NONE
1295 && ( pCpu->pCurInstr->param1 >= OP_PARM_REG_GEN32_START
1296 && pCpu->pCurInstr->param1 <= OP_PARM_REG_GEN32_END))
1297 return true;
1298 }
1299
1300 /* Almost all prefixes are bad. */
1301 if (fPrefixes)
1302 {
1303 switch (pCpu->pCurInstr->opcode)
1304 {
1305 /* nop w/ prefix(es). */
1306 case OP_NOP:
1307 return true;
1308
1309 case OP_JMP:
1310 if ( pCpu->pCurInstr->param1 != OP_PARM_Jb
1311 && pCpu->pCurInstr->param1 != OP_PARM_Jv)
1312 break;
1313 /* fall thru */
1314 case OP_JO:
1315 case OP_JNO:
1316 case OP_JC:
1317 case OP_JNC:
1318 case OP_JE:
1319 case OP_JNE:
1320 case OP_JBE:
1321 case OP_JNBE:
1322 case OP_JS:
1323 case OP_JNS:
1324 case OP_JP:
1325 case OP_JNP:
1326 case OP_JL:
1327 case OP_JNL:
1328 case OP_JLE:
1329 case OP_JNLE:
1330 /** @todo branch hinting 0x2e/0x3e... */
1331 return true;
1332 }
1333
1334 }
1335
1336 /* All but the segment prefix is bad news. */
1337 if (fPrefixes & ~DISPREFIX_SEG)
1338 {
1339 switch (pCpu->pCurInstr->opcode)
1340 {
1341 case OP_POP:
1342 case OP_PUSH:
1343 if ( pCpu->pCurInstr->param1 >= OP_PARM_REG_SEG_START
1344 && pCpu->pCurInstr->param1 <= OP_PARM_REG_SEG_END)
1345 return true;
1346 if ( (fPrefixes & ~DISPREFIX_OPSIZE)
1347 && pCpu->pCurInstr->param1 >= OP_PARM_REG_GEN32_START
1348 && pCpu->pCurInstr->param1 <= OP_PARM_REG_GEN32_END)
1349 return true;
1350 break;
1351
1352 case OP_POPA:
1353 case OP_POPF:
1354 case OP_PUSHA:
1355 case OP_PUSHF:
1356 if (fPrefixes & ~DISPREFIX_OPSIZE)
1357 return true;
1358 break;
1359 }
1360 }
1361
1362 /* Implicit 8-bit register instructions doesn't mix with operand size. */
1363 if ( (fPrefixes & DISPREFIX_OPSIZE)
1364 && ( ( pCpu->pCurInstr->param1 == OP_PARM_Gb /* r8 */
1365 && pCpu->pCurInstr->param2 == OP_PARM_Eb /* r8/mem8 */)
1366 || ( pCpu->pCurInstr->param2 == OP_PARM_Gb /* r8 */
1367 && pCpu->pCurInstr->param1 == OP_PARM_Eb /* r8/mem8 */))
1368 )
1369 {
1370 switch (pCpu->pCurInstr->opcode)
1371 {
1372 case OP_ADD:
1373 case OP_OR:
1374 case OP_ADC:
1375 case OP_SBB:
1376 case OP_AND:
1377 case OP_SUB:
1378 case OP_XOR:
1379 case OP_CMP:
1380 return true;
1381 default:
1382 break;
1383 }
1384 }
1385
1386
1387 /*
1388 * Check for the version of xyz reg,reg instruction that the assembler doesn't use.
1389 *
1390 * For example:
1391 * expected: 1aee sbb ch, dh ; SBB r8, r/m8
1392 * yasm: 18F5 sbb ch, dh ; SBB r/m8, r8
1393 */
1394 if (pCpu->ModRM.Bits.Mod == 3 /* reg,reg */)
1395 {
1396 switch (pCpu->pCurInstr->opcode)
1397 {
1398 case OP_ADD:
1399 case OP_OR:
1400 case OP_ADC:
1401 case OP_SBB:
1402 case OP_AND:
1403 case OP_SUB:
1404 case OP_XOR:
1405 case OP_CMP:
1406 if ( ( pCpu->pCurInstr->param1 == OP_PARM_Gb /* r8 */
1407 && pCpu->pCurInstr->param2 == OP_PARM_Eb /* r8/mem8 */)
1408 || ( pCpu->pCurInstr->param1 == OP_PARM_Gv /* rX */
1409 && pCpu->pCurInstr->param2 == OP_PARM_Ev /* rX/memX */))
1410 return true;
1411
1412 /* 82 (see table A-6). */
1413 if (pCpu->opcode == 0x82)
1414 return true;
1415 break;
1416
1417 /* ff /0, fe /0, ff /1, fe /0 */
1418 case OP_DEC:
1419 case OP_INC:
1420 return true;
1421
1422 case OP_POP:
1423 case OP_PUSH:
1424 Assert(pCpu->opcode == 0x8f);
1425 return true;
1426
1427 case OP_MOV:
1428 if ( pCpu->opcode == 0x8a
1429 || pCpu->opcode == 0x8b)
1430 return true;
1431 break;
1432
1433 default:
1434 break;
1435 }
1436 }
1437
1438 /* shl eax,1 will be assembled to the form without the immediate byte. */
1439 if ( pCpu->pCurInstr->param2 == OP_PARM_Ib
1440 && (uint8_t)pCpu->param2.parval == 1)
1441 {
1442 switch (pCpu->pCurInstr->opcode)
1443 {
1444 case OP_SHL:
1445 case OP_SHR:
1446 case OP_SAR:
1447 case OP_RCL:
1448 case OP_RCR:
1449 case OP_ROL:
1450 case OP_ROR:
1451 return true;
1452 }
1453 }
1454
1455 /* And some more - see table A-6. */
1456 if (pCpu->opcode == 0x82)
1457 {
1458 switch (pCpu->pCurInstr->opcode)
1459 {
1460 case OP_ADD:
1461 case OP_OR:
1462 case OP_ADC:
1463 case OP_SBB:
1464 case OP_AND:
1465 case OP_SUB:
1466 case OP_XOR:
1467 case OP_CMP:
1468 return true;
1469 break;
1470 }
1471 }
1472
1473
1474 /* check for REX.X = 1 without SIB. */
1475
1476 /* Yasm encodes setnbe al with /2 instead of /0 like the AMD manual
1477 says (intel doesn't appear to care). */
1478 switch (pCpu->pCurInstr->opcode)
1479 {
1480 case OP_SETO:
1481 case OP_SETNO:
1482 case OP_SETC:
1483 case OP_SETNC:
1484 case OP_SETE:
1485 case OP_SETNE:
1486 case OP_SETBE:
1487 case OP_SETNBE:
1488 case OP_SETS:
1489 case OP_SETNS:
1490 case OP_SETP:
1491 case OP_SETNP:
1492 case OP_SETL:
1493 case OP_SETNL:
1494 case OP_SETLE:
1495 case OP_SETNLE:
1496 AssertMsg(pCpu->opcode >= 0x90 && pCpu->opcode <= 0x9f, ("%#x\n", pCpu->opcode));
1497 if (pCpu->ModRM.Bits.Reg != 2)
1498 return true;
1499 break;
1500 }
1501
1502 /*
1503 * The MOVZX reg32,mem16 instruction without an operand size prefix
1504 * doesn't quite make sense...
1505 */
1506 if ( pCpu->pCurInstr->opcode == OP_MOVZX
1507 && pCpu->opcode == 0xB7
1508 && (pCpu->mode == DISCPUMODE_16BIT) != !!(fPrefixes & DISPREFIX_OPSIZE))
1509 return true;
1510
1511 return false;
1512}
1513
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