PageRenderTime 47ms CodeModel.GetById 9ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/third_party/libdisasm/ia32_invariant.c

http://github.com/tomahawk-player/tomahawk
C | 313 lines | 257 code | 37 blank | 19 comment | 47 complexity | d899b301b8e23a1efd73b83d43eaada7 MD5 | raw file
  1#include <stdlib.h>
  2#include <string.h>
  3
  4#include "ia32_invariant.h"
  5#include "ia32_insn.h"
  6#include "ia32_settings.h"
  7
  8extern ia32_table_desc_t *ia32_tables;
  9extern ia32_settings_t ia32_settings;
 10
 11extern size_t ia32_table_lookup( unsigned char *buf, size_t buf_len,
 12		unsigned int table, ia32_insn_t **raw_insn,
 13		 unsigned int *prefixes );
 14
 15
 16/* -------------------------------- ModR/M, SIB */
 17/* Convenience flags */
 18#define MODRM_EA  1                     /* ModR/M is an effective addr */
 19#define MODRM_reg 2                     /* ModR/M is a register */
 20
 21/* ModR/M flags */
 22#define MODRM_RM_SIB            0x04    /* R/M == 100 */
 23#define MODRM_RM_NOREG          0x05    /* R/B == 101 */
 24/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
 25#define MODRM_MOD_NODISP        0x00    /* mod == 00 */
 26#define MODRM_MOD_DISP8         0x01    /* mod == 01 */
 27#define MODRM_MOD_DISP32        0x02    /* mod == 10 */
 28#define MODRM_MOD_NOEA          0x03    /* mod == 11 */
 29/* 16-bit modrm flags */
 30#define MOD16_MOD_NODISP      0
 31#define MOD16_MOD_DISP8       1
 32#define MOD16_MOD_DISP16      2
 33#define MOD16_MOD_REG         3
 34
 35#define MOD16_RM_BXSI         0
 36#define MOD16_RM_BXDI         1
 37#define MOD16_RM_BPSI         2
 38#define MOD16_RM_BPDI         3
 39#define MOD16_RM_SI           4
 40#define MOD16_RM_DI           5
 41#define MOD16_RM_BP           6
 42#define MOD16_RM_BX           7
 43
 44/* SIB flags */
 45#define SIB_INDEX_NONE       0x04
 46#define SIB_BASE_EBP       0x05
 47#define SIB_SCALE_NOBASE    0x00
 48
 49/* Convenience struct for modR/M bitfield */
 50struct modRM_byte {  
 51   unsigned int mod : 2;
 52   unsigned int reg : 3;
 53   unsigned int rm  : 3; 
 54};
 55
 56/* Convenience struct for SIB bitfield */
 57struct SIB_byte {
 58   unsigned int scale : 2;
 59   unsigned int index : 3;
 60   unsigned int base  : 3;
 61};
 62
 63#ifdef WIN32
 64static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
 65#else
 66static inline void byte_decode(unsigned char b, struct modRM_byte *modrm) {
 67#endif
 68	/* generic bitfield-packing routine */
 69
 70	modrm->mod = b >> 6;	/* top 2 bits */
 71	modrm->reg = (b & 56) >> 3;	/* middle 3 bits */
 72	modrm->rm = b & 7;	/* bottom 3 bits */
 73}
 74static int ia32_invariant_modrm( unsigned char *in, unsigned char *out,
 75				 unsigned int mode_16, x86_invariant_op_t *op) {
 76	struct modRM_byte modrm;
 77	struct SIB_byte sib;
 78	unsigned char *c, *cin;
 79	unsigned short *s;
 80	unsigned int *i;
 81	int size = 0;	/* modrm byte is already counted */
 82
 83
 84	byte_decode(*in, &modrm);	/* get bitfields */
 85
 86	out[0] = in[0];	/* save modrm byte */
 87	cin = &in[1];
 88	c = &out[1];
 89	s = (unsigned short *)&out[1];
 90	i = (unsigned int *)&out[1];
 91
 92	op->type = op_expression;
 93	op->flags |= op_pointer;
 94	if ( ! mode_16 && modrm.rm == MODRM_RM_SIB && 
 95			      modrm.mod != MODRM_MOD_NOEA ) {
 96		size ++;
 97		byte_decode(*cin, (struct modRM_byte *)(void*)&sib);
 98
 99		out[1] = in[1];	/* save sib byte */
100		cin = &in[2];
101		c = &out[2];
102		s = (unsigned short *)&out[2];
103		i = (unsigned int *)&out[2];
104
105		if ( sib.base == SIB_BASE_EBP && ! modrm.mod ) {
106			/* disp 32 is variant! */
107			memset( i, X86_WILDCARD_BYTE, 4 );
108			size += 4;
109		}
110	}
111
112	if (! modrm.mod && modrm.rm == 101) {
113		if ( mode_16 ) {	/* straight RVA in disp */
114			memset( s, X86_WILDCARD_BYTE, 2 );
115			size += 2;
116		} else {
117			memset( i, X86_WILDCARD_BYTE, 2 );
118			size += 4;
119		}
120	} else if (modrm.mod && modrm.mod < 3) {
121		if (modrm.mod == MODRM_MOD_DISP8) {	 /* offset in disp */
122			*c = *cin;	
123			size += 1;
124		} else if ( mode_16 ) {
125			*s = (* ((unsigned short *) cin));
126			size += 2;
127		} else {
128			*i = (*((unsigned int *) cin));
129			size += 4;
130		}
131	} else if ( modrm.mod == 3 ) {
132		op->type = op_register;
133		op->flags &= ~op_pointer;
134	}
135
136	return (size);
137}
138
139
140static int ia32_decode_invariant( unsigned char *buf, size_t buf_len, 
141				ia32_insn_t *t, unsigned char *out, 
142				unsigned int prefixes, x86_invariant_t *inv) {
143
144	unsigned int addr_size, op_size, mode_16;
145	unsigned int op_flags[3] = { t->dest_flag, t->src_flag, t->aux_flag };
146	int x, type, bytes = 0, size = 0, modrm = 0;
147
148	/* set addressing mode */
149	if (ia32_settings.options & opt_16_bit) {
150		op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2;
151		addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2;
152		mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 0 : 1;
153	} else {
154		op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4;
155		addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4;
156		mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 1 : 0;
157	}
158
159	for (x = 0; x < 3; x++) {
160		inv->operands[x].access = (enum x86_op_access) 
161						OP_PERM(op_flags[x]);
162		inv->operands[x].flags = (enum x86_op_flags) 
163						(OP_FLAGS(op_flags[x]) >> 12);
164
165		switch (op_flags[x] & OPTYPE_MASK) {
166			case OPTYPE_c:
167				size = (op_size == 4) ? 2 : 1;
168				break;
169			case OPTYPE_a: case OPTYPE_v:
170				size = (op_size == 4) ? 4 : 2;
171				break;
172			case OPTYPE_p:
173				size = (op_size == 4) ? 6 : 4;
174				break;
175			case OPTYPE_b:
176				size = 1;
177				break;
178			case OPTYPE_w:
179				size = 2;
180				break;
181			case OPTYPE_d: case OPTYPE_fs: case OPTYPE_fd:
182			case OPTYPE_fe: case OPTYPE_fb: case OPTYPE_fv:
183			case OPTYPE_si: case OPTYPE_fx:
184				size = 4;
185				break;
186			case OPTYPE_s:
187				size = 6;
188				break;
189			case OPTYPE_q: case OPTYPE_pi:
190				size = 8;
191				break;
192			case OPTYPE_dq: case OPTYPE_ps: case OPTYPE_ss:
193			case OPTYPE_pd: case OPTYPE_sd:
194				size = 16;
195				break;
196			case OPTYPE_m:	
197				size = (addr_size == 4) ? 4 : 2;
198				break;
199			default:
200				break;
201		}
202
203		type = op_flags[x] & ADDRMETH_MASK;
204		switch (type) {
205			case ADDRMETH_E: case ADDRMETH_M: case ADDRMETH_Q:
206			case ADDRMETH_R: case ADDRMETH_W:
207				modrm = 1;	
208				bytes += ia32_invariant_modrm( buf, out, 
209						mode_16, &inv->operands[x]);
210				break;
211			case ADDRMETH_C: case ADDRMETH_D: case ADDRMETH_G:
212			case ADDRMETH_P: case ADDRMETH_S: case ADDRMETH_T:
213			case ADDRMETH_V:
214				inv->operands[x].type = op_register;
215				modrm = 1;
216				break;
217			case ADDRMETH_A: case ADDRMETH_O:
218				/* pad with xF4's */
219				memset( &out[bytes + modrm], X86_WILDCARD_BYTE, 
220					size );
221				bytes += size;
222				inv->operands[x].type = op_offset;
223				if ( type == ADDRMETH_O ) {
224					inv->operands[x].flags |= op_signed |
225								  op_pointer;
226				}
227				break;
228			case ADDRMETH_I: case ADDRMETH_J:
229				/* grab imm value */
230				if ((op_flags[x] & OPTYPE_MASK) == OPTYPE_v) {
231					/* assume this is an address */
232					memset( &out[bytes + modrm], 
233						X86_WILDCARD_BYTE, size );
234				} else {
235					memcpy( &out[bytes + modrm], 
236						&buf[bytes + modrm], size );
237				}
238					
239				bytes += size;
240				if ( type == ADDRMETH_J ) {
241					if ( size == 1 ) {
242						inv->operands[x].type = 
243							op_relative_near;
244					} else {
245						inv->operands[x].type = 
246							op_relative_far;
247					}
248					inv->operands[x].flags |= op_signed;
249				} else {
250					inv->operands[x].type = op_immediate;
251				}
252				break;
253			case ADDRMETH_F:
254				inv->operands[x].type = op_register;
255				break;
256			case ADDRMETH_X:
257				inv->operands[x].flags |= op_signed |
258					  op_pointer | op_ds_seg | op_string;
259				break;
260			case ADDRMETH_Y:
261				inv->operands[x].flags |= op_signed |
262					  op_pointer | op_es_seg | op_string;
263				break;
264			case ADDRMETH_RR:	
265				inv->operands[x].type = op_register;
266				break;
267			case ADDRMETH_II:	
268				inv->operands[x].type = op_immediate;
269				break;
270			default:
271				inv->operands[x].type = op_unused;
272				break;
273		}
274	}
275
276	return (bytes + modrm);
277}
278
279size_t ia32_disasm_invariant( unsigned char * buf, size_t buf_len, 
280		x86_invariant_t *inv ) {
281	ia32_insn_t *raw_insn = NULL;
282	unsigned int prefixes;
283	unsigned int type;
284	size_t size;
285	
286	/* Perform recursive table lookup starting with main table (0) */
287	size = ia32_table_lookup( buf, buf_len, 0, &raw_insn, &prefixes );
288	if ( size == INVALID_INSN || size > buf_len ) {
289		/* TODO: set errno */
290		return 0;
291	}
292
293	/* copy opcode bytes to buffer */
294	memcpy( inv->bytes, buf, size );
295
296	/* set mnemonic type and group */
297	type = raw_insn->mnem_flag & ~INS_FLAG_MASK;
298        inv->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12;
299        inv->type = (enum x86_insn_type) INS_TYPE(type);
300
301	/* handle operands */
302	size += ia32_decode_invariant( buf + size, buf_len - size, raw_insn, 
303					&buf[size - 1], prefixes, inv );
304
305	inv->size = size;
306
307	return size;		/* return size of instruction in bytes */
308}
309
310size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ) {
311	x86_invariant_t inv = { {0} };
312	return( ia32_disasm_invariant( buf, buf_len, &inv ) );
313}