1 /////////////////////////////////////////////////////////////////////////
2 // $Id: dis_decode.cc,v 1.42 2007/11/17 16:19:14 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
10 #include "dis_tables.h"
12 #define OPCODE(entry) ((BxDisasmOpcodeInfo_t*) entry->OpcodeInfo)
13 #define OPCODE_TABLE(entry) ((BxDisasmOpcodeTable_t*) entry->OpcodeInfo)
15 static const unsigned char instruction_has_modrm
[512] = {
16 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
17 /* ------------------------------- */
18 /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
19 /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
20 /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
21 /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
22 /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
23 /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
24 /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,
25 /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
26 /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
27 /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
28 /* A0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
29 /* B0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
30 /* C0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
31 /* D0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,
32 /* E0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
33 /* F0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,
34 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
35 /* ------------------------------- */
36 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0F 00 */
37 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F 10 */
38 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 0F 20 */
39 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 0F 30 */
40 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F 40 */
41 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F 50 */
42 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F 60 */
43 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 0F 70 */
44 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0F 80 */
45 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F 90 */
46 0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1, /* 0F A0 */
47 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F B0 */
48 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 0F C0 */
49 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F D0 */
50 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0F E0 */
51 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* 0F F0 */
52 /* ------------------------------- */
53 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
56 unsigned disassembler::disasm(bx_bool is_32
, bx_bool is_64
, bx_address base
, bx_address ip
, const Bit8u
*instr
, char *disbuf
)
58 x86_insn insn
= decode(is_32
, is_64
, base
, ip
, instr
, disbuf
);
62 x86_insn
disassembler::decode(bx_bool is_32
, bx_bool is_64
, bx_address base
, bx_address ip
, const Bit8u
*instr
, char *disbuf
)
65 x86_insn
insn(is_32
, is_64
);
66 const Bit8u
*instruction_begin
= instruction
= instr
;
71 db_base
= base
; // cs linear base (base for PM & cs<<4 for RM & VM)
73 disbufptr
= disbuf
; // start sprintf()'ing into beginning of buffer
75 #define SSE_PREFIX_NONE 0
76 #define SSE_PREFIX_66 1
77 #define SSE_PREFIX_F2 2
78 #define SSE_PREFIX_F3 3 /* only one SSE prefix could be used */
79 unsigned sse_prefix
= SSE_PREFIX_NONE
;
80 unsigned rex_prefix
= 0;
84 insn
.b1
= fetch_byte();
105 rex_prefix
= insn
.b1
;
109 if (! is_64
) insn
.seg_override
= ES_REG
;
114 if (! is_64
) insn
.seg_override
= CS_REG
;
119 if (! is_64
) insn
.seg_override
= SS_REG
;
124 if (! is_64
) insn
.seg_override
= DS_REG
;
129 insn
.seg_override
= FS_REG
;
134 insn
.seg_override
= GS_REG
;
138 case 0x66: // operand size override
139 if (!insn
.os_64
) insn
.os_32
= !is_32
;
140 if (!sse_prefix
) sse_prefix
= SSE_PREFIX_66
;
144 case 0x67: // address size override
145 if (!is_64
) insn
.as_32
= !is_32
;
155 sse_prefix
= SSE_PREFIX_F2
;
160 sse_prefix
= SSE_PREFIX_F3
;
175 insn
.b1
= 0x100 | fetch_byte();
180 if (rex_prefix
& 0x8) {
184 if (rex_prefix
& 0x4) insn
.rex_r
= 8;
185 if (rex_prefix
& 0x2) insn
.rex_x
= 8;
186 if (rex_prefix
& 0x1) insn
.rex_b
= 8;
189 const BxDisasmOpcodeTable_t
*opcode_table
, *entry
;
193 opcode_table
= BxDisasmOpcodes64q
;
195 opcode_table
= BxDisasmOpcodes64d
;
197 opcode_table
= BxDisasmOpcodes64w
;
200 opcode_table
= BxDisasmOpcodes32
;
202 opcode_table
= BxDisasmOpcodes16
;
205 entry
= opcode_table
+ insn
.b1
;
207 // will require 3rd byte for 3-byte opcode
208 if (entry
->Attr
& _GRP3BTAB
) b3
= fetch_byte();
210 if (instruction_has_modrm
[insn
.b1
])
215 int attr
= entry
->Attr
;
220 entry
= &(OPCODE_TABLE(entry
)[insn
.nnn
]);
224 if(sse_prefix
) insn
.prefixes
--;
225 /* For SSE opcodes, look into another 4 entries table
226 with the opcode prefixes (NONE, 0x66, 0xF2, 0xF3) */
227 entry
= &(OPCODE_TABLE(entry
)[sse_prefix
]);
231 entry
= &(OPCODE_TABLE(entry
)[insn
.mod
!= 3]); /* REG/MEM */
235 entry
= &(OPCODE_TABLE(entry
)[insn
.rm
]);
241 entry
= &(OPCODE_TABLE(entry
)[insn
.nnn
]);
243 int index
= (insn
.b1
-0xD8)*64 + (insn
.modrm
& 0x3f);
244 entry
= &(BxDisasmOpcodeInfoFP
[index
]);
249 entry
= &(BxDisasm3DNowGroup
[peek_byte()]);
253 entry
= &(OPCODE_TABLE(entry
)[b3
>> 4]);
257 entry
= &(OPCODE_TABLE(entry
)[b3
& 15]);
261 entry
= &(OPCODE_TABLE(entry
)[insn
.os_64
? 2 : insn
.os_32
]);
265 printf("Internal disassembler error - unknown attribute !\n");
266 return x86_insn(is_32
, is_64
);
269 /* get additional attributes from group table */
273 #define BRANCH_NOT_TAKEN 0x2E
274 #define BRANCH_TAKEN 0x3E
276 unsigned branch_hint
= 0;
279 for(unsigned i
=0;i
<insn
.prefixes
;i
++)
281 Bit8u prefix_byte
= *(instr
+i
);
283 if (prefix_byte
== 0xF0) {
284 const BxDisasmOpcodeTable_t
*prefix
= &(opcode_table
[prefix_byte
]);
285 dis_sprintf("%s ", OPCODE(prefix
)->IntelOpcode
);
288 if (prefix_byte
== 0xF3 || prefix_byte
== 0xF2) {
289 if (attr
!= _GRPSSE
) {
290 const BxDisasmOpcodeTable_t
*prefix
= &(opcode_table
[prefix_byte
]);
291 dis_sprintf("%s ", OPCODE(prefix
)->IntelOpcode
);
295 // branch hint for jcc instructions
296 if ((insn
.b1
>= 0x070 && insn
.b1
<= 0x07F) ||
297 (insn
.b1
>= 0x180 && insn
.b1
<= 0x18F))
299 if (prefix_byte
== BRANCH_NOT_TAKEN
|| prefix_byte
== BRANCH_TAKEN
)
300 branch_hint
= prefix_byte
;
304 const BxDisasmOpcodeInfo_t
*opcode
= OPCODE(entry
);
307 if (insn
.b1
== 0xE3 && insn
.as_32
&& !insn
.as_64
)
308 opcode
= &Ia_jecxz_Jb
;
311 if (insn
.b1
== 0x90 && !insn
.rex_b
) {
315 // print instruction disassembly
317 print_disassembly_intel(&insn
, opcode
);
319 print_disassembly_att (&insn
, opcode
);
321 if (branch_hint
== BRANCH_NOT_TAKEN
)
323 dis_sprintf(", not taken");
325 else if (branch_hint
== BRANCH_TAKEN
)
327 dis_sprintf(", taken");
330 insn
.ilen
= (unsigned)(instruction
- instruction_begin
);
335 void disassembler::dis_sprintf(char *fmt
, ...)
340 vsprintf(disbufptr
, fmt
, ap
);
343 disbufptr
+= strlen(disbufptr
);
346 void disassembler::dis_putc(char symbol
)
348 *disbufptr
++ = symbol
;