1 /*
2  * 386 definition
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7 #include <mach.h>
8 #include "ureg386.h"
9 
10 #define	REGOFF(x)	(ulong)(&((struct Ureg *) 0)->x)
11 
12 #define	REGSIZE		sizeof(struct Ureg)
13 #define	FP_CTL(x)		(REGSIZE+4*(x))
14 #define	FP_REG(x)		(FP_CTL(7)+10*(x))
15 #define	FPREGSIZE	(6*4+8*10)
16 
17 /*
18  * i386-specific debugger interface
19  */
20 
21 	char	*i386excep(Map*, Regs*);
22 
23 /*
24 static	int	i386trace(Map*, ulong, ulong, ulong, Tracer);
25 static	ulong	i386frame(Map*, ulong, ulong, ulong, ulong);
26 */
27 	int	i386foll(Map*, Regs*, u64int, u64int*);
28 	int	i386hexinst(Map*, u64int, char*, int);
29 	int	i386das(Map*, u64int, char, char*, int);
30 	int	i386instlen(Map*, u64int);
31 	int	i386unwind(Map*, Regs*, u64int*, Symbol*);
32 
33 static char *i386windregs[] = {
34 	"PC",
35 	"SP",
36 	"BP",
37 	"AX",
38 	"CX",
39 	"DX",
40 	"BX",
41 	"SI",
42 	"DI",
43 	0,
44 };
45 
46 static	Regdesc i386reglist[] = {
47 	{"DI",		REGOFF(di),	RINT, 'X'},
48 	{"SI",		REGOFF(si),	RINT, 'X'},
49 	{"BP",		REGOFF(bp),	RINT, 'X'},
50 	{"BX",		REGOFF(bx),	RINT, 'X'},
51 	{"DX",		REGOFF(dx),	RINT, 'X'},
52 	{"CX",		REGOFF(cx),	RINT, 'X'},
53 	{"AX",		REGOFF(ax),	RINT, 'X'},
54 	{"GS",		REGOFF(gs),	RINT, 'X'},
55 	{"FS",		REGOFF(fs),	RINT, 'X'},
56 	{"ES",		REGOFF(es),	RINT, 'X'},
57 	{"DS",		REGOFF(ds),	RINT, 'X'},
58 	{"TRAP",	REGOFF(trap), 	RINT, 'X'},
59 	{"ECODE",	REGOFF(ecode),	RINT, 'X'},
60 	{"PC",		REGOFF(pc),		RINT, 'X'},
61 	{"CS",		REGOFF(cs),	RINT, 'X'},
62 	{"EFLAGS",	REGOFF(flags),	RINT, 'X'},
63 	{"SP",		REGOFF(sp),		RINT, 'X'},
64 	{"SS",		REGOFF(ss),	RINT, 'X'},
65 
66 	{"E0",		FP_CTL(0),	RFLT, 'X'},
67 	{"E1",		FP_CTL(1),	RFLT, 'X'},
68 	{"E2",		FP_CTL(2),	RFLT, 'X'},
69 	{"E3",		FP_CTL(3),	RFLT, 'X'},
70 	{"E4",		FP_CTL(4),	RFLT, 'X'},
71 	{"E5",		FP_CTL(5),	RFLT, 'X'},
72 	{"E6",		FP_CTL(6),	RFLT, 'X'},
73 	{"F0",		FP_REG(7),	RFLT, '3'},
74 	{"F1",		FP_REG(6),	RFLT, '3'},
75 	{"F2",		FP_REG(5),	RFLT, '3'},
76 	{"F3",		FP_REG(4),	RFLT, '3'},
77 	{"F4",		FP_REG(3),	RFLT, '3'},
78 	{"F5",		FP_REG(2),	RFLT, '3'},
79 	{"F6",		FP_REG(1),	RFLT, '3'},
80 	{"F7",		FP_REG(0),	RFLT, '3'},
81 	{  0 }
82 };
83 
84 Mach mach386 =
85 {
86 	"386",
87 	M386,		/* machine type */
88 	i386reglist,	/* register list */
89 	REGSIZE,	/* size of registers in bytes */
90 	FPREGSIZE,	/* size of fp registers in bytes */
91 	"PC",		/* name of PC */
92 	"SP",		/* name of SP */
93 	"BP",		/* name of FP */
94 	0,		/* link register */
95 	"setSB",	/* static base register name (bogus anyways) */
96 	0,		/* static base register value */
97 	0x1000,		/* page size */
98 	0x80100000,	/* kernel base */
99 	0,		/* kernel text mask */
100 	1,		/* quantization of pc */
101 	4,		/* szaddr */
102 	4,		/* szreg */
103 	4,		/* szfloat */
104 	8,		/* szdouble */
105 
106 	i386windregs,	/* locations unwound in stack trace */
107 	9,
108 
109 	{0xCC, 0, 0, 0},	/* break point: INT 3 */
110 	1,			/* break point size */
111 
112 	i386foll,		/* following addresses */
113 	i386excep,		/* print exception */
114 	i386unwind,		/* stack unwind */
115 
116 	leswap2,			/* convert short to local byte order */
117 	leswap4,			/* convert long to local byte order */
118 	leswap8,			/* convert vlong to local byte order */
119 	leieeeftoa32,		/* single precision float pointer */
120 	leieeeftoa64,		/* double precision float pointer */
121 	leieeeftoa80,		/* long double precision floating point */
122 
123 	i386das,		/* dissembler */
124 	i386das,		/* plan9-format disassembler */
125 	0,			/* commercial disassembler */
126 	i386hexinst,		/* print instruction */
127 	i386instlen,		/* instruction size calculation */
128 };
129 
130 /*
131  * The wrapper code around Linux system calls
132  * saves AX on the stack before calling some calls
133  * (at least, __libc_nanosleep), when running in
134  * threaded programs.
135  */
136 static void
syscallhack(Map * map,Regs * regs,int * spoff)137 syscallhack(Map *map, Regs *regs, int *spoff)
138 {
139 	u64int pc;
140 	char buf[60];
141 
142 	rget(regs, "PC", &pc);
143 	if(i386das(map, pc-2, 0, buf, sizeof buf) != 2 || strncmp(buf, "INTB\t$", 6) != 0)
144 		return;
145 	if(i386das(map, pc, 0, buf, sizeof buf) != 2 || strcmp(buf, "MOVL\tDX,BX") != 0)
146 		return;
147 	if(i386das(map, pc+2, 0, buf, sizeof buf) != 3 || strcmp(buf, "XCHGL\tAX,0(SP)") != 0)
148 		return;
149 	*spoff += 4;
150 }
151 
152 int
i386unwind(Map * map,Regs * regs,u64int * next,Symbol * sym)153 i386unwind(Map *map, Regs *regs, u64int *next, Symbol *sym)
154 {
155 	int i, isp, ipc, ibp, havebp, n, spoff, off[9];
156 	ulong pc;
157 	u32int v;
158 	char buf[60], *p;
159 
160 /*print("i386unwind %s\n", sym ? sym->name : nil); */
161 	isp = windindex("SP");
162 	ipc = windindex("PC");
163 	ibp = windindex("BP");
164 	if(isp < 0 || ipc < 0 || ibp < 0){
165 		werrstr("i386unwind: cannot happen");
166 		return -1;
167 	}
168 
169 	/*
170 	 * Disassemble entry to figure out
171 	 * where values have been saved.
172 	 * Perhaps should disassemble exit path
173 	 * instead -- a random walk on the code
174 	 * should suffice to get us to a RET.
175 	 */
176 	if(sym){
177 		pc = sym->loc.addr;
178 /*print("startpc %lux\n", pc); */
179 		memset(off, 0xff, sizeof off);
180 		spoff = 0;
181 		havebp = 0;
182 		for(;;){
183 			if((n = i386das(map, pc, 0, buf, sizeof buf)) < 0)
184 				break;
185 /*print("%s\n", buf); */
186 			pc += n;
187 			if(strncmp(buf, "PUSHL\t", 6) == 0){
188 				spoff += 4;
189 				if((i = windindex(buf+6)) >= 0)
190 					off[i] = spoff;
191 			}else if(strcmp(buf, "MOVL\tSP,BP") == 0 && spoff == 4 && off[ibp] == 4){
192 				havebp = 1;
193 			}else if(strncmp(buf, "SUBL\t$", 6) == 0){
194 				if((p = strrchr(buf, ',')) && strcmp(p, ",SP") == 0){
195 /*print("spoff %s\n", buf+6); */
196 					spoff += strtol(buf+6, 0, 16);
197 				}
198 				break;
199 			}else if(strncmp(buf, "XORL\t", 5) == 0 || strncmp(buf, "MOVL\t", 5) == 0){
200 				/*
201 				 * Hope these are rescheduled non-prologue instructions
202 				 * like XORL AX, AX or MOVL $0x3, AX and thus ignorable.
203 				 */
204 			}else
205 				break;
206 		}
207 
208 		syscallhack(map, regs, &spoff);
209 
210 		if(havebp){
211 /*print("havebp\n"); */
212 			rget(regs, "BP", &next[isp]);
213 			get4(map, next[isp], &v);
214 			next[ibp] = v;
215 			next[isp] += 4;
216 		}else{
217 			rget(regs, "SP", &next[isp]);
218 /*print("old sp %lux + %d\n", next[isp], spoff); */
219 			next[isp] += spoff;
220 		}
221 		for(i=0; i<nelem(off); i++)
222 			if(off[i] != -1){
223 				get4(map, next[isp]-off[i], &v);
224 				next[i] = v;
225 			}
226 
227 		if(get4(map, next[isp], &v) < 0)
228 			return -1;
229 /*print("new pc %lux => %lux\n", next[isp], v); */
230 		next[ipc] = v;
231 		next[isp] += 4;
232 		return 0;
233 	}
234 
235 	/*
236 	 * Rely on bp chaining
237 	 */
238 	if(rget(regs, "BP", &next[isp]) < 0
239 	|| get4(map, next[isp], &v) < 0)
240 		return -1;
241 	next[ibp] = v;
242 	next[isp] += 4;
243 	if(get4(map, next[isp], &v) < 0)
244 		return -1;
245 	next[ipc] = v;
246 	next[isp] += 4;
247 	return 0;
248 }
249 
250 /*static	char	STARTSYM[] =	"_main"; */
251 /*static	char	PROFSYM[] =	"_mainp"; */
252 static	char	FRAMENAME[] =	".frame";
253 static char *excname[] =
254 {
255 	"divide error",			/* 0 */
256 	"debug exception",		/* 1 */
257 	0,0,				/* 2, 3 */
258 	"overflow",			/* 4 */
259 	"bounds check",			/* 5 */
260 	"invalid opcode",		/* 6 */
261 	"math coprocessor emulation",	/* 7 */
262 	"double fault",			/* 8 */
263 	"math coprocessor overrun",	/* 9 */
264 	"invalid TSS",			/* 10 */
265 	"segment not present",		/* 11 */
266 	"stack exception",		/* 12 */
267 	"general protection violation",	/* 13 */
268 	"page fault",			/* 14 */
269 	0,				/* 15 */
270 	"math coprocessor error",	/* 16 */
271 	0,0,0,0,0,0,0,			/* 17-23 */
272 	"clock",			/* 24 */
273 	"keyboard",			/* 25 */
274 	0,				/* 26 */
275 	"modem status",			/* 27 */
276 	"serial line status",		/* 28 */
277 	0,				/* 29 */
278 	"floppy disk",			/* 30 */
279 	0,0,0,0,0,			/* 31-35 */
280 	"mouse",			/* 36 */
281 	"math coprocessor",		/* 37 */
282 	"hard disk",			/* 38 */
283 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */
284 	0,0,0,0,0,0,0,0,0,		/* 55-63 */
285 	"system call",			/* 64 */
286 };
287 
288 char*
i386excep(Map * map,Regs * regs)289 i386excep(Map *map, Regs *regs)
290 {
291 	u64int c;
292 	u64int pc;
293 	static char buf[16];
294 
295 	if(rget(regs, "TRAP", &c) < 0)
296 		return "no trap register";
297 
298 	if(c > 64 || excname[c] == 0) {
299 		if (c == 3) {
300 			if (rget(regs, "PC", &pc) >= 0)
301 			if (get1(map, pc, (uchar*)buf, mach->bpsize) > 0)
302 			if (memcmp(buf, mach->bpinst, mach->bpsize) == 0)
303 				return "breakpoint";
304 		}
305 		sprint(buf, "exception %ld", c);
306 		return buf;
307 	} else
308 		return excname[c];
309 }
310 
311 	/* I386/486 - Disassembler and related functions */
312 
313 /*
314  *  an instruction
315  */
316 typedef struct Instr Instr;
317 struct	Instr
318 {
319 	uchar	mem[1+1+1+1+2+1+1+4+4];		/* raw instruction */
320 	uvlong	addr;		/* address of start of instruction */
321 	int	n;		/* number of bytes in instruction */
322 	char	*prefix;	/* instr prefix */
323 	char	*segment;	/* segment override */
324 	uchar	jumptype;	/* set to the operand type for jump/ret/call */
325 	uchar	amd64;
326 	uchar	rex;		/* REX prefix (or zero) */
327 	char	osize;		/* 'W' or 'L' (or 'Q' on amd64) */
328 	char	asize;		/* address size 'W' or 'L' (or 'Q' or amd64) */
329 	uchar	mod;		/* bits 6-7 of mod r/m field */
330 	uchar	reg;		/* bits 3-5 of mod r/m field */
331 	char	ss;		/* bits 6-7 of SIB */
332 	schar	index;		/* bits 3-5 of SIB */
333 	schar	base;		/* bits 0-2 of SIB */
334 	char	rip;		/* RIP-relative in amd64 mode */
335 	uchar	opre;		/* f2/f3 could introduce media */
336 	short	seg;		/* segment of far address */
337 	uint32	disp;		/* displacement */
338 	uint32 	imm;		/* immediate */
339 	uint32 	imm2;		/* second immediate operand */
340 	uvlong	imm64;		/* big immediate */
341 	char	*curr;		/* fill level in output buffer */
342 	char	*end;		/* end of output buffer */
343 	char	*err;		/* error message */
344 };
345 
346 	/* 386 register (ha!) set */
347 enum{
348 	AX=0,
349 	CX,
350 	DX,
351 	BX,
352 	SP,
353 	BP,
354 	SI,
355 	DI,
356 
357 	/* amd64 */
358 	/* be careful: some unix system headers #define R8, R9, etc */
359 	AMD64_R8,
360 	AMD64_R9,
361 	AMD64_R10,
362 	AMD64_R11,
363 	AMD64_R12,
364 	AMD64_R13,
365 	AMD64_R14,
366 	AMD64_R15
367 };
368 
369 	/* amd64 rex extension byte */
370 enum{
371 	REXW		= 1<<3,	/* =1, 64-bit operand size */
372 	REXR		= 1<<2,	/* extend modrm reg */
373 	REXX		= 1<<1,	/* extend sib index */
374 	REXB		= 1<<0	/* extend modrm r/m, sib base, or opcode reg */
375 };
376 
377 	/* Operand Format codes */
378 /*
379 %A	-	address size register modifier (!asize -> 'E')
380 %C	-	Control register CR0/CR1/CR2
381 %D	-	Debug register DR0/DR1/DR2/DR3/DR6/DR7
382 %I	-	second immediate operand
383 %O	-	Operand size register modifier (!osize -> 'E')
384 %T	-	Test register TR6/TR7
385 %S	-	size code ('W' or 'L')
386 %W	-	Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
387 %d	-	displacement 16-32 bits
388 %e	-	effective address - Mod R/M value
389 %f	-	floating point register F0-F7 - from Mod R/M register
390 %g	-	segment register
391 %i	-	immediate operand 8-32 bits
392 %p	-	PC-relative - signed displacement in immediate field
393 %r	-	Reg from Mod R/M
394 %w	-	Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
395 */
396 
397 typedef struct Optable Optable;
398 struct Optable
399 {
400 	char	operand[2];
401 	void	*proto;		/* actually either (char*) or (Optable*) */
402 };
403 	/* Operand decoding codes */
404 enum {
405 	Ib = 1,			/* 8-bit immediate - (no sign extension)*/
406 	Ibs,			/* 8-bit immediate (sign extended) */
407 	Jbs,			/* 8-bit sign-extended immediate in jump or call */
408 	Iw,			/* 16-bit immediate -> imm */
409 	Iw2,			/* 16-bit immediate -> imm2 */
410 	Iwd,			/* Operand-sized immediate (no sign extension)*/
411 	Iwdq,			/* Operand-sized immediate, possibly 64 bits */
412 	Awd,			/* Address offset */
413 	Iwds,			/* Operand-sized immediate (sign extended) */
414 	RM,			/* Word or int32 R/M field with register (/r) */
415 	RMB,			/* Byte R/M field with register (/r) */
416 	RMOP,			/* Word or int32 R/M field with op code (/digit) */
417 	RMOPB,			/* Byte R/M field with op code (/digit) */
418 	RMR,			/* R/M register only (mod = 11) */
419 	RMM,			/* R/M memory only (mod = 0/1/2) */
420 	Op_R0,			/* Base reg of Mod R/M is literal 0x00 */
421 	Op_R1,			/* Base reg of Mod R/M is literal 0x01 */
422 	FRMOP,			/* Floating point R/M field with opcode */
423 	FRMEX,			/* Extended floating point R/M field with opcode */
424 	JUMP,			/* Jump or Call flag - no operand */
425 	RET,			/* Return flag - no operand */
426 	OA,			/* literal 0x0a byte */
427 	PTR,			/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
428 	AUX,			/* Multi-byte op code - Auxiliary table */
429 	AUXMM,			/* multi-byte op code - auxiliary table chosen by prefix */
430 	PRE,			/* Instr Prefix */
431 	OPRE,			/* Instr Prefix or media op extension */
432 	SEG,			/* Segment Prefix */
433 	OPOVER,			/* Operand size override */
434 	ADDOVER,		/* Address size override */
435 };
436 
437 static Optable optab0F00[8]=
438 {
439 [0x00] =	{ 0,0,		"MOVW	LDT,%e" },
440 [0x01] =	{ 0,0,		"MOVW	TR,%e" },
441 [0x02] =	{ 0,0,		"MOVW	%e,LDT" },
442 [0x03] =	{ 0,0,		"MOVW	%e,TR" },
443 [0x04] =	{ 0,0,		"VERR	%e" },
444 [0x05] =	{ 0,0,		"VERW	%e" },
445 };
446 
447 static Optable optab0F01[8]=
448 {
449 [0x00] =	{ 0,0,		"MOVL	GDTR,%e" },
450 [0x01] =	{ 0,0,		"MOVL	IDTR,%e" },
451 [0x02] =	{ 0,0,		"MOVL	%e,GDTR" },
452 [0x03] =	{ 0,0,		"MOVL	%e,IDTR" },
453 [0x04] =	{ 0,0,		"MOVW	MSW,%e" },	/* word */
454 [0x06] =	{ 0,0,		"MOVW	%e,MSW" },	/* word */
455 [0x07] =	{ 0,0,		"INVLPG	%e" },		/* or SWAPGS */
456 };
457 
458 static Optable optab0F01F8[1]=
459 {
460 [0x00] =	{ 0,0,		"SWAPGS" },
461 };
462 
463 /* 0F71 */
464 /* 0F72 */
465 /* 0F73 */
466 
467 static Optable optab0FAE[8]=
468 {
469 [0x00] =	{ 0,0,		"FXSAVE	%e" },
470 [0x01] =	{ 0,0,		"FXRSTOR	%e" },
471 [0x02] =	{ 0,0,		"LDMXCSR	%e" },
472 [0x03] =	{ 0,0,		"STMXCSR	%e" },
473 [0x05] =	{ 0,0,		"LFENCE" },
474 [0x06] =	{ 0,0,		"MFENCE" },
475 [0x07] =	{ 0,0,		"SFENCE" },
476 };
477 
478 /* 0F18 */
479 /* 0F0D */
480 
481 static Optable optab0FBA[8]=
482 {
483 [0x04] =	{ Ib,0,		"BT%S	%i,%e" },
484 [0x05] =	{ Ib,0,		"BTS%S	%i,%e" },
485 [0x06] =	{ Ib,0,		"BTR%S	%i,%e" },
486 [0x07] =	{ Ib,0,		"BTC%S	%i,%e" },
487 };
488 
489 static Optable optab0F0F[256]=
490 {
491 [0x0c] =	{ 0,0,		"PI2FW	%m,%M" },
492 [0x0d] =	{ 0,0,		"PI2L	%m,%M" },
493 [0x1c] =	{ 0,0,		"PF2IW	%m,%M" },
494 [0x1d] =	{ 0,0,		"PF2IL	%m,%M" },
495 [0x8a] =	{ 0,0,		"PFNACC	%m,%M" },
496 [0x8e] =	{ 0,0,		"PFPNACC	%m,%M" },
497 [0x90] =	{ 0,0,		"PFCMPGE	%m,%M" },
498 [0x94] =	{ 0,0,		"PFMIN	%m,%M" },
499 [0x96] =	{ 0,0,		"PFRCP	%m,%M" },
500 [0x97] =	{ 0,0,		"PFRSQRT	%m,%M" },
501 [0x9a] =	{ 0,0,		"PFSUB	%m,%M" },
502 [0x9e] =	{ 0,0,		"PFADD	%m,%M" },
503 [0xa0] =	{ 0,0,		"PFCMPGT	%m,%M" },
504 [0xa4] =	{ 0,0,		"PFMAX	%m,%M" },
505 [0xa6] =	{ 0,0,		"PFRCPIT1	%m,%M" },
506 [0xa7] =	{ 0,0,		"PFRSQIT1	%m,%M" },
507 [0xaa] =	{ 0,0,		"PFSUBR	%m,%M" },
508 [0xae] =	{ 0,0,		"PFACC	%m,%M" },
509 [0xb0] =	{ 0,0,		"PFCMPEQ	%m,%M" },
510 [0xb4] =	{ 0,0,		"PFMUL	%m,%M" },
511 [0xb6] =	{ 0,0,		"PFRCPI2T	%m,%M" },
512 [0xb7] =	{ 0,0,		"PMULHRW	%m,%M" },
513 [0xbb] =	{ 0,0,		"PSWAPL	%m,%M" },
514 };
515 
516 static Optable optab0FC7[8]=
517 {
518 [0x01] =	{ 0,0,		"CMPXCHG8B	%e" },
519 };
520 
521 static Optable optab660F71[8]=
522 {
523 [0x02] =	{ Ib,0,		"PSRLW	%i,%X" },
524 [0x04] =	{ Ib,0,		"PSRAW	%i,%X" },
525 [0x06] =	{ Ib,0,		"PSLLW	%i,%X" },
526 };
527 
528 static Optable optab660F72[8]=
529 {
530 [0x02] =	{ Ib,0,		"PSRLL	%i,%X" },
531 [0x04] =	{ Ib,0,		"PSRAL	%i,%X" },
532 [0x06] =	{ Ib,0,		"PSLLL	%i,%X" },
533 };
534 
535 static Optable optab660F73[8]=
536 {
537 [0x02] =	{ Ib,0,		"PSRLQ	%i,%X" },
538 [0x03] =	{ Ib,0,		"PSRLO	%i,%X" },
539 [0x06] =	{ Ib,0,		"PSLLQ	%i,%X" },
540 [0x07] =	{ Ib,0,		"PSLLO	%i,%X" },
541 };
542 
543 static Optable optab660F[256]=
544 {
545 [0x2B] =	{ RM,0,		"MOVNTPD	%x,%e" },
546 [0x2E] =	{ RM,0,		"UCOMISD	%x,%X" },
547 [0x2F] =	{ RM,0,		"COMISD	%x,%X" },
548 [0x5A] =	{ RM,0,		"CVTPD2PS	%x,%X" },
549 [0x5B] =	{ RM,0,		"CVTPS2PL	%x,%X" },
550 [0x6A] =	{ RM,0,		"PUNPCKHLQ %x,%X" },
551 [0x6B] =	{ RM,0,		"PACKSSLW %x,%X" },
552 [0x6C] =	{ RM,0,		"PUNPCKLQDQ %x,%X" },
553 [0x6D] =	{ RM,0,		"PUNPCKHQDQ %x,%X" },
554 [0x6E] =	{ RM,0,		"MOV%S	%e,%X" },
555 [0x6F] =	{ RM,0,		"MOVO	%x,%X" },		/* MOVDQA */
556 [0x70] =	{ RM,Ib,		"PSHUFL	%i,%x,%X" },
557 [0x71] =	{ RMOP,0,		optab660F71 },
558 [0x72] =	{ RMOP,0,		optab660F72 },
559 [0x73] =	{ RMOP,0,		optab660F73 },
560 [0x7E] =	{ RM,0,		"MOV%S	%X,%e" },
561 [0x7F] =	{ RM,0,		"MOVO	%X,%x" },
562 [0xC4] =	{ RM,Ib,		"PINSRW	%i,%e,%X" },
563 [0xC5] =	{ RMR,Ib,		"PEXTRW	%i,%X,%e" },
564 [0xD4] =	{ RM,0,		"PADDQ	%x,%X" },
565 [0xD5] =	{ RM,0,		"PMULLW	%x,%X" },
566 [0xD6] =	{ RM,0,		"MOVQ	%X,%x" },
567 [0xE6] =	{ RM,0,		"CVTTPD2PL	%x,%X" },
568 [0xE7] =	{ RM,0,		"MOVNTO	%X,%e" },
569 [0xF7] =	{ RM,0,		"MASKMOVOU	%x,%X" },
570 };
571 
572 static Optable optabF20F[256]=
573 {
574 [0x10] =	{ RM,0,		"MOVSD	%x,%X" },
575 [0x11] =	{ RM,0,		"MOVSD	%X,%x" },
576 [0x2A] =	{ RM,0,		"CVTS%S2SD	%e,%X" },
577 [0x2C] =	{ RM,0,		"CVTTSD2S%S	%x,%r" },
578 [0x2D] =	{ RM,0,		"CVTSD2S%S	%x,%r" },
579 [0x5A] =	{ RM,0,		"CVTSD2SS	%x,%X" },
580 [0x6F] =	{ RM,0,		"MOVOU	%x,%X" },
581 [0x70] =	{ RM,Ib,		"PSHUFLW	%i,%x,%X" },
582 [0x7F] =	{ RM,0,		"MOVOU	%X,%x" },
583 [0xD6] =	{ RM,0,		"MOVQOZX	%M,%X" },
584 [0xE6] =	{ RM,0,		"CVTPD2PL	%x,%X" },
585 };
586 
587 static Optable optabF30F[256]=
588 {
589 [0x10] =	{ RM,0,		"MOVSS	%x,%X" },
590 [0x11] =	{ RM,0,		"MOVSS	%X,%x" },
591 [0x2A] =	{ RM,0,		"CVTS%S2SS	%e,%X" },
592 [0x2C] =	{ RM,0,		"CVTTSS2S%S	%x,%r" },
593 [0x2D] =	{ RM,0,		"CVTSS2S%S	%x,%r" },
594 [0x5A] =	{ RM,0,		"CVTSS2SD	%x,%X" },
595 [0x5B] =	{ RM,0,		"CVTTPS2PL	%x,%X" },
596 [0x6F] =	{ RM,0,		"MOVOU	%x,%X" },
597 [0x70] =	{ RM,Ib,		"PSHUFHW	%i,%x,%X" },
598 [0x7E] =	{ RM,0,		"MOVQOZX	%x,%X" },
599 [0x7F] =	{ RM,0,		"MOVOU	%X,%x" },
600 [0xD6] =	{ RM,0,		"MOVQOZX	%m*,%X" },
601 [0xE6] =	{ RM,0,		"CVTPL2PD	%x,%X" },
602 };
603 
604 static Optable optab0F[256]=
605 {
606 [0x00] =	{ RMOP,0,		optab0F00 },
607 [0x01] =	{ RMOP,0,		optab0F01 },
608 [0x02] =	{ RM,0,		"LAR	%e,%r" },
609 [0x03] =	{ RM,0,		"LSL	%e,%r" },
610 [0x05] =	{ 0,0,		"SYSCALL" },
611 [0x06] =	{ 0,0,		"CLTS" },
612 [0x07] =	{ 0,0,		"SYSRET" },
613 [0x08] =	{ 0,0,		"INVD" },
614 [0x09] =	{ 0,0,		"WBINVD" },
615 [0x0B] =	{ 0,0,		"UD2" },
616 [0x0F] =	{ RM,AUX,		optab0F0F },		/* 3DNow! */
617 [0x10] =	{ RM,0,		"MOVU%s	%x,%X" },
618 [0x11] =	{ RM,0,		"MOVU%s	%X,%x" },
619 [0x12] =	{ RM,0,		"MOV[H]L%s	%x,%X" },	/* TO DO: H if source is XMM */
620 [0x13] =	{ RM,0,		"MOVL%s	%X,%e" },
621 [0x14] =	{ RM,0,		"UNPCKL%s	%x,%X" },
622 [0x15] =	{ RM,0,		"UNPCKH%s	%x,%X" },
623 [0x16] =	{ RM,0,		"MOV[L]H%s	%x,%X" },	/* TO DO: L if source is XMM */
624 [0x17] =	{ RM,0,		"MOVH%s	%X,%x" },
625 [0x20] =	{ RMR,0,		"MOVL	%C,%e" },
626 [0x21] =	{ RMR,0,		"MOVL	%D,%e" },
627 [0x22] =	{ RMR,0,		"MOVL	%e,%C" },
628 [0x23] =	{ RMR,0,		"MOVL	%e,%D" },
629 [0x24] =	{ RMR,0,		"MOVL	%T,%e" },
630 [0x26] =	{ RMR,0,		"MOVL	%e,%T" },
631 [0x28] =	{ RM,0,		"MOVA%s	%x,%X" },
632 [0x29] =	{ RM,0,		"MOVA%s	%X,%x" },
633 [0x2A] =	{ RM,0,		"CVTPL2%s	%m*,%X" },
634 [0x2B] =	{ RM,0,		"MOVNT%s	%X,%e" },
635 [0x2C] =	{ RM,0,		"CVTT%s2PL	%x,%M" },
636 [0x2D] =	{ RM,0,		"CVT%s2PL	%x,%M" },
637 [0x2E] =	{ RM,0,		"UCOMISS	%x,%X" },
638 [0x2F] =	{ RM,0,		"COMISS	%x,%X" },
639 [0x30] =	{ 0,0,		"WRMSR" },
640 [0x31] =	{ 0,0,		"RDTSC" },
641 [0x32] =	{ 0,0,		"RDMSR" },
642 [0x33] =	{ 0,0,		"RDPMC" },
643 [0x42] =	{ RM,0,		"CMOVC	%e,%r" },		/* CF */
644 [0x43] =	{ RM,0,		"CMOVNC	%e,%r" },		/* ¬ CF */
645 [0x44] =	{ RM,0,		"CMOVZ	%e,%r" },		/* ZF */
646 [0x45] =	{ RM,0,		"CMOVNZ	%e,%r" },		/* ¬ ZF */
647 [0x46] =	{ RM,0,		"CMOVBE	%e,%r" },		/* CF ∨ ZF */
648 [0x47] =	{ RM,0,		"CMOVA	%e,%r" },		/* ¬CF ∧ ¬ZF */
649 [0x48] =	{ RM,0,		"CMOVS	%e,%r" },		/* SF */
650 [0x49] =	{ RM,0,		"CMOVNS	%e,%r" },		/* ¬ SF */
651 [0x4A] =	{ RM,0,		"CMOVP	%e,%r" },		/* PF */
652 [0x4B] =	{ RM,0,		"CMOVNP	%e,%r" },		/* ¬ PF */
653 [0x4C] =	{ RM,0,		"CMOVLT	%e,%r" },		/* LT ≡ OF ≠ SF */
654 [0x4D] =	{ RM,0,		"CMOVGE	%e,%r" },		/* GE ≡ ZF ∨ SF */
655 [0x4E] =	{ RM,0,		"CMOVLE	%e,%r" },		/* LE ≡ ZF ∨ LT */
656 [0x4F] =	{ RM,0,		"CMOVGT	%e,%r" },		/* GT ≡ ¬ZF ∧ GE */
657 [0x50] =	{ RM,0,		"MOVMSK%s	%X,%r" },	/* TO DO: check */
658 [0x51] =	{ RM,0,		"SQRT%s	%x,%X" },
659 [0x52] =	{ RM,0,		"RSQRT%s	%x,%X" },
660 [0x53] =	{ RM,0,		"RCP%s	%x,%X" },
661 [0x54] =	{ RM,0,		"AND%s	%x,%X" },
662 [0x55] =	{ RM,0,		"ANDN%s	%x,%X" },
663 [0x56] =	{ RM,0,		"OR%s	%x,%X" },		/* TO DO: S/D */
664 [0x57] =	{ RM,0,		"XOR%s	%x,%X" },		/* S/D */
665 [0x58] =	{ RM,0,		"ADD%s	%x,%X" },		/* S/P S/D */
666 [0x59] =	{ RM,0,		"MUL%s	%x,%X" },
667 [0x5A] =	{ RM,0,		"CVTPS2PD	%x,%X" },
668 [0x5B] =	{ RM,0,		"CVTPL2PS	%x,%X" },
669 [0x5C] =	{ RM,0,		"SUB%s	%x,%X" },
670 [0x5D] =	{ RM,0,		"MIN%s	%x,%X" },
671 [0x5E] =	{ RM,0,		"DIV%s	%x,%X" },		/* TO DO: S/P S/D */
672 [0x5F] =	{ RM,0,		"MAX%s	%x,%X" },
673 [0x60] =	{ RM,0,		"PUNPCKLBW %m,%M" },
674 [0x61] =	{ RM,0,		"PUNPCKLWL %m,%M" },
675 [0x62] =	{ RM,0,		"PUNPCKLLQ %m,%M" },
676 [0x63] =	{ RM,0,		"PACKSSWB %m,%M" },
677 [0x64] =	{ RM,0,		"PCMPGTB %m,%M" },
678 [0x65] =	{ RM,0,		"PCMPGTW %m,%M" },
679 [0x66] =	{ RM,0,		"PCMPGTL %m,%M" },
680 [0x67] =	{ RM,0,		"PACKUSWB %m,%M" },
681 [0x68] =	{ RM,0,		"PUNPCKHBW %m,%M" },
682 [0x69] =	{ RM,0,		"PUNPCKHWL %m,%M" },
683 [0x6A] =	{ RM,0,		"PUNPCKHLQ %m,%M" },
684 [0x6B] =	{ RM,0,		"PACKSSLW %m,%M" },
685 [0x6E] =	{ RM,0,		"MOV%S %e,%M" },
686 [0x6F] =	{ RM,0,		"MOVQ %m,%M" },
687 [0x70] =	{ RM,Ib,		"PSHUFW	%i,%m,%M" },
688 [0x74] =	{ RM,0,		"PCMPEQB %m,%M" },
689 [0x75] =	{ RM,0,		"PCMPEQW %m,%M" },
690 [0x76] =	{ RM,0,		"PCMPEQL %m,%M" },
691 [0x77] =	{ 0,0,		"EMMS" },
692 [0x7E] =	{ RM,0,		"MOV%S %M,%e" },
693 [0x7F] =	{ RM,0,		"MOVQ %M,%m" },
694 [0xAE] =	{ RMOP,0,		optab0FAE },
695 [0xAA] =	{ 0,0,		"RSM" },
696 [0xB0] =	{ RM,0,		"CMPXCHGB	%r,%e" },
697 [0xB1] =	{ RM,0,		"CMPXCHG%S	%r,%e" },
698 [0xC0] =	{ RMB,0,		"XADDB	%r,%e" },
699 [0xC1] =	{ RM,0,		"XADD%S	%r,%e" },
700 [0xC2] =	{ RM,Ib,		"CMP%s	%x,%X,%#i" },
701 [0xC3] =	{ RM,0,		"MOVNTI%S	%r,%e" },
702 [0xC6] =	{ RM,Ib,		"SHUF%s	%i,%x,%X" },
703 [0xC8] =	{ 0,0,		"BSWAP	AX" },
704 [0xC9] =	{ 0,0,		"BSWAP	CX" },
705 [0xCA] =	{ 0,0,		"BSWAP	DX" },
706 [0xCB] =	{ 0,0,		"BSWAP	BX" },
707 [0xCC] =	{ 0,0,		"BSWAP	SP" },
708 [0xCD] =	{ 0,0,		"BSWAP	BP" },
709 [0xCE] =	{ 0,0,		"BSWAP	SI" },
710 [0xCF] =	{ 0,0,		"BSWAP	DI" },
711 [0xD1] =	{ RM,0,		"PSRLW %m,%M" },
712 [0xD2] =	{ RM,0,		"PSRLL %m,%M" },
713 [0xD3] =	{ RM,0,		"PSRLQ %m,%M" },
714 [0xD5] =	{ RM,0,		"PMULLW %m,%M" },
715 [0xD6] =	{ RM,0,		"MOVQOZX	%m*,%X" },
716 [0xD7] =	{ RM,0,		"PMOVMSKB %m,%r" },
717 [0xD8] =	{ RM,0,		"PSUBUSB %m,%M" },
718 [0xD9] =	{ RM,0,		"PSUBUSW %m,%M" },
719 [0xDA] =	{ RM,0,		"PMINUB %m,%M" },
720 [0xDB] =	{ RM,0,		"PAND %m,%M" },
721 [0xDC] =	{ RM,0,		"PADDUSB %m,%M" },
722 [0xDD] =	{ RM,0,		"PADDUSW %m,%M" },
723 [0xDE] =	{ RM,0,		"PMAXUB %m,%M" },
724 [0xDF] =	{ RM,0,		"PANDN %m,%M" },
725 [0xE0] =	{ RM,0,		"PAVGB %m,%M" },
726 [0xE1] =	{ RM,0,		"PSRAW %m,%M" },
727 [0xE2] =	{ RM,0,		"PSRAL %m,%M" },
728 [0xE3] =	{ RM,0,		"PAVGW %m,%M" },
729 [0xE4] =	{ RM,0,		"PMULHUW %m,%M" },
730 [0xE5] =	{ RM,0,		"PMULHW %m,%M" },
731 [0xE7] =	{ RM,0,		"MOVNTQ	%M,%e" },
732 [0xE8] =	{ RM,0,		"PSUBSB %m,%M" },
733 [0xE9] =	{ RM,0,		"PSUBSW %m,%M" },
734 [0xEA] =	{ RM,0,		"PMINSW %m,%M" },
735 [0xEB] =	{ RM,0,		"POR %m,%M" },
736 [0xEC] =	{ RM,0,		"PADDSB %m,%M" },
737 [0xED] =	{ RM,0,		"PADDSW %m,%M" },
738 [0xEE] =	{ RM,0,		"PMAXSW %m,%M" },
739 [0xEF] =	{ RM,0,		"PXOR %m,%M" },
740 [0xF1] =	{ RM,0,		"PSLLW %m,%M" },
741 [0xF2] =	{ RM,0,		"PSLLL %m,%M" },
742 [0xF3] =	{ RM,0,		"PSLLQ %m,%M" },
743 [0xF4] =	{ RM,0,		"PMULULQ	%m,%M" },
744 [0xF5] =	{ RM,0,		"PMADDWL %m,%M" },
745 [0xF6] =	{ RM,0,		"PSADBW %m,%M" },
746 [0xF7] =	{ RMR,0,		"MASKMOVQ	%m,%M" },
747 [0xF8] =	{ RM,0,		"PSUBB %m,%M" },
748 [0xF9] =	{ RM,0,		"PSUBW %m,%M" },
749 [0xFA] =	{ RM,0,		"PSUBL %m,%M" },
750 [0xFC] =	{ RM,0,		"PADDB %m,%M" },
751 [0xFD] =	{ RM,0,		"PADDW %m,%M" },
752 [0xFE] =	{ RM,0,		"PADDL %m,%M" },
753 
754 [0x80] =	{ Iwds,0,		"JOS	%p" },
755 [0x81] =	{ Iwds,0,		"JOC	%p" },
756 [0x82] =	{ Iwds,0,		"JCS	%p" },
757 [0x83] =	{ Iwds,0,		"JCC	%p" },
758 [0x84] =	{ Iwds,0,		"JEQ	%p" },
759 [0x85] =	{ Iwds,0,		"JNE	%p" },
760 [0x86] =	{ Iwds,0,		"JLS	%p" },
761 [0x87] =	{ Iwds,0,		"JHI	%p" },
762 [0x88] =	{ Iwds,0,		"JMI	%p" },
763 [0x89] =	{ Iwds,0,		"JPL	%p" },
764 [0x8a] =	{ Iwds,0,		"JPS	%p" },
765 [0x8b] =	{ Iwds,0,		"JPC	%p" },
766 [0x8c] =	{ Iwds,0,		"JLT	%p" },
767 [0x8d] =	{ Iwds,0,		"JGE	%p" },
768 [0x8e] =	{ Iwds,0,		"JLE	%p" },
769 [0x8f] =	{ Iwds,0,		"JGT	%p" },
770 [0x90] =	{ RMB,0,		"SETOS	%e" },
771 [0x91] =	{ RMB,0,		"SETOC	%e" },
772 [0x92] =	{ RMB,0,		"SETCS	%e" },
773 [0x93] =	{ RMB,0,		"SETCC	%e" },
774 [0x94] =	{ RMB,0,		"SETEQ	%e" },
775 [0x95] =	{ RMB,0,		"SETNE	%e" },
776 [0x96] =	{ RMB,0,		"SETLS	%e" },
777 [0x97] =	{ RMB,0,		"SETHI	%e" },
778 [0x98] =	{ RMB,0,		"SETMI	%e" },
779 [0x99] =	{ RMB,0,		"SETPL	%e" },
780 [0x9a] =	{ RMB,0,		"SETPS	%e" },
781 [0x9b] =	{ RMB,0,		"SETPC	%e" },
782 [0x9c] =	{ RMB,0,		"SETLT	%e" },
783 [0x9d] =	{ RMB,0,		"SETGE	%e" },
784 [0x9e] =	{ RMB,0,		"SETLE	%e" },
785 [0x9f] =	{ RMB,0,		"SETGT	%e" },
786 [0xa0] =	{ 0,0,		"PUSHL	FS" },
787 [0xa1] =	{ 0,0,		"POPL	FS" },
788 [0xa2] =	{ 0,0,		"CPUID" },
789 [0xa3] =	{ RM,0,		"BT%S	%r,%e" },
790 [0xa4] =	{ RM,Ib,		"SHLD%S	%r,%i,%e" },
791 [0xa5] =	{ RM,0,		"SHLD%S	%r,CL,%e" },
792 [0xa8] =	{ 0,0,		"PUSHL	GS" },
793 [0xa9] =	{ 0,0,		"POPL	GS" },
794 [0xab] =	{ RM,0,		"BTS%S	%r,%e" },
795 [0xac] =	{ RM,Ib,		"SHRD%S	%r,%i,%e" },
796 [0xad] =	{ RM,0,		"SHRD%S	%r,CL,%e" },
797 [0xaf] =	{ RM,0,		"IMUL%S	%e,%r" },
798 [0xb2] =	{ RMM,0,		"LSS	%e,%r" },
799 [0xb3] =	{ RM,0,		"BTR%S	%r,%e" },
800 [0xb4] =	{ RMM,0,		"LFS	%e,%r" },
801 [0xb5] =	{ RMM,0,		"LGS	%e,%r" },
802 [0xb6] =	{ RMB,0,		"MOVBZX	%e,%R" },
803 [0xb7] =	{ RM,0,		"MOVWZX	%e,%R" },
804 [0xba] =	{ RMOP,0,		optab0FBA },
805 [0xbb] =	{ RM,0,		"BTC%S	%e,%r" },
806 [0xbc] =	{ RM,0,		"BSF%S	%e,%r" },
807 [0xbd] =	{ RM,0,		"BSR%S	%e,%r" },
808 [0xbe] =	{ RMB,0,		"MOVBSX	%e,%R" },
809 [0xbf] =	{ RM,0,		"MOVWSX	%e,%R" },
810 [0xc7] =	{ RMOP,0,		optab0FC7 },
811 };
812 
813 static Optable optab80[8]=
814 {
815 [0x00] =	{ Ib,0,		"ADDB	%i,%e" },
816 [0x01] =	{ Ib,0,		"ORB	%i,%e" },
817 [0x02] =	{ Ib,0,		"ADCB	%i,%e" },
818 [0x03] =	{ Ib,0,		"SBBB	%i,%e" },
819 [0x04] =	{ Ib,0,		"ANDB	%i,%e" },
820 [0x05] =	{ Ib,0,		"SUBB	%i,%e" },
821 [0x06] =	{ Ib,0,		"XORB	%i,%e" },
822 [0x07] =	{ Ib,0,		"CMPB	%e,%i" },
823 };
824 
825 static Optable optab81[8]=
826 {
827 [0x00] =	{ Iwd,0,		"ADD%S	%i,%e" },
828 [0x01] =	{ Iwd,0,		"OR%S	%i,%e" },
829 [0x02] =	{ Iwd,0,		"ADC%S	%i,%e" },
830 [0x03] =	{ Iwd,0,		"SBB%S	%i,%e" },
831 [0x04] =	{ Iwd,0,		"AND%S	%i,%e" },
832 [0x05] =	{ Iwd,0,		"SUB%S	%i,%e" },
833 [0x06] =	{ Iwd,0,		"XOR%S	%i,%e" },
834 [0x07] =	{ Iwd,0,		"CMP%S	%e,%i" },
835 };
836 
837 static Optable optab83[8]=
838 {
839 [0x00] =	{ Ibs,0,		"ADD%S	%i,%e" },
840 [0x01] =	{ Ibs,0,		"OR%S	%i,%e" },
841 [0x02] =	{ Ibs,0,		"ADC%S	%i,%e" },
842 [0x03] =	{ Ibs,0,		"SBB%S	%i,%e" },
843 [0x04] =	{ Ibs,0,		"AND%S	%i,%e" },
844 [0x05] =	{ Ibs,0,		"SUB%S	%i,%e" },
845 [0x06] =	{ Ibs,0,		"XOR%S	%i,%e" },
846 [0x07] =	{ Ibs,0,		"CMP%S	%e,%i" },
847 };
848 
849 static Optable optabC0[8] =
850 {
851 [0x00] =	{ Ib,0,		"ROLB	%i,%e" },
852 [0x01] =	{ Ib,0,		"RORB	%i,%e" },
853 [0x02] =	{ Ib,0,		"RCLB	%i,%e" },
854 [0x03] =	{ Ib,0,		"RCRB	%i,%e" },
855 [0x04] =	{ Ib,0,		"SHLB	%i,%e" },
856 [0x05] =	{ Ib,0,		"SHRB	%i,%e" },
857 [0x07] =	{ Ib,0,		"SARB	%i,%e" },
858 };
859 
860 static Optable optabC1[8] =
861 {
862 [0x00] =	{ Ib,0,		"ROL%S	%i,%e" },
863 [0x01] =	{ Ib,0,		"ROR%S	%i,%e" },
864 [0x02] =	{ Ib,0,		"RCL%S	%i,%e" },
865 [0x03] =	{ Ib,0,		"RCR%S	%i,%e" },
866 [0x04] =	{ Ib,0,		"SHL%S	%i,%e" },
867 [0x05] =	{ Ib,0,		"SHR%S	%i,%e" },
868 [0x07] =	{ Ib,0,		"SAR%S	%i,%e" },
869 };
870 
871 static Optable optabD0[8] =
872 {
873 [0x00] =	{ 0,0,		"ROLB	%e" },
874 [0x01] =	{ 0,0,		"RORB	%e" },
875 [0x02] =	{ 0,0,		"RCLB	%e" },
876 [0x03] =	{ 0,0,		"RCRB	%e" },
877 [0x04] =	{ 0,0,		"SHLB	%e" },
878 [0x05] =	{ 0,0,		"SHRB	%e" },
879 [0x07] =	{ 0,0,		"SARB	%e" },
880 };
881 
882 static Optable optabD1[8] =
883 {
884 [0x00] =	{ 0,0,		"ROL%S	%e" },
885 [0x01] =	{ 0,0,		"ROR%S	%e" },
886 [0x02] =	{ 0,0,		"RCL%S	%e" },
887 [0x03] =	{ 0,0,		"RCR%S	%e" },
888 [0x04] =	{ 0,0,		"SHL%S	%e" },
889 [0x05] =	{ 0,0,		"SHR%S	%e" },
890 [0x07] =	{ 0,0,		"SAR%S	%e" },
891 };
892 
893 static Optable optabD2[8] =
894 {
895 [0x00] =	{ 0,0,		"ROLB	CL,%e" },
896 [0x01] =	{ 0,0,		"RORB	CL,%e" },
897 [0x02] =	{ 0,0,		"RCLB	CL,%e" },
898 [0x03] =	{ 0,0,		"RCRB	CL,%e" },
899 [0x04] =	{ 0,0,		"SHLB	CL,%e" },
900 [0x05] =	{ 0,0,		"SHRB	CL,%e" },
901 [0x07] =	{ 0,0,		"SARB	CL,%e" },
902 };
903 
904 static Optable optabD3[8] =
905 {
906 [0x00] =	{ 0,0,		"ROL%S	CL,%e" },
907 [0x01] =	{ 0,0,		"ROR%S	CL,%e" },
908 [0x02] =	{ 0,0,		"RCL%S	CL,%e" },
909 [0x03] =	{ 0,0,		"RCR%S	CL,%e" },
910 [0x04] =	{ 0,0,		"SHL%S	CL,%e" },
911 [0x05] =	{ 0,0,		"SHR%S	CL,%e" },
912 [0x07] =	{ 0,0,		"SAR%S	CL,%e" },
913 };
914 
915 static Optable optabD8[8+8] =
916 {
917 [0x00] =	{ 0,0,		"FADDF	%e,F0" },
918 [0x01] =	{ 0,0,		"FMULF	%e,F0" },
919 [0x02] =	{ 0,0,		"FCOMF	%e,F0" },
920 [0x03] =	{ 0,0,		"FCOMFP	%e,F0" },
921 [0x04] =	{ 0,0,		"FSUBF	%e,F0" },
922 [0x05] =	{ 0,0,		"FSUBRF	%e,F0" },
923 [0x06] =	{ 0,0,		"FDIVF	%e,F0" },
924 [0x07] =	{ 0,0,		"FDIVRF	%e,F0" },
925 [0x08] =	{ 0,0,		"FADDD	%f,F0" },
926 [0x09] =	{ 0,0,		"FMULD	%f,F0" },
927 [0x0a] =	{ 0,0,		"FCOMD	%f,F0" },
928 [0x0b] =	{ 0,0,		"FCOMPD	%f,F0" },
929 [0x0c] =	{ 0,0,		"FSUBD	%f,F0" },
930 [0x0d] =	{ 0,0,		"FSUBRD	%f,F0" },
931 [0x0e] =	{ 0,0,		"FDIVD	%f,F0" },
932 [0x0f] =	{ 0,0,		"FDIVRD	%f,F0" },
933 };
934 /*
935  *	optabD9 and optabDB use the following encoding:
936  *	if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
937  *	else instruction = optabDx[(modrm&0x3f)+8];
938  *
939  *	the instructions for MOD == 3, follow the 8 instructions
940  *	for the other MOD values stored at the front of the table.
941  */
942 static Optable optabD9[64+8] =
943 {
944 [0x00] =	{ 0,0,		"FMOVF	%e,F0" },
945 [0x02] =	{ 0,0,		"FMOVF	F0,%e" },
946 [0x03] =	{ 0,0,		"FMOVFP	F0,%e" },
947 [0x04] =	{ 0,0,		"FLDENV%S %e" },
948 [0x05] =	{ 0,0,		"FLDCW	%e" },
949 [0x06] =	{ 0,0,		"FSTENV%S %e" },
950 [0x07] =	{ 0,0,		"FSTCW	%e" },
951 [0x08] =	{ 0,0,		"FMOVD	F0,F0" },		/* Mod R/M = 11xx xxxx*/
952 [0x09] =	{ 0,0,		"FMOVD	F1,F0" },
953 [0x0a] =	{ 0,0,		"FMOVD	F2,F0" },
954 [0x0b] =	{ 0,0,		"FMOVD	F3,F0" },
955 [0x0c] =	{ 0,0,		"FMOVD	F4,F0" },
956 [0x0d] =	{ 0,0,		"FMOVD	F5,F0" },
957 [0x0e] =	{ 0,0,		"FMOVD	F6,F0" },
958 [0x0f] =	{ 0,0,		"FMOVD	F7,F0" },
959 [0x10] =	{ 0,0,		"FXCHD	F0,F0" },
960 [0x11] =	{ 0,0,		"FXCHD	F1,F0" },
961 [0x12] =	{ 0,0,		"FXCHD	F2,F0" },
962 [0x13] =	{ 0,0,		"FXCHD	F3,F0" },
963 [0x14] =	{ 0,0,		"FXCHD	F4,F0" },
964 [0x15] =	{ 0,0,		"FXCHD	F5,F0" },
965 [0x16] =	{ 0,0,		"FXCHD	F6,F0" },
966 [0x17] =	{ 0,0,		"FXCHD	F7,F0" },
967 [0x18] =	{ 0,0,		"FNOP" },
968 [0x28] =	{ 0,0,		"FCHS" },
969 [0x29] =	{ 0,0,		"FABS" },
970 [0x2c] =	{ 0,0,		"FTST" },
971 [0x2d] =	{ 0,0,		"FXAM" },
972 [0x30] =	{ 0,0,		"FLD1" },
973 [0x31] =	{ 0,0,		"FLDL2T" },
974 [0x32] =	{ 0,0,		"FLDL2E" },
975 [0x33] =	{ 0,0,		"FLDPI" },
976 [0x34] =	{ 0,0,		"FLDLG2" },
977 [0x35] =	{ 0,0,		"FLDLN2" },
978 [0x36] =	{ 0,0,		"FLDZ" },
979 [0x38] =	{ 0,0,		"F2XM1" },
980 [0x39] =	{ 0,0,		"FYL2X" },
981 [0x3a] =	{ 0,0,		"FPTAN" },
982 [0x3b] =	{ 0,0,		"FPATAN" },
983 [0x3c] =	{ 0,0,		"FXTRACT" },
984 [0x3d] =	{ 0,0,		"FPREM1" },
985 [0x3e] =	{ 0,0,		"FDECSTP" },
986 [0x3f] =	{ 0,0,		"FNCSTP" },
987 [0x40] =	{ 0,0,		"FPREM" },
988 [0x41] =	{ 0,0,		"FYL2XP1" },
989 [0x42] =	{ 0,0,		"FSQRT" },
990 [0x43] =	{ 0,0,		"FSINCOS" },
991 [0x44] =	{ 0,0,		"FRNDINT" },
992 [0x45] =	{ 0,0,		"FSCALE" },
993 [0x46] =	{ 0,0,		"FSIN" },
994 [0x47] =	{ 0,0,		"FCOS" },
995 };
996 
997 static Optable optabDA[8+8] =
998 {
999 [0x00] =	{ 0,0,		"FADDL	%e,F0" },
1000 [0x01] =	{ 0,0,		"FMULL	%e,F0" },
1001 [0x02] =	{ 0,0,		"FCOML	%e,F0" },
1002 [0x03] =	{ 0,0,		"FCOMLP	%e,F0" },
1003 [0x04] =	{ 0,0,		"FSUBL	%e,F0" },
1004 [0x05] =	{ 0,0,		"FSUBRL	%e,F0" },
1005 [0x06] =	{ 0,0,		"FDIVL	%e,F0" },
1006 [0x07] =	{ 0,0,		"FDIVRL	%e,F0" },
1007 [0x08] =	{ 0,0,		"FCMOVCS	%f,F0" },
1008 [0x09] =	{ 0,0,		"FCMOVEQ	%f,F0" },
1009 [0x0a] =	{ 0,0,		"FCMOVLS	%f,F0" },
1010 [0x0b] =	{ 0,0,		"FCMOVUN	%f,F0" },
1011 [0x0d] =	{ Op_R1,0,		"FUCOMPP" },
1012 };
1013 
1014 static Optable optabDB[8+64] =
1015 {
1016 [0x00] =	{ 0,0,		"FMOVL	%e,F0" },
1017 [0x02] =	{ 0,0,		"FMOVL	F0,%e" },
1018 [0x03] =	{ 0,0,		"FMOVLP	F0,%e" },
1019 [0x05] =	{ 0,0,		"FMOVX	%e,F0" },
1020 [0x07] =	{ 0,0,		"FMOVXP	F0,%e" },
1021 [0x08] =	{ 0,0,		"FCMOVCC	F0,F0" },	/* Mod R/M = 11xx xxxx*/
1022 [0x09] =	{ 0,0,		"FCMOVCC	F1,F0" },
1023 [0x0a] =	{ 0,0,		"FCMOVCC	F2,F0" },
1024 [0x0b] =	{ 0,0,		"FCMOVCC	F3,F0" },
1025 [0x0c] =	{ 0,0,		"FCMOVCC	F4,F0" },
1026 [0x0d] =	{ 0,0,		"FCMOVCC	F5,F0" },
1027 [0x0e] =	{ 0,0,		"FCMOVCC	F6,F0" },
1028 [0x0f] =	{ 0,0,		"FCMOVCC	F7,F0" },
1029 [0x10] =	{ 0,0,		"FCMOVNE	F0,F0" },
1030 [0x11] =	{ 0,0,		"FCMOVNE	F1,F0" },
1031 [0x12] =	{ 0,0,		"FCMOVNE	F2,F0" },
1032 [0x13] =	{ 0,0,		"FCMOVNE	F3,F0" },
1033 [0x14] =	{ 0,0,		"FCMOVNE	F4,F0" },
1034 [0x15] =	{ 0,0,		"FCMOVNE	F5,F0" },
1035 [0x16] =	{ 0,0,		"FCMOVNE	F6,F0" },
1036 [0x17] =	{ 0,0,		"FCMOVNE	F7,F0" },
1037 [0x18] =	{ 0,0,		"FCMOVHI	F0,F0" },
1038 [0x19] =	{ 0,0,		"FCMOVHI	F1,F0" },
1039 [0x1a] =	{ 0,0,		"FCMOVHI	F2,F0" },
1040 [0x1b] =	{ 0,0,		"FCMOVHI	F3,F0" },
1041 [0x1c] =	{ 0,0,		"FCMOVHI	F4,F0" },
1042 [0x1d] =	{ 0,0,		"FCMOVHI	F5,F0" },
1043 [0x1e] =	{ 0,0,		"FCMOVHI	F6,F0" },
1044 [0x1f] =	{ 0,0,		"FCMOVHI	F7,F0" },
1045 [0x20] =	{ 0,0,		"FCMOVNU	F0,F0" },
1046 [0x21] =	{ 0,0,		"FCMOVNU	F1,F0" },
1047 [0x22] =	{ 0,0,		"FCMOVNU	F2,F0" },
1048 [0x23] =	{ 0,0,		"FCMOVNU	F3,F0" },
1049 [0x24] =	{ 0,0,		"FCMOVNU	F4,F0" },
1050 [0x25] =	{ 0,0,		"FCMOVNU	F5,F0" },
1051 [0x26] =	{ 0,0,		"FCMOVNU	F6,F0" },
1052 [0x27] =	{ 0,0,		"FCMOVNU	F7,F0" },
1053 [0x2a] =	{ 0,0,		"FCLEX" },
1054 [0x2b] =	{ 0,0,		"FINIT" },
1055 [0x30] =	{ 0,0,		"FUCOMI	F0,F0" },
1056 [0x31] =	{ 0,0,		"FUCOMI	F1,F0" },
1057 [0x32] =	{ 0,0,		"FUCOMI	F2,F0" },
1058 [0x33] =	{ 0,0,		"FUCOMI	F3,F0" },
1059 [0x34] =	{ 0,0,		"FUCOMI	F4,F0" },
1060 [0x35] =	{ 0,0,		"FUCOMI	F5,F0" },
1061 [0x36] =	{ 0,0,		"FUCOMI	F6,F0" },
1062 [0x37] =	{ 0,0,		"FUCOMI	F7,F0" },
1063 [0x38] =	{ 0,0,		"FCOMI	F0,F0" },
1064 [0x39] =	{ 0,0,		"FCOMI	F1,F0" },
1065 [0x3a] =	{ 0,0,		"FCOMI	F2,F0" },
1066 [0x3b] =	{ 0,0,		"FCOMI	F3,F0" },
1067 [0x3c] =	{ 0,0,		"FCOMI	F4,F0" },
1068 [0x3d] =	{ 0,0,		"FCOMI	F5,F0" },
1069 [0x3e] =	{ 0,0,		"FCOMI	F6,F0" },
1070 [0x3f] =	{ 0,0,		"FCOMI	F7,F0" },
1071 };
1072 
1073 static Optable optabDC[8+8] =
1074 {
1075 [0x00] =	{ 0,0,		"FADDD	%e,F0" },
1076 [0x01] =	{ 0,0,		"FMULD	%e,F0" },
1077 [0x02] =	{ 0,0,		"FCOMD	%e,F0" },
1078 [0x03] =	{ 0,0,		"FCOMDP	%e,F0" },
1079 [0x04] =	{ 0,0,		"FSUBD	%e,F0" },
1080 [0x05] =	{ 0,0,		"FSUBRD	%e,F0" },
1081 [0x06] =	{ 0,0,		"FDIVD	%e,F0" },
1082 [0x07] =	{ 0,0,		"FDIVRD	%e,F0" },
1083 [0x08] =	{ 0,0,		"FADDD	F0,%f" },
1084 [0x09] =	{ 0,0,		"FMULD	F0,%f" },
1085 [0x0c] =	{ 0,0,		"FSUBRD	F0,%f" },
1086 [0x0d] =	{ 0,0,		"FSUBD	F0,%f" },
1087 [0x0e] =	{ 0,0,		"FDIVRD	F0,%f" },
1088 [0x0f] =	{ 0,0,		"FDIVD	F0,%f" },
1089 };
1090 
1091 static Optable optabDD[8+8] =
1092 {
1093 [0x00] =	{ 0,0,		"FMOVD	%e,F0" },
1094 [0x02] =	{ 0,0,		"FMOVD	F0,%e" },
1095 [0x03] =	{ 0,0,		"FMOVDP	F0,%e" },
1096 [0x04] =	{ 0,0,		"FRSTOR%S %e" },
1097 [0x06] =	{ 0,0,		"FSAVE%S %e" },
1098 [0x07] =	{ 0,0,		"FSTSW	%e" },
1099 [0x08] =	{ 0,0,		"FFREED	%f" },
1100 [0x0a] =	{ 0,0,		"FMOVD	%f,F0" },
1101 [0x0b] =	{ 0,0,		"FMOVDP	%f,F0" },
1102 [0x0c] =	{ 0,0,		"FUCOMD	%f,F0" },
1103 [0x0d] =	{ 0,0,		"FUCOMDP %f,F0" },
1104 };
1105 
1106 static Optable optabDE[8+8] =
1107 {
1108 [0x00] =	{ 0,0,		"FADDW	%e,F0" },
1109 [0x01] =	{ 0,0,		"FMULW	%e,F0" },
1110 [0x02] =	{ 0,0,		"FCOMW	%e,F0" },
1111 [0x03] =	{ 0,0,		"FCOMWP	%e,F0" },
1112 [0x04] =	{ 0,0,		"FSUBW	%e,F0" },
1113 [0x05] =	{ 0,0,		"FSUBRW	%e,F0" },
1114 [0x06] =	{ 0,0,		"FDIVW	%e,F0" },
1115 [0x07] =	{ 0,0,		"FDIVRW	%e,F0" },
1116 [0x08] =	{ 0,0,		"FADDDP	F0,%f" },
1117 [0x09] =	{ 0,0,		"FMULDP	F0,%f" },
1118 [0x0b] =	{ Op_R1,0,		"FCOMPDP" },
1119 [0x0c] =	{ 0,0,		"FSUBRDP F0,%f" },
1120 [0x0d] =	{ 0,0,		"FSUBDP	F0,%f" },
1121 [0x0e] =	{ 0,0,		"FDIVRDP F0,%f" },
1122 [0x0f] =	{ 0,0,		"FDIVDP	F0,%f" },
1123 };
1124 
1125 static Optable optabDF[8+8] =
1126 {
1127 [0x00] =	{ 0,0,		"FMOVW	%e,F0" },
1128 [0x02] =	{ 0,0,		"FMOVW	F0,%e" },
1129 [0x03] =	{ 0,0,		"FMOVWP	F0,%e" },
1130 [0x04] =	{ 0,0,		"FBLD	%e" },
1131 [0x05] =	{ 0,0,		"FMOVL	%e,F0" },
1132 [0x06] =	{ 0,0,		"FBSTP	%e" },
1133 [0x07] =	{ 0,0,		"FMOVLP	F0,%e" },
1134 [0x0c] =	{ Op_R0,0,		"FSTSW	%OAX" },
1135 [0x0d] =	{ 0,0,		"FUCOMIP	F0,%f" },
1136 [0x0e] =	{ 0,0,		"FCOMIP	F0,%f" },
1137 };
1138 
1139 static Optable optabF6[8] =
1140 {
1141 [0x00] =	{ Ib,0,		"TESTB	%i,%e" },
1142 [0x02] =	{ 0,0,		"NOTB	%e" },
1143 [0x03] =	{ 0,0,		"NEGB	%e" },
1144 [0x04] =	{ 0,0,		"MULB	AL,%e" },
1145 [0x05] =	{ 0,0,		"IMULB	AL,%e" },
1146 [0x06] =	{ 0,0,		"DIVB	AL,%e" },
1147 [0x07] =	{ 0,0,		"IDIVB	AL,%e" },
1148 };
1149 
1150 static Optable optabF7[8] =
1151 {
1152 [0x00] =	{ Iwd,0,		"TEST%S	%i,%e" },
1153 [0x02] =	{ 0,0,		"NOT%S	%e" },
1154 [0x03] =	{ 0,0,		"NEG%S	%e" },
1155 [0x04] =	{ 0,0,		"MUL%S	%OAX,%e" },
1156 [0x05] =	{ 0,0,		"IMUL%S	%OAX,%e" },
1157 [0x06] =	{ 0,0,		"DIV%S	%OAX,%e" },
1158 [0x07] =	{ 0,0,		"IDIV%S	%OAX,%e" },
1159 };
1160 
1161 static Optable optabFE[8] =
1162 {
1163 [0x00] =	{ 0,0,		"INCB	%e" },
1164 [0x01] =	{ 0,0,		"DECB	%e" },
1165 };
1166 
1167 static Optable optabFF[8] =
1168 {
1169 [0x00] =	{ 0,0,		"INC%S	%e" },
1170 [0x01] =	{ 0,0,		"DEC%S	%e" },
1171 [0x02] =	{ JUMP,0,		"CALL*	%e" },
1172 [0x03] =	{ JUMP,0,		"CALLF*	%e" },
1173 [0x04] =	{ JUMP,0,		"JMP*	%e" },
1174 [0x05] =	{ JUMP,0,		"JMPF*	%e" },
1175 [0x06] =	{ 0,0,		"PUSHL	%e" },
1176 };
1177 
1178 static Optable optable[256+2] =
1179 {
1180 [0x00] =	{ RMB,0,		"ADDB	%r,%e" },
1181 [0x01] =	{ RM,0,		"ADD%S	%r,%e" },
1182 [0x02] =	{ RMB,0,		"ADDB	%e,%r" },
1183 [0x03] =	{ RM,0,		"ADD%S	%e,%r" },
1184 [0x04] =	{ Ib,0,		"ADDB	%i,AL" },
1185 [0x05] =	{ Iwd,0,		"ADD%S	%i,%OAX" },
1186 [0x06] =	{ 0,0,		"PUSHL	ES" },
1187 [0x07] =	{ 0,0,		"POPL	ES" },
1188 [0x08] =	{ RMB,0,		"ORB	%r,%e" },
1189 [0x09] =	{ RM,0,		"OR%S	%r,%e" },
1190 [0x0a] =	{ RMB,0,		"ORB	%e,%r" },
1191 [0x0b] =	{ RM,0,		"OR%S	%e,%r" },
1192 [0x0c] =	{ Ib,0,		"ORB	%i,AL" },
1193 [0x0d] =	{ Iwd,0,		"OR%S	%i,%OAX" },
1194 [0x0e] =	{ 0,0,		"PUSHL	CS" },
1195 [0x0f] =	{ AUXMM,0,	optab0F },
1196 [0x10] =	{ RMB,0,		"ADCB	%r,%e" },
1197 [0x11] =	{ RM,0,		"ADC%S	%r,%e" },
1198 [0x12] =	{ RMB,0,		"ADCB	%e,%r" },
1199 [0x13] =	{ RM,0,		"ADC%S	%e,%r" },
1200 [0x14] =	{ Ib,0,		"ADCB	%i,AL" },
1201 [0x15] =	{ Iwd,0,		"ADC%S	%i,%OAX" },
1202 [0x16] =	{ 0,0,		"PUSHL	SS" },
1203 [0x17] =	{ 0,0,		"POPL	SS" },
1204 [0x18] =	{ RMB,0,		"SBBB	%r,%e" },
1205 [0x19] =	{ RM,0,		"SBB%S	%r,%e" },
1206 [0x1a] =	{ RMB,0,		"SBBB	%e,%r" },
1207 [0x1b] =	{ RM,0,		"SBB%S	%e,%r" },
1208 [0x1c] =	{ Ib,0,		"SBBB	%i,AL" },
1209 [0x1d] =	{ Iwd,0,		"SBB%S	%i,%OAX" },
1210 [0x1e] =	{ 0,0,		"PUSHL	DS" },
1211 [0x1f] =	{ 0,0,		"POPL	DS" },
1212 [0x20] =	{ RMB,0,		"ANDB	%r,%e" },
1213 [0x21] =	{ RM,0,		"AND%S	%r,%e" },
1214 [0x22] =	{ RMB,0,		"ANDB	%e,%r" },
1215 [0x23] =	{ RM,0,		"AND%S	%e,%r" },
1216 [0x24] =	{ Ib,0,		"ANDB	%i,AL" },
1217 [0x25] =	{ Iwd,0,		"AND%S	%i,%OAX" },
1218 [0x26] =	{ SEG,0,		"ES:" },
1219 [0x27] =	{ 0,0,		"DAA" },
1220 [0x28] =	{ RMB,0,		"SUBB	%r,%e" },
1221 [0x29] =	{ RM,0,		"SUB%S	%r,%e" },
1222 [0x2a] =	{ RMB,0,		"SUBB	%e,%r" },
1223 [0x2b] =	{ RM,0,		"SUB%S	%e,%r" },
1224 [0x2c] =	{ Ib,0,		"SUBB	%i,AL" },
1225 [0x2d] =	{ Iwd,0,		"SUB%S	%i,%OAX" },
1226 [0x2e] =	{ SEG,0,		"CS:" },
1227 [0x2f] =	{ 0,0,		"DAS" },
1228 [0x30] =	{ RMB,0,		"XORB	%r,%e" },
1229 [0x31] =	{ RM,0,		"XOR%S	%r,%e" },
1230 [0x32] =	{ RMB,0,		"XORB	%e,%r" },
1231 [0x33] =	{ RM,0,		"XOR%S	%e,%r" },
1232 [0x34] =	{ Ib,0,		"XORB	%i,AL" },
1233 [0x35] =	{ Iwd,0,		"XOR%S	%i,%OAX" },
1234 [0x36] =	{ SEG,0,		"SS:" },
1235 [0x37] =	{ 0,0,		"AAA" },
1236 [0x38] =	{ RMB,0,		"CMPB	%r,%e" },
1237 [0x39] =	{ RM,0,		"CMP%S	%r,%e" },
1238 [0x3a] =	{ RMB,0,		"CMPB	%e,%r" },
1239 [0x3b] =	{ RM,0,		"CMP%S	%e,%r" },
1240 [0x3c] =	{ Ib,0,		"CMPB	%i,AL" },
1241 [0x3d] =	{ Iwd,0,		"CMP%S	%i,%OAX" },
1242 [0x3e] =	{ SEG,0,		"DS:" },
1243 [0x3f] =	{ 0,0,		"AAS" },
1244 [0x40] =	{ 0,0,		"INC%S	%OAX" },
1245 [0x41] =	{ 0,0,		"INC%S	%OCX" },
1246 [0x42] =	{ 0,0,		"INC%S	%ODX" },
1247 [0x43] =	{ 0,0,		"INC%S	%OBX" },
1248 [0x44] =	{ 0,0,		"INC%S	%OSP" },
1249 [0x45] =	{ 0,0,		"INC%S	%OBP" },
1250 [0x46] =	{ 0,0,		"INC%S	%OSI" },
1251 [0x47] =	{ 0,0,		"INC%S	%ODI" },
1252 [0x48] =	{ 0,0,		"DEC%S	%OAX" },
1253 [0x49] =	{ 0,0,		"DEC%S	%OCX" },
1254 [0x4a] =	{ 0,0,		"DEC%S	%ODX" },
1255 [0x4b] =	{ 0,0,		"DEC%S	%OBX" },
1256 [0x4c] =	{ 0,0,		"DEC%S	%OSP" },
1257 [0x4d] =	{ 0,0,		"DEC%S	%OBP" },
1258 [0x4e] =	{ 0,0,		"DEC%S	%OSI" },
1259 [0x4f] =	{ 0,0,		"DEC%S	%ODI" },
1260 [0x50] =	{ 0,0,		"PUSH%S	%OAX" },
1261 [0x51] =	{ 0,0,		"PUSH%S	%OCX" },
1262 [0x52] =	{ 0,0,		"PUSH%S	%ODX" },
1263 [0x53] =	{ 0,0,		"PUSH%S	%OBX" },
1264 [0x54] =	{ 0,0,		"PUSH%S	%OSP" },
1265 [0x55] =	{ 0,0,		"PUSH%S	%OBP" },
1266 [0x56] =	{ 0,0,		"PUSH%S	%OSI" },
1267 [0x57] =	{ 0,0,		"PUSH%S	%ODI" },
1268 [0x58] =	{ 0,0,		"POP%S	%OAX" },
1269 [0x59] =	{ 0,0,		"POP%S	%OCX" },
1270 [0x5a] =	{ 0,0,		"POP%S	%ODX" },
1271 [0x5b] =	{ 0,0,		"POP%S	%OBX" },
1272 [0x5c] =	{ 0,0,		"POP%S	%OSP" },
1273 [0x5d] =	{ 0,0,		"POP%S	%OBP" },
1274 [0x5e] =	{ 0,0,		"POP%S	%OSI" },
1275 [0x5f] =	{ 0,0,		"POP%S	%ODI" },
1276 [0x60] =	{ 0,0,		"PUSHA%S" },
1277 [0x61] =	{ 0,0,		"POPA%S" },
1278 [0x62] =	{ RMM,0,		"BOUND	%e,%r" },
1279 [0x63] =	{ RM,0,		"ARPL	%r,%e" },
1280 [0x64] =	{ SEG,0,		"FS:" },
1281 [0x65] =	{ SEG,0,		"GS:" },
1282 [0x66] =	{ OPOVER,0,	"" },
1283 [0x67] =	{ ADDOVER,0,	"" },
1284 [0x68] =	{ Iwd,0,		"PUSH%S	%i" },
1285 [0x69] =	{ RM,Iwd,		"IMUL%S	%e,%i,%r" },
1286 [0x6a] =	{ Ib,0,		"PUSH%S	%i" },
1287 [0x6b] =	{ RM,Ibs,		"IMUL%S	%e,%i,%r" },
1288 [0x6c] =	{ 0,0,		"INSB	DX,(%ODI)" },
1289 [0x6d] =	{ 0,0,		"INS%S	DX,(%ODI)" },
1290 [0x6e] =	{ 0,0,		"OUTSB	(%ASI),DX" },
1291 [0x6f] =	{ 0,0,		"OUTS%S	(%ASI),DX" },
1292 [0x70] =	{ Jbs,0,		"JOS	%p" },
1293 [0x71] =	{ Jbs,0,		"JOC	%p" },
1294 [0x72] =	{ Jbs,0,		"JCS	%p" },
1295 [0x73] =	{ Jbs,0,		"JCC	%p" },
1296 [0x74] =	{ Jbs,0,		"JEQ	%p" },
1297 [0x75] =	{ Jbs,0,		"JNE	%p" },
1298 [0x76] =	{ Jbs,0,		"JLS	%p" },
1299 [0x77] =	{ Jbs,0,		"JHI	%p" },
1300 [0x78] =	{ Jbs,0,		"JMI	%p" },
1301 [0x79] =	{ Jbs,0,		"JPL	%p" },
1302 [0x7a] =	{ Jbs,0,		"JPS	%p" },
1303 [0x7b] =	{ Jbs,0,		"JPC	%p" },
1304 [0x7c] =	{ Jbs,0,		"JLT	%p" },
1305 [0x7d] =	{ Jbs,0,		"JGE	%p" },
1306 [0x7e] =	{ Jbs,0,		"JLE	%p" },
1307 [0x7f] =	{ Jbs,0,		"JGT	%p" },
1308 [0x80] =	{ RMOPB,0,	optab80 },
1309 [0x81] =	{ RMOP,0,		optab81 },
1310 [0x83] =	{ RMOP,0,		optab83 },
1311 [0x84] =	{ RMB,0,		"TESTB	%r,%e" },
1312 [0x85] =	{ RM,0,		"TEST%S	%r,%e" },
1313 [0x86] =	{ RMB,0,		"XCHGB	%r,%e" },
1314 [0x87] =	{ RM,0,		"XCHG%S	%r,%e" },
1315 [0x88] =	{ RMB,0,		"MOVB	%r,%e" },
1316 [0x89] =	{ RM,0,		"MOV%S	%r,%e" },
1317 [0x8a] =	{ RMB,0,		"MOVB	%e,%r" },
1318 [0x8b] =	{ RM,0,		"MOV%S	%e,%r" },
1319 [0x8c] =	{ RM,0,		"MOVW	%g,%e" },
1320 [0x8d] =	{ RM,0,		"LEA%S	%e,%r" },
1321 [0x8e] =	{ RM,0,		"MOVW	%e,%g" },
1322 [0x8f] =	{ RM,0,		"POP%S	%e" },
1323 [0x90] =	{ 0,0,		"NOP" },
1324 [0x91] =	{ 0,0,		"XCHG	%OCX,%OAX" },
1325 [0x92] =	{ 0,0,		"XCHG	%ODX,%OAX" },
1326 [0x93] =	{ 0,0,		"XCHG	%OBX,%OAX" },
1327 [0x94] =	{ 0,0,		"XCHG	%OSP,%OAX" },
1328 [0x95] =	{ 0,0,		"XCHG	%OBP,%OAX" },
1329 [0x96] =	{ 0,0,		"XCHG	%OSI,%OAX" },
1330 [0x97] =	{ 0,0,		"XCHG	%ODI,%OAX" },
1331 [0x98] =	{ 0,0,		"%W" },			/* miserable CBW or CWDE */
1332 [0x99] =	{ 0,0,		"%w" },			/* idiotic CWD or CDQ */
1333 [0x9a] =	{ PTR,0,		"CALL%S	%d" },
1334 [0x9b] =	{ 0,0,		"WAIT" },
1335 [0x9c] =	{ 0,0,		"PUSHF" },
1336 [0x9d] =	{ 0,0,		"POPF" },
1337 [0x9e] =	{ 0,0,		"SAHF" },
1338 [0x9f] =	{ 0,0,		"LAHF" },
1339 [0xa0] =	{ Awd,0,		"MOVB	%i,AL" },
1340 [0xa1] =	{ Awd,0,		"MOV%S	%i,%OAX" },
1341 [0xa2] =	{ Awd,0,		"MOVB	AL,%i" },
1342 [0xa3] =	{ Awd,0,		"MOV%S	%OAX,%i" },
1343 [0xa4] =	{ 0,0,		"MOVSB	(%ASI),(%ADI)" },
1344 [0xa5] =	{ 0,0,		"MOVS%S	(%ASI),(%ADI)" },
1345 [0xa6] =	{ 0,0,		"CMPSB	(%ASI),(%ADI)" },
1346 [0xa7] =	{ 0,0,		"CMPS%S	(%ASI),(%ADI)" },
1347 [0xa8] =	{ Ib,0,		"TESTB	%i,AL" },
1348 [0xa9] =	{ Iwd,0,		"TEST%S	%i,%OAX" },
1349 [0xaa] =	{ 0,0,		"STOSB	AL,(%ADI)" },
1350 [0xab] =	{ 0,0,		"STOS%S	%OAX,(%ADI)" },
1351 [0xac] =	{ 0,0,		"LODSB	(%ASI),AL" },
1352 [0xad] =	{ 0,0,		"LODS%S	(%ASI),%OAX" },
1353 [0xae] =	{ 0,0,		"SCASB	(%ADI),AL" },
1354 [0xaf] =	{ 0,0,		"SCAS%S	(%ADI),%OAX" },
1355 [0xb0] =	{ Ib,0,		"MOVB	%i,AL" },
1356 [0xb1] =	{ Ib,0,		"MOVB	%i,CL" },
1357 [0xb2] =	{ Ib,0,		"MOVB	%i,DL" },
1358 [0xb3] =	{ Ib,0,		"MOVB	%i,BL" },
1359 [0xb4] =	{ Ib,0,		"MOVB	%i,AH" },
1360 [0xb5] =	{ Ib,0,		"MOVB	%i,CH" },
1361 [0xb6] =	{ Ib,0,		"MOVB	%i,DH" },
1362 [0xb7] =	{ Ib,0,		"MOVB	%i,BH" },
1363 [0xb8] =	{ Iwdq,0,		"MOV%S	%i,%OAX" },
1364 [0xb9] =	{ Iwdq,0,		"MOV%S	%i,%OCX" },
1365 [0xba] =	{ Iwdq,0,		"MOV%S	%i,%ODX" },
1366 [0xbb] =	{ Iwdq,0,		"MOV%S	%i,%OBX" },
1367 [0xbc] =	{ Iwdq,0,		"MOV%S	%i,%OSP" },
1368 [0xbd] =	{ Iwdq,0,		"MOV%S	%i,%OBP" },
1369 [0xbe] =	{ Iwdq,0,		"MOV%S	%i,%OSI" },
1370 [0xbf] =	{ Iwdq,0,		"MOV%S	%i,%ODI" },
1371 [0xc0] =	{ RMOPB,0,	optabC0 },
1372 [0xc1] =	{ RMOP,0,		optabC1 },
1373 [0xc2] =	{ Iw,0,		"RET	%i" },
1374 [0xc3] =	{ RET,0,		"RET" },
1375 [0xc4] =	{ RM,0,		"LES	%e,%r" },
1376 [0xc5] =	{ RM,0,		"LDS	%e,%r" },
1377 [0xc6] =	{ RMB,Ib,		"MOVB	%i,%e" },
1378 [0xc7] =	{ RM,Iwd,		"MOV%S	%i,%e" },
1379 [0xc8] =	{ Iw2,Ib,		"ENTER	%i,%I" },		/* loony ENTER */
1380 [0xc9] =	{ RET,0,		"LEAVE" },		/* bizarre LEAVE */
1381 [0xca] =	{ Iw,0,		"RETF	%i" },
1382 [0xcb] =	{ RET,0,		"RETF" },
1383 [0xcc] =	{ 0,0,		"INT	3" },
1384 [0xcd] =	{ Ib,0,		"INTB	%i" },
1385 [0xce] =	{ 0,0,		"INTO" },
1386 [0xcf] =	{ 0,0,		"IRET" },
1387 [0xd0] =	{ RMOPB,0,	optabD0 },
1388 [0xd1] =	{ RMOP,0,		optabD1 },
1389 [0xd2] =	{ RMOPB,0,	optabD2 },
1390 [0xd3] =	{ RMOP,0,		optabD3 },
1391 [0xd4] =	{ OA,0,		"AAM" },
1392 [0xd5] =	{ OA,0,		"AAD" },
1393 [0xd7] =	{ 0,0,		"XLAT" },
1394 [0xd8] =	{ FRMOP,0,	optabD8 },
1395 [0xd9] =	{ FRMEX,0,	optabD9 },
1396 [0xda] =	{ FRMOP,0,	optabDA },
1397 [0xdb] =	{ FRMEX,0,	optabDB },
1398 [0xdc] =	{ FRMOP,0,	optabDC },
1399 [0xdd] =	{ FRMOP,0,	optabDD },
1400 [0xde] =	{ FRMOP,0,	optabDE },
1401 [0xdf] =	{ FRMOP,0,	optabDF },
1402 [0xe0] =	{ Jbs,0,		"LOOPNE	%p" },
1403 [0xe1] =	{ Jbs,0,		"LOOPE	%p" },
1404 [0xe2] =	{ Jbs,0,		"LOOP	%p" },
1405 [0xe3] =	{ Jbs,0,		"JCXZ	%p" },
1406 [0xe4] =	{ Ib,0,		"INB	%i,AL" },
1407 [0xe5] =	{ Ib,0,		"IN%S	%i,%OAX" },
1408 [0xe6] =	{ Ib,0,		"OUTB	AL,%i" },
1409 [0xe7] =	{ Ib,0,		"OUT%S	%OAX,%i" },
1410 [0xe8] =	{ Iwds,0,		"CALL	%p" },
1411 [0xe9] =	{ Iwds,0,		"JMP	%p" },
1412 [0xea] =	{ PTR,0,		"JMP	%d" },
1413 [0xeb] =	{ Jbs,0,		"JMP	%p" },
1414 [0xec] =	{ 0,0,		"INB	DX,AL" },
1415 [0xed] =	{ 0,0,		"IN%S	DX,%OAX" },
1416 [0xee] =	{ 0,0,		"OUTB	AL,DX" },
1417 [0xef] =	{ 0,0,		"OUT%S	%OAX,DX" },
1418 [0xf0] =	{ PRE,0,		"LOCK" },
1419 [0xf2] =	{ OPRE,0,		"REPNE" },
1420 [0xf3] =	{ OPRE,0,		"REP" },
1421 [0xf4] =	{ 0,0,		"HLT" },
1422 [0xf5] =	{ 0,0,		"CMC" },
1423 [0xf6] =	{ RMOPB,0,	optabF6 },
1424 [0xf7] =	{ RMOP,0,		optabF7 },
1425 [0xf8] =	{ 0,0,		"CLC" },
1426 [0xf9] =	{ 0,0,		"STC" },
1427 [0xfa] =	{ 0,0,		"CLI" },
1428 [0xfb] =	{ 0,0,		"STI" },
1429 [0xfc] =	{ 0,0,		"CLD" },
1430 [0xfd] =	{ 0,0,		"STD" },
1431 [0xfe] =	{ RMOPB,0,	optabFE },
1432 [0xff] =	{ RMOP,0,		optabFF },
1433 [0x100] =	{ RM,0,		"MOVLQSX	%e,%r" },
1434 [0x101] =	{ RM,0,		"MOVLQZX	%e,%r" },
1435 };
1436 
1437 /*
1438  *  get a byte of the instruction
1439  */
1440 static int
igetc(Map * map,Instr * ip,uchar * c)1441 igetc(Map *map, Instr *ip, uchar *c)
1442 {
1443 	if(ip->n+1 > sizeof(ip->mem)){
1444 		werrstr("instruction too long");
1445 		return -1;
1446 	}
1447 	if (get1(map, ip->addr+ip->n, c, 1) < 0) {
1448 		werrstr("can't read instruction: %r");
1449 		return -1;
1450 	}
1451 	ip->mem[ip->n++] = *c;
1452 	return 1;
1453 }
1454 
1455 /*
1456  *  get two bytes of the instruction
1457  */
1458 static int
igets(Map * map,Instr * ip,ushort * sp)1459 igets(Map *map, Instr *ip, ushort *sp)
1460 {
1461 	uchar c;
1462 	ushort s;
1463 
1464 	if (igetc(map, ip, &c) < 0)
1465 		return -1;
1466 	s = c;
1467 	if (igetc(map, ip, &c) < 0)
1468 		return -1;
1469 	s |= (c<<8);
1470 	*sp = s;
1471 	return 1;
1472 }
1473 
1474 /*
1475  *  get 4 bytes of the instruction
1476  */
1477 static int
igetl(Map * map,Instr * ip,uint32 * lp)1478 igetl(Map *map, Instr *ip, uint32 *lp)
1479 {
1480 	ushort s;
1481 	int32	l;
1482 
1483 	if (igets(map, ip, &s) < 0)
1484 		return -1;
1485 	l = s;
1486 	if (igets(map, ip, &s) < 0)
1487 		return -1;
1488 	l |= (s<<16);
1489 	*lp = l;
1490 	return 1;
1491 }
1492 
1493 /*
1494  *  get 8 bytes of the instruction
1495  *
1496 static int
1497 igetq(Map *map, Instr *ip, vlong *qp)
1498 {
1499 	uint32	l;
1500 	uvlong q;
1501 
1502 	if (igetl(map, ip, &l) < 0)
1503 		return -1;
1504 	q = l;
1505 	if (igetl(map, ip, &l) < 0)
1506 		return -1;
1507 	q |= ((uvlong)l<<32);
1508 	*qp = q;
1509 	return 1;
1510 }
1511  */
1512 
1513 static int
getdisp(Map * map,Instr * ip,int mod,int rm,int code,int pcrel)1514 getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
1515 {
1516 	uchar c;
1517 	ushort s;
1518 
1519 	if (mod > 2)
1520 		return 1;
1521 	if (mod == 1) {
1522 		if (igetc(map, ip, &c) < 0)
1523 			return -1;
1524 		if (c&0x80)
1525 			ip->disp = c|0xffffff00;
1526 		else
1527 			ip->disp = c&0xff;
1528 	} else if (mod == 2 || rm == code) {
1529 		if (ip->asize == 'E') {
1530 			if (igetl(map, ip, &ip->disp) < 0)
1531 				return -1;
1532 			if (mod == 0)
1533 				ip->rip = pcrel;
1534 		} else {
1535 			if (igets(map, ip, &s) < 0)
1536 				return -1;
1537 			if (s&0x8000)
1538 				ip->disp = s|0xffff0000;
1539 			else
1540 				ip->disp = s;
1541 		}
1542 		if (mod == 0)
1543 			ip->base = -1;
1544 	}
1545 	return 1;
1546 }
1547 
1548 static int
modrm(Map * map,Instr * ip,uchar c)1549 modrm(Map *map, Instr *ip, uchar c)
1550 {
1551 	uchar rm, mod;
1552 
1553 	mod = (c>>6)&3;
1554 	rm = c&7;
1555 	ip->mod = mod;
1556 	ip->base = rm;
1557 	ip->reg = (c>>3)&7;
1558 	ip->rip = 0;
1559 	if (mod == 3)			/* register */
1560 		return 1;
1561 	if (ip->asize == 0) {		/* 16-bit mode */
1562 		switch(rm) {
1563 		case 0:
1564 			ip->base = BX; ip->index = SI;
1565 			break;
1566 		case 1:
1567 			ip->base = BX; ip->index = DI;
1568 			break;
1569 		case 2:
1570 			ip->base = BP; ip->index = SI;
1571 			break;
1572 		case 3:
1573 			ip->base = BP; ip->index = DI;
1574 			break;
1575 		case 4:
1576 			ip->base = SI;
1577 			break;
1578 		case 5:
1579 			ip->base = DI;
1580 			break;
1581 		case 6:
1582 			ip->base = BP;
1583 			break;
1584 		case 7:
1585 			ip->base = BX;
1586 			break;
1587 		default:
1588 			break;
1589 		}
1590 		return getdisp(map, ip, mod, rm, 6, 0);
1591 	}
1592 	if (rm == 4) {	/* scummy sib byte */
1593 		if (igetc(map, ip, &c) < 0)
1594 			return -1;
1595 		ip->ss = (c>>6)&0x03;
1596 		ip->index = (c>>3)&0x07;
1597 		if (ip->index == 4)
1598 			ip->index = -1;
1599 		ip->base = c&0x07;
1600 		return getdisp(map, ip, mod, ip->base, 5, 0);
1601 	}
1602 	return getdisp(map, ip, mod, rm, 5, ip->amd64);
1603 }
1604 
1605 static Optable *
mkinstr(Map * map,Instr * ip,uvlong pc)1606 mkinstr(Map *map, Instr *ip, uvlong pc)
1607 {
1608 	int i, n, norex;
1609 	uchar c;
1610 	ushort s;
1611 	Optable *op, *obase;
1612 	char buf[128];
1613 
1614 	memset(ip, 0, sizeof(*ip));
1615 	norex = 1;
1616 	ip->base = -1;
1617 	ip->index = -1;
1618 //	if(asstype == AI8086)
1619 //		ip->osize = 'W';
1620 //	else {
1621 		ip->osize = 'L';
1622 		ip->asize = 'E';
1623 		ip->amd64 = (machcpu == &machamd64);
1624 		norex = 0;
1625 //	}
1626 	ip->addr = pc;
1627 	if (igetc(map, ip, &c) < 0)
1628 		return 0;
1629 	obase = optable;
1630 newop:
1631 	if(ip->amd64 && !norex){
1632 		if(c >= 0x40 && c <= 0x4f) {
1633 			ip->rex = c;
1634 			if(igetc(map, ip, &c) < 0)
1635 				return 0;
1636 		}
1637 		if(c == 0x63){
1638 			if(ip->rex&REXW)
1639 				op = &obase[0x100];	/* MOVLQSX */
1640 			else
1641 				op = &obase[0x101];	/* MOVLQZX */
1642 			goto hack;
1643 		}
1644 	}
1645 	op = &obase[c];
1646 hack:
1647 	if (op->proto == 0) {
1648 badop:
1649 		n = snprint(buf, sizeof(buf), "opcode: ??");
1650 		for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
1651 			_hexify(buf+n, ip->mem[i], 1);
1652 		strcpy(buf+n, "??");
1653 		werrstr(buf);
1654 		return 0;
1655 	}
1656 	for(i = 0; i < 2 && op->operand[i]; i++) {
1657 		switch(op->operand[i]) {
1658 		case Ib:	/* 8-bit immediate - (no sign extension)*/
1659 			if (igetc(map, ip, &c) < 0)
1660 				return 0;
1661 			ip->imm = c&0xff;
1662 			ip->imm64 = ip->imm;
1663 			break;
1664 		case Jbs:	/* 8-bit jump immediate (sign extended) */
1665 			if (igetc(map, ip, &c) < 0)
1666 				return 0;
1667 			if (c&0x80)
1668 				ip->imm = c|0xffffff00;
1669 			else
1670 				ip->imm = c&0xff;
1671 			ip->imm64 = (int32)ip->imm;
1672 			ip->jumptype = Jbs;
1673 			break;
1674 		case Ibs:	/* 8-bit immediate (sign extended) */
1675 			if (igetc(map, ip, &c) < 0)
1676 				return 0;
1677 			if (c&0x80)
1678 				if (ip->osize == 'L')
1679 					ip->imm = c|0xffffff00;
1680 				else
1681 					ip->imm = c|0xff00;
1682 			else
1683 				ip->imm = c&0xff;
1684 			ip->imm64 = (int32)ip->imm;
1685 			break;
1686 		case Iw:	/* 16-bit immediate -> imm */
1687 			if (igets(map, ip, &s) < 0)
1688 				return 0;
1689 			ip->imm = s&0xffff;
1690 			ip->imm64 = ip->imm;
1691 			ip->jumptype = Iw;
1692 			break;
1693 		case Iw2:	/* 16-bit immediate -> in imm2*/
1694 			if (igets(map, ip, &s) < 0)
1695 				return 0;
1696 			ip->imm2 = s&0xffff;
1697 			break;
1698 		case Iwd:	/* Operand-sized immediate (no sign extension unless 64 bits)*/
1699 			if (ip->osize == 'L') {
1700 				if (igetl(map, ip, &ip->imm) < 0)
1701 					return 0;
1702 				ip->imm64 = ip->imm;
1703 				if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
1704 					ip->imm64 |= (vlong)(~0ULL << 32);
1705 			} else {
1706 				if (igets(map, ip, &s)< 0)
1707 					return 0;
1708 				ip->imm = s&0xffff;
1709 				ip->imm64 = ip->imm;
1710 			}
1711 			break;
1712 		case Iwdq:	/* Operand-sized immediate, possibly big */
1713 			if (ip->osize == 'L') {
1714 				if (igetl(map, ip, &ip->imm) < 0)
1715 					return 0;
1716 				ip->imm64 = ip->imm;
1717 				if (ip->rex & REXW) {
1718 					uint32 l;
1719 					if (igetl(map, ip, &l) < 0)
1720 						return 0;
1721 					ip->imm64 |= (uvlong)l << 32;
1722 				}
1723 			} else {
1724 				if (igets(map, ip, &s)< 0)
1725 					return 0;
1726 				ip->imm = s&0xffff;
1727 			}
1728 			break;
1729 		case Awd:	/* Address-sized immediate (no sign extension)*/
1730 			if (ip->asize == 'E') {
1731 				if (igetl(map, ip, &ip->imm) < 0)
1732 					return 0;
1733 				/* TO DO: REX */
1734 			} else {
1735 				if (igets(map, ip, &s)< 0)
1736 					return 0;
1737 				ip->imm = s&0xffff;
1738 			}
1739 			break;
1740 		case Iwds:	/* Operand-sized immediate (sign extended) */
1741 			if (ip->osize == 'L') {
1742 				if (igetl(map, ip, &ip->imm) < 0)
1743 					return 0;
1744 			} else {
1745 				if (igets(map, ip, &s)< 0)
1746 					return 0;
1747 				if (s&0x8000)
1748 					ip->imm = s|0xffff0000;
1749 				else
1750 					ip->imm = s&0xffff;
1751 			}
1752 			ip->jumptype = Iwds;
1753 			break;
1754 		case OA:	/* literal 0x0a byte */
1755 			if (igetc(map, ip, &c) < 0)
1756 				return 0;
1757 			if (c != 0x0a)
1758 				goto badop;
1759 			break;
1760 		case Op_R0:	/* base register must be R0 */
1761 			if (ip->base != 0)
1762 				goto badop;
1763 			break;
1764 		case Op_R1:	/* base register must be R1 */
1765 			if (ip->base != 1)
1766 				goto badop;
1767 			break;
1768 		case RMB:	/* R/M field with byte register (/r)*/
1769 			if (igetc(map, ip, &c) < 0)
1770 				return 0;
1771 			if (modrm(map, ip, c) < 0)
1772 				return 0;
1773 			ip->osize = 'B';
1774 			break;
1775 		case RM:	/* R/M field with register (/r) */
1776 			if (igetc(map, ip, &c) < 0)
1777 				return 0;
1778 			if (modrm(map, ip, c) < 0)
1779 				return 0;
1780 			break;
1781 		case RMOPB:	/* R/M field with op code (/digit) */
1782 			if (igetc(map, ip, &c) < 0)
1783 				return 0;
1784 			if (modrm(map, ip, c) < 0)
1785 				return 0;
1786 			c = ip->reg;		/* secondary op code */
1787 			obase = (Optable*)op->proto;
1788 			ip->osize = 'B';
1789 			goto newop;
1790 		case RMOP:	/* R/M field with op code (/digit) */
1791 			if (igetc(map, ip, &c) < 0)
1792 				return 0;
1793 			if (modrm(map, ip, c) < 0)
1794 				return 0;
1795 			obase = (Optable*)op->proto;
1796 			if(ip->amd64 && obase == optab0F01 && c == 0xF8)
1797 				return optab0F01F8;
1798 			c = ip->reg;
1799 			goto newop;
1800 		case FRMOP:	/* FP R/M field with op code (/digit) */
1801 			if (igetc(map, ip, &c) < 0)
1802 				return 0;
1803 			if (modrm(map, ip, c) < 0)
1804 				return 0;
1805 			if ((c&0xc0) == 0xc0)
1806 				c = ip->reg+8;		/* 16 entry table */
1807 			else
1808 				c = ip->reg;
1809 			obase = (Optable*)op->proto;
1810 			goto newop;
1811 		case FRMEX:	/* Extended FP R/M field with op code (/digit) */
1812 			if (igetc(map, ip, &c) < 0)
1813 				return 0;
1814 			if (modrm(map, ip, c) < 0)
1815 				return 0;
1816 			if ((c&0xc0) == 0xc0)
1817 				c = (c&0x3f)+8;		/* 64-entry table */
1818 			else
1819 				c = ip->reg;
1820 			obase = (Optable*)op->proto;
1821 			goto newop;
1822 		case RMR:	/* R/M register only (mod = 11) */
1823 			if (igetc(map, ip, &c) < 0)
1824 				return 0;
1825 			if ((c&0xc0) != 0xc0) {
1826 				werrstr("invalid R/M register: %x", c);
1827 				return 0;
1828 			}
1829 			if (modrm(map, ip, c) < 0)
1830 				return 0;
1831 			break;
1832 		case RMM:	/* R/M register only (mod = 11) */
1833 			if (igetc(map, ip, &c) < 0)
1834 				return 0;
1835 			if ((c&0xc0) == 0xc0) {
1836 				werrstr("invalid R/M memory mode: %x", c);
1837 				return 0;
1838 			}
1839 			if (modrm(map, ip, c) < 0)
1840 				return 0;
1841 			break;
1842 		case PTR:	/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
1843 			if (ip->osize == 'L') {
1844 				if (igetl(map, ip, &ip->disp) < 0)
1845 					return 0;
1846 			} else {
1847 				if (igets(map, ip, &s)< 0)
1848 					return 0;
1849 				ip->disp = s&0xffff;
1850 			}
1851 			if (igets(map, ip, (ushort*)&ip->seg) < 0)
1852 				return 0;
1853 			ip->jumptype = PTR;
1854 			break;
1855 		case AUXMM:	/* Multi-byte op code; prefix determines table selection */
1856 			if (igetc(map, ip, &c) < 0)
1857 				return 0;
1858 			obase = (Optable*)op->proto;
1859 			switch (ip->opre) {
1860 			case 0x66:	op = optab660F; break;
1861 			case 0xF2:	op = optabF20F; break;
1862 			case 0xF3:	op = optabF30F; break;
1863 			default:	op = nil; break;
1864 			}
1865 			if(op != nil && op[c].proto != nil)
1866 				obase = op;
1867 			norex = 1;	/* no more rex prefixes */
1868 			/* otherwise the optab entry captures it */
1869 			goto newop;
1870 		case AUX:	/* Multi-byte op code - Auxiliary table */
1871 			obase = (Optable*)op->proto;
1872 			if (igetc(map, ip, &c) < 0)
1873 				return 0;
1874 			goto newop;
1875 		case OPRE:	/* Instr Prefix or media op */
1876 			ip->opre = c;
1877 			/* fall through */
1878 		case PRE:	/* Instr Prefix */
1879 			ip->prefix = (char*)op->proto;
1880 			if (igetc(map, ip, &c) < 0)
1881 				return 0;
1882 			if (ip->opre && c == 0x0F)
1883 				ip->prefix = 0;
1884 			goto newop;
1885 		case SEG:	/* Segment Prefix */
1886 			ip->segment = (char*)op->proto;
1887 			if (igetc(map, ip, &c) < 0)
1888 				return 0;
1889 			goto newop;
1890 		case OPOVER:	/* Operand size override */
1891 			ip->opre = c;
1892 			ip->osize = 'W';
1893 			if (igetc(map, ip, &c) < 0)
1894 				return 0;
1895 			if (c == 0x0F)
1896 				ip->osize = 'L';
1897 			else if (ip->amd64 && (c&0xF0) == 0x40)
1898 				ip->osize = 'Q';
1899 			goto newop;
1900 		case ADDOVER:	/* Address size override */
1901 			ip->asize = 0;
1902 			if (igetc(map, ip, &c) < 0)
1903 				return 0;
1904 			goto newop;
1905 		case JUMP:	/* mark instruction as JUMP or RET */
1906 		case RET:
1907 			ip->jumptype = op->operand[i];
1908 			break;
1909 		default:
1910 			werrstr("bad operand type %d", op->operand[i]);
1911 			return 0;
1912 		}
1913 	}
1914 	return op;
1915 }
1916 
1917 #pragma	varargck	argpos	bprint		2
1918 
1919 static void
bprint(Instr * ip,char * fmt,...)1920 bprint(Instr *ip, char *fmt, ...)
1921 {
1922 	va_list arg;
1923 
1924 	va_start(arg, fmt);
1925 	ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
1926 	va_end(arg);
1927 }
1928 
1929 /*
1930  *  if we want to call 16 bit regs AX,BX,CX,...
1931  *  and 32 bit regs EAX,EBX,ECX,... then
1932  *  change the defs of ANAME and ONAME to:
1933  *  #define	ANAME(ip)	((ip->asize == 'E' ? "E" : "")
1934  *  #define	ONAME(ip)	((ip)->osize == 'L' ? "E" : "")
1935  */
1936 #define	ANAME(ip)	""
1937 #define	ONAME(ip)	""
1938 
1939 static char *reg[] =  {
1940 [AX] =	"AX",
1941 [CX] =	"CX",
1942 [DX] =	"DX",
1943 [BX] =	"BX",
1944 [SP] =	"SP",
1945 [BP] =	"BP",
1946 [SI] =	"SI",
1947 [DI] =	"DI",
1948 
1949 	/* amd64 */
1950 [AMD64_R8] =	"R8",
1951 [AMD64_R9] =	"R9",
1952 [AMD64_R10] =	"R10",
1953 [AMD64_R11] =	"R11",
1954 [AMD64_R12] =	"R12",
1955 [AMD64_R13] =	"R13",
1956 [AMD64_R14] =	"R14",
1957 [AMD64_R15] =	"R15",
1958 };
1959 
1960 static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
1961 static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
1962 	"R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
1963 static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
1964 
1965 static void
plocal(Instr * ip)1966 plocal(Instr *ip)
1967 {
1968 	Symbol s;
1969 	char *name;
1970 	Loc l, li;
1971 
1972 	l.type = LOFFSET;
1973 	l.offset = ip->disp;
1974 	if(ip->base == SP)
1975 		l.reg = "SP";
1976 	else
1977 		l.reg = "BP";
1978 
1979 	li.type = LADDR;
1980 	li.addr = ip->addr;
1981 	if(findsym(li, CTEXT, &s) < 0)
1982 		goto raw;
1983 
1984 	name = nil;
1985 	if(ip->base==SP && lookuplsym(&s, FRAMENAME, &s) >= 0) {
1986 		/* translate stack offset to offset from plan 9 frame pointer*/
1987 		/* XXX not sure how to do this */
1988 	}
1989 
1990 	if(name==nil && findlsym(&s, l, &s) >= 0)
1991 		name = s.name;
1992 
1993 	if(name)
1994 		bprint(ip, "%s+", name);
1995 
1996 raw:
1997 	bprint(ip, "%#lx(%s)", l.offset, l.reg);
1998 /*
1999 	if (s.value > ip->disp) {
2000 		ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
2001 		reg = "(SP)";
2002 	} else {
2003 		offset -= s.value;
2004 		ret = getauto(&s, offset, CPARAM, &s);
2005 		reg = "(FP)";
2006 	}
2007 	if (ret)
2008 		bprint(ip, "%s+", s.name);
2009 	else
2010 		offset = ip->disp;
2011 	bprint(ip, "%ux%s", offset, reg);
2012 */
2013 }
2014 
2015 static int
isjmp(Instr * ip)2016 isjmp(Instr *ip)
2017 {
2018 	switch(ip->jumptype){
2019 	case Iwds:
2020 	case Jbs:
2021 	case JUMP:
2022 		return 1;
2023 	default:
2024 		return 0;
2025 	}
2026 }
2027 
2028 /*
2029  * This is too smart for its own good, but it really is nice
2030  * to have accurate translations when debugging, and it
2031  * helps us identify which code is different in binaries that
2032  * are changed on sources.
2033  */
2034 static int
issymref(Instr * ip,Symbol * s,int32 w,int32 val)2035 issymref(Instr *ip, Symbol *s, int32 w, int32 val)
2036 {
2037 	Symbol next, tmp;
2038 	int32 isstring, size;
2039 
2040 	if (isjmp(ip))
2041 		return 1;
2042 	if (s->class==CTEXT && w==0)
2043 		return 1;
2044 	if (s->class==CDATA) {
2045 		/* use first bss symbol (or "end") rather than edata */
2046 		if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
2047 			if((indexsym(s->index+1, &tmp) && loccmp(&tmp.loc, &s->loc) == 0)
2048 			|| (indexsym(s->index-1, &tmp) && loccmp(&tmp.loc, &s->loc) == 0))
2049 				*s = tmp;
2050 		}
2051 		if (w == 0)
2052 			return 1;
2053 		for (next=*s; next.loc.addr==s->loc.addr; next=tmp)
2054 			if (!indexsym(next.index+1, &tmp))
2055 				break;
2056 		size = next.loc.addr - s->loc.addr;
2057 		if (w >= size)
2058 			return 0;
2059 		if (w > size-w)
2060 			w = size-w;
2061 		/* huge distances are usually wrong except in .string */
2062 		isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
2063 		if (w > 8192 && !isstring)
2064 			return 0;
2065 		/* medium distances are tricky - look for constants */
2066 		/* near powers of two */
2067 		if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
2068 			return 0;
2069 		return 1;
2070 	}
2071 	return 0;
2072 }
2073 
2074 static void
immediate(Instr * ip,vlong val)2075 immediate(Instr *ip, vlong val)
2076 {
2077 	Symbol s;
2078 	long w;
2079 	Loc l;
2080 
2081 	l.type = LADDR;
2082 	l.addr = val;
2083 	if (findsym(l, CANY, &s) >= 0) {		/* TO DO */
2084 		w = val - s.loc.addr;
2085 		if (w < 0)
2086 			w = -w;
2087 		if (issymref(ip, &s, w, val)) {
2088 			if (w)
2089 				bprint(ip, "%s+%#lux(SB)", s.name, w);
2090 			else
2091 				bprint(ip, "%s(SB)", s.name);
2092 			return;
2093 		}
2094 /*
2095 		if (s.class==CDATA && globalsym(&s, s.index+1)) {
2096 			w = s.value - val;
2097 			if (w < 0)
2098 				w = -w;
2099 			if (w < 4096) {
2100 				bprint(ip, "%s-%#lux(SB)", s.name, w);
2101 				return;
2102 			}
2103 		}
2104 */
2105 	}
2106 	if((ip->rex & REXW) == 0)
2107 		bprint(ip, "%lux", (long)val);
2108 	else
2109 		bprint(ip, "%llux", val);
2110 }
2111 
2112 static void
pea(Instr * ip)2113 pea(Instr *ip)
2114 {
2115 	if (ip->mod == 3) {
2116 		if (ip->osize == 'B')
2117 			bprint(ip, (ip->rex & REXB? breg64: breg)[(uchar)ip->base]);
2118 		else if(ip->rex & REXB)
2119 			bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]);
2120 		else
2121 			bprint(ip, "%s%s", ANAME(ip), reg[(uchar)ip->base]);
2122 		return;
2123 	}
2124 	if (ip->segment)
2125 		bprint(ip, ip->segment);
2126 	if (ip->asize == 'E' && ip->base == SP)
2127 		plocal(ip);
2128 	else {
2129 		if (ip->base < 0)
2130 			immediate(ip, ip->disp);
2131 		else {
2132 			bprint(ip, "%ux", ip->disp);
2133 			if(ip->rip)
2134 				bprint(ip, "(RIP)");
2135 			bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
2136 		}
2137 	}
2138 	if (ip->index >= 0)
2139 		bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
2140 }
2141 
2142 static void
prinstr(Instr * ip,char * fmt)2143 prinstr(Instr *ip, char *fmt)
2144 {
2145 	int sharp;
2146 	vlong v;
2147 
2148 	if (ip->prefix)
2149 		bprint(ip, "%s ", ip->prefix);
2150 	for (; *fmt && ip->curr < ip->end; fmt++) {
2151 		if (*fmt != '%'){
2152 			*ip->curr++ = *fmt;
2153 			continue;
2154 		}
2155 		sharp = 0;
2156 		if(*++fmt == '#') {
2157 			sharp = 1;
2158 			++fmt;
2159 		}
2160 		switch(*fmt){
2161 		case '%':
2162 			*ip->curr++ = '%';
2163 			break;
2164 		case 'A':
2165 			bprint(ip, "%s", ANAME(ip));
2166 			break;
2167 		case 'C':
2168 			bprint(ip, "CR%d", ip->reg);
2169 			break;
2170 		case 'D':
2171 			if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
2172 				bprint(ip, "DR%d",ip->reg);
2173 			else
2174 				bprint(ip, "???");
2175 			break;
2176 		case 'I':
2177 			bprint(ip, "$");
2178 			immediate(ip, ip->imm2);
2179 			break;
2180 		case 'O':
2181 			bprint(ip,"%s", ONAME(ip));
2182 			break;
2183 		case 'i':
2184 			if(!sharp)
2185 				bprint(ip, "$");
2186 			v = ip->imm;
2187 			if(ip->rex & REXW)
2188 				v = ip->imm64;
2189 			immediate(ip, v);
2190 			break;
2191 		case 'R':
2192 			bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
2193 			break;
2194 		case 'S':
2195 			if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
2196 				bprint(ip, "Q");
2197 			else
2198 				bprint(ip, "%c", ip->osize);
2199 			break;
2200 		case 's':
2201 			if(ip->opre == 0 || ip->opre == 0x66)
2202 				bprint(ip, "P");
2203 			else
2204 				bprint(ip, "S");
2205 			if(ip->opre == 0xf2 || ip->opre == 0x66)
2206 				bprint(ip, "D");
2207 			else
2208 				bprint(ip, "S");
2209 			break;
2210 		case 'T':
2211 			if (ip->reg == 6 || ip->reg == 7)
2212 				bprint(ip, "TR%d",ip->reg);
2213 			else
2214 				bprint(ip, "???");
2215 			break;
2216 		case 'W':
2217 			if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
2218 				bprint(ip, "CDQE");
2219 			else if (ip->osize == 'L')
2220 				bprint(ip,"CWDE");
2221 			else
2222 				bprint(ip, "CBW");
2223 			break;
2224 		case 'd':
2225 			bprint(ip,"%ux:%ux", ip->seg, ip->disp);
2226 			break;
2227 		case 'm':
2228 			if (ip->mod == 3 && ip->osize != 'B') {
2229 				if(fmt[1] != '*'){
2230 					if(ip->opre != 0) {
2231 						bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
2232 						break;
2233 					}
2234 				} else
2235 					fmt++;
2236 				bprint(ip, "M%d", ip->base);
2237 				break;
2238 			}
2239 			pea(ip);
2240 			break;
2241 		case 'e':
2242 			pea(ip);
2243 			break;
2244 		case 'f':
2245 			bprint(ip, "F%d", ip->base);
2246 			break;
2247 		case 'g':
2248 			if (ip->reg < 6)
2249 				bprint(ip,"%s",sreg[ip->reg]);
2250 			else
2251 				bprint(ip,"???");
2252 			break;
2253 		case 'p':
2254 			/*
2255 			 * signed immediate in the uint32 ip->imm.
2256 			 */
2257 			v = (int32)ip->imm;
2258 			immediate(ip, v+ip->addr+ip->n);
2259 			break;
2260 		case 'r':
2261 			if (ip->osize == 'B')
2262 				bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
2263 			else
2264 				bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
2265 			break;
2266 		case 'w':
2267 			if (ip->osize == 'Q' || ip->rex & REXW)
2268 				bprint(ip, "CQO");
2269 			else if (ip->osize == 'L')
2270 				bprint(ip,"CDQ");
2271 			else
2272 				bprint(ip, "CWD");
2273 			break;
2274 		case 'M':
2275 			if(ip->opre != 0)
2276 				bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
2277 			else
2278 				bprint(ip, "M%d", ip->reg);
2279 			break;
2280 		case 'x':
2281 			if (ip->mod == 3 && ip->osize != 'B') {
2282 				bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
2283 				break;
2284 			}
2285 			pea(ip);
2286 			break;
2287 		case 'X':
2288 			bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
2289 			break;
2290 		default:
2291 			bprint(ip, "%%%c", *fmt);
2292 			break;
2293 		}
2294 	}
2295 	*ip->curr = 0;		/* there's always room for 1 byte */
2296 }
2297 
2298 int
i386das(Map * map,uvlong pc,char modifier,char * buf,int n)2299 i386das(Map *map, uvlong pc, char modifier, char *buf, int n)
2300 {
2301 	Instr instr;
2302 	Optable *op;
2303 
2304 	USED(modifier);
2305 	op = mkinstr(map, &instr, pc);
2306 	if (op == 0) {
2307 		errstr(buf, n);
2308 		return -1;
2309 	}
2310 	instr.curr = buf;
2311 	instr.end = buf+n-1;
2312 	prinstr(&instr, op->proto);
2313 	return instr.n;
2314 }
2315 
2316 int
i386hexinst(Map * map,u64int pc,char * buf,int n)2317 i386hexinst(Map *map, u64int pc, char *buf, int n)
2318 {
2319 	Instr instr;
2320 	int i;
2321 
2322 	if (mkinstr(map, &instr, pc) == 0) {
2323 		errstr(buf, n);
2324 		return -1;
2325 	}
2326 	for(i = 0; i < instr.n && n > 2; i++) {
2327 		_hexify(buf, instr.mem[i], 1);
2328 		buf += 2;
2329 		n -= 2;
2330 	}
2331 	*buf = 0;
2332 	return instr.n;
2333 }
2334 
2335 int
i386instlen(Map * map,u64int pc)2336 i386instlen(Map *map, u64int pc)
2337 {
2338 	Instr i;
2339 
2340 	if (mkinstr(map, &i, pc))
2341 		return i.n;
2342 	return -1;
2343 }
2344 
2345 int
i386foll(Map * map,Regs * regs,u64int pc,u64int * foll)2346 i386foll(Map *map, Regs *regs, u64int pc, u64int *foll)
2347 {
2348 	Instr i;
2349 	Optable *op;
2350 	ushort s;
2351 	u64int l, addr;
2352 	vlong v;
2353 	int n;
2354 
2355 	op = mkinstr(map, &i, pc);
2356 	if (!op)
2357 		return -1;
2358 
2359 	n = 0;
2360 
2361 	switch(i.jumptype) {
2362 	case RET:		/* RETURN or LEAVE */
2363 	case Iw:		/* RETURN */
2364 		if (strcmp(op->proto, "LEAVE") == 0) {
2365 			if (lgeta(map, regs, locindir("BP", 0), &l) < 0)
2366 				return -1;
2367 		} else if (lgeta(map, regs, locindir(mach->sp, 0), &l) < 0)
2368 			return -1;
2369 		foll[0] = l;
2370 		return 1;
2371 	case Iwds:		/* pc relative JUMP or CALL*/
2372 	case Jbs:		/* pc relative JUMP or CALL */
2373 		v = (int32)i.imm;
2374 		foll[0] = pc+v+i.n;
2375 		n = 1;
2376 		break;
2377 	case PTR:		/* seg:displacement JUMP or CALL */
2378 		foll[0] = (i.seg<<4)+i.disp;
2379 		return 1;
2380 	case JUMP:		/* JUMP or CALL EA */
2381 
2382 		if(i.mod == 3) {
2383 			if (rget(regs, reg[i.rex&REXB? i.base+8: i.base], &foll[0]) < 0)
2384 				return -1;
2385 			return 1;
2386 		}
2387 			/* calculate the effective address */
2388 		addr = i.disp;
2389 		if (i.base >= 0) {
2390 			if (lgeta(map, regs, locindir(reg[i.rex&REXB? i.base+8: i.base], 0), &l) < 0)
2391 				return -1;
2392 			addr += l;
2393 		}
2394 		if (i.index >= 0) {
2395 			if (lgeta(map, regs, locindir(reg[i.rex&REXX? i.index+8: i.index], 0), &l) < 0)
2396 				return -1;
2397 			addr += l*(1<<i.ss);
2398 		}
2399 			/* now retrieve a seg:disp value at that address */
2400 		if (get2(map, addr, &s) < 0)			/* seg */
2401 			return -1;
2402 		foll[0] = s<<4;
2403 		addr += 2;
2404 		if (i.asize == 'L') {
2405 			if (geta(map, addr, &l) < 0)		/* disp32 */
2406 				return -1;
2407 			foll[0] += l;
2408 		} else {					/* disp16 */
2409 			if (get2(map, addr, &s) < 0)
2410 				return -1;
2411 			foll[0] += s;
2412 		}
2413 		return 1;
2414 	default:
2415 		break;
2416 	}
2417 	if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
2418 		return 1;
2419 	foll[n++] = pc+i.n;
2420 	return n;
2421 }
2422