174a4d8c2SCharles.Forsyth #include <lib9.h>
274a4d8c2SCharles.Forsyth #include <bio.h>
374a4d8c2SCharles.Forsyth #include "mach.h"
474a4d8c2SCharles.Forsyth
574a4d8c2SCharles.Forsyth /*
674a4d8c2SCharles.Forsyth * i386-specific debugger interface
7d67b7dadSforsyth * also amd64 extensions
874a4d8c2SCharles.Forsyth */
974a4d8c2SCharles.Forsyth
1074a4d8c2SCharles.Forsyth static char *i386excep(Map*, Rgetter);
1174a4d8c2SCharles.Forsyth
12d67b7dadSforsyth static int i386trace(Map*, uvlong, uvlong, uvlong, Tracer);
13d67b7dadSforsyth static uvlong i386frame(Map*, uvlong, uvlong, uvlong, uvlong);
14d67b7dadSforsyth static int i386foll(Map*, uvlong, Rgetter, uvlong*);
15d67b7dadSforsyth static int i386inst(Map*, uvlong, char, char*, int);
16d67b7dadSforsyth static int i386das(Map*, uvlong, char*, int);
17d67b7dadSforsyth static int i386instlen(Map*, uvlong);
1874a4d8c2SCharles.Forsyth
1974a4d8c2SCharles.Forsyth static char STARTSYM[] = "_main";
2074a4d8c2SCharles.Forsyth static char PROFSYM[] = "_mainp";
2174a4d8c2SCharles.Forsyth static char FRAMENAME[] = ".frame";
22773d7fd2Sforsyth static char *excname[65] =
2374a4d8c2SCharles.Forsyth {
24773d7fd2Sforsyth /*[0]*/ "divide error",
25773d7fd2Sforsyth /*[1]*/ "debug exception",
26773d7fd2Sforsyth /*[2]*/ nil,
27773d7fd2Sforsyth /*[3]*/ nil,
28773d7fd2Sforsyth /*[4]*/ "overflow",
29773d7fd2Sforsyth /*[5]*/ "bounds check",
30773d7fd2Sforsyth /*[6]*/ "invalid opcode",
31773d7fd2Sforsyth /*[7]*/ "math coprocessor emulation",
32773d7fd2Sforsyth /*[8]*/ "double fault",
33773d7fd2Sforsyth /*[9]*/ "math coprocessor overrun",
34773d7fd2Sforsyth /*[10]*/ "invalid TSS",
35773d7fd2Sforsyth /*[11]*/ "segment not present",
36773d7fd2Sforsyth /*[12]*/ "stack exception",
37773d7fd2Sforsyth /*[13]*/ "general protection violation",
38773d7fd2Sforsyth /*[14]*/ "page fault",
39773d7fd2Sforsyth /*[15]*/ nil,
40773d7fd2Sforsyth /*[16]*/ "math coprocessor error",
41773d7fd2Sforsyth /*[17]*/ "alignment check",
42773d7fd2Sforsyth /*[18]*/ "machine check",
43773d7fd2Sforsyth /*[19]*/ "floating-point exception",
44773d7fd2Sforsyth /*[20]*/ nil,
45773d7fd2Sforsyth /*[21]*/ nil,
46773d7fd2Sforsyth /*[22]*/ nil,
47773d7fd2Sforsyth /*[23]*/ nil,
48773d7fd2Sforsyth /*[24]*/ "clock",
49773d7fd2Sforsyth /*[25]*/ "keyboard",
50773d7fd2Sforsyth /*[26]*/ nil,
51773d7fd2Sforsyth /*[27]*/ "modem status",
52773d7fd2Sforsyth /*[28]*/ "serial line status",
53773d7fd2Sforsyth /*[29]*/ nil,
54773d7fd2Sforsyth /*[30]*/ "floppy disk",
55773d7fd2Sforsyth /*[31]*/ nil,
56773d7fd2Sforsyth /*[32]*/ nil,
57773d7fd2Sforsyth /*[33]*/ nil,
58773d7fd2Sforsyth /*[34]*/ nil,
59773d7fd2Sforsyth /*[35]*/ nil,
60773d7fd2Sforsyth /*[36]*/ "mouse",
61773d7fd2Sforsyth /*[37]*/ "math coprocessor",
62773d7fd2Sforsyth /*[38]*/ "hard disk",
63773d7fd2Sforsyth 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */
64773d7fd2Sforsyth 0,0,0,0,0,0,0,0,0, /* 55-63 */
65773d7fd2Sforsyth /*[64]*/ "system call",
6674a4d8c2SCharles.Forsyth };
6774a4d8c2SCharles.Forsyth
6874a4d8c2SCharles.Forsyth Machdata i386mach =
6974a4d8c2SCharles.Forsyth {
7074a4d8c2SCharles.Forsyth {0xCC, 0, 0, 0}, /* break point: INT 3 */
7174a4d8c2SCharles.Forsyth 1, /* break point size */
7274a4d8c2SCharles.Forsyth
7374a4d8c2SCharles.Forsyth leswab, /* convert short to local byte order */
7474a4d8c2SCharles.Forsyth leswal, /* convert long to local byte order */
7574a4d8c2SCharles.Forsyth leswav, /* convert vlong to local byte order */
7674a4d8c2SCharles.Forsyth i386trace, /* C traceback */
7774a4d8c2SCharles.Forsyth i386frame, /* frame finder */
7874a4d8c2SCharles.Forsyth i386excep, /* print exception */
7974a4d8c2SCharles.Forsyth 0, /* breakpoint fixup */
8074a4d8c2SCharles.Forsyth leieeesftos, /* single precision float printer */
8174a4d8c2SCharles.Forsyth leieeedftos, /* double precision float printer */
8274a4d8c2SCharles.Forsyth i386foll, /* following addresses */
8374a4d8c2SCharles.Forsyth i386inst, /* print instruction */
8474a4d8c2SCharles.Forsyth i386das, /* dissembler */
8574a4d8c2SCharles.Forsyth i386instlen, /* instruction size calculation */
8674a4d8c2SCharles.Forsyth };
8774a4d8c2SCharles.Forsyth
8874a4d8c2SCharles.Forsyth static char*
i386excep(Map * map,Rgetter rget)8974a4d8c2SCharles.Forsyth i386excep(Map *map, Rgetter rget)
9074a4d8c2SCharles.Forsyth {
9174a4d8c2SCharles.Forsyth ulong c;
92d67b7dadSforsyth uvlong pc;
9374a4d8c2SCharles.Forsyth static char buf[16];
9474a4d8c2SCharles.Forsyth
9574a4d8c2SCharles.Forsyth c = (*rget)(map, "TRAP");
9674a4d8c2SCharles.Forsyth if(c > 64 || excname[c] == 0) {
9774a4d8c2SCharles.Forsyth if (c == 3) {
9874a4d8c2SCharles.Forsyth pc = (*rget)(map, "PC");
9974a4d8c2SCharles.Forsyth if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
10074a4d8c2SCharles.Forsyth if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
10174a4d8c2SCharles.Forsyth return "breakpoint";
10274a4d8c2SCharles.Forsyth }
103d67b7dadSforsyth snprint(buf, sizeof(buf), "exception %ld", c);
10474a4d8c2SCharles.Forsyth return buf;
10574a4d8c2SCharles.Forsyth } else
10674a4d8c2SCharles.Forsyth return excname[c];
10774a4d8c2SCharles.Forsyth }
10874a4d8c2SCharles.Forsyth
10974a4d8c2SCharles.Forsyth static int
i386trace(Map * map,uvlong pc,uvlong sp,uvlong link,Tracer trace)110d67b7dadSforsyth i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
11174a4d8c2SCharles.Forsyth {
11274a4d8c2SCharles.Forsyth int i;
113d67b7dadSforsyth uvlong osp;
11474a4d8c2SCharles.Forsyth Symbol s, f;
11574a4d8c2SCharles.Forsyth
11674a4d8c2SCharles.Forsyth USED(link);
11774a4d8c2SCharles.Forsyth i = 0;
11874a4d8c2SCharles.Forsyth osp = 0;
11974a4d8c2SCharles.Forsyth while(findsym(pc, CTEXT, &s)) {
12074a4d8c2SCharles.Forsyth if (osp == sp)
12174a4d8c2SCharles.Forsyth break;
12274a4d8c2SCharles.Forsyth osp = sp;
12374a4d8c2SCharles.Forsyth
12474a4d8c2SCharles.Forsyth if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
12574a4d8c2SCharles.Forsyth break;
12674a4d8c2SCharles.Forsyth
12774a4d8c2SCharles.Forsyth if(pc != s.value) { /* not at first instruction */
12874a4d8c2SCharles.Forsyth if(findlocal(&s, FRAMENAME, &f) == 0)
12974a4d8c2SCharles.Forsyth break;
13074a4d8c2SCharles.Forsyth sp += f.value-mach->szaddr;
13174a4d8c2SCharles.Forsyth }
13274a4d8c2SCharles.Forsyth
133d67b7dadSforsyth if (geta(map, sp, &pc) < 0)
13474a4d8c2SCharles.Forsyth break;
13574a4d8c2SCharles.Forsyth
13674a4d8c2SCharles.Forsyth if(pc == 0)
13774a4d8c2SCharles.Forsyth break;
13874a4d8c2SCharles.Forsyth
13974a4d8c2SCharles.Forsyth (*trace)(map, pc, sp, &s);
14074a4d8c2SCharles.Forsyth sp += mach->szaddr;
14174a4d8c2SCharles.Forsyth
142d67b7dadSforsyth if(++i > 1000)
14374a4d8c2SCharles.Forsyth break;
14474a4d8c2SCharles.Forsyth }
14574a4d8c2SCharles.Forsyth return i;
14674a4d8c2SCharles.Forsyth }
14774a4d8c2SCharles.Forsyth
148d67b7dadSforsyth static uvlong
i386frame(Map * map,uvlong addr,uvlong pc,uvlong sp,uvlong link)149d67b7dadSforsyth i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
15074a4d8c2SCharles.Forsyth {
15174a4d8c2SCharles.Forsyth Symbol s, f;
15274a4d8c2SCharles.Forsyth
15374a4d8c2SCharles.Forsyth USED(link);
15474a4d8c2SCharles.Forsyth while (findsym(pc, CTEXT, &s)) {
15574a4d8c2SCharles.Forsyth if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
15674a4d8c2SCharles.Forsyth break;
15774a4d8c2SCharles.Forsyth
15874a4d8c2SCharles.Forsyth if(pc != s.value) { /* not first instruction */
15974a4d8c2SCharles.Forsyth if(findlocal(&s, FRAMENAME, &f) == 0)
16074a4d8c2SCharles.Forsyth break;
16174a4d8c2SCharles.Forsyth sp += f.value-mach->szaddr;
16274a4d8c2SCharles.Forsyth }
16374a4d8c2SCharles.Forsyth
16474a4d8c2SCharles.Forsyth if (s.value == addr)
16574a4d8c2SCharles.Forsyth return sp;
16674a4d8c2SCharles.Forsyth
167d67b7dadSforsyth if (geta(map, sp, &pc) < 0)
16874a4d8c2SCharles.Forsyth break;
16974a4d8c2SCharles.Forsyth sp += mach->szaddr;
17074a4d8c2SCharles.Forsyth }
17174a4d8c2SCharles.Forsyth return 0;
17274a4d8c2SCharles.Forsyth }
17374a4d8c2SCharles.Forsyth
17474a4d8c2SCharles.Forsyth /* I386/486 - Disassembler and related functions */
17574a4d8c2SCharles.Forsyth
17674a4d8c2SCharles.Forsyth /*
17774a4d8c2SCharles.Forsyth * an instruction
17874a4d8c2SCharles.Forsyth */
17974a4d8c2SCharles.Forsyth typedef struct Instr Instr;
18074a4d8c2SCharles.Forsyth struct Instr
18174a4d8c2SCharles.Forsyth {
18274a4d8c2SCharles.Forsyth uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
183d67b7dadSforsyth uvlong addr; /* address of start of instruction */
18474a4d8c2SCharles.Forsyth int n; /* number of bytes in instruction */
18574a4d8c2SCharles.Forsyth char *prefix; /* instr prefix */
18674a4d8c2SCharles.Forsyth char *segment; /* segment override */
18774a4d8c2SCharles.Forsyth uchar jumptype; /* set to the operand type for jump/ret/call */
188d67b7dadSforsyth uchar amd64;
189d67b7dadSforsyth uchar rex; /* REX prefix (or zero) */
190d67b7dadSforsyth char osize; /* 'W' or 'L' (or 'Q' on amd64) */
191d67b7dadSforsyth char asize; /* address size 'W' or 'L' (or 'Q' or amd64) */
19274a4d8c2SCharles.Forsyth uchar mod; /* bits 6-7 of mod r/m field */
19374a4d8c2SCharles.Forsyth uchar reg; /* bits 3-5 of mod r/m field */
19474a4d8c2SCharles.Forsyth char ss; /* bits 6-7 of SIB */
19574a4d8c2SCharles.Forsyth char index; /* bits 3-5 of SIB */
19674a4d8c2SCharles.Forsyth char base; /* bits 0-2 of SIB */
197d67b7dadSforsyth char rip; /* RIP-relative in amd64 mode */
198d67b7dadSforsyth uchar opre; /* f2/f3 could introduce media */
19974a4d8c2SCharles.Forsyth short seg; /* segment of far address */
20074a4d8c2SCharles.Forsyth ulong disp; /* displacement */
20174a4d8c2SCharles.Forsyth ulong imm; /* immediate */
20274a4d8c2SCharles.Forsyth ulong imm2; /* second immediate operand */
203d67b7dadSforsyth uvlong imm64; /* big immediate */
20474a4d8c2SCharles.Forsyth char *curr; /* fill level in output buffer */
20574a4d8c2SCharles.Forsyth char *end; /* end of output buffer */
20674a4d8c2SCharles.Forsyth char *err; /* error message */
20774a4d8c2SCharles.Forsyth };
20874a4d8c2SCharles.Forsyth
20974a4d8c2SCharles.Forsyth /* 386 register (ha!) set */
21074a4d8c2SCharles.Forsyth enum{
21174a4d8c2SCharles.Forsyth AX=0,
21274a4d8c2SCharles.Forsyth CX,
21374a4d8c2SCharles.Forsyth DX,
21474a4d8c2SCharles.Forsyth BX,
21574a4d8c2SCharles.Forsyth SP,
21674a4d8c2SCharles.Forsyth BP,
21774a4d8c2SCharles.Forsyth SI,
21874a4d8c2SCharles.Forsyth DI,
219d67b7dadSforsyth
220d67b7dadSforsyth /* amd64 */
221d67b7dadSforsyth R8,
222d67b7dadSforsyth R9,
223d67b7dadSforsyth R10,
224d67b7dadSforsyth R11,
225d67b7dadSforsyth R12,
226d67b7dadSforsyth R13,
227d67b7dadSforsyth R14,
228d67b7dadSforsyth R15
22974a4d8c2SCharles.Forsyth };
230d67b7dadSforsyth
231d67b7dadSforsyth /* amd64 rex extension byte */
232d67b7dadSforsyth enum{
233d67b7dadSforsyth REXW = 1<<3, /* =1, 64-bit operand size */
234d67b7dadSforsyth REXR = 1<<2, /* extend modrm reg */
235d67b7dadSforsyth REXX = 1<<1, /* extend sib index */
236d67b7dadSforsyth REXB = 1<<0 /* extend modrm r/m, sib base, or opcode reg */
237d67b7dadSforsyth };
238d67b7dadSforsyth
23974a4d8c2SCharles.Forsyth /* Operand Format codes */
24074a4d8c2SCharles.Forsyth /*
24174a4d8c2SCharles.Forsyth %A - address size register modifier (!asize -> 'E')
24274a4d8c2SCharles.Forsyth %C - Control register CR0/CR1/CR2
24374a4d8c2SCharles.Forsyth %D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
24474a4d8c2SCharles.Forsyth %I - second immediate operand
24574a4d8c2SCharles.Forsyth %O - Operand size register modifier (!osize -> 'E')
24674a4d8c2SCharles.Forsyth %T - Test register TR6/TR7
24774a4d8c2SCharles.Forsyth %S - size code ('W' or 'L')
248d67b7dadSforsyth %W - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
24974a4d8c2SCharles.Forsyth %d - displacement 16-32 bits
25074a4d8c2SCharles.Forsyth %e - effective address - Mod R/M value
25174a4d8c2SCharles.Forsyth %f - floating point register F0-F7 - from Mod R/M register
25274a4d8c2SCharles.Forsyth %g - segment register
25374a4d8c2SCharles.Forsyth %i - immediate operand 8-32 bits
25474a4d8c2SCharles.Forsyth %p - PC-relative - signed displacement in immediate field
25574a4d8c2SCharles.Forsyth %r - Reg from Mod R/M
256d67b7dadSforsyth %w - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
25774a4d8c2SCharles.Forsyth */
25874a4d8c2SCharles.Forsyth
25974a4d8c2SCharles.Forsyth typedef struct Optable Optable;
26074a4d8c2SCharles.Forsyth struct Optable
26174a4d8c2SCharles.Forsyth {
262773d7fd2Sforsyth int x;
26374a4d8c2SCharles.Forsyth char operand[2];
26474a4d8c2SCharles.Forsyth void *proto; /* actually either (char*) or (Optable*) */
26574a4d8c2SCharles.Forsyth };
26674a4d8c2SCharles.Forsyth /* Operand decoding codes */
26774a4d8c2SCharles.Forsyth enum {
26874a4d8c2SCharles.Forsyth Ib = 1, /* 8-bit immediate - (no sign extension)*/
26974a4d8c2SCharles.Forsyth Ibs, /* 8-bit immediate (sign extended) */
27074a4d8c2SCharles.Forsyth Jbs, /* 8-bit sign-extended immediate in jump or call */
27174a4d8c2SCharles.Forsyth Iw, /* 16-bit immediate -> imm */
27274a4d8c2SCharles.Forsyth Iw2, /* 16-bit immediate -> imm2 */
27374a4d8c2SCharles.Forsyth Iwd, /* Operand-sized immediate (no sign extension)*/
274d67b7dadSforsyth Iwdq, /* Operand-sized immediate, possibly 64 bits */
27574a4d8c2SCharles.Forsyth Awd, /* Address offset */
27674a4d8c2SCharles.Forsyth Iwds, /* Operand-sized immediate (sign extended) */
27774a4d8c2SCharles.Forsyth RM, /* Word or long R/M field with register (/r) */
27874a4d8c2SCharles.Forsyth RMB, /* Byte R/M field with register (/r) */
27974a4d8c2SCharles.Forsyth RMOP, /* Word or long R/M field with op code (/digit) */
28074a4d8c2SCharles.Forsyth RMOPB, /* Byte R/M field with op code (/digit) */
28174a4d8c2SCharles.Forsyth RMR, /* R/M register only (mod = 11) */
28274a4d8c2SCharles.Forsyth RMM, /* R/M memory only (mod = 0/1/2) */
28374a4d8c2SCharles.Forsyth R0, /* Base reg of Mod R/M is literal 0x00 */
28474a4d8c2SCharles.Forsyth R1, /* Base reg of Mod R/M is literal 0x01 */
28574a4d8c2SCharles.Forsyth FRMOP, /* Floating point R/M field with opcode */
28674a4d8c2SCharles.Forsyth FRMEX, /* Extended floating point R/M field with opcode */
28774a4d8c2SCharles.Forsyth JUMP, /* Jump or Call flag - no operand */
28874a4d8c2SCharles.Forsyth RET, /* Return flag - no operand */
28974a4d8c2SCharles.Forsyth OA, /* literal 0x0a byte */
29074a4d8c2SCharles.Forsyth PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
29174a4d8c2SCharles.Forsyth AUX, /* Multi-byte op code - Auxiliary table */
292d67b7dadSforsyth AUXMM, /* multi-byte op code - auxiliary table chosen by prefix */
29374a4d8c2SCharles.Forsyth PRE, /* Instr Prefix */
294d67b7dadSforsyth OPRE, /* Instr Prefix or media op extension */
29574a4d8c2SCharles.Forsyth SEG, /* Segment Prefix */
29674a4d8c2SCharles.Forsyth OPOVER, /* Operand size override */
29774a4d8c2SCharles.Forsyth ADDOVER, /* Address size override */
29874a4d8c2SCharles.Forsyth };
29974a4d8c2SCharles.Forsyth
30074a4d8c2SCharles.Forsyth static Optable optab0F00[8]=
30174a4d8c2SCharles.Forsyth {
302773d7fd2Sforsyth 0x00, 0,0, "MOVW LDT,%e",
303773d7fd2Sforsyth 0x01, 0,0, "MOVW TR,%e",
304773d7fd2Sforsyth 0x02, 0,0, "MOVW %e,LDT",
305773d7fd2Sforsyth 0x03, 0,0, "MOVW %e,TR",
306773d7fd2Sforsyth 0x04, 0,0, "VERR %e",
307773d7fd2Sforsyth 0x05, 0,0, "VERW %e",
30874a4d8c2SCharles.Forsyth };
30974a4d8c2SCharles.Forsyth
31074a4d8c2SCharles.Forsyth static Optable optab0F01[8]=
31174a4d8c2SCharles.Forsyth {
312773d7fd2Sforsyth 0x00, 0,0, "MOVL GDTR,%e",
313773d7fd2Sforsyth 0x01, 0,0, "MOVL IDTR,%e",
314773d7fd2Sforsyth 0x02, 0,0, "MOVL %e,GDTR",
315773d7fd2Sforsyth 0x03, 0,0, "MOVL %e,IDTR",
316773d7fd2Sforsyth 0x04, 0,0, "MOVW MSW,%e", /* word */
317773d7fd2Sforsyth 0x06, 0,0, "MOVW %e,MSW", /* word */
318773d7fd2Sforsyth 0x07, 0,0, "INVLPG %e", /* or SWAPGS */
31974a4d8c2SCharles.Forsyth };
32074a4d8c2SCharles.Forsyth
321d67b7dadSforsyth static Optable optab0F01F8[1]=
322d67b7dadSforsyth {
323773d7fd2Sforsyth 0x00, 0,0, "SWAPGS",
324d67b7dadSforsyth };
325d67b7dadSforsyth
326d67b7dadSforsyth /* 0F71 */
327d67b7dadSforsyth /* 0F72 */
328d67b7dadSforsyth /* 0F73 */
329d67b7dadSforsyth
330d67b7dadSforsyth static Optable optab0FAE[8]=
331d67b7dadSforsyth {
332773d7fd2Sforsyth 0x00, 0,0, "FXSAVE %e",
333773d7fd2Sforsyth 0x01, 0,0, "FXRSTOR %e",
334773d7fd2Sforsyth 0x02, 0,0, "LDMXCSR %e",
335773d7fd2Sforsyth 0x03, 0,0, "STMXCSR %e",
336773d7fd2Sforsyth 0x05, 0,0, "LFENCE",
337773d7fd2Sforsyth 0x06, 0,0, "MFENCE",
338773d7fd2Sforsyth 0x07, 0,0, "SFENCE",
339d67b7dadSforsyth };
340d67b7dadSforsyth
341d67b7dadSforsyth /* 0F18 */
342d67b7dadSforsyth /* 0F0D */
343d67b7dadSforsyth
34474a4d8c2SCharles.Forsyth static Optable optab0FBA[8]=
34574a4d8c2SCharles.Forsyth {
346773d7fd2Sforsyth 0x04, Ib,0, "BT%S %i,%e",
347773d7fd2Sforsyth 0x05, Ib,0, "BTS%S %i,%e",
348773d7fd2Sforsyth 0x06, Ib,0, "BTR%S %i,%e",
349773d7fd2Sforsyth 0x07, Ib,0, "BTC%S %i,%e",
350d67b7dadSforsyth };
351d67b7dadSforsyth
352d67b7dadSforsyth static Optable optab0F0F[256]=
353d67b7dadSforsyth {
354773d7fd2Sforsyth 0x0c, 0,0, "PI2FW %m,%M",
355773d7fd2Sforsyth 0x0d, 0,0, "PI2L %m,%M",
356773d7fd2Sforsyth 0x1c, 0,0, "PF2IW %m,%M",
357773d7fd2Sforsyth 0x1d, 0,0, "PF2IL %m,%M",
358773d7fd2Sforsyth 0x8a, 0,0, "PFNACC %m,%M",
359773d7fd2Sforsyth 0x8e, 0,0, "PFPNACC %m,%M",
360773d7fd2Sforsyth 0x90, 0,0, "PFCMPGE %m,%M",
361773d7fd2Sforsyth 0x94, 0,0, "PFMIN %m,%M",
362773d7fd2Sforsyth 0x96, 0,0, "PFRCP %m,%M",
363773d7fd2Sforsyth 0x97, 0,0, "PFRSQRT %m,%M",
364773d7fd2Sforsyth 0x9a, 0,0, "PFSUB %m,%M",
365773d7fd2Sforsyth 0x9e, 0,0, "PFADD %m,%M",
366773d7fd2Sforsyth 0xa0, 0,0, "PFCMPGT %m,%M",
367773d7fd2Sforsyth 0xa4, 0,0, "PFMAX %m,%M",
368773d7fd2Sforsyth 0xa6, 0,0, "PFRCPIT1 %m,%M",
369773d7fd2Sforsyth 0xa7, 0,0, "PFRSQIT1 %m,%M",
370773d7fd2Sforsyth 0xaa, 0,0, "PFSUBR %m,%M",
371773d7fd2Sforsyth 0xae, 0,0, "PFACC %m,%M",
372773d7fd2Sforsyth 0xb0, 0,0, "PFCMPEQ %m,%M",
373773d7fd2Sforsyth 0xb4, 0,0, "PFMUL %m,%M",
374773d7fd2Sforsyth 0xb6, 0,0, "PFRCPI2T %m,%M",
375773d7fd2Sforsyth 0xb7, 0,0, "PMULHRW %m,%M",
376773d7fd2Sforsyth 0xbb, 0,0, "PSWAPL %m,%M",
377d67b7dadSforsyth };
378d67b7dadSforsyth
379d67b7dadSforsyth static Optable optab0FC7[8]=
380d67b7dadSforsyth {
381773d7fd2Sforsyth 0x01, 0,0, "CMPXCHG8B %e",
382d67b7dadSforsyth };
383d67b7dadSforsyth
384d67b7dadSforsyth static Optable optab660F71[8]=
385d67b7dadSforsyth {
386773d7fd2Sforsyth 0x02, Ib,0, "PSRLW %i,%X",
387773d7fd2Sforsyth 0x04, Ib,0, "PSRAW %i,%X",
388773d7fd2Sforsyth 0x06, Ib,0, "PSLLW %i,%X",
389d67b7dadSforsyth };
390d67b7dadSforsyth
391d67b7dadSforsyth static Optable optab660F72[8]=
392d67b7dadSforsyth {
393773d7fd2Sforsyth 0x02, Ib,0, "PSRLL %i,%X",
394773d7fd2Sforsyth 0x04, Ib,0, "PSRAL %i,%X",
395773d7fd2Sforsyth 0x06, Ib,0, "PSLLL %i,%X",
396d67b7dadSforsyth };
397d67b7dadSforsyth
398d67b7dadSforsyth static Optable optab660F73[8]=
399d67b7dadSforsyth {
400773d7fd2Sforsyth 0x02, Ib,0, "PSRLQ %i,%X",
401773d7fd2Sforsyth 0x03, Ib,0, "PSRLO %i,%X",
402773d7fd2Sforsyth 0x06, Ib,0, "PSLLQ %i,%X",
403773d7fd2Sforsyth 0x07, Ib,0, "PSLLO %i,%X",
404d67b7dadSforsyth };
405d67b7dadSforsyth
406d67b7dadSforsyth static Optable optab660F[256]=
407d67b7dadSforsyth {
408773d7fd2Sforsyth 0x2B, RM,0, "MOVNTPD %x,%e",
409773d7fd2Sforsyth 0x2E, RM,0, "UCOMISD %x,%X",
410773d7fd2Sforsyth 0x2F, RM,0, "COMISD %x,%X",
411773d7fd2Sforsyth 0x5A, RM,0, "CVTPD2PS %x,%X",
412773d7fd2Sforsyth 0x5B, RM,0, "CVTPS2PL %x,%X",
413773d7fd2Sforsyth 0x6A, RM,0, "PUNPCKHLQ %x,%X",
414773d7fd2Sforsyth 0x6B, RM,0, "PACKSSLW %x,%X",
415773d7fd2Sforsyth 0x6C, RM,0, "PUNPCKLQDQ %x,%X",
416773d7fd2Sforsyth 0x6D, RM,0, "PUNPCKHQDQ %x,%X",
417773d7fd2Sforsyth 0x6E, RM,0, "MOV%S %e,%X",
418773d7fd2Sforsyth 0x6F, RM,0, "MOVO %x,%X", /* MOVDQA */
419773d7fd2Sforsyth 0x70, RM,Ib, "PSHUFL %i,%x,%X",
420773d7fd2Sforsyth 0x71, RMOP,0, optab660F71,
421773d7fd2Sforsyth 0x72, RMOP,0, optab660F72,
422773d7fd2Sforsyth 0x73, RMOP,0, optab660F73,
423773d7fd2Sforsyth 0x7E, RM,0, "MOV%S %X,%e",
424773d7fd2Sforsyth 0x7F, RM,0, "MOVO %X,%x",
425773d7fd2Sforsyth 0xC4, RM,Ib, "PINSRW %i,%e,%X",
426773d7fd2Sforsyth 0xC5, RMR,Ib, "PEXTRW %i,%X,%e",
427773d7fd2Sforsyth 0xD4, RM,0, "PADDQ %x,%X",
428773d7fd2Sforsyth 0xD5, RM,0, "PMULLW %x,%X",
429773d7fd2Sforsyth 0xD6, RM,0, "MOVQ %X,%x",
430773d7fd2Sforsyth 0xE6, RM,0, "CVTTPD2PL %x,%X",
431773d7fd2Sforsyth 0xE7, RM,0, "MOVNTO %X,%e",
432773d7fd2Sforsyth 0xF7, RM,0, "MASKMOVOU %x,%X",
433d67b7dadSforsyth };
434d67b7dadSforsyth
435d67b7dadSforsyth static Optable optabF20F[256]=
436d67b7dadSforsyth {
437773d7fd2Sforsyth 0x10, RM,0, "MOVSD %x,%X",
438773d7fd2Sforsyth 0x11, RM,0, "MOVSD %X,%x",
439773d7fd2Sforsyth 0x2A, RM,0, "CVTS%S2SD %e,%X",
440773d7fd2Sforsyth 0x2C, RM,0, "CVTTSD2S%S %x,%r",
441773d7fd2Sforsyth 0x2D, RM,0, "CVTSD2S%S %x,%r",
442773d7fd2Sforsyth 0x5A, RM,0, "CVTSD2SS %x,%X",
443773d7fd2Sforsyth 0x6F, RM,0, "MOVOU %x,%X",
444773d7fd2Sforsyth 0x70, RM,Ib, "PSHUFLW %i,%x,%X",
445773d7fd2Sforsyth 0x7F, RM,0, "MOVOU %X,%x",
446773d7fd2Sforsyth 0xD6, RM,0, "MOVQOZX %M,%X",
447773d7fd2Sforsyth 0xE6, RM,0, "CVTPD2PL %x,%X",
448d67b7dadSforsyth };
449d67b7dadSforsyth
450d67b7dadSforsyth static Optable optabF30F[256]=
451d67b7dadSforsyth {
452773d7fd2Sforsyth 0x10, RM,0, "MOVSS %x,%X",
453773d7fd2Sforsyth 0x11, RM,0, "MOVSS %X,%x",
454773d7fd2Sforsyth 0x2A, RM,0, "CVTS%S2SS %e,%X",
455773d7fd2Sforsyth 0x2C, RM,0, "CVTTSS2S%S %x,%r",
456773d7fd2Sforsyth 0x2D, RM,0, "CVTSS2S%S %x,%r",
457773d7fd2Sforsyth 0x5A, RM,0, "CVTSS2SD %x,%X",
458773d7fd2Sforsyth 0x5B, RM,0, "CVTTPS2PL %x,%X",
459773d7fd2Sforsyth 0x6F, RM,0, "MOVOU %x,%X",
460773d7fd2Sforsyth 0x70, RM,Ib, "PSHUFHW %i,%x,%X",
461773d7fd2Sforsyth 0x7E, RM,0, "MOVQOZX %x,%X",
462773d7fd2Sforsyth 0x7F, RM,0, "MOVOU %X,%x",
463773d7fd2Sforsyth 0xD6, RM,0, "MOVQOZX %m*,%X",
464773d7fd2Sforsyth 0xE6, RM,0, "CVTPL2PD %x,%X",
46574a4d8c2SCharles.Forsyth };
46674a4d8c2SCharles.Forsyth
46774a4d8c2SCharles.Forsyth static Optable optab0F[256]=
46874a4d8c2SCharles.Forsyth {
469773d7fd2Sforsyth 0x00, RMOP,0, optab0F00,
470773d7fd2Sforsyth 0x01, RMOP,0, optab0F01,
471773d7fd2Sforsyth 0x02, RM,0, "LAR %e,%r",
472773d7fd2Sforsyth 0x03, RM,0, "LSL %e,%r",
473773d7fd2Sforsyth 0x05, 0,0, "SYSCALL",
474773d7fd2Sforsyth 0x06, 0,0, "CLTS",
475773d7fd2Sforsyth 0x07, 0,0, "SYSRET",
476773d7fd2Sforsyth 0x08, 0,0, "INVD",
477773d7fd2Sforsyth 0x09, 0,0, "WBINVD",
478773d7fd2Sforsyth 0x0B, 0,0, "UD2",
479773d7fd2Sforsyth 0x0F, RM,AUX, optab0F0F, /* 3DNow! */
480773d7fd2Sforsyth 0x10, RM,0, "MOVU%s %x,%X",
481773d7fd2Sforsyth 0x11, RM,0, "MOVU%s %X,%x",
482773d7fd2Sforsyth 0x12, RM,0, "MOV[H]L%s %x,%X", /* TO DO: H if source is XMM */
483773d7fd2Sforsyth 0x13, RM,0, "MOVL%s %X,%e",
484773d7fd2Sforsyth 0x14, RM,0, "UNPCKL%s %x,%X",
485773d7fd2Sforsyth 0x15, RM,0, "UNPCKH%s %x,%X",
486773d7fd2Sforsyth 0x16, RM,0, "MOV[L]H%s %x,%X", /* TO DO: L if source is XMM */
487773d7fd2Sforsyth 0x17, RM,0, "MOVH%s %X,%x",
488773d7fd2Sforsyth 0x20, RMR,0, "MOVL %C,%e",
489773d7fd2Sforsyth 0x21, RMR,0, "MOVL %D,%e",
490773d7fd2Sforsyth 0x22, RMR,0, "MOVL %e,%C",
491773d7fd2Sforsyth 0x23, RMR,0, "MOVL %e,%D",
492773d7fd2Sforsyth 0x24, RMR,0, "MOVL %T,%e",
493773d7fd2Sforsyth 0x26, RMR,0, "MOVL %e,%T",
494773d7fd2Sforsyth 0x28, RM,0, "MOVA%s %x,%X",
495773d7fd2Sforsyth 0x29, RM,0, "MOVA%s %X,%x",
496773d7fd2Sforsyth 0x2A, RM,0, "CVTPL2%s %m*,%X",
497773d7fd2Sforsyth 0x2B, RM,0, "MOVNT%s %X,%e",
498773d7fd2Sforsyth 0x2C, RM,0, "CVTT%s2PL %x,%M",
499773d7fd2Sforsyth 0x2D, RM,0, "CVT%s2PL %x,%M",
500773d7fd2Sforsyth 0x2E, RM,0, "UCOMISS %x,%X",
501773d7fd2Sforsyth 0x2F, RM,0, "COMISS %x,%X",
502773d7fd2Sforsyth 0x30, 0,0, "WRMSR",
503773d7fd2Sforsyth 0x31, 0,0, "RDTSC",
504773d7fd2Sforsyth 0x32, 0,0, "RDMSR",
505773d7fd2Sforsyth 0x33, 0,0, "RDPMC",
506773d7fd2Sforsyth 0x42, RM,0, "CMOVC %e,%r", /* CF */
507773d7fd2Sforsyth 0x43, RM,0, "CMOVNC %e,%r", /* ¬ CF */
508773d7fd2Sforsyth 0x44, RM,0, "CMOVZ %e,%r", /* ZF */
509773d7fd2Sforsyth 0x45, RM,0, "CMOVNZ %e,%r", /* ¬ ZF */
510773d7fd2Sforsyth 0x46, RM,0, "CMOVBE %e,%r", /* CF ∨ ZF */
511773d7fd2Sforsyth 0x47, RM,0, "CMOVA %e,%r", /* ¬CF ∧ ¬ZF */
512773d7fd2Sforsyth 0x48, RM,0, "CMOVS %e,%r", /* SF */
513773d7fd2Sforsyth 0x49, RM,0, "CMOVNS %e,%r", /* ¬ SF */
514773d7fd2Sforsyth 0x4A, RM,0, "CMOVP %e,%r", /* PF */
515773d7fd2Sforsyth 0x4B, RM,0, "CMOVNP %e,%r", /* ¬ PF */
516773d7fd2Sforsyth 0x4C, RM,0, "CMOVLT %e,%r", /* LT ≡ OF ≠ SF */
517773d7fd2Sforsyth 0x4D, RM,0, "CMOVGE %e,%r", /* GE ≡ ZF ∨ SF */
518773d7fd2Sforsyth 0x4E, RM,0, "CMOVLE %e,%r", /* LE ≡ ZF ∨ LT */
519773d7fd2Sforsyth 0x4F, RM,0, "CMOVGT %e,%r", /* GT ≡ ¬ZF ∧ GE */
520773d7fd2Sforsyth 0x50, RM,0, "MOVMSK%s %X,%r", /* TO DO: check */
521773d7fd2Sforsyth 0x51, RM,0, "SQRT%s %x,%X",
522773d7fd2Sforsyth 0x52, RM,0, "RSQRT%s %x,%X",
523773d7fd2Sforsyth 0x53, RM,0, "RCP%s %x,%X",
524773d7fd2Sforsyth 0x54, RM,0, "AND%s %x,%X",
525773d7fd2Sforsyth 0x55, RM,0, "ANDN%s %x,%X",
526773d7fd2Sforsyth 0x56, RM,0, "OR%s %x,%X", /* TO DO: S/D */
527773d7fd2Sforsyth 0x57, RM,0, "XOR%s %x,%X", /* S/D */
528773d7fd2Sforsyth 0x58, RM,0, "ADD%s %x,%X", /* S/P S/D */
529773d7fd2Sforsyth 0x59, RM,0, "MUL%s %x,%X",
530773d7fd2Sforsyth 0x5A, RM,0, "CVTPS2PD %x,%X",
531773d7fd2Sforsyth 0x5B, RM,0, "CVTPL2PS %x,%X",
532773d7fd2Sforsyth 0x5C, RM,0, "SUB%s %x,%X",
533773d7fd2Sforsyth 0x5D, RM,0, "MIN%s %x,%X",
534773d7fd2Sforsyth 0x5E, RM,0, "DIV%s %x,%X", /* TO DO: S/P S/D */
535773d7fd2Sforsyth 0x5F, RM,0, "MAX%s %x,%X",
536773d7fd2Sforsyth 0x60, RM,0, "PUNPCKLBW %m,%M",
537773d7fd2Sforsyth 0x61, RM,0, "PUNPCKLWL %m,%M",
538773d7fd2Sforsyth 0x62, RM,0, "PUNPCKLLQ %m,%M",
539773d7fd2Sforsyth 0x63, RM,0, "PACKSSWB %m,%M",
540773d7fd2Sforsyth 0x64, RM,0, "PCMPGTB %m,%M",
541773d7fd2Sforsyth 0x65, RM,0, "PCMPGTW %m,%M",
542773d7fd2Sforsyth 0x66, RM,0, "PCMPGTL %m,%M",
543773d7fd2Sforsyth 0x67, RM,0, "PACKUSWB %m,%M",
544773d7fd2Sforsyth 0x68, RM,0, "PUNPCKHBW %m,%M",
545773d7fd2Sforsyth 0x69, RM,0, "PUNPCKHWL %m,%M",
546773d7fd2Sforsyth 0x6A, RM,0, "PUNPCKHLQ %m,%M",
547773d7fd2Sforsyth 0x6B, RM,0, "PACKSSLW %m,%M",
548773d7fd2Sforsyth 0x6E, RM,0, "MOV%S %e,%M",
549773d7fd2Sforsyth 0x6F, RM,0, "MOVQ %m,%M",
550773d7fd2Sforsyth 0x70, RM,Ib, "PSHUFW %i,%m,%M",
551773d7fd2Sforsyth 0x74, RM,0, "PCMPEQB %m,%M",
552773d7fd2Sforsyth 0x75, RM,0, "PCMPEQW %m,%M",
553773d7fd2Sforsyth 0x76, RM,0, "PCMPEQL %m,%M",
554773d7fd2Sforsyth 0x7E, RM,0, "MOV%S %M,%e",
555773d7fd2Sforsyth 0x7F, RM,0, "MOVQ %M,%m",
556773d7fd2Sforsyth 0xAE, RMOP,0, optab0FAE,
557773d7fd2Sforsyth 0xAA, 0,0, "RSM",
558773d7fd2Sforsyth 0xB0, RM,0, "CMPXCHGB %r,%e",
559773d7fd2Sforsyth 0xB1, RM,0, "CMPXCHG%S %r,%e",
560773d7fd2Sforsyth 0xC0, RMB,0, "XADDB %r,%e",
561773d7fd2Sforsyth 0xC1, RM,0, "XADD%S %r,%e",
562773d7fd2Sforsyth 0xC2, RM,Ib, "CMP%s %i,%x,%X",
563773d7fd2Sforsyth 0xC3, RM,0, "MOVNTI%S %r,%e",
564773d7fd2Sforsyth 0xC6, RM,Ib, "SHUF%s %i,%x,%X",
565773d7fd2Sforsyth 0xC8, 0,0, "BSWAP AX",
566773d7fd2Sforsyth 0xC9, 0,0, "BSWAP CX",
567773d7fd2Sforsyth 0xCA, 0,0, "BSWAP DX",
568773d7fd2Sforsyth 0xCB, 0,0, "BSWAP BX",
569773d7fd2Sforsyth 0xCC, 0,0, "BSWAP SP",
570773d7fd2Sforsyth 0xCD, 0,0, "BSWAP BP",
571773d7fd2Sforsyth 0xCE, 0,0, "BSWAP SI",
572773d7fd2Sforsyth 0xCF, 0,0, "BSWAP DI",
573773d7fd2Sforsyth 0xD1, RM,0, "PSRLW %m,%M",
574773d7fd2Sforsyth 0xD2, RM,0, "PSRLL %m,%M",
575773d7fd2Sforsyth 0xD3, RM,0, "PSRLQ %m,%M",
576773d7fd2Sforsyth 0xD5, RM,0, "PMULLW %m,%M",
577773d7fd2Sforsyth 0xD6, RM,0, "MOVQOZX %m*,%X",
578773d7fd2Sforsyth 0xD7, RM,0, "PMOVMSKB %m,%r",
579773d7fd2Sforsyth 0xD8, RM,0, "PSUBUSB %m,%M",
580773d7fd2Sforsyth 0xD9, RM,0, "PSUBUSW %m,%M",
581773d7fd2Sforsyth 0xDA, RM,0, "PMINUB %m,%M",
582773d7fd2Sforsyth 0xDB, RM,0, "PAND %m,%M",
583773d7fd2Sforsyth 0xDC, RM,0, "PADDUSB %m,%M",
584773d7fd2Sforsyth 0xDD, RM,0, "PADDUSW %m,%M",
585773d7fd2Sforsyth 0xDE, RM,0, "PMAXUB %m,%M",
586773d7fd2Sforsyth 0xDF, RM,0, "PANDN %m,%M",
587773d7fd2Sforsyth 0xE0, RM,0, "PAVGB %m,%M",
588773d7fd2Sforsyth 0xE1, RM,0, "PSRAW %m,%M",
589773d7fd2Sforsyth 0xE2, RM,0, "PSRAL %m,%M",
590773d7fd2Sforsyth 0xE3, RM,0, "PAVGW %m,%M",
591773d7fd2Sforsyth 0xE4, RM,0, "PMULHUW %m,%M",
592773d7fd2Sforsyth 0xE5, RM,0, "PMULHW %m,%M",
593773d7fd2Sforsyth 0xE7, RM,0, "MOVNTQ %M,%e",
594773d7fd2Sforsyth 0xE8, RM,0, "PSUBSB %m,%M",
595773d7fd2Sforsyth 0xE9, RM,0, "PSUBSW %m,%M",
596773d7fd2Sforsyth 0xEA, RM,0, "PMINSW %m,%M",
597773d7fd2Sforsyth 0xEB, RM,0, "POR %m,%M",
598773d7fd2Sforsyth 0xEC, RM,0, "PADDSB %m,%M",
599773d7fd2Sforsyth 0xED, RM,0, "PADDSW %m,%M",
600773d7fd2Sforsyth 0xEE, RM,0, "PMAXSW %m,%M",
601773d7fd2Sforsyth 0xEF, RM,0, "PXOR %m,%M",
602773d7fd2Sforsyth 0xF1, RM,0, "PSLLW %m,%M",
603773d7fd2Sforsyth 0xF2, RM,0, "PSLLL %m,%M",
604773d7fd2Sforsyth 0xF3, RM,0, "PSLLQ %m,%M",
605773d7fd2Sforsyth 0xF4, RM,0, "PMULULQ %m,%M",
606773d7fd2Sforsyth 0xF5, RM,0, "PMADDWL %m,%M",
607773d7fd2Sforsyth 0xF6, RM,0, "PSADBW %m,%M",
608773d7fd2Sforsyth 0xF7, RMR,0, "MASKMOVQ %m,%M",
609773d7fd2Sforsyth 0xF8, RM,0, "PSUBB %m,%M",
610773d7fd2Sforsyth 0xF9, RM,0, "PSUBW %m,%M",
611773d7fd2Sforsyth 0xFA, RM,0, "PSUBL %m,%M",
612773d7fd2Sforsyth 0xFC, RM,0, "PADDB %m,%M",
613773d7fd2Sforsyth 0xFD, RM,0, "PADDW %m,%M",
614773d7fd2Sforsyth 0xFE, RM,0, "PADDL %m,%M",
615d67b7dadSforsyth
616773d7fd2Sforsyth 0x80, Iwds,0, "JOS %p",
617773d7fd2Sforsyth 0x81, Iwds,0, "JOC %p",
618773d7fd2Sforsyth 0x82, Iwds,0, "JCS %p",
619773d7fd2Sforsyth 0x83, Iwds,0, "JCC %p",
620773d7fd2Sforsyth 0x84, Iwds,0, "JEQ %p",
621773d7fd2Sforsyth 0x85, Iwds,0, "JNE %p",
622773d7fd2Sforsyth 0x86, Iwds,0, "JLS %p",
623773d7fd2Sforsyth 0x87, Iwds,0, "JHI %p",
624773d7fd2Sforsyth 0x88, Iwds,0, "JMI %p",
625773d7fd2Sforsyth 0x89, Iwds,0, "JPL %p",
626773d7fd2Sforsyth 0x8a, Iwds,0, "JPS %p",
627773d7fd2Sforsyth 0x8b, Iwds,0, "JPC %p",
628773d7fd2Sforsyth 0x8c, Iwds,0, "JLT %p",
629773d7fd2Sforsyth 0x8d, Iwds,0, "JGE %p",
630773d7fd2Sforsyth 0x8e, Iwds,0, "JLE %p",
631773d7fd2Sforsyth 0x8f, Iwds,0, "JGT %p",
632773d7fd2Sforsyth 0x90, RMB,0, "SETOS %e",
633773d7fd2Sforsyth 0x91, RMB,0, "SETOC %e",
634773d7fd2Sforsyth 0x92, RMB,0, "SETCS %e",
635773d7fd2Sforsyth 0x93, RMB,0, "SETCC %e",
636773d7fd2Sforsyth 0x94, RMB,0, "SETEQ %e",
637773d7fd2Sforsyth 0x95, RMB,0, "SETNE %e",
638773d7fd2Sforsyth 0x96, RMB,0, "SETLS %e",
639773d7fd2Sforsyth 0x97, RMB,0, "SETHI %e",
640773d7fd2Sforsyth 0x98, RMB,0, "SETMI %e",
641773d7fd2Sforsyth 0x99, RMB,0, "SETPL %e",
642773d7fd2Sforsyth 0x9a, RMB,0, "SETPS %e",
643773d7fd2Sforsyth 0x9b, RMB,0, "SETPC %e",
644773d7fd2Sforsyth 0x9c, RMB,0, "SETLT %e",
645773d7fd2Sforsyth 0x9d, RMB,0, "SETGE %e",
646773d7fd2Sforsyth 0x9e, RMB,0, "SETLE %e",
647773d7fd2Sforsyth 0x9f, RMB,0, "SETGT %e",
648773d7fd2Sforsyth 0xa0, 0,0, "PUSHL FS",
649773d7fd2Sforsyth 0xa1, 0,0, "POPL FS",
650773d7fd2Sforsyth 0xa2, 0,0, "CPUID",
651773d7fd2Sforsyth 0xa3, RM,0, "BT%S %r,%e",
652773d7fd2Sforsyth 0xa4, RM,Ib, "SHLD%S %r,%i,%e",
653773d7fd2Sforsyth 0xa5, RM,0, "SHLD%S %r,CL,%e",
654773d7fd2Sforsyth 0xa8, 0,0, "PUSHL GS",
655773d7fd2Sforsyth 0xa9, 0,0, "POPL GS",
656773d7fd2Sforsyth 0xab, RM,0, "BTS%S %r,%e",
657773d7fd2Sforsyth 0xac, RM,Ib, "SHRD%S %r,%i,%e",
658773d7fd2Sforsyth 0xad, RM,0, "SHRD%S %r,CL,%e",
659773d7fd2Sforsyth 0xaf, RM,0, "IMUL%S %e,%r",
660773d7fd2Sforsyth 0xb2, RMM,0, "LSS %e,%r",
661773d7fd2Sforsyth 0xb3, RM,0, "BTR%S %r,%e",
662773d7fd2Sforsyth 0xb4, RMM,0, "LFS %e,%r",
663773d7fd2Sforsyth 0xb5, RMM,0, "LGS %e,%r",
664773d7fd2Sforsyth 0xb6, RMB,0, "MOVBZX %e,%R",
665773d7fd2Sforsyth 0xb7, RM,0, "MOVWZX %e,%R",
666773d7fd2Sforsyth 0xba, RMOP,0, optab0FBA,
667773d7fd2Sforsyth 0xbb, RM,0, "BTC%S %e,%r",
668773d7fd2Sforsyth 0xbc, RM,0, "BSF%S %e,%r",
669773d7fd2Sforsyth 0xbd, RM,0, "BSR%S %e,%r",
670773d7fd2Sforsyth 0xbe, RMB,0, "MOVBSX %e,%R",
671773d7fd2Sforsyth 0xbf, RM,0, "MOVWSX %e,%R",
672773d7fd2Sforsyth 0xc7, RMOP,0, optab0FC7,
67374a4d8c2SCharles.Forsyth };
67474a4d8c2SCharles.Forsyth
67574a4d8c2SCharles.Forsyth static Optable optab80[8]=
67674a4d8c2SCharles.Forsyth {
677773d7fd2Sforsyth 0x00, Ib,0, "ADDB %i,%e",
678773d7fd2Sforsyth 0x01, Ib,0, "ORB %i,%e",
679773d7fd2Sforsyth 0x02, Ib,0, "ADCB %i,%e",
680773d7fd2Sforsyth 0x03, Ib,0, "SBBB %i,%e",
681773d7fd2Sforsyth 0x04, Ib,0, "ANDB %i,%e",
682773d7fd2Sforsyth 0x05, Ib,0, "SUBB %i,%e",
683773d7fd2Sforsyth 0x06, Ib,0, "XORB %i,%e",
684773d7fd2Sforsyth 0x07, Ib,0, "CMPB %e,%i",
68574a4d8c2SCharles.Forsyth };
68674a4d8c2SCharles.Forsyth
68774a4d8c2SCharles.Forsyth static Optable optab81[8]=
68874a4d8c2SCharles.Forsyth {
689773d7fd2Sforsyth 0x00, Iwd,0, "ADD%S %i,%e",
690773d7fd2Sforsyth 0x01, Iwd,0, "OR%S %i,%e",
691773d7fd2Sforsyth 0x02, Iwd,0, "ADC%S %i,%e",
692773d7fd2Sforsyth 0x03, Iwd,0, "SBB%S %i,%e",
693773d7fd2Sforsyth 0x04, Iwd,0, "AND%S %i,%e",
694773d7fd2Sforsyth 0x05, Iwd,0, "SUB%S %i,%e",
695773d7fd2Sforsyth 0x06, Iwd,0, "XOR%S %i,%e",
696773d7fd2Sforsyth 0x07, Iwd,0, "CMP%S %e,%i",
69774a4d8c2SCharles.Forsyth };
69874a4d8c2SCharles.Forsyth
69974a4d8c2SCharles.Forsyth static Optable optab83[8]=
70074a4d8c2SCharles.Forsyth {
701773d7fd2Sforsyth 0x00, Ibs,0, "ADD%S %i,%e",
702773d7fd2Sforsyth 0x01, Ibs,0, "OR%S %i,%e",
703773d7fd2Sforsyth 0x02, Ibs,0, "ADC%S %i,%e",
704773d7fd2Sforsyth 0x03, Ibs,0, "SBB%S %i,%e",
705773d7fd2Sforsyth 0x04, Ibs,0, "AND%S %i,%e",
706773d7fd2Sforsyth 0x05, Ibs,0, "SUB%S %i,%e",
707773d7fd2Sforsyth 0x06, Ibs,0, "XOR%S %i,%e",
708773d7fd2Sforsyth 0x07, Ibs,0, "CMP%S %e,%i",
70974a4d8c2SCharles.Forsyth };
71074a4d8c2SCharles.Forsyth
71174a4d8c2SCharles.Forsyth static Optable optabC0[8] =
71274a4d8c2SCharles.Forsyth {
713773d7fd2Sforsyth 0x00, Ib,0, "ROLB %i,%e",
714773d7fd2Sforsyth 0x01, Ib,0, "RORB %i,%e",
715773d7fd2Sforsyth 0x02, Ib,0, "RCLB %i,%e",
716773d7fd2Sforsyth 0x03, Ib,0, "RCRB %i,%e",
717773d7fd2Sforsyth 0x04, Ib,0, "SHLB %i,%e",
718773d7fd2Sforsyth 0x05, Ib,0, "SHRB %i,%e",
719773d7fd2Sforsyth 0x07, Ib,0, "SARB %i,%e",
72074a4d8c2SCharles.Forsyth };
72174a4d8c2SCharles.Forsyth
72274a4d8c2SCharles.Forsyth static Optable optabC1[8] =
72374a4d8c2SCharles.Forsyth {
724773d7fd2Sforsyth 0x00, Ib,0, "ROL%S %i,%e",
725773d7fd2Sforsyth 0x01, Ib,0, "ROR%S %i,%e",
726773d7fd2Sforsyth 0x02, Ib,0, "RCL%S %i,%e",
727773d7fd2Sforsyth 0x03, Ib,0, "RCR%S %i,%e",
728773d7fd2Sforsyth 0x04, Ib,0, "SHL%S %i,%e",
729773d7fd2Sforsyth 0x05, Ib,0, "SHR%S %i,%e",
730773d7fd2Sforsyth 0x07, Ib,0, "SAR%S %i,%e",
73174a4d8c2SCharles.Forsyth };
73274a4d8c2SCharles.Forsyth
73374a4d8c2SCharles.Forsyth static Optable optabD0[8] =
73474a4d8c2SCharles.Forsyth {
735773d7fd2Sforsyth 0x00, 0,0, "ROLB %e",
736773d7fd2Sforsyth 0x01, 0,0, "RORB %e",
737773d7fd2Sforsyth 0x02, 0,0, "RCLB %e",
738773d7fd2Sforsyth 0x03, 0,0, "RCRB %e",
739773d7fd2Sforsyth 0x04, 0,0, "SHLB %e",
740773d7fd2Sforsyth 0x05, 0,0, "SHRB %e",
741773d7fd2Sforsyth 0x07, 0,0, "SARB %e",
74274a4d8c2SCharles.Forsyth };
74374a4d8c2SCharles.Forsyth
74474a4d8c2SCharles.Forsyth static Optable optabD1[8] =
74574a4d8c2SCharles.Forsyth {
746773d7fd2Sforsyth 0x00, 0,0, "ROL%S %e",
747773d7fd2Sforsyth 0x01, 0,0, "ROR%S %e",
748773d7fd2Sforsyth 0x02, 0,0, "RCL%S %e",
749773d7fd2Sforsyth 0x03, 0,0, "RCR%S %e",
750773d7fd2Sforsyth 0x04, 0,0, "SHL%S %e",
751773d7fd2Sforsyth 0x05, 0,0, "SHR%S %e",
752773d7fd2Sforsyth 0x07, 0,0, "SAR%S %e",
75374a4d8c2SCharles.Forsyth };
75474a4d8c2SCharles.Forsyth
75574a4d8c2SCharles.Forsyth static Optable optabD2[8] =
75674a4d8c2SCharles.Forsyth {
757773d7fd2Sforsyth 0x00, 0,0, "ROLB CL,%e",
758773d7fd2Sforsyth 0x01, 0,0, "RORB CL,%e",
759773d7fd2Sforsyth 0x02, 0,0, "RCLB CL,%e",
760773d7fd2Sforsyth 0x03, 0,0, "RCRB CL,%e",
761773d7fd2Sforsyth 0x04, 0,0, "SHLB CL,%e",
762773d7fd2Sforsyth 0x05, 0,0, "SHRB CL,%e",
763773d7fd2Sforsyth 0x07, 0,0, "SARB CL,%e",
76474a4d8c2SCharles.Forsyth };
76574a4d8c2SCharles.Forsyth
76674a4d8c2SCharles.Forsyth static Optable optabD3[8] =
76774a4d8c2SCharles.Forsyth {
768773d7fd2Sforsyth 0x00, 0,0, "ROL%S CL,%e",
769773d7fd2Sforsyth 0x01, 0,0, "ROR%S CL,%e",
770773d7fd2Sforsyth 0x02, 0,0, "RCL%S CL,%e",
771773d7fd2Sforsyth 0x03, 0,0, "RCR%S CL,%e",
772773d7fd2Sforsyth 0x04, 0,0, "SHL%S CL,%e",
773773d7fd2Sforsyth 0x05, 0,0, "SHR%S CL,%e",
774773d7fd2Sforsyth 0x07, 0,0, "SAR%S CL,%e",
77574a4d8c2SCharles.Forsyth };
77674a4d8c2SCharles.Forsyth
77774a4d8c2SCharles.Forsyth static Optable optabD8[8+8] =
77874a4d8c2SCharles.Forsyth {
779773d7fd2Sforsyth 0x00, 0,0, "FADDF %e,F0",
780773d7fd2Sforsyth 0x01, 0,0, "FMULF %e,F0",
781773d7fd2Sforsyth 0x02, 0,0, "FCOMF %e,F0",
782773d7fd2Sforsyth 0x03, 0,0, "FCOMFP %e,F0",
783773d7fd2Sforsyth 0x04, 0,0, "FSUBF %e,F0",
784773d7fd2Sforsyth 0x05, 0,0, "FSUBRF %e,F0",
785773d7fd2Sforsyth 0x06, 0,0, "FDIVF %e,F0",
786773d7fd2Sforsyth 0x07, 0,0, "FDIVRF %e,F0",
787773d7fd2Sforsyth 0x08, 0,0, "FADDD %f,F0",
788773d7fd2Sforsyth 0x09, 0,0, "FMULD %f,F0",
789773d7fd2Sforsyth 0x0a, 0,0, "FCOMD %f,F0",
790773d7fd2Sforsyth 0x0b, 0,0, "FCOMPD %f,F0",
791773d7fd2Sforsyth 0x0c, 0,0, "FSUBD %f,F0",
792773d7fd2Sforsyth 0x0d, 0,0, "FSUBRD %f,F0",
793773d7fd2Sforsyth 0x0e, 0,0, "FDIVD %f,F0",
794773d7fd2Sforsyth 0x0f, 0,0, "FDIVRD %f,F0",
79574a4d8c2SCharles.Forsyth };
79674a4d8c2SCharles.Forsyth /*
79774a4d8c2SCharles.Forsyth * optabD9 and optabDB use the following encoding:
79874a4d8c2SCharles.Forsyth * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
79974a4d8c2SCharles.Forsyth * else instruction = optabDx[(modrm&0x3f)+8];
80074a4d8c2SCharles.Forsyth *
80174a4d8c2SCharles.Forsyth * the instructions for MOD == 3, follow the 8 instructions
80274a4d8c2SCharles.Forsyth * for the other MOD values stored at the front of the table.
80374a4d8c2SCharles.Forsyth */
80474a4d8c2SCharles.Forsyth static Optable optabD9[64+8] =
80574a4d8c2SCharles.Forsyth {
806773d7fd2Sforsyth 0x00, 0,0, "FMOVF %e,F0",
807773d7fd2Sforsyth 0x02, 0,0, "FMOVF F0,%e",
808773d7fd2Sforsyth 0x03, 0,0, "FMOVFP F0,%e",
809773d7fd2Sforsyth 0x04, 0,0, "FLDENV%S %e",
810773d7fd2Sforsyth 0x05, 0,0, "FLDCW %e",
811773d7fd2Sforsyth 0x06, 0,0, "FSTENV%S %e",
812773d7fd2Sforsyth 0x07, 0,0, "FSTCW %e",
813773d7fd2Sforsyth 0x08, 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
814773d7fd2Sforsyth 0x09, 0,0, "FMOVD F1,F0",
815773d7fd2Sforsyth 0x0a, 0,0, "FMOVD F2,F0",
816773d7fd2Sforsyth 0x0b, 0,0, "FMOVD F3,F0",
817773d7fd2Sforsyth 0x0c, 0,0, "FMOVD F4,F0",
818773d7fd2Sforsyth 0x0d, 0,0, "FMOVD F5,F0",
819773d7fd2Sforsyth 0x0e, 0,0, "FMOVD F6,F0",
820773d7fd2Sforsyth 0x0f, 0,0, "FMOVD F7,F0",
821773d7fd2Sforsyth 0x10, 0,0, "FXCHD F0,F0",
822773d7fd2Sforsyth 0x11, 0,0, "FXCHD F1,F0",
823773d7fd2Sforsyth 0x12, 0,0, "FXCHD F2,F0",
824773d7fd2Sforsyth 0x13, 0,0, "FXCHD F3,F0",
825773d7fd2Sforsyth 0x14, 0,0, "FXCHD F4,F0",
826773d7fd2Sforsyth 0x15, 0,0, "FXCHD F5,F0",
827773d7fd2Sforsyth 0x16, 0,0, "FXCHD F6,F0",
828773d7fd2Sforsyth 0x17, 0,0, "FXCHD F7,F0",
829773d7fd2Sforsyth 0x18, 0,0, "FNOP",
830773d7fd2Sforsyth 0x28, 0,0, "FCHS",
831773d7fd2Sforsyth 0x29, 0,0, "FABS",
832773d7fd2Sforsyth 0x2c, 0,0, "FTST",
833773d7fd2Sforsyth 0x2d, 0,0, "FXAM",
834773d7fd2Sforsyth 0x30, 0,0, "FLD1",
835773d7fd2Sforsyth 0x31, 0,0, "FLDL2T",
836773d7fd2Sforsyth 0x32, 0,0, "FLDL2E",
837773d7fd2Sforsyth 0x33, 0,0, "FLDPI",
838773d7fd2Sforsyth 0x34, 0,0, "FLDLG2",
839773d7fd2Sforsyth 0x35, 0,0, "FLDLN2",
840773d7fd2Sforsyth 0x36, 0,0, "FLDZ",
841773d7fd2Sforsyth 0x38, 0,0, "F2XM1",
842773d7fd2Sforsyth 0x39, 0,0, "FYL2X",
843773d7fd2Sforsyth 0x3a, 0,0, "FPTAN",
844773d7fd2Sforsyth 0x3b, 0,0, "FPATAN",
845773d7fd2Sforsyth 0x3c, 0,0, "FXTRACT",
846773d7fd2Sforsyth 0x3d, 0,0, "FPREM1",
847773d7fd2Sforsyth 0x3e, 0,0, "FDECSTP",
848773d7fd2Sforsyth 0x3f, 0,0, "FNCSTP",
849773d7fd2Sforsyth 0x40, 0,0, "FPREM",
850773d7fd2Sforsyth 0x41, 0,0, "FYL2XP1",
851773d7fd2Sforsyth 0x42, 0,0, "FSQRT",
852773d7fd2Sforsyth 0x43, 0,0, "FSINCOS",
853773d7fd2Sforsyth 0x44, 0,0, "FRNDINT",
854773d7fd2Sforsyth 0x45, 0,0, "FSCALE",
855773d7fd2Sforsyth 0x46, 0,0, "FSIN",
856773d7fd2Sforsyth 0x47, 0,0, "FCOS",
85774a4d8c2SCharles.Forsyth };
85874a4d8c2SCharles.Forsyth
85974a4d8c2SCharles.Forsyth static Optable optabDA[8+8] =
86074a4d8c2SCharles.Forsyth {
861773d7fd2Sforsyth 0x00, 0,0, "FADDL %e,F0",
862773d7fd2Sforsyth 0x01, 0,0, "FMULL %e,F0",
863773d7fd2Sforsyth 0x02, 0,0, "FCOML %e,F0",
864773d7fd2Sforsyth 0x03, 0,0, "FCOMLP %e,F0",
865773d7fd2Sforsyth 0x04, 0,0, "FSUBL %e,F0",
866773d7fd2Sforsyth 0x05, 0,0, "FSUBRL %e,F0",
867773d7fd2Sforsyth 0x06, 0,0, "FDIVL %e,F0",
868773d7fd2Sforsyth 0x07, 0,0, "FDIVRL %e,F0",
869773d7fd2Sforsyth 0x0d, R1,0, "FUCOMPP",
87074a4d8c2SCharles.Forsyth };
87174a4d8c2SCharles.Forsyth
87274a4d8c2SCharles.Forsyth static Optable optabDB[8+64] =
87374a4d8c2SCharles.Forsyth {
874773d7fd2Sforsyth 0x00, 0,0, "FMOVL %e,F0",
875773d7fd2Sforsyth 0x02, 0,0, "FMOVL F0,%e",
876773d7fd2Sforsyth 0x03, 0,0, "FMOVLP F0,%e",
877773d7fd2Sforsyth 0x05, 0,0, "FMOVX %e,F0",
878773d7fd2Sforsyth 0x07, 0,0, "FMOVXP F0,%e",
879773d7fd2Sforsyth 0x2a, 0,0, "FCLEX",
880773d7fd2Sforsyth 0x2b, 0,0, "FINIT",
88174a4d8c2SCharles.Forsyth };
88274a4d8c2SCharles.Forsyth
88374a4d8c2SCharles.Forsyth static Optable optabDC[8+8] =
88474a4d8c2SCharles.Forsyth {
885773d7fd2Sforsyth 0x00, 0,0, "FADDD %e,F0",
886773d7fd2Sforsyth 0x01, 0,0, "FMULD %e,F0",
887773d7fd2Sforsyth 0x02, 0,0, "FCOMD %e,F0",
888773d7fd2Sforsyth 0x03, 0,0, "FCOMDP %e,F0",
889773d7fd2Sforsyth 0x04, 0,0, "FSUBD %e,F0",
890773d7fd2Sforsyth 0x05, 0,0, "FSUBRD %e,F0",
891773d7fd2Sforsyth 0x06, 0,0, "FDIVD %e,F0",
892773d7fd2Sforsyth 0x07, 0,0, "FDIVRD %e,F0",
893773d7fd2Sforsyth 0x08, 0,0, "FADDD F0,%f",
894773d7fd2Sforsyth 0x09, 0,0, "FMULD F0,%f",
895773d7fd2Sforsyth 0x0c, 0,0, "FSUBRD F0,%f",
896773d7fd2Sforsyth 0x0d, 0,0, "FSUBD F0,%f",
897773d7fd2Sforsyth 0x0e, 0,0, "FDIVRD F0,%f",
898773d7fd2Sforsyth 0x0f, 0,0, "FDIVD F0,%f",
89974a4d8c2SCharles.Forsyth };
90074a4d8c2SCharles.Forsyth
90174a4d8c2SCharles.Forsyth static Optable optabDD[8+8] =
90274a4d8c2SCharles.Forsyth {
903773d7fd2Sforsyth 0x00, 0,0, "FMOVD %e,F0",
904773d7fd2Sforsyth 0x02, 0,0, "FMOVD F0,%e",
905773d7fd2Sforsyth 0x03, 0,0, "FMOVDP F0,%e",
906773d7fd2Sforsyth 0x04, 0,0, "FRSTOR%S %e",
907773d7fd2Sforsyth 0x06, 0,0, "FSAVE%S %e",
908773d7fd2Sforsyth 0x07, 0,0, "FSTSW %e",
909773d7fd2Sforsyth 0x08, 0,0, "FFREED %f",
910773d7fd2Sforsyth 0x0a, 0,0, "FMOVD %f,F0",
911773d7fd2Sforsyth 0x0b, 0,0, "FMOVDP %f,F0",
912773d7fd2Sforsyth 0x0c, 0,0, "FUCOMD %f,F0",
913773d7fd2Sforsyth 0x0d, 0,0, "FUCOMDP %f,F0",
91474a4d8c2SCharles.Forsyth };
91574a4d8c2SCharles.Forsyth
91674a4d8c2SCharles.Forsyth static Optable optabDE[8+8] =
91774a4d8c2SCharles.Forsyth {
918773d7fd2Sforsyth 0x00, 0,0, "FADDW %e,F0",
919773d7fd2Sforsyth 0x01, 0,0, "FMULW %e,F0",
920773d7fd2Sforsyth 0x02, 0,0, "FCOMW %e,F0",
921773d7fd2Sforsyth 0x03, 0,0, "FCOMWP %e,F0",
922773d7fd2Sforsyth 0x04, 0,0, "FSUBW %e,F0",
923773d7fd2Sforsyth 0x05, 0,0, "FSUBRW %e,F0",
924773d7fd2Sforsyth 0x06, 0,0, "FDIVW %e,F0",
925773d7fd2Sforsyth 0x07, 0,0, "FDIVRW %e,F0",
926773d7fd2Sforsyth 0x08, 0,0, "FADDDP F0,%f",
927773d7fd2Sforsyth 0x09, 0,0, "FMULDP F0,%f",
928773d7fd2Sforsyth 0x0b, R1,0, "FCOMPDP",
929773d7fd2Sforsyth 0x0c, 0,0, "FSUBRDP F0,%f",
930773d7fd2Sforsyth 0x0d, 0,0, "FSUBDP F0,%f",
931773d7fd2Sforsyth 0x0e, 0,0, "FDIVRDP F0,%f",
932773d7fd2Sforsyth 0x0f, 0,0, "FDIVDP F0,%f",
93374a4d8c2SCharles.Forsyth };
93474a4d8c2SCharles.Forsyth
93574a4d8c2SCharles.Forsyth static Optable optabDF[8+8] =
93674a4d8c2SCharles.Forsyth {
937773d7fd2Sforsyth 0x00, 0,0, "FMOVW %e,F0",
938773d7fd2Sforsyth 0x02, 0,0, "FMOVW F0,%e",
939773d7fd2Sforsyth 0x03, 0,0, "FMOVWP F0,%e",
940773d7fd2Sforsyth 0x04, 0,0, "FBLD %e",
941773d7fd2Sforsyth 0x05, 0,0, "FMOVL %e,F0",
942773d7fd2Sforsyth 0x06, 0,0, "FBSTP %e",
943773d7fd2Sforsyth 0x07, 0,0, "FMOVLP F0,%e",
944773d7fd2Sforsyth 0x0c, R0,0, "FSTSW %OAX",
94574a4d8c2SCharles.Forsyth };
94674a4d8c2SCharles.Forsyth
94774a4d8c2SCharles.Forsyth static Optable optabF6[8] =
94874a4d8c2SCharles.Forsyth {
949773d7fd2Sforsyth 0x00, Ib,0, "TESTB %i,%e",
950773d7fd2Sforsyth 0x02, 0,0, "NOTB %e",
951773d7fd2Sforsyth 0x03, 0,0, "NEGB %e",
952773d7fd2Sforsyth 0x04, 0,0, "MULB AL,%e",
953773d7fd2Sforsyth 0x05, 0,0, "IMULB AL,%e",
954773d7fd2Sforsyth 0x06, 0,0, "DIVB AL,%e",
955773d7fd2Sforsyth 0x07, 0,0, "IDIVB AL,%e",
95674a4d8c2SCharles.Forsyth };
95774a4d8c2SCharles.Forsyth
95874a4d8c2SCharles.Forsyth static Optable optabF7[8] =
95974a4d8c2SCharles.Forsyth {
960773d7fd2Sforsyth 0x00, Iwd,0, "TEST%S %i,%e",
961773d7fd2Sforsyth 0x02, 0,0, "NOT%S %e",
962773d7fd2Sforsyth 0x03, 0,0, "NEG%S %e",
963773d7fd2Sforsyth 0x04, 0,0, "MUL%S %OAX,%e",
964773d7fd2Sforsyth 0x05, 0,0, "IMUL%S %OAX,%e",
965773d7fd2Sforsyth 0x06, 0,0, "DIV%S %OAX,%e",
966773d7fd2Sforsyth 0x07, 0,0, "IDIV%S %OAX,%e",
96774a4d8c2SCharles.Forsyth };
96874a4d8c2SCharles.Forsyth
96974a4d8c2SCharles.Forsyth static Optable optabFE[8] =
97074a4d8c2SCharles.Forsyth {
971773d7fd2Sforsyth 0x00, 0,0, "INCB %e",
972773d7fd2Sforsyth 0x01, 0,0, "DECB %e",
97374a4d8c2SCharles.Forsyth };
97474a4d8c2SCharles.Forsyth
97574a4d8c2SCharles.Forsyth static Optable optabFF[8] =
97674a4d8c2SCharles.Forsyth {
977773d7fd2Sforsyth 0x00, 0,0, "INC%S %e",
978773d7fd2Sforsyth 0x01, 0,0, "DEC%S %e",
979773d7fd2Sforsyth 0x02, JUMP,0, "CALL* %e",
980773d7fd2Sforsyth 0x03, JUMP,0, "CALLF* %e",
981773d7fd2Sforsyth 0x04, JUMP,0, "JMP* %e",
982773d7fd2Sforsyth 0x05, JUMP,0, "JMPF* %e",
983773d7fd2Sforsyth 0x06, 0,0, "PUSHL %e",
98474a4d8c2SCharles.Forsyth };
98574a4d8c2SCharles.Forsyth
986d67b7dadSforsyth static Optable optable[256+1] =
98774a4d8c2SCharles.Forsyth {
988773d7fd2Sforsyth 0x00, RMB,0, "ADDB %r,%e",
989773d7fd2Sforsyth 0x01, RM,0, "ADD%S %r,%e",
990773d7fd2Sforsyth 0x02, RMB,0, "ADDB %e,%r",
991773d7fd2Sforsyth 0x03, RM,0, "ADD%S %e,%r",
992773d7fd2Sforsyth 0x04, Ib,0, "ADDB %i,AL",
993773d7fd2Sforsyth 0x05, Iwd,0, "ADD%S %i,%OAX",
994773d7fd2Sforsyth 0x06, 0,0, "PUSHL ES",
995773d7fd2Sforsyth 0x07, 0,0, "POPL ES",
996773d7fd2Sforsyth 0x08, RMB,0, "ORB %r,%e",
997773d7fd2Sforsyth 0x09, RM,0, "OR%S %r,%e",
998773d7fd2Sforsyth 0x0a, RMB,0, "ORB %e,%r",
999773d7fd2Sforsyth 0x0b, RM,0, "OR%S %e,%r",
1000773d7fd2Sforsyth 0x0c, Ib,0, "ORB %i,AL",
1001773d7fd2Sforsyth 0x0d, Iwd,0, "OR%S %i,%OAX",
1002773d7fd2Sforsyth 0x0e, 0,0, "PUSHL CS",
1003773d7fd2Sforsyth 0x0f, AUXMM,0, optab0F,
1004773d7fd2Sforsyth 0x10, RMB,0, "ADCB %r,%e",
1005773d7fd2Sforsyth 0x11, RM,0, "ADC%S %r,%e",
1006773d7fd2Sforsyth 0x12, RMB,0, "ADCB %e,%r",
1007773d7fd2Sforsyth 0x13, RM,0, "ADC%S %e,%r",
1008773d7fd2Sforsyth 0x14, Ib,0, "ADCB %i,AL",
1009773d7fd2Sforsyth 0x15, Iwd,0, "ADC%S %i,%OAX",
1010773d7fd2Sforsyth 0x16, 0,0, "PUSHL SS",
1011773d7fd2Sforsyth 0x17, 0,0, "POPL SS",
1012773d7fd2Sforsyth 0x18, RMB,0, "SBBB %r,%e",
1013773d7fd2Sforsyth 0x19, RM,0, "SBB%S %r,%e",
1014773d7fd2Sforsyth 0x1a, RMB,0, "SBBB %e,%r",
1015773d7fd2Sforsyth 0x1b, RM,0, "SBB%S %e,%r",
1016773d7fd2Sforsyth 0x1c, Ib,0, "SBBB %i,AL",
1017773d7fd2Sforsyth 0x1d, Iwd,0, "SBB%S %i,%OAX",
1018773d7fd2Sforsyth 0x1e, 0,0, "PUSHL DS",
1019773d7fd2Sforsyth 0x1f, 0,0, "POPL DS",
1020773d7fd2Sforsyth 0x20, RMB,0, "ANDB %r,%e",
1021773d7fd2Sforsyth 0x21, RM,0, "AND%S %r,%e",
1022773d7fd2Sforsyth 0x22, RMB,0, "ANDB %e,%r",
1023773d7fd2Sforsyth 0x23, RM,0, "AND%S %e,%r",
1024773d7fd2Sforsyth 0x24, Ib,0, "ANDB %i,AL",
1025773d7fd2Sforsyth 0x25, Iwd,0, "AND%S %i,%OAX",
1026773d7fd2Sforsyth 0x26, SEG,0, "ES:",
1027773d7fd2Sforsyth 0x27, 0,0, "DAA",
1028773d7fd2Sforsyth 0x28, RMB,0, "SUBB %r,%e",
1029773d7fd2Sforsyth 0x29, RM,0, "SUB%S %r,%e",
1030773d7fd2Sforsyth 0x2a, RMB,0, "SUBB %e,%r",
1031773d7fd2Sforsyth 0x2b, RM,0, "SUB%S %e,%r",
1032773d7fd2Sforsyth 0x2c, Ib,0, "SUBB %i,AL",
1033773d7fd2Sforsyth 0x2d, Iwd,0, "SUB%S %i,%OAX",
1034773d7fd2Sforsyth 0x2e, SEG,0, "CS:",
1035773d7fd2Sforsyth 0x2f, 0,0, "DAS",
1036773d7fd2Sforsyth 0x30, RMB,0, "XORB %r,%e",
1037773d7fd2Sforsyth 0x31, RM,0, "XOR%S %r,%e",
1038773d7fd2Sforsyth 0x32, RMB,0, "XORB %e,%r",
1039773d7fd2Sforsyth 0x33, RM,0, "XOR%S %e,%r",
1040773d7fd2Sforsyth 0x34, Ib,0, "XORB %i,AL",
1041773d7fd2Sforsyth 0x35, Iwd,0, "XOR%S %i,%OAX",
1042773d7fd2Sforsyth 0x36, SEG,0, "SS:",
1043773d7fd2Sforsyth 0x37, 0,0, "AAA",
1044773d7fd2Sforsyth 0x38, RMB,0, "CMPB %r,%e",
1045773d7fd2Sforsyth 0x39, RM,0, "CMP%S %r,%e",
1046773d7fd2Sforsyth 0x3a, RMB,0, "CMPB %e,%r",
1047773d7fd2Sforsyth 0x3b, RM,0, "CMP%S %e,%r",
1048773d7fd2Sforsyth 0x3c, Ib,0, "CMPB %i,AL",
1049773d7fd2Sforsyth 0x3d, Iwd,0, "CMP%S %i,%OAX",
1050773d7fd2Sforsyth 0x3e, SEG,0, "DS:",
1051773d7fd2Sforsyth 0x3f, 0,0, "AAS",
1052773d7fd2Sforsyth 0x40, 0,0, "INC%S %OAX",
1053773d7fd2Sforsyth 0x41, 0,0, "INC%S %OCX",
1054773d7fd2Sforsyth 0x42, 0,0, "INC%S %ODX",
1055773d7fd2Sforsyth 0x43, 0,0, "INC%S %OBX",
1056773d7fd2Sforsyth 0x44, 0,0, "INC%S %OSP",
1057773d7fd2Sforsyth 0x45, 0,0, "INC%S %OBP",
1058773d7fd2Sforsyth 0x46, 0,0, "INC%S %OSI",
1059773d7fd2Sforsyth 0x47, 0,0, "INC%S %ODI",
1060773d7fd2Sforsyth 0x48, 0,0, "DEC%S %OAX",
1061773d7fd2Sforsyth 0x49, 0,0, "DEC%S %OCX",
1062773d7fd2Sforsyth 0x4a, 0,0, "DEC%S %ODX",
1063773d7fd2Sforsyth 0x4b, 0,0, "DEC%S %OBX",
1064773d7fd2Sforsyth 0x4c, 0,0, "DEC%S %OSP",
1065773d7fd2Sforsyth 0x4d, 0,0, "DEC%S %OBP",
1066773d7fd2Sforsyth 0x4e, 0,0, "DEC%S %OSI",
1067773d7fd2Sforsyth 0x4f, 0,0, "DEC%S %ODI",
1068773d7fd2Sforsyth 0x50, 0,0, "PUSH%S %OAX",
1069773d7fd2Sforsyth 0x51, 0,0, "PUSH%S %OCX",
1070773d7fd2Sforsyth 0x52, 0,0, "PUSH%S %ODX",
1071773d7fd2Sforsyth 0x53, 0,0, "PUSH%S %OBX",
1072773d7fd2Sforsyth 0x54, 0,0, "PUSH%S %OSP",
1073773d7fd2Sforsyth 0x55, 0,0, "PUSH%S %OBP",
1074773d7fd2Sforsyth 0x56, 0,0, "PUSH%S %OSI",
1075773d7fd2Sforsyth 0x57, 0,0, "PUSH%S %ODI",
1076773d7fd2Sforsyth 0x58, 0,0, "POP%S %OAX",
1077773d7fd2Sforsyth 0x59, 0,0, "POP%S %OCX",
1078773d7fd2Sforsyth 0x5a, 0,0, "POP%S %ODX",
1079773d7fd2Sforsyth 0x5b, 0,0, "POP%S %OBX",
1080773d7fd2Sforsyth 0x5c, 0,0, "POP%S %OSP",
1081773d7fd2Sforsyth 0x5d, 0,0, "POP%S %OBP",
1082773d7fd2Sforsyth 0x5e, 0,0, "POP%S %OSI",
1083773d7fd2Sforsyth 0x5f, 0,0, "POP%S %ODI",
1084773d7fd2Sforsyth 0x60, 0,0, "PUSHA%S",
1085773d7fd2Sforsyth 0x61, 0,0, "POPA%S",
1086773d7fd2Sforsyth 0x62, RMM,0, "BOUND %e,%r",
1087773d7fd2Sforsyth 0x63, RM,0, "ARPL %r,%e",
1088773d7fd2Sforsyth 0x64, SEG,0, "FS:",
1089773d7fd2Sforsyth 0x65, SEG,0, "GS:",
1090773d7fd2Sforsyth 0x66, OPOVER,0, "",
1091773d7fd2Sforsyth 0x67, ADDOVER,0, "",
1092773d7fd2Sforsyth 0x68, Iwd,0, "PUSH%S %i",
1093773d7fd2Sforsyth 0x69, RM,Iwd, "IMUL%S %e,%i,%r",
1094773d7fd2Sforsyth 0x6a, Ib,0, "PUSH%S %i",
1095773d7fd2Sforsyth 0x6b, RM,Ibs, "IMUL%S %e,%i,%r",
1096773d7fd2Sforsyth 0x6c, 0,0, "INSB DX,(%ODI)",
1097773d7fd2Sforsyth 0x6d, 0,0, "INS%S DX,(%ODI)",
1098773d7fd2Sforsyth 0x6e, 0,0, "OUTSB (%ASI),DX",
1099773d7fd2Sforsyth 0x6f, 0,0, "OUTS%S (%ASI),DX",
1100773d7fd2Sforsyth 0x70, Jbs,0, "JOS %p",
1101773d7fd2Sforsyth 0x71, Jbs,0, "JOC %p",
1102773d7fd2Sforsyth 0x72, Jbs,0, "JCS %p",
1103773d7fd2Sforsyth 0x73, Jbs,0, "JCC %p",
1104773d7fd2Sforsyth 0x74, Jbs,0, "JEQ %p",
1105773d7fd2Sforsyth 0x75, Jbs,0, "JNE %p",
1106773d7fd2Sforsyth 0x76, Jbs,0, "JLS %p",
1107773d7fd2Sforsyth 0x77, Jbs,0, "JHI %p",
1108773d7fd2Sforsyth 0x78, Jbs,0, "JMI %p",
1109773d7fd2Sforsyth 0x79, Jbs,0, "JPL %p",
1110773d7fd2Sforsyth 0x7a, Jbs,0, "JPS %p",
1111773d7fd2Sforsyth 0x7b, Jbs,0, "JPC %p",
1112773d7fd2Sforsyth 0x7c, Jbs,0, "JLT %p",
1113773d7fd2Sforsyth 0x7d, Jbs,0, "JGE %p",
1114773d7fd2Sforsyth 0x7e, Jbs,0, "JLE %p",
1115773d7fd2Sforsyth 0x7f, Jbs,0, "JGT %p",
1116773d7fd2Sforsyth 0x80, RMOPB,0, optab80,
1117773d7fd2Sforsyth 0x81, RMOP,0, optab81,
1118773d7fd2Sforsyth 0x83, RMOP,0, optab83,
1119773d7fd2Sforsyth 0x84, RMB,0, "TESTB %r,%e",
1120773d7fd2Sforsyth 0x85, RM,0, "TEST%S %r,%e",
1121773d7fd2Sforsyth 0x86, RMB,0, "XCHGB %r,%e",
1122773d7fd2Sforsyth 0x87, RM,0, "XCHG%S %r,%e",
1123773d7fd2Sforsyth 0x88, RMB,0, "MOVB %r,%e",
1124773d7fd2Sforsyth 0x89, RM,0, "MOV%S %r,%e",
1125773d7fd2Sforsyth 0x8a, RMB,0, "MOVB %e,%r",
1126773d7fd2Sforsyth 0x8b, RM,0, "MOV%S %e,%r",
1127773d7fd2Sforsyth 0x8c, RM,0, "MOVW %g,%e",
1128773d7fd2Sforsyth 0x8d, RM,0, "LEA%S %e,%r",
1129773d7fd2Sforsyth 0x8e, RM,0, "MOVW %e,%g",
1130773d7fd2Sforsyth 0x8f, RM,0, "POP%S %e",
1131773d7fd2Sforsyth 0x90, 0,0, "NOP",
1132773d7fd2Sforsyth 0x91, 0,0, "XCHG %OCX,%OAX",
1133773d7fd2Sforsyth 0x92, 0,0, "XCHG %ODX,%OAX",
1134773d7fd2Sforsyth 0x93, 0,0, "XCHG %OBX,%OAX",
1135773d7fd2Sforsyth 0x94, 0,0, "XCHG %OSP,%OAX",
1136773d7fd2Sforsyth 0x95, 0,0, "XCHG %OBP,%OAX",
1137773d7fd2Sforsyth 0x96, 0,0, "XCHG %OSI,%OAX",
1138773d7fd2Sforsyth 0x97, 0,0, "XCHG %ODI,%OAX",
1139773d7fd2Sforsyth 0x98, 0,0, "%W", /* miserable CBW or CWDE */
1140773d7fd2Sforsyth 0x99, 0,0, "%w", /* idiotic CWD or CDQ */
1141773d7fd2Sforsyth 0x9a, PTR,0, "CALL%S %d",
1142773d7fd2Sforsyth 0x9b, 0,0, "WAIT",
1143773d7fd2Sforsyth 0x9c, 0,0, "PUSHF",
1144773d7fd2Sforsyth 0x9d, 0,0, "POPF",
1145773d7fd2Sforsyth 0x9e, 0,0, "SAHF",
1146773d7fd2Sforsyth 0x9f, 0,0, "LAHF",
1147773d7fd2Sforsyth 0xa0, Awd,0, "MOVB %i,AL",
1148773d7fd2Sforsyth 0xa1, Awd,0, "MOV%S %i,%OAX",
1149773d7fd2Sforsyth 0xa2, Awd,0, "MOVB AL,%i",
1150773d7fd2Sforsyth 0xa3, Awd,0, "MOV%S %OAX,%i",
1151773d7fd2Sforsyth 0xa4, 0,0, "MOVSB (%ASI),(%ADI)",
1152773d7fd2Sforsyth 0xa5, 0,0, "MOVS%S (%ASI),(%ADI)",
1153773d7fd2Sforsyth 0xa6, 0,0, "CMPSB (%ASI),(%ADI)",
1154773d7fd2Sforsyth 0xa7, 0,0, "CMPS%S (%ASI),(%ADI)",
1155773d7fd2Sforsyth 0xa8, Ib,0, "TESTB %i,AL",
1156773d7fd2Sforsyth 0xa9, Iwd,0, "TEST%S %i,%OAX",
1157773d7fd2Sforsyth 0xaa, 0,0, "STOSB AL,(%ADI)",
1158773d7fd2Sforsyth 0xab, 0,0, "STOS%S %OAX,(%ADI)",
1159773d7fd2Sforsyth 0xac, 0,0, "LODSB (%ASI),AL",
1160773d7fd2Sforsyth 0xad, 0,0, "LODS%S (%ASI),%OAX",
1161773d7fd2Sforsyth 0xae, 0,0, "SCASB (%ADI),AL",
1162773d7fd2Sforsyth 0xaf, 0,0, "SCAS%S (%ADI),%OAX",
1163773d7fd2Sforsyth 0xb0, Ib,0, "MOVB %i,AL",
1164773d7fd2Sforsyth 0xb1, Ib,0, "MOVB %i,CL",
1165773d7fd2Sforsyth 0xb2, Ib,0, "MOVB %i,DL",
1166773d7fd2Sforsyth 0xb3, Ib,0, "MOVB %i,BL",
1167773d7fd2Sforsyth 0xb4, Ib,0, "MOVB %i,AH",
1168773d7fd2Sforsyth 0xb5, Ib,0, "MOVB %i,CH",
1169773d7fd2Sforsyth 0xb6, Ib,0, "MOVB %i,DH",
1170773d7fd2Sforsyth 0xb7, Ib,0, "MOVB %i,BH",
1171773d7fd2Sforsyth 0xb8, Iwdq,0, "MOV%S %i,%OAX",
1172773d7fd2Sforsyth 0xb9, Iwdq,0, "MOV%S %i,%OCX",
1173773d7fd2Sforsyth 0xba, Iwdq,0, "MOV%S %i,%ODX",
1174773d7fd2Sforsyth 0xbb, Iwdq,0, "MOV%S %i,%OBX",
1175773d7fd2Sforsyth 0xbc, Iwdq,0, "MOV%S %i,%OSP",
1176773d7fd2Sforsyth 0xbd, Iwdq,0, "MOV%S %i,%OBP",
1177773d7fd2Sforsyth 0xbe, Iwdq,0, "MOV%S %i,%OSI",
1178773d7fd2Sforsyth 0xbf, Iwdq,0, "MOV%S %i,%ODI",
1179773d7fd2Sforsyth 0xc0, RMOPB,0, optabC0,
1180773d7fd2Sforsyth 0xc1, RMOP,0, optabC1,
1181773d7fd2Sforsyth 0xc2, Iw,0, "RET %i",
1182773d7fd2Sforsyth 0xc3, RET,0, "RET",
1183773d7fd2Sforsyth 0xc4, RM,0, "LES %e,%r",
1184773d7fd2Sforsyth 0xc5, RM,0, "LDS %e,%r",
1185773d7fd2Sforsyth 0xc6, RMB,Ib, "MOVB %i,%e",
1186773d7fd2Sforsyth 0xc7, RM,Iwd, "MOV%S %i,%e",
1187773d7fd2Sforsyth 0xc8, Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
1188773d7fd2Sforsyth 0xc9, RET,0, "LEAVE", /* bizarre LEAVE */
1189773d7fd2Sforsyth 0xca, Iw,0, "RETF %i",
1190773d7fd2Sforsyth 0xcb, RET,0, "RETF",
1191773d7fd2Sforsyth 0xcc, 0,0, "INT 3",
1192773d7fd2Sforsyth 0xcd, Ib,0, "INTB %i",
1193773d7fd2Sforsyth 0xce, 0,0, "INTO",
1194773d7fd2Sforsyth 0xcf, 0,0, "IRET",
1195773d7fd2Sforsyth 0xd0, RMOPB,0, optabD0,
1196773d7fd2Sforsyth 0xd1, RMOP,0, optabD1,
1197773d7fd2Sforsyth 0xd2, RMOPB,0, optabD2,
1198773d7fd2Sforsyth 0xd3, RMOP,0, optabD3,
1199773d7fd2Sforsyth 0xd4, OA,0, "AAM",
1200773d7fd2Sforsyth 0xd5, OA,0, "AAD",
1201773d7fd2Sforsyth 0xd7, 0,0, "XLAT",
1202773d7fd2Sforsyth 0xd8, FRMOP,0, optabD8,
1203773d7fd2Sforsyth 0xd9, FRMEX,0, optabD9,
1204773d7fd2Sforsyth 0xda, FRMOP,0, optabDA,
1205773d7fd2Sforsyth 0xdb, FRMEX,0, optabDB,
1206773d7fd2Sforsyth 0xdc, FRMOP,0, optabDC,
1207773d7fd2Sforsyth 0xdd, FRMOP,0, optabDD,
1208773d7fd2Sforsyth 0xde, FRMOP,0, optabDE,
1209773d7fd2Sforsyth 0xdf, FRMOP,0, optabDF,
1210773d7fd2Sforsyth 0xe0, Jbs,0, "LOOPNE %p",
1211773d7fd2Sforsyth 0xe1, Jbs,0, "LOOPE %p",
1212773d7fd2Sforsyth 0xe2, Jbs,0, "LOOP %p",
1213773d7fd2Sforsyth 0xe3, Jbs,0, "JCXZ %p",
1214773d7fd2Sforsyth 0xe4, Ib,0, "INB %i,AL",
1215773d7fd2Sforsyth 0xe5, Ib,0, "IN%S %i,%OAX",
1216773d7fd2Sforsyth 0xe6, Ib,0, "OUTB AL,%i",
1217773d7fd2Sforsyth 0xe7, Ib,0, "OUT%S %OAX,%i",
1218773d7fd2Sforsyth 0xe8, Iwds,0, "CALL %p",
1219773d7fd2Sforsyth 0xe9, Iwds,0, "JMP %p",
1220773d7fd2Sforsyth 0xea, PTR,0, "JMP %d",
1221773d7fd2Sforsyth 0xeb, Jbs,0, "JMP %p",
1222773d7fd2Sforsyth 0xec, 0,0, "INB DX,AL",
1223773d7fd2Sforsyth 0xed, 0,0, "IN%S DX,%OAX",
1224773d7fd2Sforsyth 0xee, 0,0, "OUTB AL,DX",
1225773d7fd2Sforsyth 0xef, 0,0, "OUT%S %OAX,DX",
1226773d7fd2Sforsyth 0xf0, PRE,0, "LOCK",
1227773d7fd2Sforsyth 0xf2, OPRE,0, "REPNE",
1228773d7fd2Sforsyth 0xf3, OPRE,0, "REP",
1229773d7fd2Sforsyth 0xf4, 0,0, "HLT",
1230773d7fd2Sforsyth 0xf5, 0,0, "CMC",
1231773d7fd2Sforsyth 0xf6, RMOPB,0, optabF6,
1232773d7fd2Sforsyth 0xf7, RMOP,0, optabF7,
1233773d7fd2Sforsyth 0xf8, 0,0, "CLC",
1234773d7fd2Sforsyth 0xf9, 0,0, "STC",
1235773d7fd2Sforsyth 0xfa, 0,0, "CLI",
1236773d7fd2Sforsyth 0xfb, 0,0, "STI",
1237773d7fd2Sforsyth 0xfc, 0,0, "CLD",
1238773d7fd2Sforsyth 0xfd, 0,0, "STD",
1239773d7fd2Sforsyth 0xfe, RMOPB,0, optabFE,
1240773d7fd2Sforsyth 0xff, RMOP,0, optabFF,
1241773d7fd2Sforsyth 0x100, RM,0, "MOVLQSX %r,%e",
124274a4d8c2SCharles.Forsyth };
124374a4d8c2SCharles.Forsyth
1244773d7fd2Sforsyth static struct {
1245773d7fd2Sforsyth Optable *tab;
1246773d7fd2Sforsyth uint nel;
1247773d7fd2Sforsyth } optabtab[] = {
1248773d7fd2Sforsyth optab0F00, nelem(optab0F00),
1249773d7fd2Sforsyth optab0F01, nelem(optab0F01),
1250773d7fd2Sforsyth optab0F01F8, nelem(optab0F01F8),
1251773d7fd2Sforsyth optab0FAE, nelem(optab0FAE),
1252773d7fd2Sforsyth optab0FBA, nelem(optab0FBA),
1253773d7fd2Sforsyth optab0F0F, nelem(optab0F0F),
1254773d7fd2Sforsyth optab0FC7, nelem(optab0FC7),
1255773d7fd2Sforsyth optab660F71, nelem(optab660F71),
1256773d7fd2Sforsyth optab660F72, nelem(optab660F72),
1257773d7fd2Sforsyth optab660F73, nelem(optab660F73),
1258773d7fd2Sforsyth optab660F, nelem(optab660F),
1259773d7fd2Sforsyth optabF20F, nelem(optabF20F),
1260773d7fd2Sforsyth optabF30F, nelem(optabF30F),
1261773d7fd2Sforsyth optab0F, nelem(optab0F),
1262773d7fd2Sforsyth optab80, nelem(optab80),
1263773d7fd2Sforsyth optab81, nelem(optab81),
1264773d7fd2Sforsyth optab83, nelem(optab83),
1265773d7fd2Sforsyth optabC0, nelem(optabC0),
1266773d7fd2Sforsyth optabC1, nelem(optabC1),
1267773d7fd2Sforsyth optabD0, nelem(optabD0),
1268773d7fd2Sforsyth optabD1, nelem(optabD1),
1269773d7fd2Sforsyth optabD2, nelem(optabD2),
1270773d7fd2Sforsyth optabD3, nelem(optabD3),
1271773d7fd2Sforsyth optabD8, nelem(optabD8),
1272773d7fd2Sforsyth optabD9, nelem(optabD9),
1273773d7fd2Sforsyth optabDA, nelem(optabDA),
1274773d7fd2Sforsyth optabDB, nelem(optabDB),
1275773d7fd2Sforsyth optabDC, nelem(optabDC),
1276773d7fd2Sforsyth optabDD, nelem(optabDD),
1277773d7fd2Sforsyth optabDE, nelem(optabDE),
1278773d7fd2Sforsyth optabDF, nelem(optabDF),
1279773d7fd2Sforsyth optabF6, nelem(optabF6),
1280773d7fd2Sforsyth optabF7, nelem(optabF7),
1281773d7fd2Sforsyth optabFE, nelem(optabFE),
1282773d7fd2Sforsyth optabFF, nelem(optabFF),
1283773d7fd2Sforsyth optable, nelem(optable),
1284773d7fd2Sforsyth };
1285773d7fd2Sforsyth
1286773d7fd2Sforsyth /*
1287773d7fd2Sforsyth * compensate for Microsoft's ageing compilers
1288773d7fd2Sforsyth */
1289773d7fd2Sforsyth static void
ordertab(Optable * tab,int nel)1290773d7fd2Sforsyth ordertab(Optable *tab, int nel)
1291773d7fd2Sforsyth {
1292773d7fd2Sforsyth int i, x;
1293773d7fd2Sforsyth static Optable empty;
1294773d7fd2Sforsyth
1295773d7fd2Sforsyth for(i = nel; --i >= 0;){
1296773d7fd2Sforsyth x = tab[i].x;
1297773d7fd2Sforsyth if(x != i){
1298773d7fd2Sforsyth tab[x] = tab[i];
1299773d7fd2Sforsyth tab[i] = empty;
1300773d7fd2Sforsyth }
1301773d7fd2Sforsyth }
1302773d7fd2Sforsyth }
1303773d7fd2Sforsyth
1304773d7fd2Sforsyth static void
soptoms(void)1305773d7fd2Sforsyth soptoms(void)
1306773d7fd2Sforsyth {
1307773d7fd2Sforsyth int i;
1308773d7fd2Sforsyth static int reordered; /* assumes non-concurrent use */
1309773d7fd2Sforsyth
1310773d7fd2Sforsyth if(reordered)
1311773d7fd2Sforsyth return;
1312773d7fd2Sforsyth reordered = 1;
1313773d7fd2Sforsyth for(i = 0; i < nelem(optabtab); i++)
1314773d7fd2Sforsyth ordertab(optabtab[i].tab, optabtab[i].nel);
1315773d7fd2Sforsyth }
1316773d7fd2Sforsyth
131774a4d8c2SCharles.Forsyth /*
131874a4d8c2SCharles.Forsyth * get a byte of the instruction
131974a4d8c2SCharles.Forsyth */
132074a4d8c2SCharles.Forsyth static int
igetc(Map * map,Instr * ip,uchar * c)132174a4d8c2SCharles.Forsyth igetc(Map *map, Instr *ip, uchar *c)
132274a4d8c2SCharles.Forsyth {
132374a4d8c2SCharles.Forsyth if(ip->n+1 > sizeof(ip->mem)){
132474a4d8c2SCharles.Forsyth werrstr("instruction too long");
132574a4d8c2SCharles.Forsyth return -1;
132674a4d8c2SCharles.Forsyth }
132774a4d8c2SCharles.Forsyth if (get1(map, ip->addr+ip->n, c, 1) < 0) {
132874a4d8c2SCharles.Forsyth werrstr("can't read instruction: %r");
132974a4d8c2SCharles.Forsyth return -1;
133074a4d8c2SCharles.Forsyth }
133174a4d8c2SCharles.Forsyth ip->mem[ip->n++] = *c;
133274a4d8c2SCharles.Forsyth return 1;
133374a4d8c2SCharles.Forsyth }
133474a4d8c2SCharles.Forsyth
133574a4d8c2SCharles.Forsyth /*
133674a4d8c2SCharles.Forsyth * get two bytes of the instruction
133774a4d8c2SCharles.Forsyth */
133874a4d8c2SCharles.Forsyth static int
igets(Map * map,Instr * ip,ushort * sp)133974a4d8c2SCharles.Forsyth igets(Map *map, Instr *ip, ushort *sp)
134074a4d8c2SCharles.Forsyth {
134174a4d8c2SCharles.Forsyth uchar c;
134274a4d8c2SCharles.Forsyth ushort s;
134374a4d8c2SCharles.Forsyth
134474a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
134574a4d8c2SCharles.Forsyth return -1;
134674a4d8c2SCharles.Forsyth s = c;
134774a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
134874a4d8c2SCharles.Forsyth return -1;
134974a4d8c2SCharles.Forsyth s |= (c<<8);
135074a4d8c2SCharles.Forsyth *sp = s;
135174a4d8c2SCharles.Forsyth return 1;
135274a4d8c2SCharles.Forsyth }
135374a4d8c2SCharles.Forsyth
135474a4d8c2SCharles.Forsyth /*
135574a4d8c2SCharles.Forsyth * get 4 bytes of the instruction
135674a4d8c2SCharles.Forsyth */
135774a4d8c2SCharles.Forsyth static int
igetl(Map * map,Instr * ip,ulong * lp)135874a4d8c2SCharles.Forsyth igetl(Map *map, Instr *ip, ulong *lp)
135974a4d8c2SCharles.Forsyth {
136074a4d8c2SCharles.Forsyth ushort s;
136174a4d8c2SCharles.Forsyth long l;
136274a4d8c2SCharles.Forsyth
136374a4d8c2SCharles.Forsyth if (igets(map, ip, &s) < 0)
136474a4d8c2SCharles.Forsyth return -1;
136574a4d8c2SCharles.Forsyth l = s;
136674a4d8c2SCharles.Forsyth if (igets(map, ip, &s) < 0)
136774a4d8c2SCharles.Forsyth return -1;
136874a4d8c2SCharles.Forsyth l |= (s<<16);
136974a4d8c2SCharles.Forsyth *lp = l;
137074a4d8c2SCharles.Forsyth return 1;
137174a4d8c2SCharles.Forsyth }
137274a4d8c2SCharles.Forsyth
1373d67b7dadSforsyth /*
1374d67b7dadSforsyth * get 8 bytes of the instruction
1375d67b7dadSforsyth */
137674a4d8c2SCharles.Forsyth static int
igetq(Map * map,Instr * ip,vlong * qp)1377d67b7dadSforsyth igetq(Map *map, Instr *ip, vlong *qp)
1378d67b7dadSforsyth {
1379d67b7dadSforsyth ulong l;
1380d67b7dadSforsyth uvlong q;
1381d67b7dadSforsyth
1382d67b7dadSforsyth if (igetl(map, ip, &l) < 0)
1383d67b7dadSforsyth return -1;
1384d67b7dadSforsyth q = l;
1385d67b7dadSforsyth if (igetl(map, ip, &l) < 0)
1386d67b7dadSforsyth return -1;
1387d67b7dadSforsyth q |= ((uvlong)l<<32);
1388d67b7dadSforsyth *qp = q;
1389d67b7dadSforsyth return 1;
1390d67b7dadSforsyth }
1391d67b7dadSforsyth
1392d67b7dadSforsyth static int
getdisp(Map * map,Instr * ip,int mod,int rm,int code,int pcrel)1393d67b7dadSforsyth getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
139474a4d8c2SCharles.Forsyth {
139574a4d8c2SCharles.Forsyth uchar c;
139674a4d8c2SCharles.Forsyth ushort s;
139774a4d8c2SCharles.Forsyth
139874a4d8c2SCharles.Forsyth if (mod > 2)
139974a4d8c2SCharles.Forsyth return 1;
140074a4d8c2SCharles.Forsyth if (mod == 1) {
140174a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
140274a4d8c2SCharles.Forsyth return -1;
140374a4d8c2SCharles.Forsyth if (c&0x80)
140474a4d8c2SCharles.Forsyth ip->disp = c|0xffffff00;
140574a4d8c2SCharles.Forsyth else
140674a4d8c2SCharles.Forsyth ip->disp = c&0xff;
140774a4d8c2SCharles.Forsyth } else if (mod == 2 || rm == code) {
140874a4d8c2SCharles.Forsyth if (ip->asize == 'E') {
140974a4d8c2SCharles.Forsyth if (igetl(map, ip, &ip->disp) < 0)
141074a4d8c2SCharles.Forsyth return -1;
1411d67b7dadSforsyth if (mod == 0)
1412d67b7dadSforsyth ip->rip = pcrel;
141374a4d8c2SCharles.Forsyth } else {
141474a4d8c2SCharles.Forsyth if (igets(map, ip, &s) < 0)
141574a4d8c2SCharles.Forsyth return -1;
141674a4d8c2SCharles.Forsyth if (s&0x8000)
141774a4d8c2SCharles.Forsyth ip->disp = s|0xffff0000;
141874a4d8c2SCharles.Forsyth else
141974a4d8c2SCharles.Forsyth ip->disp = s;
142074a4d8c2SCharles.Forsyth }
142174a4d8c2SCharles.Forsyth if (mod == 0)
142274a4d8c2SCharles.Forsyth ip->base = -1;
142374a4d8c2SCharles.Forsyth }
142474a4d8c2SCharles.Forsyth return 1;
142574a4d8c2SCharles.Forsyth }
142674a4d8c2SCharles.Forsyth
142774a4d8c2SCharles.Forsyth static int
modrm(Map * map,Instr * ip,uchar c)142874a4d8c2SCharles.Forsyth modrm(Map *map, Instr *ip, uchar c)
142974a4d8c2SCharles.Forsyth {
143074a4d8c2SCharles.Forsyth uchar rm, mod;
143174a4d8c2SCharles.Forsyth
143274a4d8c2SCharles.Forsyth mod = (c>>6)&3;
143374a4d8c2SCharles.Forsyth rm = c&7;
143474a4d8c2SCharles.Forsyth ip->mod = mod;
143574a4d8c2SCharles.Forsyth ip->base = rm;
143674a4d8c2SCharles.Forsyth ip->reg = (c>>3)&7;
1437d67b7dadSforsyth ip->rip = 0;
143874a4d8c2SCharles.Forsyth if (mod == 3) /* register */
143974a4d8c2SCharles.Forsyth return 1;
144074a4d8c2SCharles.Forsyth if (ip->asize == 0) { /* 16-bit mode */
1441d67b7dadSforsyth switch(rm) {
144274a4d8c2SCharles.Forsyth case 0:
144374a4d8c2SCharles.Forsyth ip->base = BX; ip->index = SI;
144474a4d8c2SCharles.Forsyth break;
144574a4d8c2SCharles.Forsyth case 1:
144674a4d8c2SCharles.Forsyth ip->base = BX; ip->index = DI;
144774a4d8c2SCharles.Forsyth break;
144874a4d8c2SCharles.Forsyth case 2:
144974a4d8c2SCharles.Forsyth ip->base = BP; ip->index = SI;
145074a4d8c2SCharles.Forsyth break;
145174a4d8c2SCharles.Forsyth case 3:
145274a4d8c2SCharles.Forsyth ip->base = BP; ip->index = DI;
145374a4d8c2SCharles.Forsyth break;
145474a4d8c2SCharles.Forsyth case 4:
145574a4d8c2SCharles.Forsyth ip->base = SI;
145674a4d8c2SCharles.Forsyth break;
145774a4d8c2SCharles.Forsyth case 5:
145874a4d8c2SCharles.Forsyth ip->base = DI;
145974a4d8c2SCharles.Forsyth break;
146074a4d8c2SCharles.Forsyth case 6:
146174a4d8c2SCharles.Forsyth ip->base = BP;
146274a4d8c2SCharles.Forsyth break;
146374a4d8c2SCharles.Forsyth case 7:
146474a4d8c2SCharles.Forsyth ip->base = BX;
146574a4d8c2SCharles.Forsyth break;
146674a4d8c2SCharles.Forsyth default:
146774a4d8c2SCharles.Forsyth break;
146874a4d8c2SCharles.Forsyth }
1469d67b7dadSforsyth return getdisp(map, ip, mod, rm, 6, 0);
147074a4d8c2SCharles.Forsyth }
147174a4d8c2SCharles.Forsyth if (rm == 4) { /* scummy sib byte */
147274a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
147374a4d8c2SCharles.Forsyth return -1;
147474a4d8c2SCharles.Forsyth ip->ss = (c>>6)&0x03;
147574a4d8c2SCharles.Forsyth ip->index = (c>>3)&0x07;
147674a4d8c2SCharles.Forsyth if (ip->index == 4)
147774a4d8c2SCharles.Forsyth ip->index = -1;
147874a4d8c2SCharles.Forsyth ip->base = c&0x07;
1479d67b7dadSforsyth return getdisp(map, ip, mod, ip->base, 5, 0);
148074a4d8c2SCharles.Forsyth }
1481d67b7dadSforsyth return getdisp(map, ip, mod, rm, 5, ip->amd64);
148274a4d8c2SCharles.Forsyth }
148374a4d8c2SCharles.Forsyth
148474a4d8c2SCharles.Forsyth static Optable *
mkinstr(Map * map,Instr * ip,uvlong pc)1485d67b7dadSforsyth mkinstr(Map *map, Instr *ip, uvlong pc)
148674a4d8c2SCharles.Forsyth {
1487d67b7dadSforsyth int i, n, norex;
148874a4d8c2SCharles.Forsyth uchar c;
148974a4d8c2SCharles.Forsyth ushort s;
149074a4d8c2SCharles.Forsyth Optable *op, *obase;
149174a4d8c2SCharles.Forsyth char buf[128];
149274a4d8c2SCharles.Forsyth
1493773d7fd2Sforsyth soptoms();
149474a4d8c2SCharles.Forsyth memset(ip, 0, sizeof(*ip));
1495d67b7dadSforsyth norex = 1;
149674a4d8c2SCharles.Forsyth ip->base = -1;
149774a4d8c2SCharles.Forsyth ip->index = -1;
149874a4d8c2SCharles.Forsyth if(asstype == AI8086)
149974a4d8c2SCharles.Forsyth ip->osize = 'W';
150074a4d8c2SCharles.Forsyth else {
150174a4d8c2SCharles.Forsyth ip->osize = 'L';
150274a4d8c2SCharles.Forsyth ip->asize = 'E';
1503d67b7dadSforsyth ip->amd64 = asstype != AI386;
1504d67b7dadSforsyth norex = 0;
150574a4d8c2SCharles.Forsyth }
150674a4d8c2SCharles.Forsyth ip->addr = pc;
150774a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
150874a4d8c2SCharles.Forsyth return 0;
150974a4d8c2SCharles.Forsyth obase = optable;
151074a4d8c2SCharles.Forsyth newop:
1511d67b7dadSforsyth if(ip->amd64 && !norex){
1512d67b7dadSforsyth if(c >= 0x40 && c <= 0x4f) {
1513d67b7dadSforsyth ip->rex = c;
1514d67b7dadSforsyth if(igetc(map, ip, &c) < 0)
1515d67b7dadSforsyth return 0;
1516d67b7dadSforsyth }
1517d67b7dadSforsyth if(c == 0x63){
1518d67b7dadSforsyth op = &obase[0x100]; /* MOVLQSX */
1519d67b7dadSforsyth goto hack;
1520d67b7dadSforsyth }
1521d67b7dadSforsyth }
152274a4d8c2SCharles.Forsyth op = &obase[c];
1523d67b7dadSforsyth hack:
152474a4d8c2SCharles.Forsyth if (op->proto == 0) {
152574a4d8c2SCharles.Forsyth badop:
152674a4d8c2SCharles.Forsyth n = snprint(buf, sizeof(buf), "opcode: ??");
152774a4d8c2SCharles.Forsyth for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
152874a4d8c2SCharles.Forsyth _hexify(buf+n, ip->mem[i], 1);
152974a4d8c2SCharles.Forsyth strcpy(buf+n, "??");
153074a4d8c2SCharles.Forsyth werrstr(buf);
153174a4d8c2SCharles.Forsyth return 0;
153274a4d8c2SCharles.Forsyth }
153374a4d8c2SCharles.Forsyth for(i = 0; i < 2 && op->operand[i]; i++) {
1534d67b7dadSforsyth switch(op->operand[i]) {
153574a4d8c2SCharles.Forsyth case Ib: /* 8-bit immediate - (no sign extension)*/
153674a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
153774a4d8c2SCharles.Forsyth return 0;
153874a4d8c2SCharles.Forsyth ip->imm = c&0xff;
1539d67b7dadSforsyth ip->imm64 = ip->imm;
154074a4d8c2SCharles.Forsyth break;
154174a4d8c2SCharles.Forsyth case Jbs: /* 8-bit jump immediate (sign extended) */
154274a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
154374a4d8c2SCharles.Forsyth return 0;
154474a4d8c2SCharles.Forsyth if (c&0x80)
154574a4d8c2SCharles.Forsyth ip->imm = c|0xffffff00;
154674a4d8c2SCharles.Forsyth else
154774a4d8c2SCharles.Forsyth ip->imm = c&0xff;
1548d67b7dadSforsyth ip->imm64 = (long)ip->imm;
154974a4d8c2SCharles.Forsyth ip->jumptype = Jbs;
155074a4d8c2SCharles.Forsyth break;
155174a4d8c2SCharles.Forsyth case Ibs: /* 8-bit immediate (sign extended) */
155274a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
155374a4d8c2SCharles.Forsyth return 0;
155474a4d8c2SCharles.Forsyth if (c&0x80)
155574a4d8c2SCharles.Forsyth if (ip->osize == 'L')
155674a4d8c2SCharles.Forsyth ip->imm = c|0xffffff00;
155774a4d8c2SCharles.Forsyth else
155874a4d8c2SCharles.Forsyth ip->imm = c|0xff00;
155974a4d8c2SCharles.Forsyth else
156074a4d8c2SCharles.Forsyth ip->imm = c&0xff;
1561d67b7dadSforsyth ip->imm64 = (long)ip->imm;
156274a4d8c2SCharles.Forsyth break;
156374a4d8c2SCharles.Forsyth case Iw: /* 16-bit immediate -> imm */
156474a4d8c2SCharles.Forsyth if (igets(map, ip, &s) < 0)
156574a4d8c2SCharles.Forsyth return 0;
156674a4d8c2SCharles.Forsyth ip->imm = s&0xffff;
1567d67b7dadSforsyth ip->imm64 = ip->imm;
156874a4d8c2SCharles.Forsyth ip->jumptype = Iw;
156974a4d8c2SCharles.Forsyth break;
157074a4d8c2SCharles.Forsyth case Iw2: /* 16-bit immediate -> in imm2*/
157174a4d8c2SCharles.Forsyth if (igets(map, ip, &s) < 0)
157274a4d8c2SCharles.Forsyth return 0;
157374a4d8c2SCharles.Forsyth ip->imm2 = s&0xffff;
157474a4d8c2SCharles.Forsyth break;
1575d67b7dadSforsyth case Iwd: /* Operand-sized immediate (no sign extension unless 64 bits)*/
157674a4d8c2SCharles.Forsyth if (ip->osize == 'L') {
157774a4d8c2SCharles.Forsyth if (igetl(map, ip, &ip->imm) < 0)
157874a4d8c2SCharles.Forsyth return 0;
1579d67b7dadSforsyth ip->imm64 = ip->imm;
1580d67b7dadSforsyth if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
1581d67b7dadSforsyth ip->imm64 |= (vlong)~0 << 32;
1582d67b7dadSforsyth } else {
1583d67b7dadSforsyth if (igets(map, ip, &s)< 0)
1584d67b7dadSforsyth return 0;
1585d67b7dadSforsyth ip->imm = s&0xffff;
1586d67b7dadSforsyth ip->imm64 = ip->imm;
1587d67b7dadSforsyth }
1588d67b7dadSforsyth break;
1589d67b7dadSforsyth case Iwdq: /* Operand-sized immediate, possibly big */
1590d67b7dadSforsyth if (ip->osize == 'L') {
1591d67b7dadSforsyth if (igetl(map, ip, &ip->imm) < 0)
1592d67b7dadSforsyth return 0;
1593d67b7dadSforsyth ip->imm64 = ip->imm;
1594d67b7dadSforsyth if (ip->rex & REXW) {
1595d67b7dadSforsyth ulong l;
1596d67b7dadSforsyth if (igetl(map, ip, &l) < 0)
1597d67b7dadSforsyth return 0;
1598d67b7dadSforsyth ip->imm64 |= (uvlong)l << 32;
1599d67b7dadSforsyth }
160074a4d8c2SCharles.Forsyth } else {
160174a4d8c2SCharles.Forsyth if (igets(map, ip, &s)< 0)
160274a4d8c2SCharles.Forsyth return 0;
160374a4d8c2SCharles.Forsyth ip->imm = s&0xffff;
160474a4d8c2SCharles.Forsyth }
160574a4d8c2SCharles.Forsyth break;
160674a4d8c2SCharles.Forsyth case Awd: /* Address-sized immediate (no sign extension)*/
160774a4d8c2SCharles.Forsyth if (ip->asize == 'E') {
160874a4d8c2SCharles.Forsyth if (igetl(map, ip, &ip->imm) < 0)
160974a4d8c2SCharles.Forsyth return 0;
1610d67b7dadSforsyth /* TO DO: REX */
161174a4d8c2SCharles.Forsyth } else {
161274a4d8c2SCharles.Forsyth if (igets(map, ip, &s)< 0)
161374a4d8c2SCharles.Forsyth return 0;
161474a4d8c2SCharles.Forsyth ip->imm = s&0xffff;
161574a4d8c2SCharles.Forsyth }
161674a4d8c2SCharles.Forsyth break;
161774a4d8c2SCharles.Forsyth case Iwds: /* Operand-sized immediate (sign extended) */
161874a4d8c2SCharles.Forsyth if (ip->osize == 'L') {
161974a4d8c2SCharles.Forsyth if (igetl(map, ip, &ip->imm) < 0)
162074a4d8c2SCharles.Forsyth return 0;
162174a4d8c2SCharles.Forsyth } else {
162274a4d8c2SCharles.Forsyth if (igets(map, ip, &s)< 0)
162374a4d8c2SCharles.Forsyth return 0;
162474a4d8c2SCharles.Forsyth if (s&0x8000)
162574a4d8c2SCharles.Forsyth ip->imm = s|0xffff0000;
162674a4d8c2SCharles.Forsyth else
162774a4d8c2SCharles.Forsyth ip->imm = s&0xffff;
162874a4d8c2SCharles.Forsyth }
162974a4d8c2SCharles.Forsyth ip->jumptype = Iwds;
163074a4d8c2SCharles.Forsyth break;
163174a4d8c2SCharles.Forsyth case OA: /* literal 0x0a byte */
163274a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
163374a4d8c2SCharles.Forsyth return 0;
163474a4d8c2SCharles.Forsyth if (c != 0x0a)
163574a4d8c2SCharles.Forsyth goto badop;
163674a4d8c2SCharles.Forsyth break;
163774a4d8c2SCharles.Forsyth case R0: /* base register must be R0 */
163874a4d8c2SCharles.Forsyth if (ip->base != 0)
163974a4d8c2SCharles.Forsyth goto badop;
164074a4d8c2SCharles.Forsyth break;
164174a4d8c2SCharles.Forsyth case R1: /* base register must be R1 */
164274a4d8c2SCharles.Forsyth if (ip->base != 1)
164374a4d8c2SCharles.Forsyth goto badop;
164474a4d8c2SCharles.Forsyth break;
164574a4d8c2SCharles.Forsyth case RMB: /* R/M field with byte register (/r)*/
164674a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
164774a4d8c2SCharles.Forsyth return 0;
164874a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
164974a4d8c2SCharles.Forsyth return 0;
165074a4d8c2SCharles.Forsyth ip->osize = 'B';
165174a4d8c2SCharles.Forsyth break;
165274a4d8c2SCharles.Forsyth case RM: /* R/M field with register (/r) */
165374a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
165474a4d8c2SCharles.Forsyth return 0;
165574a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
165674a4d8c2SCharles.Forsyth return 0;
165774a4d8c2SCharles.Forsyth break;
165874a4d8c2SCharles.Forsyth case RMOPB: /* R/M field with op code (/digit) */
165974a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
166074a4d8c2SCharles.Forsyth return 0;
166174a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
166274a4d8c2SCharles.Forsyth return 0;
166374a4d8c2SCharles.Forsyth c = ip->reg; /* secondary op code */
166474a4d8c2SCharles.Forsyth obase = (Optable*)op->proto;
166574a4d8c2SCharles.Forsyth ip->osize = 'B';
166674a4d8c2SCharles.Forsyth goto newop;
166774a4d8c2SCharles.Forsyth case RMOP: /* R/M field with op code (/digit) */
166874a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
166974a4d8c2SCharles.Forsyth return 0;
167074a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
167174a4d8c2SCharles.Forsyth return 0;
167274a4d8c2SCharles.Forsyth obase = (Optable*)op->proto;
1673d67b7dadSforsyth if(ip->amd64 && obase == optab0F01 && c == 0xF8)
1674d67b7dadSforsyth return optab0F01F8;
1675d67b7dadSforsyth c = ip->reg;
167674a4d8c2SCharles.Forsyth goto newop;
167774a4d8c2SCharles.Forsyth case FRMOP: /* FP R/M field with op code (/digit) */
167874a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
167974a4d8c2SCharles.Forsyth return 0;
168074a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
168174a4d8c2SCharles.Forsyth return 0;
168274a4d8c2SCharles.Forsyth if ((c&0xc0) == 0xc0)
168374a4d8c2SCharles.Forsyth c = ip->reg+8; /* 16 entry table */
168474a4d8c2SCharles.Forsyth else
168574a4d8c2SCharles.Forsyth c = ip->reg;
168674a4d8c2SCharles.Forsyth obase = (Optable*)op->proto;
168774a4d8c2SCharles.Forsyth goto newop;
168874a4d8c2SCharles.Forsyth case FRMEX: /* Extended FP R/M field with op code (/digit) */
168974a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
169074a4d8c2SCharles.Forsyth return 0;
169174a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
169274a4d8c2SCharles.Forsyth return 0;
169374a4d8c2SCharles.Forsyth if ((c&0xc0) == 0xc0)
169474a4d8c2SCharles.Forsyth c = (c&0x3f)+8; /* 64-entry table */
169574a4d8c2SCharles.Forsyth else
169674a4d8c2SCharles.Forsyth c = ip->reg;
169774a4d8c2SCharles.Forsyth obase = (Optable*)op->proto;
169874a4d8c2SCharles.Forsyth goto newop;
169974a4d8c2SCharles.Forsyth case RMR: /* R/M register only (mod = 11) */
170074a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
170174a4d8c2SCharles.Forsyth return 0;
170274a4d8c2SCharles.Forsyth if ((c&0xc0) != 0xc0) {
170374a4d8c2SCharles.Forsyth werrstr("invalid R/M register: %x", c);
170474a4d8c2SCharles.Forsyth return 0;
170574a4d8c2SCharles.Forsyth }
170674a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
170774a4d8c2SCharles.Forsyth return 0;
170874a4d8c2SCharles.Forsyth break;
170974a4d8c2SCharles.Forsyth case RMM: /* R/M register only (mod = 11) */
171074a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
171174a4d8c2SCharles.Forsyth return 0;
171274a4d8c2SCharles.Forsyth if ((c&0xc0) == 0xc0) {
171374a4d8c2SCharles.Forsyth werrstr("invalid R/M memory mode: %x", c);
171474a4d8c2SCharles.Forsyth return 0;
171574a4d8c2SCharles.Forsyth }
171674a4d8c2SCharles.Forsyth if (modrm(map, ip, c) < 0)
171774a4d8c2SCharles.Forsyth return 0;
171874a4d8c2SCharles.Forsyth break;
171974a4d8c2SCharles.Forsyth case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
172074a4d8c2SCharles.Forsyth if (ip->osize == 'L') {
172174a4d8c2SCharles.Forsyth if (igetl(map, ip, &ip->disp) < 0)
172274a4d8c2SCharles.Forsyth return 0;
172374a4d8c2SCharles.Forsyth } else {
172474a4d8c2SCharles.Forsyth if (igets(map, ip, &s)< 0)
172574a4d8c2SCharles.Forsyth return 0;
172674a4d8c2SCharles.Forsyth ip->disp = s&0xffff;
172774a4d8c2SCharles.Forsyth }
172874a4d8c2SCharles.Forsyth if (igets(map, ip, (ushort*)&ip->seg) < 0)
172974a4d8c2SCharles.Forsyth return 0;
173074a4d8c2SCharles.Forsyth ip->jumptype = PTR;
173174a4d8c2SCharles.Forsyth break;
1732d67b7dadSforsyth case AUXMM: /* Multi-byte op code; prefix determines table selection */
1733d67b7dadSforsyth if (igetc(map, ip, &c) < 0)
1734d67b7dadSforsyth return 0;
1735d67b7dadSforsyth obase = (Optable*)op->proto;
1736d67b7dadSforsyth switch (ip->opre) {
1737d67b7dadSforsyth case 0x66: op = optab660F; break;
1738d67b7dadSforsyth case 0xF2: op = optabF20F; break;
1739d67b7dadSforsyth case 0xF3: op = optabF30F; break;
1740d67b7dadSforsyth default: op = nil; break;
1741d67b7dadSforsyth }
1742d67b7dadSforsyth if(op != nil && op[c].proto != nil)
1743d67b7dadSforsyth obase = op;
1744d67b7dadSforsyth norex = 1; /* no more rex prefixes */
1745d67b7dadSforsyth /* otherwise the optab entry captures it */
1746d67b7dadSforsyth goto newop;
174774a4d8c2SCharles.Forsyth case AUX: /* Multi-byte op code - Auxiliary table */
174874a4d8c2SCharles.Forsyth obase = (Optable*)op->proto;
174974a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
175074a4d8c2SCharles.Forsyth return 0;
175174a4d8c2SCharles.Forsyth goto newop;
1752d67b7dadSforsyth case OPRE: /* Instr Prefix or media op */
1753d67b7dadSforsyth ip->opre = c;
1754d67b7dadSforsyth /* fall through */
175574a4d8c2SCharles.Forsyth case PRE: /* Instr Prefix */
175674a4d8c2SCharles.Forsyth ip->prefix = (char*)op->proto;
175774a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
175874a4d8c2SCharles.Forsyth return 0;
1759d67b7dadSforsyth if (ip->opre && c == 0x0F)
1760d67b7dadSforsyth ip->prefix = 0;
176174a4d8c2SCharles.Forsyth goto newop;
176274a4d8c2SCharles.Forsyth case SEG: /* Segment Prefix */
176374a4d8c2SCharles.Forsyth ip->segment = (char*)op->proto;
176474a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
176574a4d8c2SCharles.Forsyth return 0;
176674a4d8c2SCharles.Forsyth goto newop;
176774a4d8c2SCharles.Forsyth case OPOVER: /* Operand size override */
1768d67b7dadSforsyth ip->opre = c;
176974a4d8c2SCharles.Forsyth ip->osize = 'W';
177074a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
177174a4d8c2SCharles.Forsyth return 0;
1772d67b7dadSforsyth if (c == 0x0F)
1773d67b7dadSforsyth ip->osize = 'L';
1774d67b7dadSforsyth else if (ip->amd64 && (c&0xF0) == 0x40)
1775d67b7dadSforsyth ip->osize = 'Q';
177674a4d8c2SCharles.Forsyth goto newop;
177774a4d8c2SCharles.Forsyth case ADDOVER: /* Address size override */
177874a4d8c2SCharles.Forsyth ip->asize = 0;
177974a4d8c2SCharles.Forsyth if (igetc(map, ip, &c) < 0)
178074a4d8c2SCharles.Forsyth return 0;
178174a4d8c2SCharles.Forsyth goto newop;
178274a4d8c2SCharles.Forsyth case JUMP: /* mark instruction as JUMP or RET */
178374a4d8c2SCharles.Forsyth case RET:
178474a4d8c2SCharles.Forsyth ip->jumptype = op->operand[i];
178574a4d8c2SCharles.Forsyth break;
178674a4d8c2SCharles.Forsyth default:
178774a4d8c2SCharles.Forsyth werrstr("bad operand type %d", op->operand[i]);
178874a4d8c2SCharles.Forsyth return 0;
178974a4d8c2SCharles.Forsyth }
179074a4d8c2SCharles.Forsyth }
179174a4d8c2SCharles.Forsyth return op;
179274a4d8c2SCharles.Forsyth }
179374a4d8c2SCharles.Forsyth
1794d67b7dadSforsyth #pragma varargck argpos bprint 2
1795d67b7dadSforsyth
179674a4d8c2SCharles.Forsyth static void
bprint(Instr * ip,char * fmt,...)179774a4d8c2SCharles.Forsyth bprint(Instr *ip, char *fmt, ...)
179874a4d8c2SCharles.Forsyth {
179974a4d8c2SCharles.Forsyth va_list arg;
180074a4d8c2SCharles.Forsyth
180174a4d8c2SCharles.Forsyth va_start(arg, fmt);
180274a4d8c2SCharles.Forsyth ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
180374a4d8c2SCharles.Forsyth va_end(arg);
180474a4d8c2SCharles.Forsyth }
180574a4d8c2SCharles.Forsyth
180674a4d8c2SCharles.Forsyth /*
180774a4d8c2SCharles.Forsyth * if we want to call 16 bit regs AX,BX,CX,...
180874a4d8c2SCharles.Forsyth * and 32 bit regs EAX,EBX,ECX,... then
180974a4d8c2SCharles.Forsyth * change the defs of ANAME and ONAME to:
181074a4d8c2SCharles.Forsyth * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
181174a4d8c2SCharles.Forsyth * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
181274a4d8c2SCharles.Forsyth */
181374a4d8c2SCharles.Forsyth #define ANAME(ip) ""
181474a4d8c2SCharles.Forsyth #define ONAME(ip) ""
181574a4d8c2SCharles.Forsyth
181674a4d8c2SCharles.Forsyth static char *reg[] = {
1817773d7fd2Sforsyth "AX",
1818773d7fd2Sforsyth "CX",
1819773d7fd2Sforsyth "DX",
1820773d7fd2Sforsyth "BX",
1821773d7fd2Sforsyth "SP",
1822773d7fd2Sforsyth "BP",
1823773d7fd2Sforsyth "SI",
1824773d7fd2Sforsyth "DI",
1825d67b7dadSforsyth
1826d67b7dadSforsyth /* amd64 */
1827773d7fd2Sforsyth "R8",
1828773d7fd2Sforsyth "R9",
1829773d7fd2Sforsyth "R10",
1830773d7fd2Sforsyth "R11",
1831773d7fd2Sforsyth "R12",
1832773d7fd2Sforsyth "R13",
1833773d7fd2Sforsyth "R14",
1834773d7fd2Sforsyth "R15",
183574a4d8c2SCharles.Forsyth };
183674a4d8c2SCharles.Forsyth
183774a4d8c2SCharles.Forsyth static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
1838d67b7dadSforsyth static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
1839d67b7dadSforsyth "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
184074a4d8c2SCharles.Forsyth static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
184174a4d8c2SCharles.Forsyth
184274a4d8c2SCharles.Forsyth static void
plocal(Instr * ip)184374a4d8c2SCharles.Forsyth plocal(Instr *ip)
184474a4d8c2SCharles.Forsyth {
1845d67b7dadSforsyth int ret;
1846d67b7dadSforsyth long offset;
184774a4d8c2SCharles.Forsyth Symbol s;
184874a4d8c2SCharles.Forsyth char *reg;
184974a4d8c2SCharles.Forsyth
185074a4d8c2SCharles.Forsyth offset = ip->disp;
185174a4d8c2SCharles.Forsyth if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
185274a4d8c2SCharles.Forsyth bprint(ip, "%lux(SP)", offset);
185374a4d8c2SCharles.Forsyth return;
185474a4d8c2SCharles.Forsyth }
185574a4d8c2SCharles.Forsyth
185674a4d8c2SCharles.Forsyth if (s.value > ip->disp) {
185774a4d8c2SCharles.Forsyth ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
185874a4d8c2SCharles.Forsyth reg = "(SP)";
185974a4d8c2SCharles.Forsyth } else {
186074a4d8c2SCharles.Forsyth offset -= s.value;
186174a4d8c2SCharles.Forsyth ret = getauto(&s, offset, CPARAM, &s);
186274a4d8c2SCharles.Forsyth reg = "(FP)";
186374a4d8c2SCharles.Forsyth }
186474a4d8c2SCharles.Forsyth if (ret)
186574a4d8c2SCharles.Forsyth bprint(ip, "%s+", s.name);
186674a4d8c2SCharles.Forsyth else
186774a4d8c2SCharles.Forsyth offset = ip->disp;
186874a4d8c2SCharles.Forsyth bprint(ip, "%lux%s", offset, reg);
186974a4d8c2SCharles.Forsyth }
187074a4d8c2SCharles.Forsyth
1871d67b7dadSforsyth static int
isjmp(Instr * ip)1872d67b7dadSforsyth isjmp(Instr *ip)
1873d67b7dadSforsyth {
1874d67b7dadSforsyth switch(ip->jumptype){
1875d67b7dadSforsyth case Iwds:
1876d67b7dadSforsyth case Jbs:
1877d67b7dadSforsyth case JUMP:
1878d67b7dadSforsyth return 1;
1879d67b7dadSforsyth default:
1880d67b7dadSforsyth return 0;
1881d67b7dadSforsyth }
1882d67b7dadSforsyth }
1883d67b7dadSforsyth
1884d67b7dadSforsyth /*
1885d67b7dadSforsyth * This is too smart for its own good, but it really is nice
1886d67b7dadSforsyth * to have accurate translations when debugging, and it
1887d67b7dadSforsyth * helps us identify which code is different in binaries that
1888d67b7dadSforsyth * are changed on sources.
1889d67b7dadSforsyth */
1890d67b7dadSforsyth static int
issymref(Instr * ip,Symbol * s,long w,long val)1891d67b7dadSforsyth issymref(Instr *ip, Symbol *s, long w, long val)
1892d67b7dadSforsyth {
1893d67b7dadSforsyth Symbol next, tmp;
1894d67b7dadSforsyth long isstring, size;
1895d67b7dadSforsyth
1896d67b7dadSforsyth if (isjmp(ip))
1897d67b7dadSforsyth return 1;
1898d67b7dadSforsyth if (s->class==CTEXT && w==0)
1899d67b7dadSforsyth return 1;
1900d67b7dadSforsyth if (s->class==CDATA) {
1901d67b7dadSforsyth /* use first bss symbol (or "end") rather than edata */
1902d67b7dadSforsyth if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
1903d67b7dadSforsyth if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value)
1904d67b7dadSforsyth || (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value))
1905d67b7dadSforsyth *s = tmp;
1906d67b7dadSforsyth }
1907d67b7dadSforsyth if (w == 0)
1908d67b7dadSforsyth return 1;
1909d67b7dadSforsyth for (next=*s; next.value==s->value; next=tmp)
1910d67b7dadSforsyth if (!globalsym(&tmp, next.index+1))
1911d67b7dadSforsyth break;
1912d67b7dadSforsyth size = next.value - s->value;
1913d67b7dadSforsyth if (w >= size)
1914d67b7dadSforsyth return 0;
1915d67b7dadSforsyth if (w > size-w)
1916d67b7dadSforsyth w = size-w;
1917d67b7dadSforsyth /* huge distances are usually wrong except in .string */
1918d67b7dadSforsyth isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
1919d67b7dadSforsyth if (w > 8192 && !isstring)
1920d67b7dadSforsyth return 0;
1921d67b7dadSforsyth /* medium distances are tricky - look for constants */
1922d67b7dadSforsyth /* near powers of two */
1923d67b7dadSforsyth if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
1924d67b7dadSforsyth return 0;
1925d67b7dadSforsyth return 1;
1926d67b7dadSforsyth }
1927d67b7dadSforsyth return 0;
1928d67b7dadSforsyth }
1929d67b7dadSforsyth
1930d67b7dadSforsyth static void
immediate(Instr * ip,vlong val)1931d67b7dadSforsyth immediate(Instr *ip, vlong val)
1932d67b7dadSforsyth {
1933d67b7dadSforsyth Symbol s;
1934d67b7dadSforsyth long w;
1935d67b7dadSforsyth
1936d67b7dadSforsyth if (findsym(val, CANY, &s)) { /* TO DO */
1937d67b7dadSforsyth w = val - s.value;
1938d67b7dadSforsyth if (w < 0)
1939d67b7dadSforsyth w = -w;
1940d67b7dadSforsyth if (issymref(ip, &s, w, val)) {
1941d67b7dadSforsyth if (w)
1942d67b7dadSforsyth bprint(ip, "%s+%lux(SB)", s.name, w);
1943d67b7dadSforsyth else
1944d67b7dadSforsyth bprint(ip, "%s(SB)", s.name);
1945d67b7dadSforsyth return;
1946d67b7dadSforsyth }
1947d67b7dadSforsyth /*
1948d67b7dadSforsyth if (s.class==CDATA && globalsym(&s, s.index+1)) {
1949d67b7dadSforsyth w = s.value - val;
1950d67b7dadSforsyth if (w < 0)
1951d67b7dadSforsyth w = -w;
1952d67b7dadSforsyth if (w < 4096) {
1953d67b7dadSforsyth bprint(ip, "%s-%lux(SB)", s.name, w);
1954d67b7dadSforsyth return;
1955d67b7dadSforsyth }
1956d67b7dadSforsyth }
1957d67b7dadSforsyth */
1958d67b7dadSforsyth }
1959d67b7dadSforsyth if((ip->rex & REXW) == 0)
1960d67b7dadSforsyth bprint(ip, "%lux", (long)val);
1961d67b7dadSforsyth else
1962d67b7dadSforsyth bprint(ip, "%llux", val);
1963d67b7dadSforsyth }
1964d67b7dadSforsyth
196574a4d8c2SCharles.Forsyth static void
pea(Instr * ip)196674a4d8c2SCharles.Forsyth pea(Instr *ip)
196774a4d8c2SCharles.Forsyth {
196874a4d8c2SCharles.Forsyth if (ip->mod == 3) {
196974a4d8c2SCharles.Forsyth if (ip->osize == 'B')
1970d67b7dadSforsyth bprint(ip, (ip->rex & REXB? breg64: breg)[ip->base]);
1971d67b7dadSforsyth else if(ip->rex & REXB)
1972d67b7dadSforsyth bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]);
197374a4d8c2SCharles.Forsyth else
197474a4d8c2SCharles.Forsyth bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
197574a4d8c2SCharles.Forsyth return;
197674a4d8c2SCharles.Forsyth }
197774a4d8c2SCharles.Forsyth if (ip->segment)
197874a4d8c2SCharles.Forsyth bprint(ip, ip->segment);
197974a4d8c2SCharles.Forsyth if (ip->asize == 'E' && ip->base == SP)
198074a4d8c2SCharles.Forsyth plocal(ip);
198174a4d8c2SCharles.Forsyth else {
1982d67b7dadSforsyth if (ip->base < 0)
1983d67b7dadSforsyth immediate(ip, ip->disp);
1984d67b7dadSforsyth else {
198574a4d8c2SCharles.Forsyth bprint(ip, "%lux", ip->disp);
1986d67b7dadSforsyth if(ip->rip)
1987d67b7dadSforsyth bprint(ip, "(RIP)");
1988d67b7dadSforsyth bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
1989d67b7dadSforsyth }
199074a4d8c2SCharles.Forsyth }
199174a4d8c2SCharles.Forsyth if (ip->index >= 0)
1992d67b7dadSforsyth bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
199374a4d8c2SCharles.Forsyth }
199474a4d8c2SCharles.Forsyth
199574a4d8c2SCharles.Forsyth static void
prinstr(Instr * ip,char * fmt)199674a4d8c2SCharles.Forsyth prinstr(Instr *ip, char *fmt)
199774a4d8c2SCharles.Forsyth {
1998d67b7dadSforsyth vlong v;
1999d67b7dadSforsyth
200074a4d8c2SCharles.Forsyth if (ip->prefix)
200174a4d8c2SCharles.Forsyth bprint(ip, "%s ", ip->prefix);
200274a4d8c2SCharles.Forsyth for (; *fmt && ip->curr < ip->end; fmt++) {
2003d67b7dadSforsyth if (*fmt != '%'){
200474a4d8c2SCharles.Forsyth *ip->curr++ = *fmt;
2005d67b7dadSforsyth continue;
2006d67b7dadSforsyth }
2007d67b7dadSforsyth switch(*++fmt){
200874a4d8c2SCharles.Forsyth case '%':
200974a4d8c2SCharles.Forsyth *ip->curr++ = '%';
201074a4d8c2SCharles.Forsyth break;
201174a4d8c2SCharles.Forsyth case 'A':
201274a4d8c2SCharles.Forsyth bprint(ip, "%s", ANAME(ip));
201374a4d8c2SCharles.Forsyth break;
201474a4d8c2SCharles.Forsyth case 'C':
201574a4d8c2SCharles.Forsyth bprint(ip, "CR%d", ip->reg);
201674a4d8c2SCharles.Forsyth break;
201774a4d8c2SCharles.Forsyth case 'D':
201874a4d8c2SCharles.Forsyth if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
201974a4d8c2SCharles.Forsyth bprint(ip, "DR%d",ip->reg);
202074a4d8c2SCharles.Forsyth else
2021*45a20ab7Sforsyth bprint(ip, "?");
202274a4d8c2SCharles.Forsyth break;
202374a4d8c2SCharles.Forsyth case 'I':
202474a4d8c2SCharles.Forsyth bprint(ip, "$");
202574a4d8c2SCharles.Forsyth immediate(ip, ip->imm2);
202674a4d8c2SCharles.Forsyth break;
202774a4d8c2SCharles.Forsyth case 'O':
202874a4d8c2SCharles.Forsyth bprint(ip,"%s", ONAME(ip));
202974a4d8c2SCharles.Forsyth break;
203074a4d8c2SCharles.Forsyth case 'i':
203174a4d8c2SCharles.Forsyth bprint(ip, "$");
2032d67b7dadSforsyth v = ip->imm;
2033d67b7dadSforsyth if(ip->rex & REXW)
2034d67b7dadSforsyth v = ip->imm64;
2035d67b7dadSforsyth immediate(ip, v);
203674a4d8c2SCharles.Forsyth break;
203774a4d8c2SCharles.Forsyth case 'R':
2038d67b7dadSforsyth bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
203974a4d8c2SCharles.Forsyth break;
204074a4d8c2SCharles.Forsyth case 'S':
2041d67b7dadSforsyth if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
2042d67b7dadSforsyth bprint(ip, "Q");
2043d67b7dadSforsyth else
204474a4d8c2SCharles.Forsyth bprint(ip, "%c", ip->osize);
204574a4d8c2SCharles.Forsyth break;
2046d67b7dadSforsyth case 's':
2047d67b7dadSforsyth if(ip->opre == 0 || ip->opre == 0x66)
2048d67b7dadSforsyth bprint(ip, "P");
2049d67b7dadSforsyth else
2050d67b7dadSforsyth bprint(ip, "S");
2051d67b7dadSforsyth if(ip->opre == 0xf2 || ip->opre == 0x66)
2052d67b7dadSforsyth bprint(ip, "D");
2053d67b7dadSforsyth else
2054d67b7dadSforsyth bprint(ip, "S");
2055d67b7dadSforsyth break;
205674a4d8c2SCharles.Forsyth case 'T':
205774a4d8c2SCharles.Forsyth if (ip->reg == 6 || ip->reg == 7)
205874a4d8c2SCharles.Forsyth bprint(ip, "TR%d",ip->reg);
205974a4d8c2SCharles.Forsyth else
2060*45a20ab7Sforsyth bprint(ip, "?");
206174a4d8c2SCharles.Forsyth break;
2062d67b7dadSforsyth case 'W':
2063d67b7dadSforsyth if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
2064d67b7dadSforsyth bprint(ip, "CDQE");
2065d67b7dadSforsyth else if (ip->osize == 'L')
206674a4d8c2SCharles.Forsyth bprint(ip,"CWDE");
206774a4d8c2SCharles.Forsyth else
206874a4d8c2SCharles.Forsyth bprint(ip, "CBW");
206974a4d8c2SCharles.Forsyth break;
207074a4d8c2SCharles.Forsyth case 'd':
2071d67b7dadSforsyth bprint(ip,"%ux:%lux",ip->seg,ip->disp);
2072d67b7dadSforsyth break;
2073d67b7dadSforsyth case 'm':
2074d67b7dadSforsyth if (ip->mod == 3 && ip->osize != 'B') {
2075d67b7dadSforsyth if(fmt[1] != '*'){
2076d67b7dadSforsyth if(ip->opre != 0) {
2077d67b7dadSforsyth bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
2078d67b7dadSforsyth break;
2079d67b7dadSforsyth }
2080d67b7dadSforsyth } else
2081d67b7dadSforsyth fmt++;
2082d67b7dadSforsyth bprint(ip, "M%d", ip->base);
2083d67b7dadSforsyth break;
2084d67b7dadSforsyth }
2085d67b7dadSforsyth pea(ip);
208674a4d8c2SCharles.Forsyth break;
208774a4d8c2SCharles.Forsyth case 'e':
208874a4d8c2SCharles.Forsyth pea(ip);
208974a4d8c2SCharles.Forsyth break;
209074a4d8c2SCharles.Forsyth case 'f':
209174a4d8c2SCharles.Forsyth bprint(ip, "F%d", ip->base);
209274a4d8c2SCharles.Forsyth break;
209374a4d8c2SCharles.Forsyth case 'g':
209474a4d8c2SCharles.Forsyth if (ip->reg < 6)
209574a4d8c2SCharles.Forsyth bprint(ip,"%s",sreg[ip->reg]);
209674a4d8c2SCharles.Forsyth else
2097*45a20ab7Sforsyth bprint(ip,"?");
209874a4d8c2SCharles.Forsyth break;
209974a4d8c2SCharles.Forsyth case 'p':
2100d67b7dadSforsyth /*
2101d67b7dadSforsyth * signed immediate in the ulong ip->imm.
2102d67b7dadSforsyth */
2103d67b7dadSforsyth v = (long)ip->imm;
2104d67b7dadSforsyth immediate(ip, v+ip->addr+ip->n);
210574a4d8c2SCharles.Forsyth break;
210674a4d8c2SCharles.Forsyth case 'r':
210774a4d8c2SCharles.Forsyth if (ip->osize == 'B')
2108d67b7dadSforsyth bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
210974a4d8c2SCharles.Forsyth else
2110d67b7dadSforsyth bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
211174a4d8c2SCharles.Forsyth break;
2112d67b7dadSforsyth case 'w':
2113d67b7dadSforsyth if (ip->osize == 'Q' || ip->rex & REXW)
2114d67b7dadSforsyth bprint(ip, "CQO");
2115d67b7dadSforsyth else if (ip->osize == 'L')
211674a4d8c2SCharles.Forsyth bprint(ip,"CDQ");
211774a4d8c2SCharles.Forsyth else
211874a4d8c2SCharles.Forsyth bprint(ip, "CWD");
211974a4d8c2SCharles.Forsyth break;
2120d67b7dadSforsyth case 'M':
2121d67b7dadSforsyth if(ip->opre != 0)
2122d67b7dadSforsyth bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
2123d67b7dadSforsyth else
2124d67b7dadSforsyth bprint(ip, "M%d", ip->reg);
2125d67b7dadSforsyth break;
2126d67b7dadSforsyth case 'x':
2127d67b7dadSforsyth if (ip->mod == 3 && ip->osize != 'B') {
2128d67b7dadSforsyth bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
2129d67b7dadSforsyth break;
2130d67b7dadSforsyth }
2131d67b7dadSforsyth pea(ip);
2132d67b7dadSforsyth break;
2133d67b7dadSforsyth case 'X':
2134d67b7dadSforsyth bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
2135d67b7dadSforsyth break;
213674a4d8c2SCharles.Forsyth default:
213774a4d8c2SCharles.Forsyth bprint(ip, "%%%c", *fmt);
213874a4d8c2SCharles.Forsyth break;
213974a4d8c2SCharles.Forsyth }
214074a4d8c2SCharles.Forsyth }
214174a4d8c2SCharles.Forsyth *ip->curr = 0; /* there's always room for 1 byte */
214274a4d8c2SCharles.Forsyth }
214374a4d8c2SCharles.Forsyth
214474a4d8c2SCharles.Forsyth static int
i386inst(Map * map,uvlong pc,char modifier,char * buf,int n)2145d67b7dadSforsyth i386inst(Map *map, uvlong pc, char modifier, char *buf, int n)
214674a4d8c2SCharles.Forsyth {
214774a4d8c2SCharles.Forsyth Instr instr;
214874a4d8c2SCharles.Forsyth Optable *op;
214974a4d8c2SCharles.Forsyth
215074a4d8c2SCharles.Forsyth USED(modifier);
215174a4d8c2SCharles.Forsyth op = mkinstr(map, &instr, pc);
215274a4d8c2SCharles.Forsyth if (op == 0) {
215374a4d8c2SCharles.Forsyth errstr(buf, n);
215474a4d8c2SCharles.Forsyth return -1;
215574a4d8c2SCharles.Forsyth }
215674a4d8c2SCharles.Forsyth instr.curr = buf;
215774a4d8c2SCharles.Forsyth instr.end = buf+n-1;
215874a4d8c2SCharles.Forsyth prinstr(&instr, op->proto);
215974a4d8c2SCharles.Forsyth return instr.n;
216074a4d8c2SCharles.Forsyth }
216174a4d8c2SCharles.Forsyth
216274a4d8c2SCharles.Forsyth static int
i386das(Map * map,uvlong pc,char * buf,int n)2163d67b7dadSforsyth i386das(Map *map, uvlong pc, char *buf, int n)
216474a4d8c2SCharles.Forsyth {
216574a4d8c2SCharles.Forsyth Instr instr;
216674a4d8c2SCharles.Forsyth int i;
216774a4d8c2SCharles.Forsyth
216874a4d8c2SCharles.Forsyth if (mkinstr(map, &instr, pc) == 0) {
216974a4d8c2SCharles.Forsyth errstr(buf, n);
217074a4d8c2SCharles.Forsyth return -1;
217174a4d8c2SCharles.Forsyth }
217274a4d8c2SCharles.Forsyth for(i = 0; i < instr.n && n > 2; i++) {
217374a4d8c2SCharles.Forsyth _hexify(buf, instr.mem[i], 1);
217474a4d8c2SCharles.Forsyth buf += 2;
217574a4d8c2SCharles.Forsyth n -= 2;
217674a4d8c2SCharles.Forsyth }
217774a4d8c2SCharles.Forsyth *buf = 0;
217874a4d8c2SCharles.Forsyth return instr.n;
217974a4d8c2SCharles.Forsyth }
218074a4d8c2SCharles.Forsyth
218174a4d8c2SCharles.Forsyth static int
i386instlen(Map * map,uvlong pc)2182d67b7dadSforsyth i386instlen(Map *map, uvlong pc)
218374a4d8c2SCharles.Forsyth {
218474a4d8c2SCharles.Forsyth Instr i;
218574a4d8c2SCharles.Forsyth
218674a4d8c2SCharles.Forsyth if (mkinstr(map, &i, pc))
218774a4d8c2SCharles.Forsyth return i.n;
218874a4d8c2SCharles.Forsyth return -1;
218974a4d8c2SCharles.Forsyth }
219074a4d8c2SCharles.Forsyth
219174a4d8c2SCharles.Forsyth static int
i386foll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)2192d67b7dadSforsyth i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
219374a4d8c2SCharles.Forsyth {
219474a4d8c2SCharles.Forsyth Instr i;
219574a4d8c2SCharles.Forsyth Optable *op;
219674a4d8c2SCharles.Forsyth ushort s;
2197d67b7dadSforsyth uvlong l, addr;
2198d67b7dadSforsyth vlong v;
219974a4d8c2SCharles.Forsyth int n;
220074a4d8c2SCharles.Forsyth
220174a4d8c2SCharles.Forsyth op = mkinstr(map, &i, pc);
220274a4d8c2SCharles.Forsyth if (!op)
220374a4d8c2SCharles.Forsyth return -1;
220474a4d8c2SCharles.Forsyth
220574a4d8c2SCharles.Forsyth n = 0;
220674a4d8c2SCharles.Forsyth
220774a4d8c2SCharles.Forsyth switch(i.jumptype) {
220874a4d8c2SCharles.Forsyth case RET: /* RETURN or LEAVE */
220974a4d8c2SCharles.Forsyth case Iw: /* RETURN */
221074a4d8c2SCharles.Forsyth if (strcmp(op->proto, "LEAVE") == 0) {
2211d67b7dadSforsyth if (geta(map, (*rget)(map, "BP"), &l) < 0)
221274a4d8c2SCharles.Forsyth return -1;
2213d67b7dadSforsyth } else if (geta(map, (*rget)(map, mach->sp), &l) < 0)
221474a4d8c2SCharles.Forsyth return -1;
221574a4d8c2SCharles.Forsyth foll[0] = l;
221674a4d8c2SCharles.Forsyth return 1;
221774a4d8c2SCharles.Forsyth case Iwds: /* pc relative JUMP or CALL*/
221874a4d8c2SCharles.Forsyth case Jbs: /* pc relative JUMP or CALL */
2219d67b7dadSforsyth v = (long)i.imm;
2220d67b7dadSforsyth foll[0] = pc+v+i.n;
222174a4d8c2SCharles.Forsyth n = 1;
222274a4d8c2SCharles.Forsyth break;
222374a4d8c2SCharles.Forsyth case PTR: /* seg:displacement JUMP or CALL */
222474a4d8c2SCharles.Forsyth foll[0] = (i.seg<<4)+i.disp;
222574a4d8c2SCharles.Forsyth return 1;
222674a4d8c2SCharles.Forsyth case JUMP: /* JUMP or CALL EA */
222774a4d8c2SCharles.Forsyth
222874a4d8c2SCharles.Forsyth if(i.mod == 3) {
2229d67b7dadSforsyth foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]);
223074a4d8c2SCharles.Forsyth return 1;
223174a4d8c2SCharles.Forsyth }
223274a4d8c2SCharles.Forsyth /* calculate the effective address */
223374a4d8c2SCharles.Forsyth addr = i.disp;
223474a4d8c2SCharles.Forsyth if (i.base >= 0) {
2235d67b7dadSforsyth if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0)
223674a4d8c2SCharles.Forsyth return -1;
223774a4d8c2SCharles.Forsyth addr += l;
223874a4d8c2SCharles.Forsyth }
223974a4d8c2SCharles.Forsyth if (i.index >= 0) {
2240d67b7dadSforsyth if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0)
224174a4d8c2SCharles.Forsyth return -1;
224274a4d8c2SCharles.Forsyth addr += l*(1<<i.ss);
224374a4d8c2SCharles.Forsyth }
224474a4d8c2SCharles.Forsyth /* now retrieve a seg:disp value at that address */
224574a4d8c2SCharles.Forsyth if (get2(map, addr, &s) < 0) /* seg */
224674a4d8c2SCharles.Forsyth return -1;
224774a4d8c2SCharles.Forsyth foll[0] = s<<4;
224874a4d8c2SCharles.Forsyth addr += 2;
224974a4d8c2SCharles.Forsyth if (i.asize == 'L') {
2250d67b7dadSforsyth if (geta(map, addr, &l) < 0) /* disp32 */
225174a4d8c2SCharles.Forsyth return -1;
225274a4d8c2SCharles.Forsyth foll[0] += l;
225374a4d8c2SCharles.Forsyth } else { /* disp16 */
225474a4d8c2SCharles.Forsyth if (get2(map, addr, &s) < 0)
225574a4d8c2SCharles.Forsyth return -1;
225674a4d8c2SCharles.Forsyth foll[0] += s;
225774a4d8c2SCharles.Forsyth }
225874a4d8c2SCharles.Forsyth return 1;
225974a4d8c2SCharles.Forsyth default:
226074a4d8c2SCharles.Forsyth break;
226174a4d8c2SCharles.Forsyth }
226274a4d8c2SCharles.Forsyth if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
226374a4d8c2SCharles.Forsyth return 1;
226474a4d8c2SCharles.Forsyth foll[n++] = pc+i.n;
226574a4d8c2SCharles.Forsyth return n;
226674a4d8c2SCharles.Forsyth }
2267