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}
314