10 #define REGOFF(x) (ulong)(&((struct Ureg *) 0)->x)
12 #define REGSIZE sizeof(struct Ureg)
13 #define FP_CTL(x) (REGSIZE+4*(x))
14 #define FP_REG(x) (FP_CTL(7)+10*(x))
15 #define FPREGSIZE (6*4+8*10)
18 * i386-specific debugger interface
21 static char *i386excep(Map*, Regs*);
24 static int i386trace(Map*, ulong, ulong, ulong, Tracer);
25 static ulong i386frame(Map*, ulong, ulong, ulong, ulong);
27 static int i386foll(Map*, Regs*, ulong, ulong*);
28 static int i386hexinst(Map*, ulong, char*, int);
29 static int i386das(Map*, ulong, char, char*, int);
30 static int i386instlen(Map*, ulong);
31 static char *i386windregs[];
32 static int i386unwind(Map*, Regs*, ulong*);
34 static Regdesc i386reglist[] = {
35 {"DI", REGOFF(di), RINT, 'X'},
36 {"SI", REGOFF(si), RINT, 'X'},
37 {"BP", REGOFF(bp), RINT, 'X'},
38 {"BX", REGOFF(bx), RINT, 'X'},
39 {"DX", REGOFF(dx), RINT, 'X'},
40 {"CX", REGOFF(cx), RINT, 'X'},
41 {"AX", REGOFF(ax), RINT, 'X'},
42 {"GS", REGOFF(gs), RINT, 'X'},
43 {"FS", REGOFF(fs), RINT, 'X'},
44 {"ES", REGOFF(es), RINT, 'X'},
45 {"DS", REGOFF(ds), RINT, 'X'},
46 {"TRAP", REGOFF(trap), RINT, 'X'},
47 {"ECODE", REGOFF(ecode), RINT, 'X'},
48 {"PC", REGOFF(pc), RINT, 'X'},
49 {"CS", REGOFF(cs), RINT, 'X'},
50 {"EFLAGS", REGOFF(flags), RINT, 'X'},
51 {"SP", REGOFF(sp), RINT, 'X'},
52 {"SS", REGOFF(ss), RINT, 'X'},
54 {"E0", FP_CTL(0), RFLT, 'X'},
55 {"E1", FP_CTL(1), RFLT, 'X'},
56 {"E2", FP_CTL(2), RFLT, 'X'},
57 {"E3", FP_CTL(3), RFLT, 'X'},
58 {"E4", FP_CTL(4), RFLT, 'X'},
59 {"E5", FP_CTL(5), RFLT, 'X'},
60 {"E6", FP_CTL(6), RFLT, 'X'},
61 {"F0", FP_REG(7), RFLT, '3'},
62 {"F1", FP_REG(6), RFLT, '3'},
63 {"F2", FP_REG(5), RFLT, '3'},
64 {"F3", FP_REG(4), RFLT, '3'},
65 {"F4", FP_REG(3), RFLT, '3'},
66 {"F5", FP_REG(2), RFLT, '3'},
67 {"F6", FP_REG(1), RFLT, '3'},
68 {"F7", FP_REG(0), RFLT, '3'},
75 M386, /* machine type */
76 i386reglist, /* register list */
77 REGSIZE, /* size of registers in bytes */
78 FPREGSIZE, /* size of fp registers in bytes */
79 "PC", /* name of PC */
80 "SP", /* name of SP */
81 "BP", /* name of FP */
82 0, /* link register */
83 "setSB", /* static base register name (bogus anyways) */
84 0, /* static base register value */
85 0x1000, /* page size */
86 0x80100000, /* kernel base */
87 0, /* kernel text mask */
88 1, /* quantization of pc */
94 i386windregs, /* locations unwound in stack trace */
97 {0xCC, 0, 0, 0}, /* break point: INT 3 */
98 1, /* break point size */
100 i386foll, /* following addresses */
101 i386excep, /* print exception */
102 i386unwind, /* stack unwind */
104 leswap2, /* convert short to local byte order */
105 leswap4, /* convert long to local byte order */
106 leswap8, /* convert vlong to local byte order */
107 leieeeftoa32, /* single precision float pointer */
108 leieeeftoa64, /* double precision float pointer */
109 leieeeftoa80, /* long double precision floating point */
111 i386das, /* dissembler */
112 i386das, /* plan9-format disassembler */
113 0, /* commercial disassembler */
114 i386hexinst, /* print instruction */
115 i386instlen, /* instruction size calculation */
118 static char *i386windregs[] = {
132 i386unwind(Map *map, Regs *regs, ulong *next)
138 /* No symbol information, use frame pointer and do the best we can. */
139 isp = windindex("SP");
140 ipc = windindex("PC");
141 ibp = windindex("BP");
142 if(isp < 0 || ipc < 0 || ibp < 0){
143 werrstr("i386unwind: cannot happen");
149 if(get4(map, bp, &v) < 0)
155 if(get4(map, bp+4, &v) < 0)
162 //static char STARTSYM[] = "_main";
163 //static char PROFSYM[] = "_mainp";
164 static char FRAMENAME[] = ".frame";
165 static char *excname[] =
168 [1] "debug exception",
171 [6] "invalid opcode",
172 [7] "math coprocessor emulation",
174 [9] "math coprocessor overrun",
176 [11] "segment not present",
177 [12] "stack exception",
178 [13] "general protection violation",
180 [16] "math coprocessor error",
184 [28] "serial line status",
187 [37] "math coprocessor",
193 i386excep(Map *map, Regs *regs)
199 if(rget(regs, "TRAP", &c) < 0)
200 return "no trap register";
202 if(c > 64 || excname[c] == 0) {
204 if (rget(regs, "PC", &pc) >= 0)
205 if (get1(map, pc, (uchar*)buf, mach->bpsize) > 0)
206 if (memcmp(buf, mach->bpinst, mach->bpsize) == 0)
209 sprint(buf, "exception %ld", c);
215 /* I386/486 - Disassembler and related functions */
220 typedef struct Instr Instr;
223 uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
224 ulong addr; /* address of start of instruction */
225 int n; /* number of bytes in instruction */
226 char *prefix; /* instr prefix */
227 char *segment; /* segment override */
228 uchar jumptype; /* set to the operand type for jump/ret/call */
229 char osize; /* 'W' or 'L' */
230 char asize; /* address size 'W' or 'L' */
231 uchar mod; /* bits 6-7 of mod r/m field */
232 uchar reg; /* bits 3-5 of mod r/m field */
233 char ss; /* bits 6-7 of SIB */
234 char index; /* bits 3-5 of SIB */
235 char base; /* bits 0-2 of SIB */
236 short seg; /* segment of far address */
237 ulong disp; /* displacement */
238 ulong imm; /* immediate */
239 ulong imm2; /* second immediate operand */
240 char *curr; /* fill level in output buffer */
241 char *end; /* end of output buffer */
242 char *err; /* error message */
245 /* 386 register (ha!) set */
256 /* Operand Format codes */
258 %A - address size register modifier (!asize -> 'E')
259 %C - Control register CR0/CR1/CR2
260 %D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
261 %I - second immediate operand
262 %O - Operand size register modifier (!osize -> 'E')
263 %T - Test register TR6/TR7
264 %S - size code ('W' or 'L')
265 %X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
266 %d - displacement 16-32 bits
267 %e - effective address - Mod R/M value
268 %f - floating point register F0-F7 - from Mod R/M register
269 %g - segment register
270 %i - immediate operand 8-32 bits
271 %p - PC-relative - signed displacement in immediate field
272 %r - Reg from Mod R/M
273 %x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
276 typedef struct Optable Optable;
280 void *proto; /* actually either (char*) or (Optable*) */
282 /* Operand decoding codes */
284 Ib = 1, /* 8-bit immediate - (no sign extension)*/
285 Ibs, /* 8-bit immediate (sign extended) */
286 Jbs, /* 8-bit sign-extended immediate in jump or call */
287 Iw, /* 16-bit immediate -> imm */
288 Iw2, /* 16-bit immediate -> imm2 */
289 Iwd, /* Operand-sized immediate (no sign extension)*/
290 Awd, /* Address offset */
291 Iwds, /* Operand-sized immediate (sign extended) */
292 RM, /* Word or long R/M field with register (/r) */
293 RMB, /* Byte R/M field with register (/r) */
294 RMOP, /* Word or long R/M field with op code (/digit) */
295 RMOPB, /* Byte R/M field with op code (/digit) */
296 RMR, /* R/M register only (mod = 11) */
297 RMM, /* R/M memory only (mod = 0/1/2) */
298 R0, /* Base reg of Mod R/M is literal 0x00 */
299 R1, /* Base reg of Mod R/M is literal 0x01 */
300 FRMOP, /* Floating point R/M field with opcode */
301 FRMEX, /* Extended floating point R/M field with opcode */
302 JUMP, /* Jump or Call flag - no operand */
303 RET, /* Return flag - no operand */
304 OA, /* literal 0x0a byte */
305 PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
306 AUX, /* Multi-byte op code - Auxiliary table */
307 PRE, /* Instr Prefix */
308 SEG, /* Segment Prefix */
309 OPOVER, /* Operand size override */
310 ADDOVER, /* Address size override */
313 static Optable optab0F00[8]=
315 [0x00] 0,0, "MOVW LDT,%e",
316 [0x01] 0,0, "MOVW TR,%e",
317 [0x02] 0,0, "MOVW %e,LDT",
318 [0x03] 0,0, "MOVW %e,TR",
319 [0x04] 0,0, "VERR %e",
320 [0x05] 0,0, "VERW %e",
323 static Optable optab0F01[8]=
325 [0x00] 0,0, "MOVL GDTR,%e",
326 [0x01] 0,0, "MOVL IDTR,%e",
327 [0x02] 0,0, "MOVL %e,GDTR",
328 [0x03] 0,0, "MOVL %e,IDTR",
329 [0x04] 0,0, "MOVW MSW,%e", /* word */
330 [0x06] 0,0, "MOVW %e,MSW", /* word */
333 static Optable optab0FBA[8]=
335 [0x04] Ib,0, "BT%S %i,%e",
336 [0x05] Ib,0, "BTS%S %i,%e",
337 [0x06] Ib,0, "BTR%S %i,%e",
338 [0x07] Ib,0, "BTC%S %i,%e",
341 static Optable optab0F[256]=
343 [0x00] RMOP,0, optab0F00,
344 [0x01] RMOP,0, optab0F01,
345 [0x02] RM,0, "LAR %e,%r",
346 [0x03] RM,0, "LSL %e,%r",
349 [0x09] 0,0, "WBINVD",
350 [0x20] RMR,0, "MOVL %C,%e",
351 [0x21] RMR,0, "MOVL %D,%e",
352 [0x22] RMR,0, "MOVL %e,%C",
353 [0x23] RMR,0, "MOVL %e,%D",
354 [0x24] RMR,0, "MOVL %T,%e",
355 [0x26] RMR,0, "MOVL %e,%T",
359 [0x42] RM,0, "CMOVC %e,%r", /* CF */
360 [0x43] RM,0, "CMOVNC %e,%r", /* ¬ CF */
361 [0x44] RM,0, "CMOVZ %e,%r", /* ZF */
362 [0x45] RM,0, "CMOVNZ %e,%r", /* ¬ ZF */
363 [0x46] RM,0, "CMOVBE %e,%r", /* CF ∨ ZF */
364 [0x47] RM,0, "CMOVA %e,%r", /* ¬CF ∧ ¬ZF */
365 [0x48] RM,0, "CMOVS %e,%r", /* SF */
366 [0x49] RM,0, "CMOVNS %e,%r", /* ¬ SF */
367 [0x4A] RM,0, "CMOVP %e,%r", /* PF */
368 [0x4B] RM,0, "CMOVNP %e,%r", /* ¬ PF */
369 [0x4C] RM,0, "CMOVLT %e,%r", /* LT ≡ OF ≠ SF */
370 [0x4D] RM,0, "CMOVGE %e,%r", /* GE ≡ ZF ∨ SF */
371 [0x4E] RM,0, "CMOVLE %e,%r", /* LE ≡ ZF ∨ LT */
372 [0x4F] RM,0, "CMOVGT %e,%r", /* GT ≡ ¬ZF ∧ GE */
373 [0x80] Iwds,0, "JOS %p",
374 [0x81] Iwds,0, "JOC %p",
375 [0x82] Iwds,0, "JCS %p",
376 [0x83] Iwds,0, "JCC %p",
377 [0x84] Iwds,0, "JEQ %p",
378 [0x85] Iwds,0, "JNE %p",
379 [0x86] Iwds,0, "JLS %p",
380 [0x87] Iwds,0, "JHI %p",
381 [0x88] Iwds,0, "JMI %p",
382 [0x89] Iwds,0, "JPL %p",
383 [0x8a] Iwds,0, "JPS %p",
384 [0x8b] Iwds,0, "JPC %p",
385 [0x8c] Iwds,0, "JLT %p",
386 [0x8d] Iwds,0, "JGE %p",
387 [0x8e] Iwds,0, "JLE %p",
388 [0x8f] Iwds,0, "JGT %p",
389 [0x90] RMB,0, "SETOS %e",
390 [0x91] RMB,0, "SETOC %e",
391 [0x92] RMB,0, "SETCS %e",
392 [0x93] RMB,0, "SETCC %e",
393 [0x94] RMB,0, "SETEQ %e",
394 [0x95] RMB,0, "SETNE %e",
395 [0x96] RMB,0, "SETLS %e",
396 [0x97] RMB,0, "SETHI %e",
397 [0x98] RMB,0, "SETMI %e",
398 [0x99] RMB,0, "SETPL %e",
399 [0x9a] RMB,0, "SETPS %e",
400 [0x9b] RMB,0, "SETPC %e",
401 [0x9c] RMB,0, "SETLT %e",
402 [0x9d] RMB,0, "SETGE %e",
403 [0x9e] RMB,0, "SETLE %e",
404 [0x9f] RMB,0, "SETGT %e",
405 [0xa0] 0,0, "PUSHL FS",
406 [0xa1] 0,0, "POPL FS",
408 [0xa3] RM,0, "BT%S %r,%e",
409 [0xa4] RM,Ib, "SHLD%S %r,%i,%e",
410 [0xa5] RM,0, "SHLD%S %r,CL,%e",
411 [0xa8] 0,0, "PUSHL GS",
412 [0xa9] 0,0, "POPL GS",
413 [0xab] RM,0, "BTS%S %r,%e",
414 [0xac] RM,Ib, "SHRD%S %r,%i,%e",
415 [0xad] RM,0, "SHRD%S %r,CL,%e",
416 [0xaf] RM,0, "IMUL%S %e,%r",
417 [0xb2] RMM,0, "LSS %e,%r",
418 [0xb3] RM,0, "BTR%S %r,%e",
419 [0xb4] RMM,0, "LFS %e,%r",
420 [0xb5] RMM,0, "LGS %e,%r",
421 [0xb6] RMB,0, "MOVBZX %e,%R",
422 [0xb7] RM,0, "MOVWZX %e,%R",
423 [0xba] RMOP,0, optab0FBA,
424 [0xbb] RM,0, "BTC%S %e,%r",
425 [0xbc] RM,0, "BSF%S %e,%r",
426 [0xbd] RM,0, "BSR%S %e,%r",
427 [0xbe] RMB,0, "MOVBSX %e,%R",
428 [0xbf] RM,0, "MOVWSX %e,%R",
431 static Optable optab80[8]=
433 [0x00] Ib,0, "ADDB %i,%e",
434 [0x01] Ib,0, "ORB %i,%e",
435 [0x02] Ib,0, "ADCB %i,%e",
436 [0x03] Ib,0, "SBBB %i,%e",
437 [0x04] Ib,0, "ANDB %i,%e",
438 [0x05] Ib,0, "SUBB %i,%e",
439 [0x06] Ib,0, "XORB %i,%e",
440 [0x07] Ib,0, "CMPB %e,%i",
443 static Optable optab81[8]=
445 [0x00] Iwd,0, "ADD%S %i,%e",
446 [0x01] Iwd,0, "OR%S %i,%e",
447 [0x02] Iwd,0, "ADC%S %i,%e",
448 [0x03] Iwd,0, "SBB%S %i,%e",
449 [0x04] Iwd,0, "AND%S %i,%e",
450 [0x05] Iwd,0, "SUB%S %i,%e",
451 [0x06] Iwd,0, "XOR%S %i,%e",
452 [0x07] Iwd,0, "CMP%S %e,%i",
455 static Optable optab83[8]=
457 [0x00] Ibs,0, "ADD%S %i,%e",
458 [0x01] Ibs,0, "OR%S %i,%e",
459 [0x02] Ibs,0, "ADC%S %i,%e",
460 [0x03] Ibs,0, "SBB%S %i,%e",
461 [0x04] Ibs,0, "AND%S %i,%e",
462 [0x05] Ibs,0, "SUB%S %i,%e",
463 [0x06] Ibs,0, "XOR%S %i,%e",
464 [0x07] Ibs,0, "CMP%S %e,%i",
467 static Optable optabC0[8] =
469 [0x00] Ib,0, "ROLB %i,%e",
470 [0x01] Ib,0, "RORB %i,%e",
471 [0x02] Ib,0, "RCLB %i,%e",
472 [0x03] Ib,0, "RCRB %i,%e",
473 [0x04] Ib,0, "SHLB %i,%e",
474 [0x05] Ib,0, "SHRB %i,%e",
475 [0x07] Ib,0, "SARB %i,%e",
478 static Optable optabC1[8] =
480 [0x00] Ib,0, "ROL%S %i,%e",
481 [0x01] Ib,0, "ROR%S %i,%e",
482 [0x02] Ib,0, "RCL%S %i,%e",
483 [0x03] Ib,0, "RCR%S %i,%e",
484 [0x04] Ib,0, "SHL%S %i,%e",
485 [0x05] Ib,0, "SHR%S %i,%e",
486 [0x07] Ib,0, "SAR%S %i,%e",
489 static Optable optabD0[8] =
491 [0x00] 0,0, "ROLB %e",
492 [0x01] 0,0, "RORB %e",
493 [0x02] 0,0, "RCLB %e",
494 [0x03] 0,0, "RCRB %e",
495 [0x04] 0,0, "SHLB %e",
496 [0x05] 0,0, "SHRB %e",
497 [0x07] 0,0, "SARB %e",
500 static Optable optabD1[8] =
502 [0x00] 0,0, "ROL%S %e",
503 [0x01] 0,0, "ROR%S %e",
504 [0x02] 0,0, "RCL%S %e",
505 [0x03] 0,0, "RCR%S %e",
506 [0x04] 0,0, "SHL%S %e",
507 [0x05] 0,0, "SHR%S %e",
508 [0x07] 0,0, "SAR%S %e",
511 static Optable optabD2[8] =
513 [0x00] 0,0, "ROLB CL,%e",
514 [0x01] 0,0, "RORB CL,%e",
515 [0x02] 0,0, "RCLB CL,%e",
516 [0x03] 0,0, "RCRB CL,%e",
517 [0x04] 0,0, "SHLB CL,%e",
518 [0x05] 0,0, "SHRB CL,%e",
519 [0x07] 0,0, "SARB CL,%e",
522 static Optable optabD3[8] =
524 [0x00] 0,0, "ROL%S CL,%e",
525 [0x01] 0,0, "ROR%S CL,%e",
526 [0x02] 0,0, "RCL%S CL,%e",
527 [0x03] 0,0, "RCR%S CL,%e",
528 [0x04] 0,0, "SHL%S CL,%e",
529 [0x05] 0,0, "SHR%S CL,%e",
530 [0x07] 0,0, "SAR%S CL,%e",
533 static Optable optabD8[8+8] =
535 [0x00] 0,0, "FADDF %e,F0",
536 [0x01] 0,0, "FMULF %e,F0",
537 [0x02] 0,0, "FCOMF %e,F0",
538 [0x03] 0,0, "FCOMFP %e,F0",
539 [0x04] 0,0, "FSUBF %e,F0",
540 [0x05] 0,0, "FSUBRF %e,F0",
541 [0x06] 0,0, "FDIVF %e,F0",
542 [0x07] 0,0, "FDIVRF %e,F0",
543 [0x08] 0,0, "FADDD %f,F0",
544 [0x09] 0,0, "FMULD %f,F0",
545 [0x0a] 0,0, "FCOMD %f,F0",
546 [0x0b] 0,0, "FCOMPD %f,F0",
547 [0x0c] 0,0, "FSUBD %f,F0",
548 [0x0d] 0,0, "FSUBRD %f,F0",
549 [0x0e] 0,0, "FDIVD %f,F0",
550 [0x0f] 0,0, "FDIVRD %f,F0",
553 * optabD9 and optabDB use the following encoding:
554 * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
555 * else instruction = optabDx[(modrm&0x3f)+8];
557 * the instructions for MOD == 3, follow the 8 instructions
558 * for the other MOD values stored at the front of the table.
560 static Optable optabD9[64+8] =
562 [0x00] 0,0, "FMOVF %e,F0",
563 [0x02] 0,0, "FMOVF F0,%e",
564 [0x03] 0,0, "FMOVFP F0,%e",
565 [0x04] 0,0, "FLDENV%S %e",
566 [0x05] 0,0, "FLDCW %e",
567 [0x06] 0,0, "FSTENV%S %e",
568 [0x07] 0,0, "FSTCW %e",
569 [0x08] 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
570 [0x09] 0,0, "FMOVD F1,F0",
571 [0x0a] 0,0, "FMOVD F2,F0",
572 [0x0b] 0,0, "FMOVD F3,F0",
573 [0x0c] 0,0, "FMOVD F4,F0",
574 [0x0d] 0,0, "FMOVD F5,F0",
575 [0x0e] 0,0, "FMOVD F6,F0",
576 [0x0f] 0,0, "FMOVD F7,F0",
577 [0x10] 0,0, "FXCHD F0,F0",
578 [0x11] 0,0, "FXCHD F1,F0",
579 [0x12] 0,0, "FXCHD F2,F0",
580 [0x13] 0,0, "FXCHD F3,F0",
581 [0x14] 0,0, "FXCHD F4,F0",
582 [0x15] 0,0, "FXCHD F5,F0",
583 [0x16] 0,0, "FXCHD F6,F0",
584 [0x17] 0,0, "FXCHD F7,F0",
591 [0x31] 0,0, "FLDL2T",
592 [0x32] 0,0, "FLDL2E",
594 [0x34] 0,0, "FLDLG2",
595 [0x35] 0,0, "FLDLN2",
600 [0x3b] 0,0, "FPATAN",
601 [0x3c] 0,0, "FXTRACT",
602 [0x3d] 0,0, "FPREM1",
603 [0x3e] 0,0, "FDECSTP",
604 [0x3f] 0,0, "FNCSTP",
606 [0x41] 0,0, "FYL2XP1",
608 [0x43] 0,0, "FSINCOS",
609 [0x44] 0,0, "FRNDINT",
610 [0x45] 0,0, "FSCALE",
615 static Optable optabDA[8+8] =
617 [0x00] 0,0, "FADDL %e,F0",
618 [0x01] 0,0, "FMULL %e,F0",
619 [0x02] 0,0, "FCOML %e,F0",
620 [0x03] 0,0, "FCOMLP %e,F0",
621 [0x04] 0,0, "FSUBL %e,F0",
622 [0x05] 0,0, "FSUBRL %e,F0",
623 [0x06] 0,0, "FDIVL %e,F0",
624 [0x07] 0,0, "FDIVRL %e,F0",
625 [0x0d] R1,0, "FUCOMPP",
628 static Optable optabDB[8+64] =
630 [0x00] 0,0, "FMOVL %e,F0",
631 [0x02] 0,0, "FMOVL F0,%e",
632 [0x03] 0,0, "FMOVLP F0,%e",
633 [0x05] 0,0, "FMOVX %e,F0",
634 [0x07] 0,0, "FMOVXP F0,%e",
639 static Optable optabDC[8+8] =
641 [0x00] 0,0, "FADDD %e,F0",
642 [0x01] 0,0, "FMULD %e,F0",
643 [0x02] 0,0, "FCOMD %e,F0",
644 [0x03] 0,0, "FCOMDP %e,F0",
645 [0x04] 0,0, "FSUBD %e,F0",
646 [0x05] 0,0, "FSUBRD %e,F0",
647 [0x06] 0,0, "FDIVD %e,F0",
648 [0x07] 0,0, "FDIVRD %e,F0",
649 [0x08] 0,0, "FADDD F0,%f",
650 [0x09] 0,0, "FMULD F0,%f",
651 [0x0c] 0,0, "FSUBRD F0,%f",
652 [0x0d] 0,0, "FSUBD F0,%f",
653 [0x0e] 0,0, "FDIVRD F0,%f",
654 [0x0f] 0,0, "FDIVD F0,%f",
657 static Optable optabDD[8+8] =
659 [0x00] 0,0, "FMOVD %e,F0",
660 [0x02] 0,0, "FMOVD F0,%e",
661 [0x03] 0,0, "FMOVDP F0,%e",
662 [0x04] 0,0, "FRSTOR%S %e",
663 [0x06] 0,0, "FSAVE%S %e",
664 [0x07] 0,0, "FSTSW %e",
665 [0x08] 0,0, "FFREED %f",
666 [0x0a] 0,0, "FMOVD %f,F0",
667 [0x0b] 0,0, "FMOVDP %f,F0",
668 [0x0c] 0,0, "FUCOMD %f,F0",
669 [0x0d] 0,0, "FUCOMDP %f,F0",
672 static Optable optabDE[8+8] =
674 [0x00] 0,0, "FADDW %e,F0",
675 [0x01] 0,0, "FMULW %e,F0",
676 [0x02] 0,0, "FCOMW %e,F0",
677 [0x03] 0,0, "FCOMWP %e,F0",
678 [0x04] 0,0, "FSUBW %e,F0",
679 [0x05] 0,0, "FSUBRW %e,F0",
680 [0x06] 0,0, "FDIVW %e,F0",
681 [0x07] 0,0, "FDIVRW %e,F0",
682 [0x08] 0,0, "FADDDP F0,%f",
683 [0x09] 0,0, "FMULDP F0,%f",
684 [0x0b] R1,0, "FCOMPDP",
685 [0x0c] 0,0, "FSUBRDP F0,%f",
686 [0x0d] 0,0, "FSUBDP F0,%f",
687 [0x0e] 0,0, "FDIVRDP F0,%f",
688 [0x0f] 0,0, "FDIVDP F0,%f",
691 static Optable optabDF[8+8] =
693 [0x00] 0,0, "FMOVW %e,F0",
694 [0x02] 0,0, "FMOVW F0,%e",
695 [0x03] 0,0, "FMOVWP F0,%e",
696 [0x04] 0,0, "FBLD %e",
697 [0x05] 0,0, "FMOVL %e,F0",
698 [0x06] 0,0, "FBSTP %e",
699 [0x07] 0,0, "FMOVLP F0,%e",
700 [0x0c] R0,0, "FSTSW %OAX",
703 static Optable optabF6[8] =
705 [0x00] Ib,0, "TESTB %i,%e",
706 [0x02] 0,0, "NOTB %e",
707 [0x03] 0,0, "NEGB %e",
708 [0x04] 0,0, "MULB AL,%e",
709 [0x05] 0,0, "IMULB AL,%e",
710 [0x06] 0,0, "DIVB AL,%e",
711 [0x07] 0,0, "IDIVB AL,%e",
714 static Optable optabF7[8] =
716 [0x00] Iwd,0, "TEST%S %i,%e",
717 [0x02] 0,0, "NOT%S %e",
718 [0x03] 0,0, "NEG%S %e",
719 [0x04] 0,0, "MUL%S %OAX,%e",
720 [0x05] 0,0, "IMUL%S %OAX,%e",
721 [0x06] 0,0, "DIV%S %OAX,%e",
722 [0x07] 0,0, "IDIV%S %OAX,%e",
725 static Optable optabFE[8] =
727 [0x00] 0,0, "INCB %e",
728 [0x01] 0,0, "DECB %e",
731 static Optable optabFF[8] =
733 [0x00] 0,0, "INC%S %e",
734 [0x01] 0,0, "DEC%S %e",
735 [0x02] JUMP,0, "CALL* %e",
736 [0x03] JUMP,0, "CALLF* %e",
737 [0x04] JUMP,0, "JMP* %e",
738 [0x05] JUMP,0, "JMPF* %e",
739 [0x06] 0,0, "PUSHL %e",
742 static Optable optable[256] =
744 [0x00] RMB,0, "ADDB %r,%e",
745 [0x01] RM,0, "ADD%S %r,%e",
746 [0x02] RMB,0, "ADDB %e,%r",
747 [0x03] RM,0, "ADD%S %e,%r",
748 [0x04] Ib,0, "ADDB %i,AL",
749 [0x05] Iwd,0, "ADD%S %i,%OAX",
750 [0x06] 0,0, "PUSHL ES",
751 [0x07] 0,0, "POPL ES",
752 [0x08] RMB,0, "ORB %r,%e",
753 [0x09] RM,0, "OR%S %r,%e",
754 [0x0a] RMB,0, "ORB %e,%r",
755 [0x0b] RM,0, "OR%S %e,%r",
756 [0x0c] Ib,0, "ORB %i,AL",
757 [0x0d] Iwd,0, "OR%S %i,%OAX",
758 [0x0e] 0,0, "PUSHL CS",
759 [0x0f] AUX,0, optab0F,
760 [0x10] RMB,0, "ADCB %r,%e",
761 [0x11] RM,0, "ADC%S %r,%e",
762 [0x12] RMB,0, "ADCB %e,%r",
763 [0x13] RM,0, "ADC%S %e,%r",
764 [0x14] Ib,0, "ADCB %i,AL",
765 [0x15] Iwd,0, "ADC%S %i,%OAX",
766 [0x16] 0,0, "PUSHL SS",
767 [0x17] 0,0, "POPL SS",
768 [0x18] RMB,0, "SBBB %r,%e",
769 [0x19] RM,0, "SBB%S %r,%e",
770 [0x1a] RMB,0, "SBBB %e,%r",
771 [0x1b] RM,0, "SBB%S %e,%r",
772 [0x1c] Ib,0, "SBBB %i,AL",
773 [0x1d] Iwd,0, "SBB%S %i,%OAX",
774 [0x1e] 0,0, "PUSHL DS",
775 [0x1f] 0,0, "POPL DS",
776 [0x20] RMB,0, "ANDB %r,%e",
777 [0x21] RM,0, "AND%S %r,%e",
778 [0x22] RMB,0, "ANDB %e,%r",
779 [0x23] RM,0, "AND%S %e,%r",
780 [0x24] Ib,0, "ANDB %i,AL",
781 [0x25] Iwd,0, "AND%S %i,%OAX",
784 [0x28] RMB,0, "SUBB %r,%e",
785 [0x29] RM,0, "SUB%S %r,%e",
786 [0x2a] RMB,0, "SUBB %e,%r",
787 [0x2b] RM,0, "SUB%S %e,%r",
788 [0x2c] Ib,0, "SUBB %i,AL",
789 [0x2d] Iwd,0, "SUB%S %i,%OAX",
792 [0x30] RMB,0, "XORB %r,%e",
793 [0x31] RM,0, "XOR%S %r,%e",
794 [0x32] RMB,0, "XORB %e,%r",
795 [0x33] RM,0, "XOR%S %e,%r",
796 [0x34] Ib,0, "XORB %i,AL",
797 [0x35] Iwd,0, "XOR%S %i,%OAX",
800 [0x38] RMB,0, "CMPB %r,%e",
801 [0x39] RM,0, "CMP%S %r,%e",
802 [0x3a] RMB,0, "CMPB %e,%r",
803 [0x3b] RM,0, "CMP%S %e,%r",
804 [0x3c] Ib,0, "CMPB %i,AL",
805 [0x3d] Iwd,0, "CMP%S %i,%OAX",
808 [0x40] 0,0, "INC%S %OAX",
809 [0x41] 0,0, "INC%S %OCX",
810 [0x42] 0,0, "INC%S %ODX",
811 [0x43] 0,0, "INC%S %OBX",
812 [0x44] 0,0, "INC%S %OSP",
813 [0x45] 0,0, "INC%S %OBP",
814 [0x46] 0,0, "INC%S %OSI",
815 [0x47] 0,0, "INC%S %ODI",
816 [0x48] 0,0, "DEC%S %OAX",
817 [0x49] 0,0, "DEC%S %OCX",
818 [0x4a] 0,0, "DEC%S %ODX",
819 [0x4b] 0,0, "DEC%S %OBX",
820 [0x4c] 0,0, "DEC%S %OSP",
821 [0x4d] 0,0, "DEC%S %OBP",
822 [0x4e] 0,0, "DEC%S %OSI",
823 [0x4f] 0,0, "DEC%S %ODI",
824 [0x50] 0,0, "PUSH%S %OAX",
825 [0x51] 0,0, "PUSH%S %OCX",
826 [0x52] 0,0, "PUSH%S %ODX",
827 [0x53] 0,0, "PUSH%S %OBX",
828 [0x54] 0,0, "PUSH%S %OSP",
829 [0x55] 0,0, "PUSH%S %OBP",
830 [0x56] 0,0, "PUSH%S %OSI",
831 [0x57] 0,0, "PUSH%S %ODI",
832 [0x58] 0,0, "POP%S %OAX",
833 [0x59] 0,0, "POP%S %OCX",
834 [0x5a] 0,0, "POP%S %ODX",
835 [0x5b] 0,0, "POP%S %OBX",
836 [0x5c] 0,0, "POP%S %OSP",
837 [0x5d] 0,0, "POP%S %OBP",
838 [0x5e] 0,0, "POP%S %OSI",
839 [0x5f] 0,0, "POP%S %ODI",
840 [0x60] 0,0, "PUSHA%S",
841 [0x61] 0,0, "POPA%S",
842 [0x62] RMM,0, "BOUND %e,%r",
843 [0x63] RM,0, "ARPL %r,%e",
847 [0x67] ADDOVER,0, "",
848 [0x68] Iwd,0, "PUSH%S %i",
849 [0x69] RM,Iwd, "IMUL%S %e,%i,%r",
850 [0x6a] Ib,0, "PUSH%S %i",
851 [0x6b] RM,Ibs, "IMUL%S %e,%i,%r",
852 [0x6c] 0,0, "INSB DX,(%ODI)",
853 [0x6d] 0,0, "INS%S DX,(%ODI)",
854 [0x6e] 0,0, "OUTSB (%ASI),DX",
855 [0x6f] 0,0, "OUTS%S (%ASI),DX",
856 [0x70] Jbs,0, "JOS %p",
857 [0x71] Jbs,0, "JOC %p",
858 [0x72] Jbs,0, "JCS %p",
859 [0x73] Jbs,0, "JCC %p",
860 [0x74] Jbs,0, "JEQ %p",
861 [0x75] Jbs,0, "JNE %p",
862 [0x76] Jbs,0, "JLS %p",
863 [0x77] Jbs,0, "JHI %p",
864 [0x78] Jbs,0, "JMI %p",
865 [0x79] Jbs,0, "JPL %p",
866 [0x7a] Jbs,0, "JPS %p",
867 [0x7b] Jbs,0, "JPC %p",
868 [0x7c] Jbs,0, "JLT %p",
869 [0x7d] Jbs,0, "JGE %p",
870 [0x7e] Jbs,0, "JLE %p",
871 [0x7f] Jbs,0, "JGT %p",
872 [0x80] RMOPB,0, optab80,
873 [0x81] RMOP,0, optab81,
874 [0x83] RMOP,0, optab83,
875 [0x84] RMB,0, "TESTB %r,%e",
876 [0x85] RM,0, "TEST%S %r,%e",
877 [0x86] RMB,0, "XCHGB %r,%e",
878 [0x87] RM,0, "XCHG%S %r,%e",
879 [0x88] RMB,0, "MOVB %r,%e",
880 [0x89] RM,0, "MOV%S %r,%e",
881 [0x8a] RMB,0, "MOVB %e,%r",
882 [0x8b] RM,0, "MOV%S %e,%r",
883 [0x8c] RM,0, "MOVW %g,%e",
884 [0x8d] RM,0, "LEA %e,%r",
885 [0x8e] RM,0, "MOVW %e,%g",
886 [0x8f] RM,0, "POP%S %e",
888 [0x91] 0,0, "XCHG %OCX,%OAX",
889 [0x92] 0,0, "XCHG %ODX,%OAX",
890 [0x93] 0,0, "XCHG %OBX,%OAX",
891 [0x94] 0,0, "XCHG %OSP,%OAX",
892 [0x95] 0,0, "XCHG %OBP,%OAX",
893 [0x96] 0,0, "XCHG %OSI,%OAX",
894 [0x97] 0,0, "XCHG %ODI,%OAX",
895 [0x98] 0,0, "%X", /* miserable CBW or CWDE */
896 [0x99] 0,0, "%x", /* idiotic CWD or CDQ */
897 [0x9a] PTR,0, "CALL%S %d",
903 [0xa0] Awd,0, "MOVB %i,AL",
904 [0xa1] Awd,0, "MOV%S %i,%OAX",
905 [0xa2] Awd,0, "MOVB AL,%i",
906 [0xa3] Awd,0, "MOV%S %OAX,%i",
907 [0xa4] 0,0, "MOVSB (%ASI),(%ADI)",
908 [0xa5] 0,0, "MOVS%S (%ASI),(%ADI)",
909 [0xa6] 0,0, "CMPSB (%ASI),(%ADI)",
910 [0xa7] 0,0, "CMPS%S (%ASI),(%ADI)",
911 [0xa8] Ib,0, "TESTB %i,AL",
912 [0xa9] Iwd,0, "TEST%S %i,%OAX",
913 [0xaa] 0,0, "STOSB AL,(%ADI)",
914 [0xab] 0,0, "STOS%S %OAX,(%ADI)",
915 [0xac] 0,0, "LODSB (%ASI),AL",
916 [0xad] 0,0, "LODS%S (%ASI),%OAX",
917 [0xae] 0,0, "SCASB (%ADI),AL",
918 [0xaf] 0,0, "SCAS%S (%ADI),%OAX",
919 [0xb0] Ib,0, "MOVB %i,AL",
920 [0xb1] Ib,0, "MOVB %i,CL",
921 [0xb2] Ib,0, "MOVB %i,DL",
922 [0xb3] Ib,0, "MOVB %i,BL",
923 [0xb4] Ib,0, "MOVB %i,AH",
924 [0xb5] Ib,0, "MOVB %i,CH",
925 [0xb6] Ib,0, "MOVB %i,DH",
926 [0xb7] Ib,0, "MOVB %i,BH",
927 [0xb8] Iwd,0, "MOV%S %i,%OAX",
928 [0xb9] Iwd,0, "MOV%S %i,%OCX",
929 [0xba] Iwd,0, "MOV%S %i,%ODX",
930 [0xbb] Iwd,0, "MOV%S %i,%OBX",
931 [0xbc] Iwd,0, "MOV%S %i,%OSP",
932 [0xbd] Iwd,0, "MOV%S %i,%OBP",
933 [0xbe] Iwd,0, "MOV%S %i,%OSI",
934 [0xbf] Iwd,0, "MOV%S %i,%ODI",
935 [0xc0] RMOPB,0, optabC0,
936 [0xc1] RMOP,0, optabC1,
937 [0xc2] Iw,0, "RET %i",
939 [0xc4] RM,0, "LES %e,%r",
940 [0xc5] RM,0, "LDS %e,%r",
941 [0xc6] RMB,Ib, "MOVB %i,%e",
942 [0xc7] RM,Iwd, "MOV%S %i,%e",
943 [0xc8] Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
944 [0xc9] RET,0, "LEAVE", /* bizarre LEAVE */
945 [0xca] Iw,0, "RETF %i",
946 [0xcb] RET,0, "RETF",
948 [0xcd] Ib,0, "INTB %i",
951 [0xd0] RMOPB,0, optabD0,
952 [0xd1] RMOP,0, optabD1,
953 [0xd2] RMOPB,0, optabD2,
954 [0xd3] RMOP,0, optabD3,
958 [0xd8] FRMOP,0, optabD8,
959 [0xd9] FRMEX,0, optabD9,
960 [0xda] FRMOP,0, optabDA,
961 [0xdb] FRMEX,0, optabDB,
962 [0xdc] FRMOP,0, optabDC,
963 [0xdd] FRMOP,0, optabDD,
964 [0xde] FRMOP,0, optabDE,
965 [0xdf] FRMOP,0, optabDF,
966 [0xe0] Jbs,0, "LOOPNE %p",
967 [0xe1] Jbs,0, "LOOPE %p",
968 [0xe2] Jbs,0, "LOOP %p",
969 [0xe3] Jbs,0, "JCXZ %p",
970 [0xe4] Ib,0, "INB %i,AL",
971 [0xe5] Ib,0, "IN%S %i,%OAX",
972 [0xe6] Ib,0, "OUTB AL,%i",
973 [0xe7] Ib,0, "OUT%S %OAX,%i",
974 [0xe8] Iwds,0, "CALL %p",
975 [0xe9] Iwds,0, "JMP %p",
976 [0xea] PTR,0, "JMP %d",
977 [0xeb] Jbs,0, "JMP %p",
978 [0xec] 0,0, "INB DX,AL",
979 [0xed] 0,0, "IN%S DX,%OAX",
980 [0xee] 0,0, "OUTB AL,DX",
981 [0xef] 0,0, "OUT%S %OAX,DX",
982 [0xf0] PRE,0, "LOCK",
983 [0xf2] PRE,0, "REPNE",
987 [0xf6] RMOPB,0, optabF6,
988 [0xf7] RMOP,0, optabF7,
995 [0xfe] RMOPB,0, optabFE,
996 [0xff] RMOP,0, optabFF,
1000 * get a byte of the instruction
1003 igetc(Map * map, Instr *ip, uchar *c)
1005 if(ip->n+1 > sizeof(ip->mem)){
1006 werrstr("instruction too long");
1009 if (get1(map, ip->addr+ip->n, c, 1) < 0) {
1010 werrstr("can't read instruction: %r");
1013 ip->mem[ip->n++] = *c;
1018 * get two bytes of the instruction
1021 igets(Map *map, Instr *ip, ushort *sp)
1026 if (igetc(map, ip, &c) < 0)
1029 if (igetc(map, ip, &c) < 0)
1037 * get 4 bytes of the instruction
1040 igetl(Map *map, Instr *ip, ulong *lp)
1045 if (igets(map, ip, &s) < 0)
1048 if (igets(map, ip, &s) < 0)
1056 getdisp(Map *map, Instr *ip, int mod, int rm, int code)
1064 if (igetc(map, ip, &c) < 0)
1067 ip->disp = c|0xffffff00;
1070 } else if (mod == 2 || rm == code) {
1071 if (ip->asize == 'E') {
1072 if (igetl(map, ip, &ip->disp) < 0)
1075 if (igets(map, ip, &s) < 0)
1078 ip->disp = s|0xffff0000;
1089 modrm(Map *map, Instr *ip, uchar c)
1098 if (mod == 3) /* register */
1100 if (ip->asize == 0) { /* 16-bit mode */
1104 ip->base = BX; ip->index = SI;
1107 ip->base = BX; ip->index = DI;
1110 ip->base = BP; ip->index = SI;
1113 ip->base = BP; ip->index = DI;
1130 return getdisp(map, ip, mod, rm, 6);
1132 if (rm == 4) { /* scummy sib byte */
1133 if (igetc(map, ip, &c) < 0)
1135 ip->ss = (c>>6)&0x03;
1136 ip->index = (c>>3)&0x07;
1140 return getdisp(map, ip, mod, ip->base, 5);
1142 return getdisp(map, ip, mod, rm, 5);
1146 mkinstr(Map *map, Instr *ip, ulong pc)
1151 Optable *op, *obase;
1154 memset(ip, 0, sizeof(*ip));
1157 if(0) /* asstype == AI8086) */
1164 if (igetc(map, ip, &c) < 0)
1169 if (op->proto == 0) {
1171 n = snprint(buf, sizeof(buf), "opcode: ??");
1172 for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
1173 _hexify(buf+n, ip->mem[i], 1);
1174 strcpy(buf+n, "??");
1178 for(i = 0; i < 2 && op->operand[i]; i++) {
1179 switch(op->operand[i])
1181 case Ib: /* 8-bit immediate - (no sign extension)*/
1182 if (igetc(map, ip, &c) < 0)
1186 case Jbs: /* 8-bit jump immediate (sign extended) */
1187 if (igetc(map, ip, &c) < 0)
1190 ip->imm = c|0xffffff00;
1195 case Ibs: /* 8-bit immediate (sign extended) */
1196 if (igetc(map, ip, &c) < 0)
1199 if (ip->osize == 'L')
1200 ip->imm = c|0xffffff00;
1206 case Iw: /* 16-bit immediate -> imm */
1207 if (igets(map, ip, &s) < 0)
1212 case Iw2: /* 16-bit immediate -> in imm2*/
1213 if (igets(map, ip, &s) < 0)
1215 ip->imm2 = s&0xffff;
1217 case Iwd: /* Operand-sized immediate (no sign extension)*/
1218 if (ip->osize == 'L') {
1219 if (igetl(map, ip, &ip->imm) < 0)
1222 if (igets(map, ip, &s)< 0)
1227 case Awd: /* Address-sized immediate (no sign extension)*/
1228 if (ip->asize == 'E') {
1229 if (igetl(map, ip, &ip->imm) < 0)
1232 if (igets(map, ip, &s)< 0)
1237 case Iwds: /* Operand-sized immediate (sign extended) */
1238 if (ip->osize == 'L') {
1239 if (igetl(map, ip, &ip->imm) < 0)
1242 if (igets(map, ip, &s)< 0)
1245 ip->imm = s|0xffff0000;
1249 ip->jumptype = Iwds;
1251 case OA: /* literal 0x0a byte */
1252 if (igetc(map, ip, &c) < 0)
1257 case R0: /* base register must be R0 */
1261 case R1: /* base register must be R1 */
1265 case RMB: /* R/M field with byte register (/r)*/
1266 if (igetc(map, ip, &c) < 0)
1268 if (modrm(map, ip, c) < 0)
1272 case RM: /* R/M field with register (/r) */
1273 if (igetc(map, ip, &c) < 0)
1275 if (modrm(map, ip, c) < 0)
1278 case RMOPB: /* R/M field with op code (/digit) */
1279 if (igetc(map, ip, &c) < 0)
1281 if (modrm(map, ip, c) < 0)
1283 c = ip->reg; /* secondary op code */
1284 obase = (Optable*)op->proto;
1287 case RMOP: /* R/M field with op code (/digit) */
1288 if (igetc(map, ip, &c) < 0)
1290 if (modrm(map, ip, c) < 0)
1293 obase = (Optable*)op->proto;
1295 case FRMOP: /* FP R/M field with op code (/digit) */
1296 if (igetc(map, ip, &c) < 0)
1298 if (modrm(map, ip, c) < 0)
1300 if ((c&0xc0) == 0xc0)
1301 c = ip->reg+8; /* 16 entry table */
1304 obase = (Optable*)op->proto;
1306 case FRMEX: /* Extended FP R/M field with op code (/digit) */
1307 if (igetc(map, ip, &c) < 0)
1309 if (modrm(map, ip, c) < 0)
1311 if ((c&0xc0) == 0xc0)
1312 c = (c&0x3f)+8; /* 64-entry table */
1315 obase = (Optable*)op->proto;
1317 case RMR: /* R/M register only (mod = 11) */
1318 if (igetc(map, ip, &c) < 0)
1320 if ((c&0xc0) != 0xc0) {
1321 werrstr("invalid R/M register: %x", c);
1324 if (modrm(map, ip, c) < 0)
1327 case RMM: /* R/M register only (mod = 11) */
1328 if (igetc(map, ip, &c) < 0)
1330 if ((c&0xc0) == 0xc0) {
1331 werrstr("invalid R/M memory mode: %x", c);
1334 if (modrm(map, ip, c) < 0)
1337 case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
1338 if (ip->osize == 'L') {
1339 if (igetl(map, ip, &ip->disp) < 0)
1342 if (igets(map, ip, &s)< 0)
1344 ip->disp = s&0xffff;
1346 if (igets(map, ip, (ushort*)&ip->seg) < 0)
1350 case AUX: /* Multi-byte op code - Auxiliary table */
1351 obase = (Optable*)op->proto;
1352 if (igetc(map, ip, &c) < 0)
1355 case PRE: /* Instr Prefix */
1356 ip->prefix = (char*)op->proto;
1357 if (igetc(map, ip, &c) < 0)
1360 case SEG: /* Segment Prefix */
1361 ip->segment = (char*)op->proto;
1362 if (igetc(map, ip, &c) < 0)
1365 case OPOVER: /* Operand size override */
1367 if (igetc(map, ip, &c) < 0)
1370 case ADDOVER: /* Address size override */
1372 if (igetc(map, ip, &c) < 0)
1375 case JUMP: /* mark instruction as JUMP or RET */
1377 ip->jumptype = op->operand[i];
1380 werrstr("bad operand type %d", op->operand[i]);
1388 bprint(Instr *ip, char *fmt, ...)
1393 ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
1398 * if we want to call 16 bit regs AX,BX,CX,...
1399 * and 32 bit regs EAX,EBX,ECX,... then
1400 * change the defs of ANAME and ONAME to:
1401 * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
1402 * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
1404 #define ANAME(ip) ""
1405 #define ONAME(ip) ""
1407 static char *reg[] = {
1418 static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
1419 static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
1429 l.offset = ip->disp;
1437 if(findsym(li, CTEXT, &s) < 0)
1441 if(ip->base==SP && lookuplsym(&s, FRAMENAME, &s) >= 0){
1442 /* translate stack offset to offset from plan 9 frame pointer */
1443 /* XXX not sure how to do this */
1446 if(name==nil && findlsym(&s, l, &s) >= 0)
1450 bprint(ip, "%s+", name);
1453 bprint(ip, "%lx(%s)", l.offset, l.reg);
1459 switch(ip->jumptype){
1470 * This is too smart for its own good, but it really is nice
1471 * to have accurate translations when debugging, and it
1472 * helps us identify which code is different in binaries that
1473 * are changed on sources.
1476 issymref(Instr *ip, Symbol *s, long w, long val)
1479 long isstring, size;
1483 if (s->class==CTEXT && w==0)
1485 if (s->class==CDATA) {
1486 /* use first bss symbol (or "end") rather than edata */
1487 if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
1488 if((indexsym(s->index+1, &tmp) && loccmp(&tmp.loc, &s->loc)==0)
1489 || (indexsym(s->index-1, &tmp) && loccmp(&tmp.loc, &s->loc)==0))
1494 for (next=*s; next.loc.addr==s->loc.addr; next=tmp)
1495 if (!indexsym(next.index+1, &tmp))
1497 size = next.loc.addr - s->loc.addr;
1502 /* huge distances are usually wrong except in .string */
1503 isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
1504 if (w > 8192 && !isstring)
1506 /* medium distances are tricky - look for constants */
1507 /* near powers of two */
1508 if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
1516 immediate(Instr *ip, long val)
1524 if (findsym(l, CANY, &s) >= 0) {
1525 w = val - s.loc.addr;
1528 if (issymref(ip, &s, w, val)) {
1530 bprint(ip, "%s+%lux(SB)", s.name, w);
1532 bprint(ip, "%s(SB)", s.name);
1535 if (s.class==CDATA && indexsym(s.index+1, &s) >= 0) {
1536 w = s.loc.addr - val;
1540 bprint(ip, "%s-%lux(SB)", s.name, w);
1545 bprint(ip, "%lux", val);
1552 if (ip->osize == 'B')
1553 bprint(ip, breg[(uchar)ip->base]);
1555 bprint(ip, "%s%s", ANAME(ip), reg[(uchar)ip->base]);
1559 bprint(ip, ip->segment);
1560 if (ip->asize == 'E' && (ip->base == SP || ip->base == BP))
1564 immediate(ip, ip->disp);
1566 bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]);
1569 bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss);
1573 prinstr(Instr *ip, char *fmt)
1576 bprint(ip, "%s ", ip->prefix);
1577 for (; *fmt && ip->curr < ip->end; fmt++) {
1586 bprint(ip, "%s", ANAME(ip));
1589 bprint(ip, "CR%d", ip->reg);
1592 if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
1593 bprint(ip, "DR%d",ip->reg);
1599 immediate(ip, ip->imm2);
1602 bprint(ip,"%s", ONAME(ip));
1606 immediate(ip,ip->imm);
1609 bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
1612 bprint(ip, "%c", ip->osize);
1615 if (ip->reg == 6 || ip->reg == 7)
1616 bprint(ip, "TR%d",ip->reg);
1621 if (ip->osize == 'L')
1627 bprint(ip,"%lux:%lux",ip->seg,ip->disp);
1633 bprint(ip, "F%d", ip->base);
1637 bprint(ip,"%s",sreg[ip->reg]);
1642 immediate(ip, ip->imm+ip->addr+ip->n);
1645 if (ip->osize == 'B')
1646 bprint(ip,"%s",breg[ip->reg]);
1648 bprint(ip, reg[ip->reg]);
1651 if (ip->osize == 'L')
1657 bprint(ip, "%%%c", *fmt);
1661 *ip->curr = 0; /* there's always room for 1 byte */
1665 i386das(Map *map, ulong pc, char modifier, char *buf, int n)
1671 op = mkinstr(map, &instr, pc);
1677 instr.end = buf+n-1;
1678 prinstr(&instr, op->proto);
1683 i386hexinst(Map *map, ulong pc, char *buf, int n)
1688 if (mkinstr(map, &instr, pc) == 0) {
1692 for(i = 0; i < instr.n && n > 2; i++) {
1693 _hexify(buf, instr.mem[i], 1);
1702 i386instlen(Map *map, ulong pc)
1706 if (mkinstr(map, &i, pc))
1712 i386foll(Map *map, Regs *regs, ulong pc, ulong *foll)
1721 op = mkinstr(map, &i, pc);
1727 switch(i.jumptype) {
1728 case RET: /* RETURN or LEAVE */
1729 case Iw: /* RETURN */
1730 if (strcmp(op->proto, "LEAVE") == 0) {
1731 if (lget4(map, regs, locindir("BP", 0), &l) < 0)
1733 } else if (lget4(map, regs, locindir(mach->sp, 0), &l) < 0)
1737 case Iwds: /* pc relative JUMP or CALL*/
1738 case Jbs: /* pc relative JUMP or CALL */
1739 foll[0] = pc+i.imm+i.n;
1742 case PTR: /* seg:displacement JUMP or CALL */
1743 foll[0] = (i.seg<<4)+i.disp;
1745 case JUMP: /* JUMP or CALL EA */
1748 if (rget(regs, reg[(uchar)i.base], &foll[0]) < 0)
1752 /* calculate the effective address */
1755 if (lget4(map, regs, locindir(reg[(uchar)i.base], 0), &l) < 0)
1760 if (lget4(map, regs, locindir(reg[(uchar)i.index], 0), &l) < 0)
1762 addr += l*(1<<i.ss);
1764 /* now retrieve a seg:disp value at that address */
1765 if (get2(map, addr, &s) < 0) /* seg */
1769 if (i.asize == 'L') {
1770 if (get4(map, addr, &l) < 0) /* disp32 */
1773 } else { /* disp16 */
1774 if (get2(map, addr, &s) < 0)
1782 if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)