OLD | NEW |
| (Empty) |
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 | |
8 extern ia32_table_desc_t *ia32_tables; | |
9 extern ia32_settings_t ia32_settings; | |
10 | |
11 extern 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 */ | |
50 struct 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 */ | |
57 struct SIB_byte { | |
58 unsigned int scale : 2; | |
59 unsigned int index : 3; | |
60 unsigned int base : 3; | |
61 }; | |
62 | |
63 #ifdef WIN32 | |
64 static void byte_decode(unsigned char b, struct modRM_byte *modrm) { | |
65 #else | |
66 static 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 } | |
74 static 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 | |
140 static 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 | |
279 size_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 | |
310 size_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 } | |
OLD | NEW |