1 |
/* |
2 |
* HT Editor |
3 |
* x86dis.cc |
4 |
* |
5 |
* Copyright (C) 1999-2002 Stefan Weyergraf |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License version 2 as |
9 |
* published by the Free Software Foundation. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
*/ |
20 |
|
21 |
#include <cstdio> |
22 |
#include <cstring> |
23 |
#include <cstdlib> |
24 |
|
25 |
#include "x86dis.h" |
26 |
|
27 |
#define mkmod(modrm) (((modrm)>>6)&3) |
28 |
#define mkreg(modrm) (((modrm)>>3)&7) |
29 |
#define mkrm(modrm) ((modrm)&7) |
30 |
|
31 |
#define mkscale(modrm) (((modrm)>>6)&3) |
32 |
#define mkindex(modrm) (((modrm)>>3)&7) |
33 |
#define mkbase(modrm) ((modrm)&7) |
34 |
|
35 |
int modrm16_1[8] = { X86_REG_BX, X86_REG_BX, X86_REG_BP, X86_REG_BP, |
36 |
X86_REG_SI, X86_REG_DI, X86_REG_BP, X86_REG_BX}; |
37 |
int modrm16_2[8] = { X86_REG_SI, X86_REG_DI, X86_REG_SI, X86_REG_DI, |
38 |
X86_REG_NO, X86_REG_NO, X86_REG_NO, X86_REG_NO}; |
39 |
|
40 |
int sibbase[8] = { X86_REG_AX, X86_REG_CX, X86_REG_DX, X86_REG_BX, |
41 |
X86_REG_SP, X86_REG_BP, X86_REG_SI, X86_REG_DI }; |
42 |
|
43 |
int sibindex[8] = { X86_REG_AX, X86_REG_CX, X86_REG_DX, X86_REG_BX, |
44 |
X86_REG_NO, X86_REG_BP, X86_REG_SI, X86_REG_DI }; |
45 |
|
46 |
int sibscale[4] = {1, 2, 4, 8}; |
47 |
|
48 |
/* |
49 |
* CLASS X86Disassembler |
50 |
*/ |
51 |
|
52 |
X86Disassembler::X86Disassembler() |
53 |
{ |
54 |
} |
55 |
|
56 |
X86Disassembler::X86Disassembler(int _opsize, int _addrsize) |
57 |
{ |
58 |
opsize=_opsize; |
59 |
addrsize=_addrsize; |
60 |
} |
61 |
|
62 |
X86Disassembler::~X86Disassembler() |
63 |
{ |
64 |
} |
65 |
|
66 |
dis_insn *X86Disassembler::decode(const byte *code, int Maxlen, CPU_ADDR Addr) |
67 |
{ |
68 |
ocodep=code; |
69 |
/* initialize */ |
70 |
codep=ocodep; |
71 |
maxlen=Maxlen; |
72 |
seg=Addr.addr32.seg; |
73 |
addr=Addr.addr32.offset; |
74 |
modrm=-1; |
75 |
sib=-1; |
76 |
memset(&insn, 0, sizeof(insn)); |
77 |
insn.invalid=false; |
78 |
insn.eopsize=opsize; |
79 |
insn.eaddrsize=opsize; |
80 |
|
81 |
prefixes(); |
82 |
|
83 |
insn.opcode=c; |
84 |
decode_insn(&x86_insns[insn.opcode]); |
85 |
|
86 |
if (insn.invalid) { |
87 |
insn.name="db"; |
88 |
insn.size=1; |
89 |
insn.op[0].type=X86_OPTYPE_IMM; |
90 |
insn.op[0].size=1; |
91 |
insn.op[0].imm=*code; |
92 |
insn.lockprefix=X86_PREFIX_NO; |
93 |
insn.repprefix=X86_PREFIX_NO; |
94 |
insn.segprefix=X86_PREFIX_NO; |
95 |
for (int i=1; i<3; i++) insn.op[i].type=X86_OPTYPE_EMPTY; |
96 |
} else { |
97 |
insn.size=codep-ocodep; |
98 |
} |
99 |
return &insn; |
100 |
} |
101 |
|
102 |
void X86Disassembler::decode_modrm(x86_insn_op *op, char size, int allow_reg, int allow_mem, int mmx) |
103 |
{ |
104 |
int modrm=getmodrm(); |
105 |
int mod=mkmod(modrm); |
106 |
int rm=mkrm(modrm); |
107 |
if (mod==3) { |
108 |
/* reg */ |
109 |
if (!allow_reg) { |
110 |
invalidate(); |
111 |
return; |
112 |
} |
113 |
if (mmx) { |
114 |
op->type=X86_OPTYPE_MMX; |
115 |
op->size=8; |
116 |
op->mmx=rm; |
117 |
} else { |
118 |
op->type=X86_OPTYPE_REG; |
119 |
op->size=esizeop(size); |
120 |
op->reg=rm; |
121 |
} |
122 |
} else { |
123 |
/* mem */ |
124 |
if (!allow_mem) { |
125 |
invalidate(); |
126 |
return; |
127 |
} |
128 |
op->mem.addrsize=insn.eaddrsize; |
129 |
if (insn.eaddrsize==X86_ADDRSIZE16) { |
130 |
op->type=X86_OPTYPE_MEM; |
131 |
op->size=esizeop(size); |
132 |
op->mem.floatptr=isfloat(size); |
133 |
if ((mod==0) && (rm==6)) { |
134 |
op->mem.hasdisp=1; |
135 |
op->mem.disp=getword(); |
136 |
op->mem.base=X86_REG_NO; |
137 |
op->mem.index=X86_REG_NO; |
138 |
op->mem.scale=0; |
139 |
} else { |
140 |
op->mem.base=modrm16_1[rm]; |
141 |
op->mem.index=modrm16_2[rm]; |
142 |
op->mem.scale=1; |
143 |
switch (mod) { |
144 |
case 0: |
145 |
op->mem.hasdisp=0; |
146 |
op->mem.disp=0; |
147 |
break; |
148 |
case 1: |
149 |
op->mem.hasdisp=1; |
150 |
op->mem.disp=(char)getbyte(); |
151 |
break; |
152 |
case 2: |
153 |
op->mem.hasdisp=1; |
154 |
op->mem.disp=(short)getword(); |
155 |
break; |
156 |
} |
157 |
} |
158 |
} else { |
159 |
op->type=X86_OPTYPE_MEM; |
160 |
op->size=esizeop(size); |
161 |
op->mem.floatptr=isfloat(size); |
162 |
if ((mod==0) && (rm==5)) { |
163 |
op->mem.hasdisp=1; |
164 |
op->mem.disp=getdword(); |
165 |
op->mem.base=X86_REG_NO; |
166 |
op->mem.index=X86_REG_NO; |
167 |
op->mem.scale=0; |
168 |
} else if (rm==4) { |
169 |
decode_sib(op, mod); |
170 |
} else { |
171 |
op->mem.base=rm; |
172 |
op->mem.index=X86_REG_NO; |
173 |
op->mem.scale=1; |
174 |
switch (mod) { |
175 |
case 0: |
176 |
op->mem.hasdisp=0; |
177 |
op->mem.disp=0; |
178 |
break; |
179 |
case 1: |
180 |
op->mem.hasdisp=1; |
181 |
op->mem.disp=(char)getbyte(); |
182 |
break; |
183 |
case 2: |
184 |
op->mem.hasdisp=1; |
185 |
op->mem.disp=getdword(); |
186 |
break; |
187 |
} |
188 |
} |
189 |
} |
190 |
} |
191 |
} |
192 |
|
193 |
void X86Disassembler::decode_insn(x86opc_insn *xinsn) |
194 |
{ |
195 |
if (!xinsn->name) { |
196 |
x86opc_insn_op_special special=*((x86opc_insn_op_special*)(&xinsn->op[0])); |
197 |
switch (special.type) { |
198 |
case SPECIAL_TYPE_INVALID: |
199 |
invalidate(); |
200 |
break; |
201 |
case SPECIAL_TYPE_PREFIX: |
202 |
switch (c) { |
203 |
case 0x0f: |
204 |
if (insn.opcodeclass == X86DIS_OPCODE_CLASS_STD) { |
205 |
insn.opcode = getbyte(); |
206 |
insn.opcodeclass = X86DIS_OPCODE_CLASS_EXT; |
207 |
decode_insn(&x86_insns_ext[insn.opcode]); |
208 |
break; |
209 |
} |
210 |
default: |
211 |
invalidate(); |
212 |
break; |
213 |
} |
214 |
break; |
215 |
case SPECIAL_TYPE_GROUP: { |
216 |
int m = mkreg(getmodrm()); |
217 |
insn.opcode |= m<<8; |
218 |
decode_insn(&x86_group_insns[(int)special.data][m]); |
219 |
break; |
220 |
} |
221 |
case SPECIAL_TYPE_FGROUP: { |
222 |
int m = getmodrm(); |
223 |
if (mkmod(m) == 3) { |
224 |
x86opc_finsn f = x86_float_group_insns[(int)special.data][mkreg(m)]; |
225 |
/* fprintf(stderr, "special.data=%d, m=%d, mkreg(m)=%d, mkrm(m)=%d\n", special.data, m, mkreg(m), mkrm(m));*/ |
226 |
if (f.group) { |
227 |
decode_insn(&f.group[mkrm(m)]); |
228 |
} else if (f.insn.name) { |
229 |
decode_insn(&f.insn); |
230 |
} else invalidate(); |
231 |
} else { |
232 |
decode_insn(&x86_modfloat_group_insns[(int)special.data][mkreg(m)]); |
233 |
} |
234 |
break; |
235 |
} |
236 |
} |
237 |
} else { |
238 |
insn.name=xinsn->name; |
239 |
for (int i=0; i<3; i++) { |
240 |
decode_op(&insn.op[i], &xinsn->op[i]); |
241 |
} |
242 |
} |
243 |
} |
244 |
|
245 |
void X86Disassembler::decode_op(x86_insn_op *op, x86opc_insn_op *xop) |
246 |
{ |
247 |
switch (xop->type) { |
248 |
case TYPE_0: |
249 |
return; |
250 |
case TYPE_A: { |
251 |
/* direct address without ModR/M */ |
252 |
op->type=X86_OPTYPE_FARPTR; |
253 |
op->size=esizeop(xop->size); |
254 |
switch (op->size) { |
255 |
case 4: |
256 |
op->farptr.offset=getword(); |
257 |
op->farptr.seg=getword(); |
258 |
break; |
259 |
case 6: |
260 |
op->farptr.offset=getdword(); |
261 |
op->farptr.seg=getword(); |
262 |
break; |
263 |
} |
264 |
break; |
265 |
} |
266 |
case TYPE_C: { |
267 |
/* reg of ModR/M picks control register */ |
268 |
op->type=X86_OPTYPE_CRX; |
269 |
op->size=esizeop(xop->size); |
270 |
op->crx=mkreg(getmodrm()); |
271 |
break; |
272 |
} |
273 |
case TYPE_D: { |
274 |
/* reg of ModR/M picks debug register */ |
275 |
op->type=X86_OPTYPE_DRX; |
276 |
op->size=esizeop(xop->size); |
277 |
op->drx=mkreg(getmodrm()); |
278 |
break; |
279 |
} |
280 |
case TYPE_E: { |
281 |
/* ModR/M (general reg or memory) */ |
282 |
decode_modrm(op, xop->size, (xop->size!=SIZE_P), 1, 0); |
283 |
break; |
284 |
} |
285 |
case TYPE_F: { |
286 |
/* r/m of ModR/M picks a fpu register */ |
287 |
op->type=X86_OPTYPE_STX; |
288 |
op->size=10; |
289 |
op->stx=mkrm(getmodrm()); |
290 |
break; |
291 |
} |
292 |
case TYPE_Fx: { |
293 |
/* extra picks a fpu register */ |
294 |
op->type=X86_OPTYPE_STX; |
295 |
op->size=10; |
296 |
op->stx=xop->extra; |
297 |
break; |
298 |
} |
299 |
case TYPE_G: { |
300 |
/* reg of ModR/M picks general register */ |
301 |
op->type=X86_OPTYPE_REG; |
302 |
op->size=esizeop(xop->size); |
303 |
op->reg=mkreg(getmodrm()); |
304 |
break; |
305 |
} |
306 |
case TYPE_Is: { |
307 |
/* signed immediate */ |
308 |
op->type=X86_OPTYPE_IMM; |
309 |
op->size=esizeop(xop->extendedsize); |
310 |
int s=esizeop(xop->size); |
311 |
switch (s) { |
312 |
case 1: |
313 |
op->imm=(char)getbyte(); |
314 |
break; |
315 |
case 2: |
316 |
op->imm=(short)getword(); |
317 |
break; |
318 |
case 4: |
319 |
op->imm=getdword(); |
320 |
break; |
321 |
} |
322 |
switch (op->size) { |
323 |
case 1: |
324 |
op->imm&=0xff; |
325 |
break; |
326 |
case 2: |
327 |
op->imm&=0xffff; |
328 |
break; |
329 |
} |
330 |
break; |
331 |
} |
332 |
case TYPE_I: { |
333 |
/* unsigned immediate */ |
334 |
op->type=X86_OPTYPE_IMM; |
335 |
op->size=esizeop(xop->extendedsize); |
336 |
int s=esizeop(xop->size); |
337 |
switch (s) { |
338 |
case 1: |
339 |
op->imm=getbyte(); |
340 |
break; |
341 |
case 2: |
342 |
op->imm=getword(); |
343 |
break; |
344 |
case 4: |
345 |
op->imm=getdword(); |
346 |
break; |
347 |
} |
348 |
break; |
349 |
} |
350 |
case TYPE_Ix: { |
351 |
/* fixed immediate */ |
352 |
op->type=X86_OPTYPE_IMM; |
353 |
op->size=esizeop(xop->extendedsize); |
354 |
op->imm=xop->extra; |
355 |
break; |
356 |
} |
357 |
case TYPE_J: { |
358 |
/* relative branch offset */ |
359 |
op->type=X86_OPTYPE_IMM; |
360 |
// op->size=esizeaddr(xop->extendedsize); |
361 |
op->size=(addrsize==X86_ADDRSIZE32) ? 4 : 2; |
362 |
int s=esizeop(xop->size); |
363 |
switch (s) { |
364 |
case 1: |
365 |
op->imm=(char)getbyte()+addr; |
366 |
break; |
367 |
case 2: |
368 |
op->imm=(short)getword()+addr; |
369 |
break; |
370 |
case 4: |
371 |
op->imm=getdword()+addr; |
372 |
break; |
373 |
} |
374 |
break; |
375 |
} |
376 |
case TYPE_M: { |
377 |
/* ModR/M (memory only) */ |
378 |
decode_modrm(op, xop->size, 0, 1, 0); |
379 |
break; |
380 |
} |
381 |
case TYPE_O: { |
382 |
/* direct memory without ModR/M */ |
383 |
op->type=X86_OPTYPE_MEM; |
384 |
op->size=esizeop(xop->size); |
385 |
op->mem.floatptr=isfloat(xop->size); |
386 |
op->mem.addrsize=insn.eaddrsize; |
387 |
switch (insn.eaddrsize) { |
388 |
case X86_ADDRSIZE16: |
389 |
op->mem.hasdisp=1; |
390 |
op->mem.disp=getword(); |
391 |
break; |
392 |
case X86_ADDRSIZE32: |
393 |
op->mem.hasdisp=1; |
394 |
op->mem.disp=getdword(); |
395 |
break; |
396 |
} |
397 |
op->mem.base=X86_REG_NO; |
398 |
op->mem.index=X86_REG_NO; |
399 |
op->mem.scale=1; |
400 |
break; |
401 |
} |
402 |
case TYPE_P: { |
403 |
/* reg of ModR/M picks MMX register */ |
404 |
op->type=X86_OPTYPE_MMX; |
405 |
op->size=8; |
406 |
op->mmx=mkreg(getmodrm()); |
407 |
break; |
408 |
} |
409 |
case TYPE_Q: { |
410 |
/* ModR/M (MMX reg or memory) */ |
411 |
decode_modrm(op, xop->size, 1, 1, 1); |
412 |
break; |
413 |
} |
414 |
case TYPE_R: { |
415 |
/* rm of ModR/M picks general register */ |
416 |
op->type=X86_OPTYPE_REG; |
417 |
op->size=esizeop(xop->size); |
418 |
op->reg=mkrm(getmodrm()); |
419 |
break; |
420 |
} |
421 |
case TYPE_Rx: { |
422 |
/* extra picks register */ |
423 |
op->type=X86_OPTYPE_REG; |
424 |
op->size=esizeop(xop->size); |
425 |
op->reg=xop->extra; |
426 |
break; |
427 |
} |
428 |
case TYPE_S: { |
429 |
/* reg of ModR/M picks segment register */ |
430 |
op->type=X86_OPTYPE_SEG; |
431 |
op->size=esizeop(xop->size); |
432 |
op->seg=mkreg(getmodrm()); |
433 |
if (op->seg>5) invalidate(); |
434 |
break; |
435 |
} |
436 |
case TYPE_Sx: { |
437 |
/* extra picks segment register */ |
438 |
op->type=X86_OPTYPE_SEG; |
439 |
op->size=esizeop(xop->size); |
440 |
op->seg=xop->extra; |
441 |
if (op->seg>5) invalidate(); |
442 |
break; |
443 |
} |
444 |
case TYPE_T: { |
445 |
/* reg of ModR/M picks test register */ |
446 |
op->type=X86_OPTYPE_TRX; |
447 |
op->size=esizeop(xop->size); |
448 |
op->trx=mkreg(getmodrm()); |
449 |
break; |
450 |
} |
451 |
} |
452 |
} |
453 |
|
454 |
void X86Disassembler::decode_sib(x86_insn_op *op, int mod) |
455 |
{ |
456 |
int sib=getsib(); |
457 |
int scale=mkscale(sib); |
458 |
int index=mkindex(sib); |
459 |
int base=mkbase(sib); |
460 |
int disp=mod; |
461 |
if (base==5) { |
462 |
if (mod==0) { |
463 |
op->mem.base=X86_REG_NO; |
464 |
disp=2; |
465 |
} else { |
466 |
op->mem.base=X86_REG_BP; |
467 |
} |
468 |
op->mem.index=sibindex[index]; |
469 |
op->mem.scale=sibscale[scale]; |
470 |
} else { |
471 |
op->mem.base=sibbase[base]; |
472 |
op->mem.index=sibindex[index]; |
473 |
op->mem.scale=sibscale[scale]; |
474 |
} |
475 |
switch (disp) { |
476 |
case 0: |
477 |
op->mem.hasdisp=0; |
478 |
op->mem.disp=0; |
479 |
break; |
480 |
case 1: |
481 |
op->mem.hasdisp=1; |
482 |
op->mem.disp=(char)getbyte(); |
483 |
break; |
484 |
case 2: |
485 |
op->mem.hasdisp=1; |
486 |
op->mem.disp=getdword(); |
487 |
break; |
488 |
} |
489 |
} |
490 |
|
491 |
dis_insn *X86Disassembler::duplicateInsn(dis_insn *disasm_insn) |
492 |
{ |
493 |
x86dis_insn *insn = (x86dis_insn *)malloc(sizeof (x86dis_insn)); |
494 |
*insn = *(x86dis_insn *)disasm_insn; |
495 |
return insn; |
496 |
} |
497 |
|
498 |
int X86Disassembler::esizeaddr(char c) |
499 |
{ |
500 |
switch (c) { |
501 |
case SIZE_B: |
502 |
return 1; |
503 |
case SIZE_W: |
504 |
return 2; |
505 |
case SIZE_D: |
506 |
return 4; |
507 |
case SIZE_Q: |
508 |
return 8; |
509 |
case SIZE_S: |
510 |
return 4; |
511 |
case SIZE_L: |
512 |
return 8; |
513 |
case SIZE_T: |
514 |
return 10; |
515 |
case SIZE_C: |
516 |
if (insn.eaddrsize==X86_ADDRSIZE16) return 1; else return 2; |
517 |
case SIZE_V: |
518 |
if (insn.eaddrsize==X86_ADDRSIZE16) return 2; else return 4; |
519 |
case SIZE_P: |
520 |
if (insn.eaddrsize==X86_ADDRSIZE16) return 4; else return 6; |
521 |
} |
522 |
return 0; |
523 |
} |
524 |
|
525 |
int X86Disassembler::esizeop(char c) |
526 |
{ |
527 |
switch (c) { |
528 |
case SIZE_B: |
529 |
return 1; |
530 |
case SIZE_W: |
531 |
return 2; |
532 |
case SIZE_D: |
533 |
return 4; |
534 |
case SIZE_Q: |
535 |
return 8; |
536 |
case SIZE_S: |
537 |
return 4; |
538 |
case SIZE_L: |
539 |
return 8; |
540 |
case SIZE_T: |
541 |
return 10; |
542 |
case SIZE_C: |
543 |
if (insn.eopsize==X86_OPSIZE16) return 1; else return 2; |
544 |
case SIZE_V: |
545 |
if (insn.eopsize==X86_OPSIZE16) return 2; else return 4; |
546 |
case SIZE_P: |
547 |
if (insn.eopsize==X86_OPSIZE16) return 4; else return 6; |
548 |
} |
549 |
return 0; |
550 |
} |
551 |
|
552 |
byte X86Disassembler::getbyte() |
553 |
{ |
554 |
if (codep-ocodep+1<=maxlen) { |
555 |
addr+=1; |
556 |
return *(codep++); |
557 |
} else { |
558 |
invalidate(); |
559 |
return 0; |
560 |
} |
561 |
} |
562 |
|
563 |
word X86Disassembler::getword() |
564 |
{ |
565 |
if (codep-ocodep+2<=maxlen) { |
566 |
word w; |
567 |
addr += 2; |
568 |
w = codep[0] | (codep[1]<<8); |
569 |
codep += 2; |
570 |
return w; |
571 |
} else { |
572 |
invalidate(); |
573 |
return 0; |
574 |
} |
575 |
} |
576 |
|
577 |
dword X86Disassembler::getdword() |
578 |
{ |
579 |
if (codep-ocodep+4<=maxlen) { |
580 |
dword w; |
581 |
addr += 4; |
582 |
w = codep[0] | (codep[1]<<8) | (codep[2]<<16) | (codep[3]<<24); |
583 |
codep += 4; |
584 |
return w; |
585 |
} else { |
586 |
invalidate(); |
587 |
return 0; |
588 |
} |
589 |
} |
590 |
|
591 |
void X86Disassembler::getOpcodeMetrics(int &min_length, int &max_length, int &min_look_ahead, int &avg_look_ahead, int &addr_align) |
592 |
{ |
593 |
min_length = 1; |
594 |
max_length = 15; |
595 |
min_look_ahead = 120; // 1/2/3/4/5/6/8/10/12/15 |
596 |
avg_look_ahead = 24; // 1/2/3/4/6/8/12/24 |
597 |
addr_align = 1; |
598 |
} |
599 |
|
600 |
int X86Disassembler::getmodrm() |
601 |
{ |
602 |
if (modrm==-1) modrm=getbyte(); |
603 |
return modrm; |
604 |
} |
605 |
|
606 |
char *X86Disassembler::getName() |
607 |
{ |
608 |
return "x86/Disassembler"; |
609 |
} |
610 |
|
611 |
int X86Disassembler::getsib() |
612 |
{ |
613 |
if (sib==-1) sib=getbyte(); |
614 |
return sib; |
615 |
} |
616 |
|
617 |
byte X86Disassembler::getSize(dis_insn *disasm_insn) |
618 |
{ |
619 |
return ((x86dis_insn*)disasm_insn)->size; |
620 |
} |
621 |
|
622 |
void X86Disassembler::invalidate() |
623 |
{ |
624 |
insn.invalid=1; |
625 |
} |
626 |
|
627 |
int X86Disassembler::isfloat(char c) |
628 |
{ |
629 |
switch (c) { |
630 |
case SIZE_S: |
631 |
case SIZE_L: |
632 |
case SIZE_T: |
633 |
return 1; |
634 |
} |
635 |
return 0; |
636 |
} |
637 |
|
638 |
void X86Disassembler::prefixes() |
639 |
{ |
640 |
bool notprefix=0; |
641 |
insn.lockprefix=X86_PREFIX_NO; |
642 |
insn.repprefix=X86_PREFIX_NO; |
643 |
insn.segprefix=X86_PREFIX_NO; |
644 |
while ((codep-ocodep<15) && (!notprefix)) { |
645 |
c=getbyte(); |
646 |
switch (c) { |
647 |
case 0x26: |
648 |
insn.segprefix=X86_PREFIX_ES; |
649 |
break; |
650 |
case 0x2e: |
651 |
insn.segprefix=X86_PREFIX_CS; |
652 |
break; |
653 |
case 0x36: |
654 |
insn.segprefix=X86_PREFIX_SS; |
655 |
break; |
656 |
case 0x3e: |
657 |
insn.segprefix=X86_PREFIX_DS; |
658 |
break; |
659 |
case 0x64: |
660 |
insn.segprefix=X86_PREFIX_FS; |
661 |
break; |
662 |
case 0x65: |
663 |
insn.segprefix=X86_PREFIX_GS; |
664 |
break; |
665 |
case 0x66: |
666 |
insn.eopsize=(opsize==X86_OPSIZE16) ? X86_OPSIZE32 : X86_OPSIZE16; |
667 |
break; |
668 |
case 0x67: |
669 |
insn.eaddrsize=(addrsize==X86_ADDRSIZE16) ? X86_ADDRSIZE32 : X86_ADDRSIZE16; |
670 |
break; |
671 |
case 0xf0: |
672 |
insn.lockprefix=X86_PREFIX_LOCK; |
673 |
break; |
674 |
case 0xf2: |
675 |
insn.repprefix=X86_PREFIX_REPNZ; |
676 |
break; |
677 |
case 0xf3: |
678 |
insn.repprefix=X86_PREFIX_REPZ; |
679 |
break; |
680 |
default: |
681 |
notprefix=1; |
682 |
} |
683 |
} |
684 |
} |
685 |
|
686 |
int X86Disassembler::special_param_ambiguity(x86dis_insn *disasm_insn) |
687 |
{ |
688 |
int regc=0, memc=0, segc=0; |
689 |
for (int i=0; i<3; i++) { |
690 |
switch (disasm_insn->op[i].type) { |
691 |
case X86_OPTYPE_SEG: |
692 |
segc++; |
693 |
case X86_OPTYPE_REG: |
694 |
case X86_OPTYPE_CRX: |
695 |
case X86_OPTYPE_DRX: |
696 |
case X86_OPTYPE_TRX: |
697 |
case X86_OPTYPE_STX: |
698 |
case X86_OPTYPE_MMX: |
699 |
regc++; |
700 |
break; |
701 |
case X86_OPTYPE_MEM: |
702 |
memc++; |
703 |
break; |
704 |
} |
705 |
} |
706 |
return (memc && !regc) |
707 |
|| (memc && segc) |
708 |
|| (strcmp(disasm_insn->name, "movzx") == 0) |
709 |
|| (strcmp(disasm_insn->name, "movsx") == 0); |
710 |
} |
711 |
|
712 |
void X86Disassembler::str_op(char *opstr, int *opstrlen, x86dis_insn *insn, x86_insn_op *op, bool explicit_params) |
713 |
{ |
714 |
const char *cs_default = get_cs(e_cs_default); |
715 |
const char *cs_number = get_cs(e_cs_number); |
716 |
const char *cs_symbol = get_cs(e_cs_symbol); |
717 |
|
718 |
*opstrlen=0; |
719 |
switch (op->type) { |
720 |
case X86_OPTYPE_IMM: { |
721 |
CPU_ADDR a; |
722 |
// FIXME: hack |
723 |
if ((insn->name[0]=='j') || strcmp(insn->name, "call")==0) { |
724 |
a.addr32.seg = seg; |
725 |
} else { |
726 |
a.addr32.seg = 0; |
727 |
} |
728 |
a.addr32.offset = op->imm; |
729 |
int slen; |
730 |
char *s=(addr_sym_func) ? addr_sym_func(a, &slen, addr_sym_func_context) : NULL; |
731 |
if (s) { |
732 |
memmove(opstr, s, slen); |
733 |
opstr[slen]=0; |
734 |
*opstrlen=slen; |
735 |
} else { |
736 |
char *g=opstr; |
737 |
strcpy(g, cs_number); g += strlen(cs_number); |
738 |
switch (op->size) { |
739 |
case 1: |
740 |
hexd(&g, 2, options, op->imm); |
741 |
break; |
742 |
case 2: |
743 |
hexd(&g, 4, options, op->imm); |
744 |
break; |
745 |
case 4: |
746 |
hexd(&g, 8, options, op->imm); |
747 |
break; |
748 |
} |
749 |
strcpy(g, cs_default); g += strlen(cs_default); |
750 |
} |
751 |
break; |
752 |
} |
753 |
case X86_OPTYPE_REG: { |
754 |
int j; |
755 |
switch (op->size) { |
756 |
case 1: j=0; break; |
757 |
case 2: j=1; break; |
758 |
case 4: j=2; break; |
759 |
default: |
760 |
j=-1; |
761 |
} |
762 |
if (j!=-1) sprintf(opstr, x86_regs[j][op->reg]); |
763 |
break; |
764 |
} |
765 |
case X86_OPTYPE_SEG: |
766 |
if (x86_segs[op->seg]) { |
767 |
sprintf(opstr, x86_segs[op->seg]); |
768 |
} |
769 |
break; |
770 |
case X86_OPTYPE_CRX: |
771 |
sprintf(opstr, "cr%d", op->crx); |
772 |
break; |
773 |
case X86_OPTYPE_DRX: |
774 |
sprintf(opstr, "dr%d", op->drx); |
775 |
break; |
776 |
case X86_OPTYPE_TRX: |
777 |
sprintf(opstr, "tr%d", op->trx); |
778 |
break; |
779 |
case X86_OPTYPE_STX: |
780 |
if (op->stx) { |
781 |
sprintf(opstr, "st(%d)", op->stx); |
782 |
} else { |
783 |
strcpy(opstr, "st"); |
784 |
} |
785 |
break; |
786 |
case X86_OPTYPE_MMX: |
787 |
sprintf(opstr, "mm%d", op->mmx); |
788 |
break; |
789 |
case X86_OPTYPE_MEM: { |
790 |
char *d=opstr; |
791 |
int reg; |
792 |
if (explicit_params) { |
793 |
if (op->mem.floatptr) { |
794 |
switch (op->size) { |
795 |
case 4: |
796 |
d+=sprintf(d, "single ptr "); |
797 |
break; |
798 |
case 8: |
799 |
d+=sprintf(d, "double ptr "); |
800 |
break; |
801 |
case 10: |
802 |
d+=sprintf(d, "extended ptr "); |
803 |
break; |
804 |
} |
805 |
} else { |
806 |
switch (op->size) { |
807 |
case 1: |
808 |
d+=sprintf(d, "byte ptr "); |
809 |
break; |
810 |
case 2: |
811 |
d+=sprintf(d, "word ptr "); |
812 |
break; |
813 |
case 4: |
814 |
d+=sprintf(d, "dword ptr "); |
815 |
break; |
816 |
case 6: |
817 |
d+=sprintf(d, "pword ptr "); |
818 |
break; |
819 |
case 8: |
820 |
d+=sprintf(d, "qword ptr "); |
821 |
break; |
822 |
} |
823 |
} |
824 |
} |
825 |
if (insn->eaddrsize==X86_ADDRSIZE16) reg=1; else reg=2; |
826 |
if (insn->segprefix!=X86_PREFIX_NO) d+=sprintf(d, "%s%s:%s", x86_segs[insn->segprefix], cs_symbol, cs_default); |
827 |
strcpy(d, cs_symbol); d += strlen(cs_symbol); |
828 |
*(d++)='['; |
829 |
strcpy(d, cs_default); d += strlen(cs_default); |
830 |
|
831 |
int optimize_addr=options & X86DIS_STYLE_OPTIMIZE_ADDR; |
832 |
int first=1; |
833 |
if (optimize_addr && (op->mem.base!=X86_REG_NO) && (op->mem.base==op->mem.index)) { |
834 |
d+=sprintf(d, "%s%s*%s%d%s", x86_regs[reg][op->mem.index], cs_symbol, cs_number, op->mem.scale+1, cs_default); |
835 |
first=0; |
836 |
} else { |
837 |
if (op->mem.base!=X86_REG_NO) { |
838 |
d+=sprintf(d, "%s", x86_regs[reg][op->mem.base]); |
839 |
first=0; |
840 |
} |
841 |
if (op->mem.index!=X86_REG_NO) { |
842 |
if (!first) *(d++)='+'; |
843 |
if ((op->mem.scale==1)) { |
844 |
d+=sprintf(d, "%s", x86_regs[reg][op->mem.index]); |
845 |
} else { |
846 |
d+=sprintf(d, "%s%s*%s%d%s", x86_regs[reg][op->mem.index], cs_symbol, cs_number, op->mem.scale, cs_default); |
847 |
} |
848 |
first=0; |
849 |
} |
850 |
} |
851 |
if ((!optimize_addr && op->mem.hasdisp) || (optimize_addr && op->mem.disp) || first) { |
852 |
CPU_ADDR a; |
853 |
a.addr32.seg = 0; // FIXME: not ok |
854 |
a.addr32.offset=op->mem.disp; |
855 |
int slen; |
856 |
char *s=(addr_sym_func) ? addr_sym_func(a, &slen, addr_sym_func_context) : 0; |
857 |
if (s) { |
858 |
if (!first) { |
859 |
strcpy(d, cs_symbol); d += strlen(cs_symbol); |
860 |
*(d++)='+'; |
861 |
strcpy(d, cs_default); d += strlen(cs_default); |
862 |
} |
863 |
memmove(d, s, slen); |
864 |
d+=slen; |
865 |
*opstrlen=d-opstr; |
866 |
} else { |
867 |
dword q; |
868 |
switch (op->mem.addrsize) { |
869 |
case X86_ADDRSIZE16: |
870 |
q=op->mem.disp; |
871 |
if (!first) { |
872 |
strcpy(d, cs_symbol); d += strlen(cs_symbol); |
873 |
if (op->mem.disp&0x80000000) { |
874 |
*(d++)='-'; |
875 |
q=-q; |
876 |
} else *(d++)='+'; |
877 |
} |
878 |
strcpy(d, cs_number); d += strlen(cs_number); |
879 |
hexd(&d, 4, options, q); |
880 |
strcpy(d, cs_default); d += strlen(cs_default); |
881 |
break; |
882 |
case X86_ADDRSIZE32: |
883 |
q=op->mem.disp; |
884 |
if (!first) { |
885 |
strcpy(d, cs_symbol); d += strlen(cs_symbol); |
886 |
if (op->mem.disp&0x80000000) { |
887 |
*(d++)='-'; |
888 |
q=-q; |
889 |
} else *(d++)='+'; |
890 |
} |
891 |
strcpy(d, cs_number); d += strlen(cs_number); |
892 |
hexd(&d, 8, options, q); |
893 |
strcpy(d, cs_default); d += strlen(cs_default); |
894 |
break; |
895 |
} |
896 |
} |
897 |
} |
898 |
strcpy(d, cs_symbol); d += strlen(cs_symbol); |
899 |
*(d++)=']'; |
900 |
strcpy(d, cs_default); d += strlen(cs_default); |
901 |
if (*opstrlen) |
902 |
*opstrlen += strlen(cs_symbol) + 1 + strlen(cs_default); |
903 |
*d=0; |
904 |
break; |
905 |
} |
906 |
case X86_OPTYPE_FARPTR: { |
907 |
CPU_ADDR a; |
908 |
/* a.addr32.seg = op->farptr.seg; |
909 |
a.addr32.offset = op->farptr.offset; |
910 |
*/ |
911 |
a.addr32.seg = op->farptr.seg; |
912 |
a.addr32.offset = op->farptr.offset; |
913 |
int slen; |
914 |
char *s=(addr_sym_func) ? addr_sym_func(a, &slen, addr_sym_func_context) : 0; |
915 |
if (s) { |
916 |
memmove(opstr, s, slen); |
917 |
opstr[slen]=0; |
918 |
*opstrlen=slen; |
919 |
} else { |
920 |
char *g=opstr; |
921 |
hexd(&g, 4, options, op->farptr.seg); |
922 |
strcpy(g, cs_symbol); g += strlen(cs_symbol); |
923 |
*(g++)=':'; |
924 |
strcpy(g, cs_default); g += strlen(cs_default); |
925 |
switch (op->size) { |
926 |
case 4: |
927 |
hexd(&g, 4, options, op->farptr.offset); |
928 |
break; |
929 |
case 6: |
930 |
hexd(&g, 8, options, op->farptr.offset); |
931 |
break; |
932 |
} |
933 |
} |
934 |
break; |
935 |
} |
936 |
default: |
937 |
opstr[0]=0; |
938 |
} |
939 |
} |
940 |
|
941 |
void X86Disassembler::str_format(char **str, char **format, char *p, char *n, char *op[3], int oplen[3], char stopchar, int print) |
942 |
{ |
943 |
const char *cs_default = get_cs(e_cs_default); |
944 |
const char *cs_symbol = get_cs(e_cs_symbol); |
945 |
|
946 |
char *f=*format; |
947 |
char *s=*str; |
948 |
while (*f) { |
949 |
if (*f==stopchar) break; |
950 |
switch (*f) { |
951 |
case '\t': |
952 |
if (print) do *(s++)=' '; while ((s-insnstr) % DIS_STYLE_TABSIZE); |
953 |
break; |
954 |
case DISASM_STRF_VAR: |
955 |
f++; |
956 |
if (print) { |
957 |
char *t=0; |
958 |
int tl=0; |
959 |
switch (*f) { |
960 |
case DISASM_STRF_PREFIX: |
961 |
t=p; |
962 |
break; |
963 |
case DISASM_STRF_NAME: |
964 |
t=n; |
965 |
break; |
966 |
case DISASM_STRF_FIRST: |
967 |
t=op[0]; |
968 |
tl=oplen[0]; |
969 |
break; |
970 |
case DISASM_STRF_SECOND: |
971 |
t=op[1]; |
972 |
tl=oplen[1]; |
973 |
break; |
974 |
case DISASM_STRF_THIRD: |
975 |
t=op[2]; |
976 |
tl=oplen[2]; |
977 |
break; |
978 |
} |
979 |
if (tl) { |
980 |
memmove(s, t, tl); |
981 |
s+=tl; |
982 |
*s=0; |
983 |
} else { |
984 |
strcpy(s, t); |
985 |
s += strlen(s); |
986 |
} |
987 |
} |
988 |
break; |
989 |
case DISASM_STRF_COND: { |
990 |
char *t=0; |
991 |
f++; |
992 |
switch (*f) { |
993 |
case DISASM_STRF_PREFIX: |
994 |
t=p; |
995 |
break; |
996 |
case DISASM_STRF_NAME: |
997 |
t=n; |
998 |
break; |
999 |
case DISASM_STRF_FIRST: |
1000 |
t=op[0]; |
1001 |
break; |
1002 |
case DISASM_STRF_SECOND: |
1003 |
t=op[1]; |
1004 |
break; |
1005 |
case DISASM_STRF_THIRD: |
1006 |
t=op[2]; |
1007 |
break; |
1008 |
} |
1009 |
f+=2; |
1010 |
if ((t) && (t[0])) { |
1011 |
str_format(&s, &f, p, n, op, oplen, *(f-1), 1); |
1012 |
} else { |
1013 |
str_format(&s, &f, p, n, op, oplen, *(f-1), 0); |
1014 |
} |
1015 |
break; |
1016 |
} |
1017 |
default: |
1018 |
if (print) { |
1019 |
bool x = (strchr(",.-=+-*/[]()", *f) != NULL) && *f; |
1020 |
if (x) { strcpy(s, cs_symbol); s += strlen(cs_symbol); } |
1021 |
*(s++) = *f; |
1022 |
if (x) { strcpy(s, cs_default); s += strlen(cs_default); } |
1023 |
} |
1024 |
} |
1025 |
f++; |
1026 |
} |
1027 |
*s=0; |
1028 |
*format=f; |
1029 |
*str=s; |
1030 |
} |
1031 |
|
1032 |
char *X86Disassembler::str(dis_insn *disasm_insn, int options) |
1033 |
{ |
1034 |
return strf(disasm_insn, options, DISASM_STRF_DEFAULT_FORMAT); |
1035 |
} |
1036 |
|
1037 |
char *X86Disassembler::strf(dis_insn *disasm_insn, int opt, char *format) |
1038 |
{ |
1039 |
x86dis_insn *insn = (x86dis_insn*)disasm_insn; |
1040 |
char prefix[64]; |
1041 |
char *p = prefix; |
1042 |
options = opt; |
1043 |
*p = 0; |
1044 |
if (insn->lockprefix == X86_PREFIX_LOCK) p+=sprintf(p, "lock "); |
1045 |
if (insn->repprefix == X86_PREFIX_REPZ) { |
1046 |
p += sprintf(p, "repz "); |
1047 |
} else if (insn->repprefix == X86_PREFIX_REPNZ) { |
1048 |
p += sprintf(p, "repnz "); |
1049 |
} |
1050 |
if ((p != prefix) && (*(p-1) == ' ')) { |
1051 |
p--; |
1052 |
*p = 0; |
1053 |
} |
1054 |
|
1055 |
bool explicit_params = ((options & X86DIS_STYLE_EXPLICIT_MEMSIZE) || |
1056 |
special_param_ambiguity(insn)); |
1057 |
|
1058 |
char ops[3][512]; /* FIXME: possible buffer overflow ! */ |
1059 |
char *op[3]; |
1060 |
int oplen[3]; |
1061 |
|
1062 |
if (options & DIS_STYLE_HIGHLIGHT) enable_highlighting(); |
1063 |
for (int i=0; i<3; i++) { |
1064 |
op[i]=(char*)&ops[i]; |
1065 |
str_op(op[i], &oplen[i], insn, &insn->op[i], explicit_params); |
1066 |
} |
1067 |
char *s=insnstr; |
1068 |
char n[32]; |
1069 |
switch (insn->eopsize) { |
1070 |
case X86_OPSIZE16: |
1071 |
sprintf(n, insn->name, 'w'); |
1072 |
break; |
1073 |
case X86_OPSIZE32: |
1074 |
sprintf(n, insn->name, 'd'); |
1075 |
break; |
1076 |
default: |
1077 |
strcpy(n, insn->name); |
1078 |
break; |
1079 |
} |
1080 |
str_format(&s, &format, prefix, n, op, oplen, 0, 1); |
1081 |
disable_highlighting(); |
1082 |
return insnstr; |
1083 |
} |
1084 |
|
1085 |
bool X86Disassembler::validInsn(dis_insn *disasm_insn) |
1086 |
{ |
1087 |
return !((x86dis_insn *)disasm_insn)->invalid; |
1088 |
} |
1089 |
|