12b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#include "ia32_modrm.h"
22b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#include "ia32_reg.h"
32b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#include "x86_imm.h"
42b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
52b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register
62b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * values obtained from decoding the ModR/M or SIB byte, since they
72b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1.
82b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * ADDENDUM: this is only the case when the register value is used
92b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * directly as an index into the register table, not when it is added to
102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * a genregs offset. */
112b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
122b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* -------------------------------- ModR/M, SIB */
132b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* ModR/M flags */
142b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_RM_SIB            0x04    /* R/M == 100 */
152b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_RM_NOREG          0x05    /* R/B == 101 */
162b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
172b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
182b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_NODISP        0x00    /* mod == 00 */
192b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_DISP8         0x01    /* mod == 01 */
202b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_DISP32        0x02    /* mod == 10 */
212b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MODRM_MOD_NOEA          0x03    /* mod == 11 */
222b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
232b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* 16-bit modrm flags */
242b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_NODISP      0
252b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_DISP8       1
262b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_DISP16      2
272b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_MOD_REG         3
282b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
292b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BXSI         0
302b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BXDI         1
312b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BPSI         2
322b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BPDI         3
332b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_SI           4
342b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_DI           5
352b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BP           6
362b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define MOD16_RM_BX           7
372b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
382b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* SIB flags */
392b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define SIB_INDEX_NONE       0x04
402b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define SIB_BASE_EBP       0x05
412b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#define SIB_SCALE_NOBASE    0x00
422b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
432b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* Convenience struct for modR/M bitfield */
442b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstruct modRM_byte {
452b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org   unsigned int mod : 2;
462b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org   unsigned int reg : 3;
472b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org   unsigned int rm  : 3;
482b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org};
492b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
502b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* Convenience struct for SIB bitfield */
512b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstruct SIB_byte {
522b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org   unsigned int scale : 2;
532b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org   unsigned int index : 3;
542b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org   unsigned int base  : 3;
552b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org};
562b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
572b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
582b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#if 0
592b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint modrm_rm[] = {0,1,2,3,MODRM_RM_SIB,MODRM_MOD_DISP32,6,7};
602b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint modrm_reg[] = {0, 1, 2, 3, 4, 5, 6, 7};
612b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint modrm_mod[]  = {0, MODRM_MOD_DISP8, MODRM_MOD_DISP32, MODRM_MOD_NOEA};
622b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint sib_scl[] = {0, 2, 4, 8};
632b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint sib_idx[] = {0, 1, 2, 3, SIB_INDEX_NONE, 5, 6, 7 };
642b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgint sib_bas[] = {0, 1, 2, 3, 4, SIB_SCALE_NOBASE, 6, 7 };
652b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org#endif
662b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
672b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* this is needed to replace x86_imm_signsized() which does not sign-extend
682b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org * to dest */
692b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic unsigned int imm32_signsized( unsigned char *buf, size_t buf_len,
702b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org				     int32_t *dest, unsigned int size ) {
712b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if ( size > buf_len ) {
722b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		return 0;
732b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
742b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
752b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	switch (size) {
762b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case 1:
772b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			*dest = *((signed char *) buf);
782b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
792b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case 2:
802b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			*dest = *((signed short *) buf);
812b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
822b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case 4:
832b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		default:
842b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			*dest = *((signed int *) buf);
852b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
862b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
872b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
882b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	return size;
892b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}
902b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
912b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
922b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
932b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic void byte_decode(unsigned char b, struct modRM_byte *modrm) {
942b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* generic bitfield-packing routine */
952b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
962b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	modrm->mod = b >> 6;	/* top 2 bits */
972b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	modrm->reg = (b & 56) >> 3;	/* middle 3 bits */
982b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	modrm->rm = b & 7;	/* bottom 3 bits */
992b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}
1002b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1012b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1022b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic size_t sib_decode( unsigned char *buf, size_t buf_len, x86_ea_t *ea,
1032b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			  unsigned int mod ) {
1042b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* set Address Expression fields (scale, index, base, disp)
1052b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 * according to the contents of the SIB byte.
1062b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 *  b points to the SIB byte in the instruction-stream buffer; the
1072b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 *    byte after b[0] is therefore the byte after the SIB
1082b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 *  returns number of bytes 'used', including the SIB byte */
1092b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	size_t size = 1;		/* start at 1 for SIB byte */
1102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	struct SIB_byte sib;
1112b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1122b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if ( buf_len < 1 ) {
1132b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		return 0;
1142b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
1152b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1162b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	byte_decode( *buf, (struct modRM_byte *)(void*)&sib );  /* get bit-fields */
1172b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1182b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if ( sib.base == SIB_BASE_EBP && ! mod ) {  /* if base == 101 (ebp) */
1192b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	    /* IF BASE == EBP, deal with exception */
1202b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* IF (ModR/M did not create a Disp */
1212b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* ... create a 32-bit Displacement */
1222b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		imm32_signsized( &buf[1], buf_len, &ea->disp, sizeof(int32_t));
1232b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ea->disp_size = sizeof(int32_t);
1242b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ea->disp_sign = (ea->disp < 0) ? 1 : 0;
1252b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		size += 4;	/* add sizeof disp to count */
1262b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1272b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	} else {
1282b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* ELSE BASE refers to a General Register */
1292b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ia32_handle_register( &ea->base, sib.base + 1 );
1302b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
1312b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1322b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* set scale to 1, 2, 4, 8 */
1332b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	ea->scale = 1 << sib.scale;
1342b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1352b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if (sib.index != SIB_INDEX_NONE) {
1362b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* IF INDEX is not 'ESP' (100) */
1372b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ia32_handle_register( &ea->index, sib.index + 1 );
1382b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
1392b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1402b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	return (size);		/* return number of bytes processed */
1412b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}
1422b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1432b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgstatic size_t modrm_decode16( unsigned char *buf, unsigned int buf_len,
1442b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			    x86_op_t *op, struct modRM_byte *modrm ) {
1452b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* 16-bit mode: hackish, but not as hackish as 32-bit mode ;) */
1462b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */
1472b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	x86_ea_t * ea = &op->data.expression;
1482b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1492b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	switch( modrm->rm ) {
1502b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_BXSI:
1512b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
1522b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6);
1532b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1542b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_BXDI:
1552b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
1562b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7);
1572b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_BPSI:
1582b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			op->flags |= op_ss_seg;
1592b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5);
1602b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6);
1612b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1622b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_BPDI:
1632b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			op->flags |= op_ss_seg;
1642b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5);
1652b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7);
1662b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1672b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_SI:
1682b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 6);
1692b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1702b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_DI:
1712b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 7);
1722b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1732b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_BP:
1742b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			if ( modrm->mod != MOD16_MOD_NODISP ) {
1752b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org				op->flags |= op_ss_seg;
1762b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org				ia32_handle_register(&ea->base,
1772b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org						     REG_WORD_OFFSET + 5);
1782b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			}
1792b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1802b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		case MOD16_RM_BX:
1812b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
1822b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			break;
1832b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
1842b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1852b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* move to byte after ModR/M */
1862b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	++buf;
1872b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	--buf_len;
1882b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
1892b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if ( modrm->mod == MOD16_MOD_DISP8 ) {
1902b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		imm32_signsized( buf, buf_len, &ea->disp, sizeof(char) );
1912b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ea->disp_sign = (ea->disp < 0) ? 1 : 0;
1922b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ea->disp_size = sizeof(char);
1932b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		size += sizeof(char);
1942b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	} else if ( modrm->mod == MOD16_MOD_DISP16 ) {
1952b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		imm32_signsized( buf, buf_len, &ea->disp, sizeof(short) );
1962b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ea->disp_sign = (ea->disp < 0) ? 1 : 0;
1972b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ea->disp_size = sizeof(short);
1982b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		size += sizeof(short);
1992b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
2002b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2012b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	return size;
2022b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}
2032b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2042b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org/* TODO : Mark index modes
2052b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org    Use addressing mode flags to imply arrays (index), structure (disp),
2062b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org    two-dimensional arrays [disp + index], classes [ea reg], and so on.
2072b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org*/
2082b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgsize_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len,
2092b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			    x86_op_t *op, x86_insn_t *insn, size_t gen_regs ) {
2102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* create address expression and/or fill operand based on value of
2112b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 * ModR/M byte. Calls sib_decode as appropriate.
2122b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 *    flags specifies whether Reg or mod+R/M fields are being decoded
2132b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	 *  returns the number of bytes in the instruction, including modR/M */
2142b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	struct modRM_byte modrm;
2152b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	size_t size = 1;	/* # of bytes decoded [1 for modR/M byte] */
2162b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	x86_ea_t * ea;
2172b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2182b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2192b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	byte_decode(*buf, &modrm);	/* get bitfields */
2202b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2212b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* first, handle the case where the mod field is a register only */
2222b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if ( modrm.mod == MODRM_MOD_NOEA ) {
2232b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		op->type = op_register;
2242b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		ia32_handle_register(&op->data.reg, modrm.rm + gen_regs);
2252b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org                /* increase insn size by 1 for modrm byte */
2262b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 		return 1;
2272b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 	}
2282b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2292b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* then deal with cases where there is an effective address */
2302b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	ea = &op->data.expression;
2312b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	op->type = op_expression;
2322b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	op->flags |= op_pointer;
2332b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2342b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if ( insn->addr_size == 2 ) {
2352b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* gah! 16 bit mode! */
2362b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		return modrm_decode16( buf, buf_len, op, &modrm);
2372b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
2382b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2392b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	/* move to byte after ModR/M */
2402b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	++buf;
2412b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	--buf_len;
2422b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2432b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	if (modrm.mod == MODRM_MOD_NODISP) {	/* if mod == 00 */
2442b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2452b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* IF MOD == No displacement, just Indirect Register */
2462b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		if (modrm.rm == MODRM_RM_NOREG) {	/* if r/m == 101 */
2472b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* IF RM == No Register, just Displacement */
2482b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* This is an Intel Moronic Exception TM */
2492b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			imm32_signsized( buf, buf_len, &ea->disp,
2502b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org					sizeof(int32_t) );
2512b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ea->disp_size = sizeof(int32_t);
2522b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ea->disp_sign = (ea->disp < 0) ? 1 : 0;
2532b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			size += 4;	/* add sizeof disp to count */
2542b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2552b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		} else if (modrm.rm == MODRM_RM_SIB) {	/* if r/m == 100 */
2562b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* ELSE IF an SIB byte is present */
2572b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* TODO: check for 0 retval */
2582b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			size += sib_decode( buf, buf_len, ea, modrm.mod);
2592b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* move to byte after SIB for displacement */
2602b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			++buf;
2612b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			--buf_len;
2622b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		} else {	/* modR/M specifies base register */
2632b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* ELSE RM encodes a general register */
2642b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register( &ea->base, modrm.rm + 1 );
2652b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		}
2662b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	} else { 					/* mod is 01 or 10 */
2672b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		if (modrm.rm == MODRM_RM_SIB) {	/* rm == 100 */
2682b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* IF base is an AddrExpr specified by an SIB byte */
2692b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* TODO: check for 0 retval */
2702b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			size += sib_decode( buf, buf_len, ea, modrm.mod);
2712b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* move to byte after SIB for displacement */
2722b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			++buf;
2732b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			--buf_len;
2742b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		} else {
2752b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* ELSE base is a general register */
2762b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ia32_handle_register( &ea->base, modrm.rm + 1 );
2772b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		}
2782b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2792b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		/* ELSE mod + r/m specify a disp##[base] or disp##(SIB) */
2802b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		if (modrm.mod == MODRM_MOD_DISP8) {		/* mod == 01 */
2812b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* If this is an 8-bit displacement */
2822b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			imm32_signsized( buf, buf_len, &ea->disp,
2832b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org					sizeof(char));
2842b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ea->disp_size = sizeof(char);
2852b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ea->disp_sign = (ea->disp < 0) ? 1 : 0;
2862b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			size += 1;	/* add sizeof disp to count */
2872b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2882b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		} else {
2892b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			/* Displacement is dependent on address size */
2902b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			imm32_signsized( buf, buf_len, &ea->disp,
2912b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org					insn->addr_size);
2922b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ea->disp_size = insn->addr_size;
2932b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			ea->disp_sign = (ea->disp < 0) ? 1 : 0;
2942b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org			size += 4;
2952b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org		}
2962b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	}
2972b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
2982b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	return size;		/* number of bytes found in instruction */
2992b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}
3002b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
3012b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.orgvoid ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ) {
3022b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	struct modRM_byte modrm;
3032b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	byte_decode( byte, &modrm );	/* get bitfields */
3042b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
3052b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org 	/* set operand to register ID */
3062b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	op->type = op_register;
3072b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	ia32_handle_register(&op->data.reg, modrm.reg + gen_regs);
3082b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org
3092b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org	return;
3102b4274afc4fae883d1251a7a420e24fd526a9f16cdn@chromium.org}
311