Blob


1 /*
2 * 386 definition
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7 #include <mach.h>
8 #include "ureg386.h"
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)
17 /*
18 * i386-specific debugger interface
19 */
21 static char *i386excep(Map*, Regs*);
23 /*
24 static int i386trace(Map*, ulong, ulong, ulong, Tracer);
25 static ulong i386frame(Map*, ulong, ulong, ulong, ulong);
26 */
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'},
69 { 0 }
70 };
72 Mach mach386 =
73 {
74 "386",
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 */
89 4, /* szaddr */
90 4, /* szreg */
91 4, /* szfloat */
92 8, /* szdouble */
94 i386windregs, /* locations unwound in stack trace */
95 9,
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 */
116 };
118 static char *i386windregs[] = {
119 "PC",
120 "SP",
121 "BP",
122 "AX",
123 "CX",
124 "DX",
125 "BX",
126 "SI",
127 "DI",
128 0,
129 };
131 static int
132 i386unwind(Map *map, Regs *regs, ulong *next)
134 int isp, ipc, ibp;
135 ulong bp;
136 u32int v;
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");
144 return -1;
147 bp = next[ibp];
149 if(get4(map, bp, &v) < 0)
150 return -1;
151 next[ibp] = v;
153 next[isp] = bp+4;
155 if(get4(map, bp+4, &v) < 0)
156 return -1;
157 next[ipc] = v;
159 return 0;
162 //static char STARTSYM[] = "_main";
163 //static char PROFSYM[] = "_mainp";
164 static char FRAMENAME[] = ".frame";
165 static char *excname[] =
167 [0] "divide error",
168 [1] "debug exception",
169 [4] "overflow",
170 [5] "bounds check",
171 [6] "invalid opcode",
172 [7] "math coprocessor emulation",
173 [8] "double fault",
174 [9] "math coprocessor overrun",
175 [10] "invalid TSS",
176 [11] "segment not present",
177 [12] "stack exception",
178 [13] "general protection violation",
179 [14] "page fault",
180 [16] "math coprocessor error",
181 [24] "clock",
182 [25] "keyboard",
183 [27] "modem status",
184 [28] "serial line status",
185 [30] "floppy disk",
186 [36] "mouse",
187 [37] "math coprocessor",
188 [38] "hard disk",
189 [64] "system call",
190 };
192 static char*
193 i386excep(Map *map, Regs *regs)
195 ulong c;
196 ulong pc;
197 static char buf[16];
199 if(rget(regs, "TRAP", &c) < 0)
200 return "no trap register";
202 if(c > 64 || excname[c] == 0) {
203 if (c == 3) {
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)
207 return "breakpoint";
209 sprint(buf, "exception %ld", c);
210 return buf;
211 } else
212 return excname[c];
215 /* I386/486 - Disassembler and related functions */
217 /*
218 * an instruction
219 */
220 typedef struct Instr Instr;
221 struct 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 */
243 };
245 /* 386 register (ha!) set */
246 enum{
247 AX=0,
248 CX,
249 DX,
250 BX,
251 SP,
252 BP,
253 SI,
254 DI,
255 };
256 /* Operand Format codes */
257 /*
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"
274 */
276 typedef struct Optable Optable;
277 struct Optable
279 char operand[2];
280 void *proto; /* actually either (char*) or (Optable*) */
281 };
282 /* Operand decoding codes */
283 enum {
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 */
311 };
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",
321 };
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 */
331 };
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",
339 };
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",
347 [0x06] 0,0, "CLTS",
348 [0x08] 0,0, "INVD",
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",
356 [0x30] 0,0, "WRMSR",
357 [0x31] 0,0, "RDTSC",
358 [0x32] 0,0, "RDMSR",
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",
407 [0xa2] 0,0, "CPUID",
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",
429 };
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",
441 };
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",
453 };
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",
465 };
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",
476 };
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",
487 };
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",
498 };
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",
509 };
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",
520 };
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",
531 };
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",
551 };
552 /*
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.
559 */
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",
585 [0x18] 0,0, "FNOP",
586 [0x28] 0,0, "FCHS",
587 [0x29] 0,0, "FABS",
588 [0x2c] 0,0, "FTST",
589 [0x2d] 0,0, "FXAM",
590 [0x30] 0,0, "FLD1",
591 [0x31] 0,0, "FLDL2T",
592 [0x32] 0,0, "FLDL2E",
593 [0x33] 0,0, "FLDPI",
594 [0x34] 0,0, "FLDLG2",
595 [0x35] 0,0, "FLDLN2",
596 [0x36] 0,0, "FLDZ",
597 [0x38] 0,0, "F2XM1",
598 [0x39] 0,0, "FYL2X",
599 [0x3a] 0,0, "FPTAN",
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",
605 [0x40] 0,0, "FPREM",
606 [0x41] 0,0, "FYL2XP1",
607 [0x42] 0,0, "FSQRT",
608 [0x43] 0,0, "FSINCOS",
609 [0x44] 0,0, "FRNDINT",
610 [0x45] 0,0, "FSCALE",
611 [0x46] 0,0, "FSIN",
612 [0x47] 0,0, "FCOS",
613 };
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",
626 };
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",
635 [0x2a] 0,0, "FCLEX",
636 [0x2b] 0,0, "FINIT",
637 };
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",
655 };
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",
670 };
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",
689 };
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",
701 };
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",
712 };
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",
723 };
725 static Optable optabFE[8] =
727 [0x00] 0,0, "INCB %e",
728 [0x01] 0,0, "DECB %e",
729 };
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",
740 };
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",
782 [0x26] SEG,0, "ES:",
783 [0x27] 0,0, "DAA",
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",
790 [0x2e] SEG,0, "CS:",
791 [0x2f] 0,0, "DAS",
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",
798 [0x36] SEG,0, "SS:",
799 [0x37] 0,0, "AAA",
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",
806 [0x3e] SEG,0, "DS:",
807 [0x3f] 0,0, "AAS",
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",
844 [0x64] SEG,0, "FS:",
845 [0x65] SEG,0, "GS:",
846 [0x66] OPOVER,0, "",
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",
887 [0x90] 0,0, "NOP",
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",
898 [0x9b] 0,0, "WAIT",
899 [0x9c] 0,0, "PUSHF",
900 [0x9d] 0,0, "POPF",
901 [0x9e] 0,0, "SAHF",
902 [0x9f] 0,0, "LAHF",
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",
938 [0xc3] RET,0, "RET",
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",
947 [0xcc] 0,0, "INT 3",
948 [0xcd] Ib,0, "INTB %i",
949 [0xce] 0,0, "INTO",
950 [0xcf] 0,0, "IRET",
951 [0xd0] RMOPB,0, optabD0,
952 [0xd1] RMOP,0, optabD1,
953 [0xd2] RMOPB,0, optabD2,
954 [0xd3] RMOP,0, optabD3,
955 [0xd4] OA,0, "AAM",
956 [0xd5] OA,0, "AAD",
957 [0xd7] 0,0, "XLAT",
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",
984 [0xf3] PRE,0, "REP",
985 [0xf4] 0,0, "HALT",
986 [0xf5] 0,0, "CMC",
987 [0xf6] RMOPB,0, optabF6,
988 [0xf7] RMOP,0, optabF7,
989 [0xf8] 0,0, "CLC",
990 [0xf9] 0,0, "STC",
991 [0xfa] 0,0, "CLI",
992 [0xfb] 0,0, "STI",
993 [0xfc] 0,0, "CLD",
994 [0xfd] 0,0, "STD",
995 [0xfe] RMOPB,0, optabFE,
996 [0xff] RMOP,0, optabFF,
997 };
999 /*
1000 * get a byte of the instruction
1002 static int
1003 igetc(Map * map, Instr *ip, uchar *c)
1005 if(ip->n+1 > sizeof(ip->mem)){
1006 werrstr("instruction too long");
1007 return -1;
1009 if (get1(map, ip->addr+ip->n, c, 1) < 0) {
1010 werrstr("can't read instruction: %r");
1011 return -1;
1013 ip->mem[ip->n++] = *c;
1014 return 1;
1018 * get two bytes of the instruction
1020 static int
1021 igets(Map *map, Instr *ip, ushort *sp)
1023 uchar c;
1024 ushort s;
1026 if (igetc(map, ip, &c) < 0)
1027 return -1;
1028 s = c;
1029 if (igetc(map, ip, &c) < 0)
1030 return -1;
1031 s |= (c<<8);
1032 *sp = s;
1033 return 1;
1037 * get 4 bytes of the instruction
1039 static int
1040 igetl(Map *map, Instr *ip, ulong *lp)
1042 ushort s;
1043 long l;
1045 if (igets(map, ip, &s) < 0)
1046 return -1;
1047 l = s;
1048 if (igets(map, ip, &s) < 0)
1049 return -1;
1050 l |= (s<<16);
1051 *lp = l;
1052 return 1;
1055 static int
1056 getdisp(Map *map, Instr *ip, int mod, int rm, int code)
1058 uchar c;
1059 ushort s;
1061 if (mod > 2)
1062 return 1;
1063 if (mod == 1) {
1064 if (igetc(map, ip, &c) < 0)
1065 return -1;
1066 if (c&0x80)
1067 ip->disp = c|0xffffff00;
1068 else
1069 ip->disp = c&0xff;
1070 } else if (mod == 2 || rm == code) {
1071 if (ip->asize == 'E') {
1072 if (igetl(map, ip, &ip->disp) < 0)
1073 return -1;
1074 } else {
1075 if (igets(map, ip, &s) < 0)
1076 return -1;
1077 if (s&0x8000)
1078 ip->disp = s|0xffff0000;
1079 else
1080 ip->disp = s;
1082 if (mod == 0)
1083 ip->base = -1;
1085 return 1;
1088 static int
1089 modrm(Map *map, Instr *ip, uchar c)
1091 uchar rm, mod;
1093 mod = (c>>6)&3;
1094 rm = c&7;
1095 ip->mod = mod;
1096 ip->base = rm;
1097 ip->reg = (c>>3)&7;
1098 if (mod == 3) /* register */
1099 return 1;
1100 if (ip->asize == 0) { /* 16-bit mode */
1101 switch(rm)
1103 case 0:
1104 ip->base = BX; ip->index = SI;
1105 break;
1106 case 1:
1107 ip->base = BX; ip->index = DI;
1108 break;
1109 case 2:
1110 ip->base = BP; ip->index = SI;
1111 break;
1112 case 3:
1113 ip->base = BP; ip->index = DI;
1114 break;
1115 case 4:
1116 ip->base = SI;
1117 break;
1118 case 5:
1119 ip->base = DI;
1120 break;
1121 case 6:
1122 ip->base = BP;
1123 break;
1124 case 7:
1125 ip->base = BX;
1126 break;
1127 default:
1128 break;
1130 return getdisp(map, ip, mod, rm, 6);
1132 if (rm == 4) { /* scummy sib byte */
1133 if (igetc(map, ip, &c) < 0)
1134 return -1;
1135 ip->ss = (c>>6)&0x03;
1136 ip->index = (c>>3)&0x07;
1137 if (ip->index == 4)
1138 ip->index = -1;
1139 ip->base = c&0x07;
1140 return getdisp(map, ip, mod, ip->base, 5);
1142 return getdisp(map, ip, mod, rm, 5);
1145 static Optable *
1146 mkinstr(Map *map, Instr *ip, ulong pc)
1148 int i, n;
1149 uchar c;
1150 ushort s;
1151 Optable *op, *obase;
1152 char buf[128];
1154 memset(ip, 0, sizeof(*ip));
1155 ip->base = -1;
1156 ip->index = -1;
1157 if(0) /* asstype == AI8086) */
1158 ip->osize = 'W';
1159 else {
1160 ip->osize = 'L';
1161 ip->asize = 'E';
1163 ip->addr = pc;
1164 if (igetc(map, ip, &c) < 0)
1165 return 0;
1166 obase = optable;
1167 newop:
1168 op = &obase[c];
1169 if (op->proto == 0) {
1170 badop:
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, "??");
1175 werrstr(buf);
1176 return 0;
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)
1183 return 0;
1184 ip->imm = c&0xff;
1185 break;
1186 case Jbs: /* 8-bit jump immediate (sign extended) */
1187 if (igetc(map, ip, &c) < 0)
1188 return 0;
1189 if (c&0x80)
1190 ip->imm = c|0xffffff00;
1191 else
1192 ip->imm = c&0xff;
1193 ip->jumptype = Jbs;
1194 break;
1195 case Ibs: /* 8-bit immediate (sign extended) */
1196 if (igetc(map, ip, &c) < 0)
1197 return 0;
1198 if (c&0x80)
1199 if (ip->osize == 'L')
1200 ip->imm = c|0xffffff00;
1201 else
1202 ip->imm = c|0xff00;
1203 else
1204 ip->imm = c&0xff;
1205 break;
1206 case Iw: /* 16-bit immediate -> imm */
1207 if (igets(map, ip, &s) < 0)
1208 return 0;
1209 ip->imm = s&0xffff;
1210 ip->jumptype = Iw;
1211 break;
1212 case Iw2: /* 16-bit immediate -> in imm2*/
1213 if (igets(map, ip, &s) < 0)
1214 return 0;
1215 ip->imm2 = s&0xffff;
1216 break;
1217 case Iwd: /* Operand-sized immediate (no sign extension)*/
1218 if (ip->osize == 'L') {
1219 if (igetl(map, ip, &ip->imm) < 0)
1220 return 0;
1221 } else {
1222 if (igets(map, ip, &s)< 0)
1223 return 0;
1224 ip->imm = s&0xffff;
1226 break;
1227 case Awd: /* Address-sized immediate (no sign extension)*/
1228 if (ip->asize == 'E') {
1229 if (igetl(map, ip, &ip->imm) < 0)
1230 return 0;
1231 } else {
1232 if (igets(map, ip, &s)< 0)
1233 return 0;
1234 ip->imm = s&0xffff;
1236 break;
1237 case Iwds: /* Operand-sized immediate (sign extended) */
1238 if (ip->osize == 'L') {
1239 if (igetl(map, ip, &ip->imm) < 0)
1240 return 0;
1241 } else {
1242 if (igets(map, ip, &s)< 0)
1243 return 0;
1244 if (s&0x8000)
1245 ip->imm = s|0xffff0000;
1246 else
1247 ip->imm = s&0xffff;
1249 ip->jumptype = Iwds;
1250 break;
1251 case OA: /* literal 0x0a byte */
1252 if (igetc(map, ip, &c) < 0)
1253 return 0;
1254 if (c != 0x0a)
1255 goto badop;
1256 break;
1257 case R0: /* base register must be R0 */
1258 if (ip->base != 0)
1259 goto badop;
1260 break;
1261 case R1: /* base register must be R1 */
1262 if (ip->base != 1)
1263 goto badop;
1264 break;
1265 case RMB: /* R/M field with byte register (/r)*/
1266 if (igetc(map, ip, &c) < 0)
1267 return 0;
1268 if (modrm(map, ip, c) < 0)
1269 return 0;
1270 ip->osize = 'B';
1271 break;
1272 case RM: /* R/M field with register (/r) */
1273 if (igetc(map, ip, &c) < 0)
1274 return 0;
1275 if (modrm(map, ip, c) < 0)
1276 return 0;
1277 break;
1278 case RMOPB: /* R/M field with op code (/digit) */
1279 if (igetc(map, ip, &c) < 0)
1280 return 0;
1281 if (modrm(map, ip, c) < 0)
1282 return 0;
1283 c = ip->reg; /* secondary op code */
1284 obase = (Optable*)op->proto;
1285 ip->osize = 'B';
1286 goto newop;
1287 case RMOP: /* R/M field with op code (/digit) */
1288 if (igetc(map, ip, &c) < 0)
1289 return 0;
1290 if (modrm(map, ip, c) < 0)
1291 return 0;
1292 c = ip->reg;
1293 obase = (Optable*)op->proto;
1294 goto newop;
1295 case FRMOP: /* FP R/M field with op code (/digit) */
1296 if (igetc(map, ip, &c) < 0)
1297 return 0;
1298 if (modrm(map, ip, c) < 0)
1299 return 0;
1300 if ((c&0xc0) == 0xc0)
1301 c = ip->reg+8; /* 16 entry table */
1302 else
1303 c = ip->reg;
1304 obase = (Optable*)op->proto;
1305 goto newop;
1306 case FRMEX: /* Extended FP R/M field with op code (/digit) */
1307 if (igetc(map, ip, &c) < 0)
1308 return 0;
1309 if (modrm(map, ip, c) < 0)
1310 return 0;
1311 if ((c&0xc0) == 0xc0)
1312 c = (c&0x3f)+8; /* 64-entry table */
1313 else
1314 c = ip->reg;
1315 obase = (Optable*)op->proto;
1316 goto newop;
1317 case RMR: /* R/M register only (mod = 11) */
1318 if (igetc(map, ip, &c) < 0)
1319 return 0;
1320 if ((c&0xc0) != 0xc0) {
1321 werrstr("invalid R/M register: %x", c);
1322 return 0;
1324 if (modrm(map, ip, c) < 0)
1325 return 0;
1326 break;
1327 case RMM: /* R/M register only (mod = 11) */
1328 if (igetc(map, ip, &c) < 0)
1329 return 0;
1330 if ((c&0xc0) == 0xc0) {
1331 werrstr("invalid R/M memory mode: %x", c);
1332 return 0;
1334 if (modrm(map, ip, c) < 0)
1335 return 0;
1336 break;
1337 case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
1338 if (ip->osize == 'L') {
1339 if (igetl(map, ip, &ip->disp) < 0)
1340 return 0;
1341 } else {
1342 if (igets(map, ip, &s)< 0)
1343 return 0;
1344 ip->disp = s&0xffff;
1346 if (igets(map, ip, (ushort*)&ip->seg) < 0)
1347 return 0;
1348 ip->jumptype = PTR;
1349 break;
1350 case AUX: /* Multi-byte op code - Auxiliary table */
1351 obase = (Optable*)op->proto;
1352 if (igetc(map, ip, &c) < 0)
1353 return 0;
1354 goto newop;
1355 case PRE: /* Instr Prefix */
1356 ip->prefix = (char*)op->proto;
1357 if (igetc(map, ip, &c) < 0)
1358 return 0;
1359 goto newop;
1360 case SEG: /* Segment Prefix */
1361 ip->segment = (char*)op->proto;
1362 if (igetc(map, ip, &c) < 0)
1363 return 0;
1364 goto newop;
1365 case OPOVER: /* Operand size override */
1366 ip->osize = 'W';
1367 if (igetc(map, ip, &c) < 0)
1368 return 0;
1369 goto newop;
1370 case ADDOVER: /* Address size override */
1371 ip->asize = 0;
1372 if (igetc(map, ip, &c) < 0)
1373 return 0;
1374 goto newop;
1375 case JUMP: /* mark instruction as JUMP or RET */
1376 case RET:
1377 ip->jumptype = op->operand[i];
1378 break;
1379 default:
1380 werrstr("bad operand type %d", op->operand[i]);
1381 return 0;
1384 return op;
1387 static void
1388 bprint(Instr *ip, char *fmt, ...)
1390 va_list arg;
1392 va_start(arg, fmt);
1393 ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
1394 va_end(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[] = {
1408 [AX] "AX",
1409 [CX] "CX",
1410 [DX] "DX",
1411 [BX] "BX",
1412 [SP] "SP",
1413 [BP] "BP",
1414 [SI] "SI",
1415 [DI] "DI",
1418 static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
1419 static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
1421 static void
1422 plocal(Instr *ip)
1424 Symbol s;
1425 char *name;
1426 Loc l, li;
1428 l.type = LOFFSET;
1429 l.offset = ip->disp;
1430 if(ip->base == SP)
1431 l.reg = "SP";
1432 else
1433 l.reg = "BP";
1435 li.type = LADDR;
1436 li.addr = ip->addr;
1437 if(findsym(li, CTEXT, &s) < 0)
1438 goto raw;
1440 name = nil;
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)
1447 name = s.name;
1449 if(name)
1450 bprint(ip, "%s+", name);
1452 raw:
1453 bprint(ip, "%lx(%s)", l.offset, l.reg);
1456 static int
1457 isjmp(Instr *ip)
1459 switch(ip->jumptype){
1460 case Iwds:
1461 case Jbs:
1462 case JUMP:
1463 return 1;
1464 default:
1465 return 0;
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.
1475 static int
1476 issymref(Instr *ip, Symbol *s, long w, long val)
1478 Symbol next, tmp;
1479 long isstring, size;
1481 if (isjmp(ip))
1482 return 1;
1483 if (s->class==CTEXT && w==0)
1484 return 1;
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))
1490 *s = tmp;
1492 if (w == 0)
1493 return 1;
1494 for (next=*s; next.loc.addr==s->loc.addr; next=tmp)
1495 if (!indexsym(next.index+1, &tmp))
1496 break;
1497 size = next.loc.addr - s->loc.addr;
1498 if (w >= size)
1499 return 0;
1500 if (w > size-w)
1501 w = size-w;
1502 /* huge distances are usually wrong except in .string */
1503 isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
1504 if (w > 8192 && !isstring)
1505 return 0;
1506 /* medium distances are tricky - look for constants */
1507 /* near powers of two */
1508 if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
1509 return 0;
1510 return 1;
1512 return 0;
1515 static void
1516 immediate(Instr *ip, long val)
1518 Symbol s;
1519 long w;
1520 Loc l;
1522 l.type = LADDR;
1523 l.addr = val;
1524 if (findsym(l, CANY, &s) >= 0) {
1525 w = val - s.loc.addr;
1526 if (w < 0)
1527 w = -w;
1528 if (issymref(ip, &s, w, val)) {
1529 if (w)
1530 bprint(ip, "%s+%lux(SB)", s.name, w);
1531 else
1532 bprint(ip, "%s(SB)", s.name);
1533 return;
1535 if (s.class==CDATA && indexsym(s.index+1, &s) >= 0) {
1536 w = s.loc.addr - val;
1537 if (w < 0)
1538 w = -w;
1539 if (w < 4096) {
1540 bprint(ip, "%s-%lux(SB)", s.name, w);
1541 return;
1545 bprint(ip, "%lux", val);
1548 static void
1549 pea(Instr *ip)
1551 if (ip->mod == 3) {
1552 if (ip->osize == 'B')
1553 bprint(ip, breg[(uchar)ip->base]);
1554 else
1555 bprint(ip, "%s%s", ANAME(ip), reg[(uchar)ip->base]);
1556 return;
1558 if (ip->segment)
1559 bprint(ip, ip->segment);
1560 if (ip->asize == 'E' && (ip->base == SP || ip->base == BP))
1561 plocal(ip);
1562 else {
1563 if (ip->base < 0)
1564 immediate(ip, ip->disp);
1565 else
1566 bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]);
1568 if (ip->index >= 0)
1569 bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss);
1572 static void
1573 prinstr(Instr *ip, char *fmt)
1575 if (ip->prefix)
1576 bprint(ip, "%s ", ip->prefix);
1577 for (; *fmt && ip->curr < ip->end; fmt++) {
1578 if (*fmt != '%')
1579 *ip->curr++ = *fmt;
1580 else switch(*++fmt)
1582 case '%':
1583 *ip->curr++ = '%';
1584 break;
1585 case 'A':
1586 bprint(ip, "%s", ANAME(ip));
1587 break;
1588 case 'C':
1589 bprint(ip, "CR%d", ip->reg);
1590 break;
1591 case 'D':
1592 if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
1593 bprint(ip, "DR%d",ip->reg);
1594 else
1595 bprint(ip, "???");
1596 break;
1597 case 'I':
1598 bprint(ip, "$");
1599 immediate(ip, ip->imm2);
1600 break;
1601 case 'O':
1602 bprint(ip,"%s", ONAME(ip));
1603 break;
1604 case 'i':
1605 bprint(ip, "$");
1606 immediate(ip,ip->imm);
1607 break;
1608 case 'R':
1609 bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
1610 break;
1611 case 'S':
1612 bprint(ip, "%c", ip->osize);
1613 break;
1614 case 'T':
1615 if (ip->reg == 6 || ip->reg == 7)
1616 bprint(ip, "TR%d",ip->reg);
1617 else
1618 bprint(ip, "???");
1619 break;
1620 case 'X':
1621 if (ip->osize == 'L')
1622 bprint(ip,"CWDE");
1623 else
1624 bprint(ip, "CBW");
1625 break;
1626 case 'd':
1627 bprint(ip,"%lux:%lux",ip->seg,ip->disp);
1628 break;
1629 case 'e':
1630 pea(ip);
1631 break;
1632 case 'f':
1633 bprint(ip, "F%d", ip->base);
1634 break;
1635 case 'g':
1636 if (ip->reg < 6)
1637 bprint(ip,"%s",sreg[ip->reg]);
1638 else
1639 bprint(ip,"???");
1640 break;
1641 case 'p':
1642 immediate(ip, ip->imm+ip->addr+ip->n);
1643 break;
1644 case 'r':
1645 if (ip->osize == 'B')
1646 bprint(ip,"%s",breg[ip->reg]);
1647 else
1648 bprint(ip, reg[ip->reg]);
1649 break;
1650 case 'x':
1651 if (ip->osize == 'L')
1652 bprint(ip,"CDQ");
1653 else
1654 bprint(ip, "CWD");
1655 break;
1656 default:
1657 bprint(ip, "%%%c", *fmt);
1658 break;
1661 *ip->curr = 0; /* there's always room for 1 byte */
1664 static int
1665 i386das(Map *map, ulong pc, char modifier, char *buf, int n)
1667 Instr instr;
1668 Optable *op;
1670 USED(modifier);
1671 op = mkinstr(map, &instr, pc);
1672 if (op == 0) {
1673 errstr(buf, n);
1674 return -1;
1676 instr.curr = buf;
1677 instr.end = buf+n-1;
1678 prinstr(&instr, op->proto);
1679 return instr.n;
1682 static int
1683 i386hexinst(Map *map, ulong pc, char *buf, int n)
1685 Instr instr;
1686 int i;
1688 if (mkinstr(map, &instr, pc) == 0) {
1689 errstr(buf, n);
1690 return -1;
1692 for(i = 0; i < instr.n && n > 2; i++) {
1693 _hexify(buf, instr.mem[i], 1);
1694 buf += 2;
1695 n -= 2;
1697 *buf = 0;
1698 return instr.n;
1701 static int
1702 i386instlen(Map *map, ulong pc)
1704 Instr i;
1706 if (mkinstr(map, &i, pc))
1707 return i.n;
1708 return -1;
1711 static int
1712 i386foll(Map *map, Regs *regs, ulong pc, ulong *foll)
1714 Instr i;
1715 Optable *op;
1716 ushort s;
1717 ulong addr;
1718 u32int l;
1719 int n;
1721 op = mkinstr(map, &i, pc);
1722 if (!op)
1723 return -1;
1725 n = 0;
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)
1732 return -1;
1733 } else if (lget4(map, regs, locindir(mach->sp, 0), &l) < 0)
1734 return -1;
1735 foll[0] = l;
1736 return 1;
1737 case Iwds: /* pc relative JUMP or CALL*/
1738 case Jbs: /* pc relative JUMP or CALL */
1739 foll[0] = pc+i.imm+i.n;
1740 n = 1;
1741 break;
1742 case PTR: /* seg:displacement JUMP or CALL */
1743 foll[0] = (i.seg<<4)+i.disp;
1744 return 1;
1745 case JUMP: /* JUMP or CALL EA */
1747 if(i.mod == 3) {
1748 if (rget(regs, reg[(uchar)i.base], &foll[0]) < 0)
1749 return -1;
1750 return 1;
1752 /* calculate the effective address */
1753 addr = i.disp;
1754 if (i.base >= 0) {
1755 if (lget4(map, regs, locindir(reg[(uchar)i.base], 0), &l) < 0)
1756 return -1;
1757 addr += l;
1759 if (i.index >= 0) {
1760 if (lget4(map, regs, locindir(reg[(uchar)i.index], 0), &l) < 0)
1761 return -1;
1762 addr += l*(1<<i.ss);
1764 /* now retrieve a seg:disp value at that address */
1765 if (get2(map, addr, &s) < 0) /* seg */
1766 return -1;
1767 foll[0] = s<<4;
1768 addr += 2;
1769 if (i.asize == 'L') {
1770 if (get4(map, addr, &l) < 0) /* disp32 */
1771 return -1;
1772 foll[0] += l;
1773 } else { /* disp16 */
1774 if (get2(map, addr, &s) < 0)
1775 return -1;
1776 foll[0] += s;
1778 return 1;
1779 default:
1780 break;
1782 if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
1783 return 1;
1784 foll[n++] = pc+i.n;
1785 return n;