- implemented LBA48 support (since BIOS functions are limited to 32 bit, the
[bochs-mirror.git] / disasm / dis_decode.cc
blob36733f10f19f066899165c1ad0139c161344fae5
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: dis_decode.cc,v 1.42 2007/11/17 16:19:14 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <string.h>
9 #include "disasm.h"
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);
59 return insn.ilen;
62 x86_insn disassembler::decode(bx_bool is_32, bx_bool is_64, bx_address base, bx_address ip, const Bit8u *instr, char *disbuf)
64 if (is_64) is_32 = 1;
65 x86_insn insn(is_32, is_64);
66 const Bit8u *instruction_begin = instruction = instr;
67 resolve_modrm = NULL;
68 unsigned b3 = 0;
70 db_eip = ip;
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;
82 for(;;)
84 insn.b1 = fetch_byte();
85 insn.prefixes++;
87 switch(insn.b1) {
88 case 0x40: // rex
89 case 0x41:
90 case 0x42:
91 case 0x43:
92 case 0x44:
93 case 0x45:
94 case 0x46:
95 case 0x47:
96 case 0x48:
97 case 0x49:
98 case 0x4A:
99 case 0x4B:
100 case 0x4C:
101 case 0x4D:
102 case 0x4E:
103 case 0x4F:
104 if (! is_64) break;
105 rex_prefix = insn.b1;
106 continue;
108 case 0x26: // ES:
109 if (! is_64) insn.seg_override = ES_REG;
110 rex_prefix = 0;
111 continue;
113 case 0x2e: // CS:
114 if (! is_64) insn.seg_override = CS_REG;
115 rex_prefix = 0;
116 continue;
118 case 0x36: // SS:
119 if (! is_64) insn.seg_override = SS_REG;
120 rex_prefix = 0;
121 continue;
123 case 0x3e: // DS:
124 if (! is_64) insn.seg_override = DS_REG;
125 rex_prefix = 0;
126 continue;
128 case 0x64: // FS:
129 insn.seg_override = FS_REG;
130 rex_prefix = 0;
131 continue;
133 case 0x65: // GS:
134 insn.seg_override = GS_REG;
135 rex_prefix = 0;
136 continue;
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;
141 rex_prefix = 0;
142 continue;
144 case 0x67: // address size override
145 if (!is_64) insn.as_32 = !is_32;
146 insn.as_64 = 0;
147 rex_prefix = 0;
148 continue;
150 case 0xf0: // lock
151 rex_prefix = 0;
152 continue;
154 case 0xf2: // repne
155 sse_prefix = SSE_PREFIX_F2;
156 rex_prefix = 0;
157 continue;
159 case 0xf3: // rep
160 sse_prefix = SSE_PREFIX_F3;
161 rex_prefix = 0;
162 continue;
164 // no more prefixes
165 default:
166 break;
169 insn.prefixes--;
170 break;
173 if (insn.b1 == 0x0f)
175 insn.b1 = 0x100 | fetch_byte();
178 if (rex_prefix) {
179 insn.extend8b = 1;
180 if (rex_prefix & 0x8) {
181 insn.os_64 = 1;
182 insn.os_32 = 1;
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;
191 if (is_64) {
192 if (insn.os_64)
193 opcode_table = BxDisasmOpcodes64q;
194 else if (insn.os_32)
195 opcode_table = BxDisasmOpcodes64d;
196 else
197 opcode_table = BxDisasmOpcodes64w;
198 } else {
199 if (insn.os_32)
200 opcode_table = BxDisasmOpcodes32;
201 else
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])
212 decode_modrm(&insn);
215 int attr = entry->Attr;
216 while(attr)
218 switch(attr) {
219 case _GROUPN:
220 entry = &(OPCODE_TABLE(entry)[insn.nnn]);
221 break;
223 case _GRPSSE:
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]);
228 break;
230 case _SPLIT11B:
231 entry = &(OPCODE_TABLE(entry)[insn.mod != 3]); /* REG/MEM */
232 break;
234 case _GRPRM:
235 entry = &(OPCODE_TABLE(entry)[insn.rm]);
236 break;
238 case _GRPFP:
239 if(insn.mod != 3)
241 entry = &(OPCODE_TABLE(entry)[insn.nnn]);
242 } else {
243 int index = (insn.b1-0xD8)*64 + (insn.modrm & 0x3f);
244 entry = &(BxDisasmOpcodeInfoFP[index]);
246 break;
248 case _GRP3DNOW:
249 entry = &(BxDisasm3DNowGroup[peek_byte()]);
250 break;
252 case _GRP3BTAB:
253 entry = &(OPCODE_TABLE(entry)[b3 >> 4]);
254 break;
256 case _GRP3BOP:
257 entry = &(OPCODE_TABLE(entry)[b3 & 15]);
258 break;
260 case _GRP64B:
261 entry = &(OPCODE_TABLE(entry)[insn.os_64 ? 2 : insn.os_32]);
262 break;
264 default:
265 printf("Internal disassembler error - unknown attribute !\n");
266 return x86_insn(is_32, is_64);
269 /* get additional attributes from group table */
270 attr = entry->Attr;
273 #define BRANCH_NOT_TAKEN 0x2E
274 #define BRANCH_TAKEN 0x3E
276 unsigned branch_hint = 0;
278 // print prefixes
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);
306 // patch jecx opcode
307 if (insn.b1 == 0xE3 && insn.as_32 && !insn.as_64)
308 opcode = &Ia_jecxz_Jb;
310 // fix nop opcode
311 if (insn.b1 == 0x90 && !insn.rex_b) {
312 opcode = &Ia_nop;
315 // print instruction disassembly
316 if (intel_mode)
317 print_disassembly_intel(&insn, opcode);
318 else
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);
332 return insn;
335 void disassembler::dis_sprintf(char *fmt, ...)
337 va_list ap;
339 va_start(ap, fmt);
340 vsprintf(disbufptr, fmt, ap);
341 va_end(ap);
343 disbufptr += strlen(disbufptr);
346 void disassembler::dis_putc(char symbol)
348 *disbufptr++ = symbol;
349 *disbufptr = 0;