blob: d63dc255ecb8ead6a2472159f508d70f06d8854b [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* disasm.c where all the _work_ gets done in the Netwide Disassembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
7 *
8 * initial version 27/iii/95 by Simon Tatham
9 */
10
11#include <stdio.h>
12#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000013#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000014
15#include "nasm.h"
16#include "disasm.h"
17#include "sync.h"
18#include "insns.h"
19
20#include "names.c"
21
22extern struct itemplate **itable[];
23
24/*
25 * Flags that go into the `segment' field of `insn' structures
26 * during disassembly.
27 */
28#define SEG_RELATIVE 1
29#define SEG_32BIT 2
30#define SEG_RMREG 4
31#define SEG_DISP8 8
32#define SEG_DISP16 16
33#define SEG_DISP32 32
34#define SEG_NODISP 64
35#define SEG_SIGNED 128
36
Keith Kaniosb7a89542007-04-12 02:40:54 +000037static int whichreg(int32_t regflags, int regval)
H. Peter Anvineba20a72002-04-30 20:53:55 +000038{
H. Peter Anvin232badb2002-06-06 02:41:20 +000039#include "regdis.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000040
41 if (!(REG_AL & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000042 return R_AL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000043 if (!(REG_AX & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000044 return R_AX;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000045 if (!(REG_EAX & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000046 return R_EAX;
H. Peter Anvin10101f22003-02-24 23:22:45 +000047 if (!(REG_DL & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000048 return R_DL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000049 if (!(REG_DX & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000050 return R_DX;
H. Peter Anvin10101f22003-02-24 23:22:45 +000051 if (!(REG_EDX & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000052 return R_EDX;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 if (!(REG_CL & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000054 return R_CL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000055 if (!(REG_CX & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000056 return R_CX;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000057 if (!(REG_ECX & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000058 return R_ECX;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000059 if (!(FPU0 & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000060 return R_ST0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +000061 if (!(REG_CS & ~regflags))
H. Peter Anvin232badb2002-06-06 02:41:20 +000062 return (regval == 1) ? R_CS : 0;
H. Peter Anvin76690a12002-04-30 20:52:49 +000063 if (!(REG_DESS & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000064 return (regval == 0 || regval == 2
65 || regval == 3 ? sreg[regval] : 0);
H. Peter Anvin76690a12002-04-30 20:52:49 +000066 if (!(REG_FSGS & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000067 return (regval == 4 || regval == 5 ? sreg[regval] : 0);
H. Peter Anvin232badb2002-06-06 02:41:20 +000068 if (!(REG_SEG67 & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000069 return (regval == 6 || regval == 7 ? sreg[regval] : 0);
H. Peter Anvin232badb2002-06-06 02:41:20 +000070
71 /* All the entries below look up regval in an 8-entry array */
72 if (regval < 0 || regval > 7)
H. Peter Anvine2c80182005-01-15 22:15:51 +000073 return 0;
H. Peter Anvin232badb2002-06-06 02:41:20 +000074
H. Peter Anvine2c80182005-01-15 22:15:51 +000075 if (!((REGMEM | BITS8) & ~regflags))
76 return reg8[regval];
77 if (!((REGMEM | BITS16) & ~regflags))
78 return reg16[regval];
79 if (!((REGMEM | BITS32) & ~regflags))
80 return reg32[regval];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000081 if (!(REG_SREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000082 return sreg[regval];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000083 if (!(REG_CREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000084 return creg[regval];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000085 if (!(REG_DREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000086 return dreg[regval];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000087 if (!(REG_TREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000088 return treg[regval];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000089 if (!(FPUREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000090 return fpureg[regval];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000091 if (!(MMXREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000092 return mmxreg[regval];
H. Peter Anvin4836e332002-04-30 20:56:43 +000093 if (!(XMMREG & ~regflags))
H. Peter Anvine2c80182005-01-15 22:15:51 +000094 return xmmreg[regval];
H. Peter Anvin232badb2002-06-06 02:41:20 +000095
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096 return 0;
97}
98
Keith Kaniosa6dfa782007-04-13 16:47:53 +000099static const char *whichcond(int condval)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000100{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000101 static int conds[] = {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000102 C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
103 C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000104 };
105 return conditions[conds[condval]];
106}
107
108/*
109 * Process an effective address (ModRM) specification.
110 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000111static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000112 int segsize, operand * op)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000113{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000114 int mod, rm, scale, index, base;
115
116 mod = (modrm >> 6) & 03;
117 rm = modrm & 07;
118
H. Peter Anvine2c80182005-01-15 22:15:51 +0000119 if (mod == 3) { /* pure register version */
120 op->basereg = rm;
121 op->segment |= SEG_RMREG;
122 return data;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123 }
124
125 op->addr_size = 0;
126
127 if (asize == 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000128 /*
129 * <mod> specifies the displacement size (none, byte or
130 * word), and <rm> specifies the register combination.
131 * Exception: mod=0,rm=6 does not specify [BP] as one might
132 * expect, but instead specifies [disp16].
133 */
134 op->indexreg = op->basereg = -1;
135 op->scale = 1; /* always, in 16 bits */
136 switch (rm) {
137 case 0:
138 op->basereg = R_BX;
139 op->indexreg = R_SI;
140 break;
141 case 1:
142 op->basereg = R_BX;
143 op->indexreg = R_DI;
144 break;
145 case 2:
146 op->basereg = R_BP;
147 op->indexreg = R_SI;
148 break;
149 case 3:
150 op->basereg = R_BP;
151 op->indexreg = R_DI;
152 break;
153 case 4:
154 op->basereg = R_SI;
155 break;
156 case 5:
157 op->basereg = R_DI;
158 break;
159 case 6:
160 op->basereg = R_BP;
161 break;
162 case 7:
163 op->basereg = R_BX;
164 break;
165 }
166 if (rm == 6 && mod == 0) { /* special case */
167 op->basereg = -1;
168 if (segsize != 16)
169 op->addr_size = 16;
170 mod = 2; /* fake disp16 */
171 }
172 switch (mod) {
173 case 0:
174 op->segment |= SEG_NODISP;
175 break;
176 case 1:
177 op->segment |= SEG_DISP8;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000178 op->offset = (char)*data++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000179 break;
180 case 2:
181 op->segment |= SEG_DISP16;
182 op->offset = *data++;
183 op->offset |= ((unsigned)*data++) << 8;
184 break;
185 }
186 return data;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000187 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000188 /*
189 * Once again, <mod> specifies displacement size (this time
190 * none, byte or *dword*), while <rm> specifies the base
191 * register. Again, [EBP] is missing, replaced by a pure
192 * disp32 (this time that's mod=0,rm=*5*). However, rm=4
193 * indicates not a single base register, but instead the
194 * presence of a SIB byte...
195 */
196 op->indexreg = -1;
197 switch (rm) {
198 case 0:
199 op->basereg = R_EAX;
200 break;
201 case 1:
202 op->basereg = R_ECX;
203 break;
204 case 2:
205 op->basereg = R_EDX;
206 break;
207 case 3:
208 op->basereg = R_EBX;
209 break;
210 case 5:
211 op->basereg = R_EBP;
212 break;
213 case 6:
214 op->basereg = R_ESI;
215 break;
216 case 7:
217 op->basereg = R_EDI;
218 break;
219 }
220 if (rm == 5 && mod == 0) {
221 op->basereg = -1;
222 if (segsize != 32)
223 op->addr_size = 32;
224 mod = 2; /* fake disp32 */
225 }
226 if (rm == 4) { /* process SIB */
227 scale = (*data >> 6) & 03;
228 index = (*data >> 3) & 07;
229 base = *data & 07;
230 data++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000231
H. Peter Anvine2c80182005-01-15 22:15:51 +0000232 op->scale = 1 << scale;
233 switch (index) {
234 case 0:
235 op->indexreg = R_EAX;
236 break;
237 case 1:
238 op->indexreg = R_ECX;
239 break;
240 case 2:
241 op->indexreg = R_EDX;
242 break;
243 case 3:
244 op->indexreg = R_EBX;
245 break;
246 case 4:
247 op->indexreg = -1;
248 break;
249 case 5:
250 op->indexreg = R_EBP;
251 break;
252 case 6:
253 op->indexreg = R_ESI;
254 break;
255 case 7:
256 op->indexreg = R_EDI;
257 break;
258 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000259
H. Peter Anvine2c80182005-01-15 22:15:51 +0000260 switch (base) {
261 case 0:
262 op->basereg = R_EAX;
263 break;
264 case 1:
265 op->basereg = R_ECX;
266 break;
267 case 2:
268 op->basereg = R_EDX;
269 break;
270 case 3:
271 op->basereg = R_EBX;
272 break;
273 case 4:
274 op->basereg = R_ESP;
275 break;
276 case 6:
277 op->basereg = R_ESI;
278 break;
279 case 7:
280 op->basereg = R_EDI;
281 break;
282 case 5:
283 if (mod == 0) {
284 mod = 2;
285 op->basereg = -1;
286 } else
287 op->basereg = R_EBP;
288 break;
289 }
290 }
291 switch (mod) {
292 case 0:
293 op->segment |= SEG_NODISP;
294 break;
295 case 1:
296 op->segment |= SEG_DISP8;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000297 op->offset = (char)*data++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000298 break;
299 case 2:
300 op->segment |= SEG_DISP32;
301 op->offset = *data++;
302 op->offset |= ((unsigned)*data++) << 8;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000303 op->offset |= ((int32_t)*data++) << 16;
304 op->offset |= ((int32_t)*data++) << 24;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000305 break;
306 }
307 return data;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000308 }
309}
310
311/*
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000312 * Determine whether the instruction template in t corresponds to the data
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000313 * stream in data. Return the number of bytes matched if so.
314 */
Keith Kaniosb7a89542007-04-12 02:40:54 +0000315static int matches(struct itemplate *t, uint8_t *data, int asize,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 int osize, int segsize, int rep, insn * ins)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000317{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000318 uint8_t *r = (uint8_t *)(t->code);
319 uint8_t *origdata = data;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000320 int a_used = FALSE, o_used = FALSE;
321 int drep = 0;
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000322
H. Peter Anvine2c80182005-01-15 22:15:51 +0000323 if (rep == 0xF2)
324 drep = P_REPNE;
325 else if (rep == 0xF3)
326 drep = P_REP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000327
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 while (*r) {
329 int c = *r++;
330 if (c >= 01 && c <= 03) {
331 while (c--)
332 if (*r++ != *data++)
333 return FALSE;
334 }
335 if (c == 04) {
336 switch (*data++) {
337 case 0x07:
338 ins->oprs[0].basereg = 0;
339 break;
340 case 0x17:
341 ins->oprs[0].basereg = 2;
342 break;
343 case 0x1F:
344 ins->oprs[0].basereg = 3;
345 break;
346 default:
347 return FALSE;
348 }
349 }
350 if (c == 05) {
351 switch (*data++) {
352 case 0xA1:
353 ins->oprs[0].basereg = 4;
354 break;
355 case 0xA9:
356 ins->oprs[0].basereg = 5;
357 break;
358 default:
359 return FALSE;
360 }
361 }
362 if (c == 06) {
363 switch (*data++) {
364 case 0x06:
365 ins->oprs[0].basereg = 0;
366 break;
367 case 0x0E:
368 ins->oprs[0].basereg = 1;
369 break;
370 case 0x16:
371 ins->oprs[0].basereg = 2;
372 break;
373 case 0x1E:
374 ins->oprs[0].basereg = 3;
375 break;
376 default:
377 return FALSE;
378 }
379 }
380 if (c == 07) {
381 switch (*data++) {
382 case 0xA0:
383 ins->oprs[0].basereg = 4;
384 break;
385 case 0xA8:
386 ins->oprs[0].basereg = 5;
387 break;
388 default:
389 return FALSE;
390 }
391 }
392 if (c >= 010 && c <= 012) {
393 int t = *r++, d = *data++;
394 if (d < t || d > t + 7)
395 return FALSE;
396 else {
397 ins->oprs[c - 010].basereg = d - t;
398 ins->oprs[c - 010].segment |= SEG_RMREG;
399 }
400 }
401 if (c == 017)
402 if (*data++)
403 return FALSE;
404 if (c >= 014 && c <= 016) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000405 ins->oprs[c - 014].offset = (char)*data++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000406 ins->oprs[c - 014].segment |= SEG_SIGNED;
407 }
408 if (c >= 020 && c <= 022)
409 ins->oprs[c - 020].offset = *data++;
410 if (c >= 024 && c <= 026)
411 ins->oprs[c - 024].offset = *data++;
412 if (c >= 030 && c <= 032) {
413 ins->oprs[c - 030].offset = *data++;
414 ins->oprs[c - 030].offset |= (((unsigned)*data++) << 8);
415 }
416 if (c >= 034 && c <= 036) {
417 ins->oprs[c - 034].offset = *data++;
418 ins->oprs[c - 034].offset |= (((unsigned)*data++) << 8);
419 if (osize == 32) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000420 ins->oprs[c - 034].offset |= (((int32_t)*data++) << 16);
421 ins->oprs[c - 034].offset |= (((int32_t)*data++) << 24);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 }
423 if (segsize != asize)
424 ins->oprs[c - 034].addr_size = asize;
425 }
426 if (c >= 040 && c <= 042) {
427 ins->oprs[c - 040].offset = *data++;
428 ins->oprs[c - 040].offset |= (((unsigned)*data++) << 8);
Keith Kaniosb7a89542007-04-12 02:40:54 +0000429 ins->oprs[c - 040].offset |= (((int32_t)*data++) << 16);
430 ins->oprs[c - 040].offset |= (((int32_t)*data++) << 24);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 }
432 if (c >= 044 && c <= 046) {
433 ins->oprs[c - 044].offset = *data++;
434 ins->oprs[c - 044].offset |= (((unsigned)*data++) << 8);
435 if (asize == 32) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000436 ins->oprs[c - 044].offset |= (((int32_t)*data++) << 16);
437 ins->oprs[c - 044].offset |= (((int32_t)*data++) << 24);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000438 }
439 if (segsize != asize)
440 ins->oprs[c - 044].addr_size = asize;
441 }
442 if (c >= 050 && c <= 052) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000443 ins->oprs[c - 050].offset = (char)*data++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000444 ins->oprs[c - 050].segment |= SEG_RELATIVE;
445 }
446 if (c >= 060 && c <= 062) {
447 ins->oprs[c - 060].offset = *data++;
448 ins->oprs[c - 060].offset |= (((unsigned)*data++) << 8);
449 ins->oprs[c - 060].segment |= SEG_RELATIVE;
450 ins->oprs[c - 060].segment &= ~SEG_32BIT;
451 }
452 if (c >= 064 && c <= 066) {
453 ins->oprs[c - 064].offset = *data++;
454 ins->oprs[c - 064].offset |= (((unsigned)*data++) << 8);
455 if (osize == 32) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000456 ins->oprs[c - 064].offset |= (((int32_t)*data++) << 16);
457 ins->oprs[c - 064].offset |= (((int32_t)*data++) << 24);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000458 ins->oprs[c - 064].segment |= SEG_32BIT;
459 } else
460 ins->oprs[c - 064].segment &= ~SEG_32BIT;
461 ins->oprs[c - 064].segment |= SEG_RELATIVE;
462 if (segsize != osize) {
463 ins->oprs[c - 064].type =
464 (ins->oprs[c - 064].type & NON_SIZE)
465 | ((osize == 16) ? BITS16 : BITS32);
466 }
467 }
468 if (c >= 070 && c <= 072) {
469 ins->oprs[c - 070].offset = *data++;
470 ins->oprs[c - 070].offset |= (((unsigned)*data++) << 8);
Keith Kaniosb7a89542007-04-12 02:40:54 +0000471 ins->oprs[c - 070].offset |= (((int32_t)*data++) << 16);
472 ins->oprs[c - 070].offset |= (((int32_t)*data++) << 24);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 ins->oprs[c - 070].segment |= SEG_32BIT | SEG_RELATIVE;
474 }
475 if (c >= 0100 && c < 0130) {
476 int modrm = *data++;
477 ins->oprs[c & 07].basereg = (modrm >> 3) & 07;
478 ins->oprs[c & 07].segment |= SEG_RMREG;
479 data = do_ea(data, modrm, asize, segsize,
480 &ins->oprs[(c >> 3) & 07]);
481 }
482 if (c >= 0130 && c <= 0132) {
483 ins->oprs[c - 0130].offset = *data++;
484 ins->oprs[c - 0130].offset |= (((unsigned)*data++) << 8);
485 }
486 if (c >= 0140 && c <= 0142) {
487 ins->oprs[c - 0140].offset = *data++;
488 ins->oprs[c - 0140].offset |= (((unsigned)*data++) << 8);
Keith Kaniosb7a89542007-04-12 02:40:54 +0000489 ins->oprs[c - 0140].offset |= (((int32_t)*data++) << 16);
490 ins->oprs[c - 0140].offset |= (((int32_t)*data++) << 24);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000491 }
492 if (c >= 0200 && c <= 0277) {
493 int modrm = *data++;
494 if (((modrm >> 3) & 07) != (c & 07))
495 return FALSE; /* spare field doesn't match up */
496 data = do_ea(data, modrm, asize, segsize,
497 &ins->oprs[(c >> 3) & 07]);
498 }
499 if (c >= 0300 && c <= 0302) {
500 if (asize)
501 ins->oprs[c - 0300].segment |= SEG_32BIT;
502 else
503 ins->oprs[c - 0300].segment &= ~SEG_32BIT;
504 a_used = TRUE;
505 }
506 if (c == 0310) {
507 if (asize == 32)
508 return FALSE;
509 else
510 a_used = TRUE;
511 }
512 if (c == 0311) {
513 if (asize == 16)
514 return FALSE;
515 else
516 a_used = TRUE;
517 }
518 if (c == 0312) {
519 if (asize != segsize)
520 return FALSE;
521 else
522 a_used = TRUE;
523 }
524 if (c == 0320) {
525 if (osize == 32)
526 return FALSE;
527 else
528 o_used = TRUE;
529 }
530 if (c == 0321) {
531 if (osize == 16)
532 return FALSE;
533 else
534 o_used = TRUE;
535 }
536 if (c == 0322) {
537 if (osize != segsize)
538 return FALSE;
539 else
540 o_used = TRUE;
541 }
542 if (c == 0330) {
543 int t = *r++, d = *data++;
544 if (d < t || d > t + 15)
545 return FALSE;
546 else
547 ins->condition = d - t;
548 }
549 if (c == 0331) {
550 if (rep)
551 return FALSE;
552 }
553 if (c == 0332) {
554 if (drep == P_REP)
555 drep = P_REPE;
556 }
557 if (c == 0333) {
558 if (rep != 0xF3)
559 return FALSE;
560 drep = 0;
561 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000562 }
563
564 /*
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000565 * Check for unused rep or a/o prefixes.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000566 */
567 ins->nprefix = 0;
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000568 if (drep)
569 ins->prefixes[ins->nprefix++] = drep;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000570 if (!a_used && asize != segsize)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000571 ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000572 if (!o_used && osize != segsize)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000573 ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000574
575 return data - origdata;
576}
577
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000578int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
Keith Kaniosb7a89542007-04-12 02:40:54 +0000579 int32_t offset, int autosync, uint32_t prefer)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000580{
H. Peter Anvin4836e332002-04-30 20:56:43 +0000581 struct itemplate **p, **best_p;
582 int length, best_length = 0;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000583 char *segover;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000584 int rep, lock, asize, osize, i, slen, colon;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000585 uint8_t *origdata;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000586 int works;
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000587 insn tmp_ins, ins;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000588 uint32_t goodness, best;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000589
590 /*
591 * Scan for prefixes.
592 */
593 asize = osize = segsize;
594 segover = NULL;
595 rep = lock = 0;
596 origdata = data;
597 for (;;) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000598 if (*data == 0xF3 || *data == 0xF2)
599 rep = *data++;
600 else if (*data == 0xF0)
601 lock = *data++;
602 else if (*data == 0x2E || *data == 0x36 || *data == 0x3E ||
603 *data == 0x26 || *data == 0x64 || *data == 0x65) {
604 switch (*data++) {
605 case 0x2E:
606 segover = "cs";
607 break;
608 case 0x36:
609 segover = "ss";
610 break;
611 case 0x3E:
612 segover = "ds";
613 break;
614 case 0x26:
615 segover = "es";
616 break;
617 case 0x64:
618 segover = "fs";
619 break;
620 case 0x65:
621 segover = "gs";
622 break;
623 }
624 } else if (*data == 0x66)
625 osize = 48 - segsize, data++;
626 else if (*data == 0x67)
627 asize = 48 - segsize, data++;
628 else
629 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000630 }
631
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000632 tmp_ins.oprs[0].segment = tmp_ins.oprs[1].segment =
H. Peter Anvine2c80182005-01-15 22:15:51 +0000633 tmp_ins.oprs[2].segment =
634 tmp_ins.oprs[0].addr_size = tmp_ins.oprs[1].addr_size =
635 tmp_ins.oprs[2].addr_size = (segsize == 16 ? 0 : SEG_32BIT);
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000636 tmp_ins.condition = -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000637 best = ~0UL; /* Worst possible */
H. Peter Anvin4836e332002-04-30 20:56:43 +0000638 best_p = NULL;
639 for (p = itable[*data]; *p; p++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000640 if ((length = matches(*p, data, asize, osize,
641 segsize, rep, &tmp_ins))) {
642 works = TRUE;
643 /*
644 * Final check to make sure the types of r/m match up.
645 */
646 for (i = 0; i < (*p)->operands; i++) {
647 if (
648 /* If it's a mem-only EA but we have a register, die. */
649 ((tmp_ins.oprs[i].segment & SEG_RMREG) &&
650 !(MEMORY & ~(*p)->opd[i])) ||
651 /* If it's a reg-only EA but we have a memory ref, die. */
652 (!(tmp_ins.oprs[i].segment & SEG_RMREG) &&
653 !(REGNORM & ~(*p)->opd[i]) &&
654 !((*p)->opd[i] & REG_SMASK)) ||
655 /* Register type mismatch (eg FS vs REG_DESS): die. */
656 ((((*p)->opd[i] & (REGISTER | FPUREG)) ||
657 (tmp_ins.oprs[i].segment & SEG_RMREG)) &&
658 !whichreg((*p)->opd[i],
659 tmp_ins.oprs[i].basereg))) {
660 works = FALSE;
661 break;
662 }
663 }
664
665 if (works) {
666 goodness = ((*p)->flags & IF_PFMASK) ^ prefer;
667 if (goodness < best) {
668 /* This is the best one found so far */
669 best = goodness;
670 best_p = p;
671 best_length = length;
672 ins = tmp_ins;
673 }
674 }
675 }
H. Peter Anvin4836e332002-04-30 20:56:43 +0000676 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000677
H. Peter Anvinef7468f2002-04-30 20:57:59 +0000678 if (!best_p)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 return 0; /* no instruction was matched */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000680
H. Peter Anvin4836e332002-04-30 20:56:43 +0000681 /* Pick the best match */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000682 p = best_p;
H. Peter Anvin4836e332002-04-30 20:56:43 +0000683 length = best_length;
684
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000685 slen = 0;
686
Ed Beroset64ab5192004-12-15 23:32:57 +0000687 /* TODO: snprintf returns the value that the string would have if
H. Peter Anvine2c80182005-01-15 22:15:51 +0000688 * the buffer were long enough, and not the actual length of
689 * the returned string, so each instance of using the return
690 * value of snprintf should actually be checked to assure that
691 * the return value is "sane." Maybe a macro wrapper could
692 * be used for that purpose.
693 */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000694 if (lock)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000695 slen += snprintf(output + slen, outbufsize - slen, "lock ");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000696 for (i = 0; i < ins.nprefix; i++)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000697 switch (ins.prefixes[i]) {
698 case P_REP:
699 slen += snprintf(output + slen, outbufsize - slen, "rep ");
700 break;
701 case P_REPE:
702 slen += snprintf(output + slen, outbufsize - slen, "repe ");
703 break;
704 case P_REPNE:
705 slen += snprintf(output + slen, outbufsize - slen, "repne ");
706 break;
707 case P_A16:
708 slen += snprintf(output + slen, outbufsize - slen, "a16 ");
709 break;
710 case P_A32:
711 slen += snprintf(output + slen, outbufsize - slen, "a32 ");
712 break;
713 case P_O16:
714 slen += snprintf(output + slen, outbufsize - slen, "o16 ");
715 break;
716 case P_O32:
717 slen += snprintf(output + slen, outbufsize - slen, "o32 ");
718 break;
719 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000720
721 for (i = 0; i < elements(ico); i++)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000722 if ((*p)->opcode == ico[i]) {
723 slen +=
724 snprintf(output + slen, outbufsize - slen, "%s%s", icn[i],
725 whichcond(ins.condition));
726 break;
727 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000728 if (i >= elements(ico))
H. Peter Anvine2c80182005-01-15 22:15:51 +0000729 slen +=
730 snprintf(output + slen, outbufsize - slen, "%s",
731 insn_names[(*p)->opcode]);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000732 colon = FALSE;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000733 length += data - origdata; /* fix up for prefixes */
734 for (i = 0; i < (*p)->operands; i++) {
735 output[slen++] = (colon ? ':' : i == 0 ? ' ' : ',');
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000736
H. Peter Anvine2c80182005-01-15 22:15:51 +0000737 if (ins.oprs[i].segment & SEG_RELATIVE) {
738 ins.oprs[i].offset += offset + length;
739 /*
740 * sort out wraparound
741 */
742 if (!(ins.oprs[i].segment & SEG_32BIT))
743 ins.oprs[i].offset &= 0xFFFF;
744 /*
745 * add sync marker, if autosync is on
746 */
747 if (autosync)
748 add_sync(ins.oprs[i].offset, 0L);
749 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000750
H. Peter Anvine2c80182005-01-15 22:15:51 +0000751 if ((*p)->opd[i] & COLON)
752 colon = TRUE;
753 else
754 colon = FALSE;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000755
H. Peter Anvine2c80182005-01-15 22:15:51 +0000756 if (((*p)->opd[i] & (REGISTER | FPUREG)) ||
757 (ins.oprs[i].segment & SEG_RMREG)) {
758 ins.oprs[i].basereg = whichreg((*p)->opd[i],
759 ins.oprs[i].basereg);
760 if ((*p)->opd[i] & TO)
761 slen += snprintf(output + slen, outbufsize - slen, "to ");
762 slen += snprintf(output + slen, outbufsize - slen, "%s",
763 reg_names[ins.oprs[i].basereg -
764 EXPR_REG_START]);
765 } else if (!(UNITY & ~(*p)->opd[i])) {
766 output[slen++] = '1';
767 } else if ((*p)->opd[i] & IMMEDIATE) {
768 if ((*p)->opd[i] & BITS8) {
769 slen +=
770 snprintf(output + slen, outbufsize - slen, "byte ");
771 if (ins.oprs[i].segment & SEG_SIGNED) {
772 if (ins.oprs[i].offset < 0) {
773 ins.oprs[i].offset *= -1;
774 output[slen++] = '-';
775 } else
776 output[slen++] = '+';
777 }
778 } else if ((*p)->opd[i] & BITS16) {
779 slen +=
780 snprintf(output + slen, outbufsize - slen, "word ");
781 } else if ((*p)->opd[i] & BITS32) {
782 slen +=
783 snprintf(output + slen, outbufsize - slen, "dword ");
784 } else if ((*p)->opd[i] & NEAR) {
785 slen +=
786 snprintf(output + slen, outbufsize - slen, "near ");
787 } else if ((*p)->opd[i] & SHORT) {
788 slen +=
789 snprintf(output + slen, outbufsize - slen, "short ");
790 }
791 slen +=
792 snprintf(output + slen, outbufsize - slen, "0x%lx",
793 ins.oprs[i].offset);
794 } else if (!(MEM_OFFS & ~(*p)->opd[i])) {
795 slen +=
796 snprintf(output + slen, outbufsize - slen, "[%s%s%s0x%lx]",
Keith Kaniosb7a89542007-04-12 02:40:54 +0000797 ((const char*)segover ? (const char*)segover : ""), /* placate type mistmatch warning */
798 ((const char*)segover ? ":" : ""), /* by using (const char*) instead of uint8_t* */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000799 (ins.oprs[i].addr_size ==
800 32 ? "dword " : ins.oprs[i].addr_size ==
801 16 ? "word " : ""), ins.oprs[i].offset);
802 segover = NULL;
803 } else if (!(REGMEM & ~(*p)->opd[i])) {
804 int started = FALSE;
805 if ((*p)->opd[i] & BITS8)
806 slen +=
807 snprintf(output + slen, outbufsize - slen, "byte ");
808 if ((*p)->opd[i] & BITS16)
809 slen +=
810 snprintf(output + slen, outbufsize - slen, "word ");
811 if ((*p)->opd[i] & BITS32)
812 slen +=
813 snprintf(output + slen, outbufsize - slen, "dword ");
814 if ((*p)->opd[i] & BITS64)
815 slen +=
816 snprintf(output + slen, outbufsize - slen, "qword ");
817 if ((*p)->opd[i] & BITS80)
818 slen +=
819 snprintf(output + slen, outbufsize - slen, "tword ");
820 if ((*p)->opd[i] & FAR)
821 slen += snprintf(output + slen, outbufsize - slen, "far ");
822 if ((*p)->opd[i] & NEAR)
823 slen +=
824 snprintf(output + slen, outbufsize - slen, "near ");
825 output[slen++] = '[';
826 if (ins.oprs[i].addr_size)
827 slen += snprintf(output + slen, outbufsize - slen, "%s",
828 (ins.oprs[i].addr_size == 32 ? "dword " :
829 ins.oprs[i].addr_size ==
830 16 ? "word " : ""));
831 if (segover) {
832 slen +=
833 snprintf(output + slen, outbufsize - slen, "%s:",
834 segover);
835 segover = NULL;
836 }
837 if (ins.oprs[i].basereg != -1) {
838 slen += snprintf(output + slen, outbufsize - slen, "%s",
839 reg_names[(ins.oprs[i].basereg -
840 EXPR_REG_START)]);
841 started = TRUE;
842 }
843 if (ins.oprs[i].indexreg != -1) {
844 if (started)
845 output[slen++] = '+';
846 slen += snprintf(output + slen, outbufsize - slen, "%s",
847 reg_names[(ins.oprs[i].indexreg -
848 EXPR_REG_START)]);
849 if (ins.oprs[i].scale > 1)
850 slen +=
851 snprintf(output + slen, outbufsize - slen, "*%d",
852 ins.oprs[i].scale);
853 started = TRUE;
854 }
855 if (ins.oprs[i].segment & SEG_DISP8) {
856 int sign = '+';
857 if (ins.oprs[i].offset & 0x80) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000858 ins.oprs[i].offset = -(char)ins.oprs[i].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000859 sign = '-';
860 }
861 slen +=
862 snprintf(output + slen, outbufsize - slen, "%c0x%lx",
863 sign, ins.oprs[i].offset);
864 } else if (ins.oprs[i].segment & SEG_DISP16) {
865 if (started)
866 output[slen++] = '+';
867 slen +=
868 snprintf(output + slen, outbufsize - slen, "0x%lx",
869 ins.oprs[i].offset);
870 } else if (ins.oprs[i].segment & SEG_DISP32) {
871 if (started)
872 output[slen++] = '+';
873 slen +=
874 snprintf(output + slen, outbufsize - slen, "0x%lx",
875 ins.oprs[i].offset);
876 }
877 output[slen++] = ']';
878 } else {
879 slen +=
880 snprintf(output + slen, outbufsize - slen, "<operand%d>",
881 i);
882 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000883 }
884 output[slen] = '\0';
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 if (segover) { /* unused segment override */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000886 char *p = output;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000887 int count = slen + 1;
888 while (count--)
889 p[count + 3] = p[count];
890 strncpy(output, segover, 2);
891 output[2] = ' ';
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000892 }
893 return length;
894}
895
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000896int32_t eatbyte(uint8_t *data, char *output, int outbufsize)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000897{
Ed Beroset92348172004-12-15 18:27:50 +0000898 snprintf(output, outbufsize, "db 0x%02X", *data);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000899 return 1;
900}