PageRenderTime 58ms CodeModel.GetById 11ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/third_party/libdisasm/ia32_modrm.c

http://github.com/tomahawk-player/tomahawk
C | 310 lines | 206 code | 47 blank | 57 comment | 35 complexity | d13a67d5599c8289afd1b7a34743e5f2 MD5 | raw file
  1#include "ia32_modrm.h"
  2#include "ia32_reg.h"
  3#include "x86_imm.h"
  4
  5/* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register
  6 * values obtained from decoding the ModR/M or SIB byte, since they
  7 * are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1.
  8 * ADDENDUM: this is only the case when the register value is used
  9 * directly as an index into the register table, not when it is added to
 10 * a genregs offset. */
 11
 12/* -------------------------------- ModR/M, SIB */
 13/* ModR/M flags */
 14#define MODRM_RM_SIB            0x04    /* R/M == 100 */
 15#define MODRM_RM_NOREG          0x05    /* R/B == 101 */
 16
 17/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
 18#define MODRM_MOD_NODISP        0x00    /* mod == 00 */
 19#define MODRM_MOD_DISP8         0x01    /* mod == 01 */
 20#define MODRM_MOD_DISP32        0x02    /* mod == 10 */
 21#define MODRM_MOD_NOEA          0x03    /* mod == 11 */
 22
 23/* 16-bit modrm flags */
 24#define MOD16_MOD_NODISP      0
 25#define MOD16_MOD_DISP8       1
 26#define MOD16_MOD_DISP16      2
 27#define MOD16_MOD_REG         3
 28
 29#define MOD16_RM_BXSI         0
 30#define MOD16_RM_BXDI         1
 31#define MOD16_RM_BPSI         2
 32#define MOD16_RM_BPDI         3
 33#define MOD16_RM_SI           4
 34#define MOD16_RM_DI           5
 35#define MOD16_RM_BP           6
 36#define MOD16_RM_BX           7
 37
 38/* SIB flags */
 39#define SIB_INDEX_NONE       0x04
 40#define SIB_BASE_EBP       0x05
 41#define SIB_SCALE_NOBASE    0x00
 42
 43/* Convenience struct for modR/M bitfield */
 44struct modRM_byte {  
 45   unsigned int mod : 2;
 46   unsigned int reg : 3;
 47   unsigned int rm  : 3; 
 48};
 49
 50/* Convenience struct for SIB bitfield */
 51struct SIB_byte {
 52   unsigned int scale : 2;
 53   unsigned int index : 3;
 54   unsigned int base  : 3;
 55};
 56
 57
 58#if 0
 59int modrm_rm[] = {0,1,2,3,MODRM_RM_SIB,MODRM_MOD_DISP32,6,7};
 60int modrm_reg[] = {0, 1, 2, 3, 4, 5, 6, 7};
 61int modrm_mod[]  = {0, MODRM_MOD_DISP8, MODRM_MOD_DISP32, MODRM_MOD_NOEA};
 62int sib_scl[] = {0, 2, 4, 8};
 63int sib_idx[] = {0, 1, 2, 3, SIB_INDEX_NONE, 5, 6, 7 };
 64int sib_bas[] = {0, 1, 2, 3, 4, SIB_SCALE_NOBASE, 6, 7 };
 65#endif
 66
 67/* this is needed to replace x86_imm_signsized() which does not sign-extend
 68 * to dest */
 69static unsigned int imm32_signsized( unsigned char *buf, size_t buf_len,
 70				     int32_t *dest, unsigned int size ) {
 71	if ( size > buf_len ) {
 72		return 0;
 73	}
 74
 75	switch (size) {
 76		case 1:
 77			*dest = *((signed char *) buf);
 78			break;
 79		case 2:
 80			*dest = *((signed short *) buf);
 81			break;
 82		case 4:
 83		default:
 84			*dest = *((signed int *) buf);
 85			break;
 86	}
 87
 88	return size;
 89}
 90
 91
 92
 93static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
 94	/* generic bitfield-packing routine */
 95
 96	modrm->mod = b >> 6;	/* top 2 bits */
 97	modrm->reg = (b & 56) >> 3;	/* middle 3 bits */
 98	modrm->rm = b & 7;	/* bottom 3 bits */
 99}
100
101
102static size_t sib_decode( unsigned char *buf, size_t buf_len, x86_ea_t *ea, 
103			  unsigned int mod ) {
104	/* set Address Expression fields (scale, index, base, disp) 
105	 * according to the contents of the SIB byte.
106	 *  b points to the SIB byte in the instruction-stream buffer; the
107	 *    byte after b[0] is therefore the byte after the SIB
108	 *  returns number of bytes 'used', including the SIB byte */
109	size_t size = 1;		/* start at 1 for SIB byte */
110	struct SIB_byte sib;
111
112	if ( buf_len < 1 ) {
113		return 0;
114	}
115
116	byte_decode( *buf, (struct modRM_byte *)(void*)&sib );  /* get bit-fields */
117
118	if ( sib.base == SIB_BASE_EBP && ! mod ) {  /* if base == 101 (ebp) */
119	    /* IF BASE == EBP, deal with exception */
120		/* IF (ModR/M did not create a Disp */
121		/* ... create a 32-bit Displacement */
122		imm32_signsized( &buf[1], buf_len, &ea->disp, sizeof(int32_t));
123		ea->disp_size = sizeof(int32_t);
124		ea->disp_sign = (ea->disp < 0) ? 1 : 0;
125		size += 4;	/* add sizeof disp to count */
126
127	} else {
128		/* ELSE BASE refers to a General Register */
129		ia32_handle_register( &ea->base, sib.base + 1 );
130	}
131
132	/* set scale to 1, 2, 4, 8 */
133	ea->scale = 1 << sib.scale;
134
135	if (sib.index != SIB_INDEX_NONE) {
136		/* IF INDEX is not 'ESP' (100) */
137		ia32_handle_register( &ea->index, sib.index + 1 );
138	}
139
140	return (size);		/* return number of bytes processed */
141}
142
143static size_t modrm_decode16( unsigned char *buf, unsigned int buf_len,
144			    x86_op_t *op, struct modRM_byte *modrm ) {
145	/* 16-bit mode: hackish, but not as hackish as 32-bit mode ;) */
146	size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */
147	x86_ea_t * ea = &op->data.expression;
148
149	switch( modrm->rm ) {
150		case MOD16_RM_BXSI:
151			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
152			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6);
153			break;
154		case MOD16_RM_BXDI:
155			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
156			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7);
157		case MOD16_RM_BPSI:
158			op->flags |= op_ss_seg;
159			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5);
160			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6);
161			break;
162		case MOD16_RM_BPDI:
163			op->flags |= op_ss_seg;
164			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5);
165			ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7);
166			break;
167		case MOD16_RM_SI:
168			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 6);
169			break;
170		case MOD16_RM_DI:
171			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 7);
172			break;
173		case MOD16_RM_BP:
174			if ( modrm->mod != MOD16_MOD_NODISP ) {
175				op->flags |= op_ss_seg;
176				ia32_handle_register(&ea->base, 
177						     REG_WORD_OFFSET + 5);
178			}
179			break;
180		case MOD16_RM_BX:
181			ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
182			break;
183	}
184
185	/* move to byte after ModR/M */
186	++buf;
187	--buf_len;
188
189	if ( modrm->mod == MOD16_MOD_DISP8 ) {
190		imm32_signsized( buf, buf_len, &ea->disp, sizeof(char) );
191		ea->disp_sign = (ea->disp < 0) ? 1 : 0;
192		ea->disp_size = sizeof(char);
193		size += sizeof(char);
194	} else if ( modrm->mod == MOD16_MOD_DISP16 ) {
195		imm32_signsized( buf, buf_len, &ea->disp, sizeof(short) );
196		ea->disp_sign = (ea->disp < 0) ? 1 : 0;
197		ea->disp_size = sizeof(short);
198		size += sizeof(short);
199	} 
200
201	return size;
202}
203
204/* TODO : Mark index modes
205    Use addressing mode flags to imply arrays (index), structure (disp),
206    two-dimensional arrays [disp + index], classes [ea reg], and so on.
207*/
208size_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len,
209			    x86_op_t *op, x86_insn_t *insn, size_t gen_regs ) {
210	/* create address expression and/or fill operand based on value of
211	 * ModR/M byte. Calls sib_decode as appropriate.
212	 *    flags specifies whether Reg or mod+R/M fields are being decoded
213	 *  returns the number of bytes in the instruction, including modR/M */
214	struct modRM_byte modrm;
215	size_t size = 1;	/* # of bytes decoded [1 for modR/M byte] */
216	x86_ea_t * ea;
217
218
219	byte_decode(*buf, &modrm);	/* get bitfields */
220
221	/* first, handle the case where the mod field is a register only */
222	if ( modrm.mod == MODRM_MOD_NOEA ) {
223		op->type = op_register;
224		ia32_handle_register(&op->data.reg, modrm.rm + gen_regs);
225                /* increase insn size by 1 for modrm byte */
226 		return 1;
227 	}
228 
229	/* then deal with cases where there is an effective address */
230	ea = &op->data.expression;
231	op->type = op_expression;
232	op->flags |= op_pointer;
233
234	if ( insn->addr_size == 2 ) {
235		/* gah! 16 bit mode! */
236		return modrm_decode16( buf, buf_len, op, &modrm);
237	}
238
239	/* move to byte after ModR/M */
240	++buf;
241	--buf_len;
242
243	if (modrm.mod == MODRM_MOD_NODISP) {	/* if mod == 00 */
244
245		/* IF MOD == No displacement, just Indirect Register */
246		if (modrm.rm == MODRM_RM_NOREG) {	/* if r/m == 101 */
247			/* IF RM == No Register, just Displacement */
248			/* This is an Intel Moronic Exception TM */
249			imm32_signsized( buf, buf_len, &ea->disp, 
250					sizeof(int32_t) );
251			ea->disp_size = sizeof(int32_t);
252			ea->disp_sign = (ea->disp < 0) ? 1 : 0;
253			size += 4;	/* add sizeof disp to count */
254
255		} else if (modrm.rm == MODRM_RM_SIB) {	/* if r/m == 100 */
256			/* ELSE IF an SIB byte is present */
257			/* TODO: check for 0 retval */
258			size += sib_decode( buf, buf_len, ea, modrm.mod);
259			/* move to byte after SIB for displacement */
260			++buf;
261			--buf_len;
262		} else {	/* modR/M specifies base register */
263			/* ELSE RM encodes a general register */
264			ia32_handle_register( &ea->base, modrm.rm + 1 );
265		}
266	} else { 					/* mod is 01 or 10 */
267		if (modrm.rm == MODRM_RM_SIB) {	/* rm == 100 */
268			/* IF base is an AddrExpr specified by an SIB byte */
269			/* TODO: check for 0 retval */
270			size += sib_decode( buf, buf_len, ea, modrm.mod);
271			/* move to byte after SIB for displacement */
272			++buf;
273			--buf_len;
274		} else {
275			/* ELSE base is a general register */
276			ia32_handle_register( &ea->base, modrm.rm + 1 );
277		}
278
279		/* ELSE mod + r/m specify a disp##[base] or disp##(SIB) */
280		if (modrm.mod == MODRM_MOD_DISP8) {		/* mod == 01 */
281			/* If this is an 8-bit displacement */
282			imm32_signsized( buf, buf_len, &ea->disp, 
283					sizeof(char));
284			ea->disp_size = sizeof(char);
285			ea->disp_sign = (ea->disp < 0) ? 1 : 0;
286			size += 1;	/* add sizeof disp to count */
287
288		} else {
289			/* Displacement is dependent on address size */
290			imm32_signsized( buf, buf_len, &ea->disp, 
291					insn->addr_size);
292			ea->disp_size = insn->addr_size;
293			ea->disp_sign = (ea->disp < 0) ? 1 : 0;
294			size += 4;
295		}
296	}
297
298	return size;		/* number of bytes found in instruction */
299}
300
301void ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ) {
302	struct modRM_byte modrm;
303	byte_decode( byte, &modrm );	/* get bitfields */
304
305 	/* set operand to register ID */
306	op->type = op_register;
307	ia32_handle_register(&op->data.reg, modrm.reg + gen_regs);
308
309	return;
310}